Minimum of a variable and a constant in PULP python integer programming - min

I am stuck with a problem in Integer Programming constraint using PULP in python. I have 2 variables x1, x2 and a constant y. How do i write a constraint on x1 = min(x2 ,y1).
I have written below two condition:
x1 < y1;
x1 < x2
But it is giving me x1 = 0 for my problem.
It should take one of the values from x2 and y1
Thanks in advance. Will really appreciate your help.
Code used:
*import pandas as pd
from pulp import *
data = pd.read_csv("Test.csv")
limit = LpVariable("limit",0, 1000, cat='Integer')
sales = LpVariable.dicts("Sales", (i for i in data.index), lowBound=0, cat="Integer")
####### Defining the Problem
prob = pulp.LpProblem("Profit", pulp.LpMaximize)
prob += pulp.lpSum((1-data.loc[i,'Prize']) * sales[i] for i in data.index)
####### Constraints
for idx in data.index:
max_sales = data.loc[idx, 'Sales'] + data.loc[idx, 'Rejec']
prob += sales[idx] <= max_sales
prob += sales[idx] <= limit
###### Getting the output
prob.solve()
for v in prob.variables():
print v.name,v.varValue
print value(prob.objective)
Data Used (try.csv)
enter image description here

Related

Need to plot multiple values over each number of iterations (python help)

I'm trying to plot the multiple values one gets for 'f_12' over a certain number of iterations. It should look something like points with high oscillations when there is low iterations 'N' and then it converges to a rough value of 0.204. I'm getting the correct outputs for 'f_12' but I'm having a really hard time doing the plots. New to python here.
start = time.time()
# looking for F_12 via monte carlo method
# Inputs
# N = number of rays to generate
N = 1000
# w = width of plates
w = 1
# h = vertical seperation of plates
# L = horizontal offset of plates (L=w=h)
L = 1
h = 1
p_points = 100
# counter for number of rays and number of hits
rays = 0
hits = 0
while rays < N:
rays = rays + 1
# random origin of rays along w on surface 1
Rx = random.uniform(0, 1)
Rt = random.uniform(0, 1)
Rph = random.uniform(0, 1)
x1 = Rx * w
# polar and azimuth angles - random ray directions
theta = np.arcsin(np.sqrt(Rt))
phi = 2*np.pi*Rph
# theta = np.arcsin(Rt)
xi = x1 + h*np.tan(theta)*np.cos(phi)
if xi >= L and xi <= (L+w):
hit = 1
else:
hit = 0
hits = hits + hit
gap = N/ p_points
r = rays%gap
if r == 0:
F = hits/ rays
plt.figure(figsize=(8, 4))
plt.plot(N, F, linewidth=2)
plt.xlabel("N - Rays")
plt.ylabel("F_12")
plt.show()
f_12 = hits/ N
print(f"F_12 = {f_12} at N = {N} iterations")
# Grab Currrent Time After Running the Code
end = time.time()
#Subtract Start Time from The End Time
total_time = end - start
f_time = round(total_time)
print(f"Running time = {f_time} seconds")

Maximizing with constraint for number of distinct SKU not greater than X

I'm building a optimization tool using Pulp.
It's purpose is to define which SKU to take and which SKU to leave from each warehouse.
I'm having trouble with the following constraint:
"The maximum of different SKUs selected should not exceed 500"
That is to say, that no matter how many units you take, as long as they do not exceed 500 varieties (different SKUs), its all good.
This is what I've got so far
#simplex
df=pd.read_excel(ruta+"actual/202109.xlsx", nrows=20) #leemos la nueva base del mes
# Create variables and model
x = pulp.LpVariable.dicts("x", df.index, lowBound=0)
mod = pulp.LpProblem("Budget", pulp.LpMaximize)
# Objective function
objvals = {idx: (1.0)*(df['costo_unitario'][idx]) for idx in df.index}
mod += sum([x[idx]*objvals[idx] for idx in df.index])
# Lower and upper bounds:
for idx in df.index:
mod += x[idx] <= df['unidades_sobrestock'][idx]
# Budget sum
mod += sum([x[idx] for idx in df.index]) <= max_uni
# Solve model
mod.solve()
# Output solution
for idx in df.index:
print (str(idx) + " " + str(x[idx].value()))
print ('Objective' + " " + str(pulp.value(mod.objective)))
In the same dataframe, I have a column with the SKU of each particular row df['SKU']
I'm imagining that the constraint should look something like:
for idx in df.index:
mod += df['SKU'].count(distinct) <= 500
but that doesn't seem to work.
Thanks!
You will need a binary variable y[i] to indicate if a SKU is used. In math-like notation:
x[i] ≤ maxx[i]*y[i] (y[i] = 0 ==> x[i] = 0)
sum(i, y[i]) ≤ maxy (limit number of different SKUs)
y[i] ∈ {0,1} (binary variable)
where
maxx[i] = upperbound on x[i]
maxy = limit on number of different SKUs

Can't get dimensions of arrays equal to plot with MatPlotLib

I am trying to create a plot of arrays where one is calculated based on my x-axis calculated in a for loop. I've gone through my code multiple times and tested in between what exactly the lengths are for my arrays, but I can't seem to think of a solution that makes them equal length.
This is the code I have started with:
import numpy as np
import matplotlib.pyplot as plt
a = 1 ;b = 2 ;c = 3; d = 1; e = 2
t0 = 0
t_end = 10
dt = 0.05
t = np.arange(t0, t_end, dt)
n = len(t)
fout = 1
M = 1
Ca = np.zeros(n)
Ca[0] = a; Cb[0] = b
Cc[0] = 0;
k1 = 1
def rA(Ca, Cb, Cc, t):
-k1 * Ca**a * Cb**b * dt
return -k1 * Ca**a * Cb**b * dt
while e > 1e-3:
t = np.arange(t0, t_end, dt)
n = len(t)
for i in range(1,n-1):
Ca[i+1] = Ca[i] + rA(Ca[i], Cb[i], Cc[i], t[i])
e = abs((M-Ca[n-1])/M)
M = Ca[n-1]
dt = dt/2
plt.plot(t, Ca)
plt.grid()
plt.show()
Afterwards, I try to calculate a second function for different y-values. Within the for loop I added:
Cb[i+1] = Cb[i] + rB(Ca[i], Cb[i], Cc[i], t[i])
While also defining rB in a similar manner as rA. The error code I received at this point is:
IndexError: index 200 is out of bounds for axis 0 with size 200
I feel like it has to do with the way I'm initializing the arrays for my Ca. To put it in MatLab code, something I'm more familiar with, looks like this in MatLab:
Ca = zeros(1,n)
I have recreated the code I have written here in MatLab and I do receive a plot. So I'm wondering where I am going wrong here?
So I thought my best course of action was to change n to an int by just changing it in the while loop.
but after changing n = len(t) to n = 100 I received the following error message:
ValueError: x and y must have same first dimension, but have shapes (200,) and (400,)
As my previous question was something trivial I just kept on missing out on, I feel like this is the same. But I have spent over an hour looking and trying fixes without succes.

Is there a way to fit a normal curve to points?

As a small project I've made a program the throws nd dice an nt number of times. At each throw it sums the results from the dice and adds it to a list. At the end the data is rappresented with matplot.
import random
from collections import Counter
import matplotlib.pyplot as plt
nd = int(input("Insert number of dice: "))
nt = int(input("Insert number of throws: "))
print(nd, " dice thrown ", nt, " times")
print("Generating sums, please hold....")
c = 0
i = 0
sum = 0
sums = []
while nt >= i :
while nd >= c:
g = random.randint(1, 6)
sum = sum + g
c += 1
sums.append(sum)
i = i+1
c=0
sum = 0
print("Throw ", i, " of ", nt)
sums.sort()
max = max(sums)
min = min(sums)
print("||Maximum result: ", max, " ||Minimum result: ", min)
print("Now ordering results")
f = Counter(sums)
y = list(f.values())
x = list(f.keys())
print("Rappresenting results")
plt.plot(x, y)
plt.xlabel("Risultati")
plt.ylabel("Frequenza")
plt.title("Distribuzione delle somme")
plt.grid(True)
plt.tight_layout()
plt.show()
The resultant graph looks something like this:
I would like to know how to fit a gaussian curve to the points in order to make the graph clearer
The mean and the standard deviation of the sums are the parameters needed for the Gaussian normal. The pdf of a distribution has an area of 1. To scale it to the same size as the histogram, it needs to be multiplied with the number of input values (len(sums)).
Converting the code to work with numpy arrays, makes everything much faster:
import numpy as np
from collections import Counter
import matplotlib.pyplot as plt
from scipy.stats import norm
nd = 10000 # int(input("Insert number of dice: "))
nt = 10000 # int(input("Insert number of throws: "))
print(nd, "dice thrown", nt, "times")
print("Generating sums, please hold....")
sums = np.zeros(nt, dtype=np.int)
for i in range(nt):
sums[i] = np.sum(np.random.randint(1, 7, nd))
sums.sort()
xmax = sums.max()
xmin = sums.min()
print("||Maximum result: ", xmax, " ||Minimum result: ", xmin)
print("Now ordering results")
f = Counter(sums)
y = list(f.values())
x = list(f.keys())
print("Plotting results")
plt.plot(x, y)
mean = sums.mean()
std = sums.std()
xs = np.arange(xmin, xmax + 1)
plt.plot(xs, norm.pdf(xs, mean, std) * len(sums), color='red', alpha=0.7, lw=3)
plt.margins(x=0)
plt.xlim(xmin, xmax)
plt.ylim(ymin=0)
plt.tight_layout()
plt.show()
PS: Here is some code to add to the code of the question, using numpy only for calculating the mean and the standard deviation. (Note that as you use sum as a variable name, you get an error when you try to use Python's sum() function. Therefore, it is highly recommended to avoid naming variables such as sum and max.)
def f(x):
return norm.pdf(x, mean, std) * len(sums)
mean = np.mean(sums)
std = np.std(sums)
xs = range(xmin, xmax+1)
ys = [f(x) for x in xs]
plt.plot(xs, ys, color='red', lw=3)

Calculate the sum of the digits using python [duplicate]

This question already has an answer here:
Competitive Programming Python: Repeated sum of digits Error
(1 answer)
Closed 5 years ago.
I would like to find the sum of the digits using python. when i enter a birth year 1982 the result should be 1+9+8+2 = 20 final total result is 2+0 = 2.
The reason that i am posting this question is i didn't find any simple python solution for this.
This is my code
num = int(input("Enter your birth year: "))
x = num //1000
x1 = (num - x*1000)//100
x2 = (num - x*1000 - x1*100)//10
x3 = num - x*1000 - x1*100 - x2*10
x4 = x+x1+x2+x3
num2 = int(x4)
x6 = num2 //10
x7 = (num2 -x6)//10
print("your birth number is" ,x6+x7)
but i am not getting the correct sum value.
Sum the digits of an integer until the result is a one-digit integer:
def sum_digits(num):
num = str(num)
if len(num) < 2:
return int(num)
else:
return sum_digits(sum([int(dig) for dig in str(num)]))
>> sum_digits(1982)
2
Or a simpler version for the case your number is a year:
def sum_digits(num):
return sum([int(dig) for dig in str(num)])
Just call the function twice
>> sum_digits(sum_digits(1982))
2
Try adding some debug statements to inspect values as your program runs.
num = int(input("Enter your birth year: "))
x = num //1000
x1 = (num - x*1000)//100
x2 = (num - x*1000 - x1*100)//10
x3 = num - x*1000 - x1*100 - x2*10
print (x, x1, x2, x3)
x4 = x+x1+x2+x3
print (x4)
num2 = int(x4)
x6 = num2 //10
x7 = (num2 -x6)//10
print (x6, x7)
print("your birth number is" ,x6+x7)
You'll quickly find your problem.