I'm trying to solve the following using OR tools:
Given the following bags containing different colors of balls:
bag
red
blue
green
black
A
10
5
85
0
B
25
50
25
0
C
0
100
0
0
D
90
5
5
0
E
2
0
98
0
F
0
0
0
100
How many of each type of bag would I need to have an equal number of each color of ball?
For cases like this where there is an exact answer, the following code:
bags= [
[10,5,85,0],
[25,50,25,0],
[0,100,0,0],
[90,5,5,0],
[2,0,98,0],
[0,0,0,100]
]
bags_n = len(bags)
color_n = len(bags[0])
print(f'Bags: {bags_n}')
print(f'Colors: {color_n}')
color_count= [0] * color_n
for c in range(color_n):
for b in bags:
color_count[c]+= b[c]
print(color_count)
print(f'Inital total: {sum(color_count)}')
print(f'Inital equal share: {sum(color_count)//color_n}')
model = cp_model.CpModel()
weights = []
for r in range(bags_n):
weights.append(model.NewIntVar(1,1000,f'Weight of Bag: {r}'))
total = model.NewIntVar(0, 100000, 'total')
model.Add(
sum(flatten(
[[bags[r][c] * weights[r] for r in range(bags_n)] for c in range(color_n)]
)) == total
)
equal = model.NewIntVar(0, 10000, 'equal share')
model.AddDivisionEquality(equal, total, color_n)
for c in range(color_n):
diff_c = model.NewIntVar(0, 1000, 'diff_'+str(c))
model.Add(diff_c == sum([bags[r][c] * weights[r] for r in range(bags_n)]) - equal)
model.AddAbsEquality(0, diff_c)
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print(f'Maximum of objective function: {solver.ObjectiveValue()}\n')
for v in weights:
print(f'{solver.Value(v)}')
print(f'total = {solver.Value(total)}')
print(f'equal share = {solver.Value(equal)}')
else:
print(status)
gives back valid weights:
82
2
70
78
5
79
If I change the setup to something like
bags= [
[50,40,10],
[30,20,50],
[30,30,40],
[30,25,45],
]
The model becomes infeasible, I assume due to the fact that there are no weights that satisfy the AbsEquality for every color.
How can I change this to get me the solution closest to an even distribution even if a perfect solution is infeasable?
Christopher Hamkins' suggestion worked great:
bags= [
[50,40,10],
[30,20,50],
[30,30,40],
[30,25,45],
]
bags_n = len(bags)
color_n = len(bags[0])
print(f'Bags: {bags_n}')
print(f'Colors: {color_n}')
color_count= [0] * color_n
for c in range(color_n):
for b in bags:
color_count[c]+= b[c]
print(color_count)
print(["{0:.0%}".format(c/sum(color_count)) for c in color_count])
model = cp_model.CpModel()
weights = []
for r in range(bags_n):
weights.append(model.NewIntVar(1,500,f'Weight of Bag: {r}'))
max = model.NewIntVar(0,100000000,f'Max')
model.AddMaxEquality(max,
[sum([bags[r][c] * weights[r] for r in range(bags_n)]) for c in range(color_n)]
)
min = model.NewIntVar(0,100000000,f'Min')
model.AddMinEquality(min,
[sum([bags[r][c] * weights[r] for r in range(bags_n)]) for c in range(color_n)]
)
diff = model.NewIntVar(0,100000000,f'Diff')
model.Add(max - min == diff)
model.Minimize(diff)
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print(f'max = {solver.Value(max)}')
print(f'min = {solver.Value(min)}')
print(f'diff = {solver.Value(diff)}')
bag_weights = [0] * bags_n
for i,v in enumerate(weights):
bag_weights[i] = solver.Value(v)
print(f'{solver.Value(v)}')
color_count = [0] * color_n
for c in range(color_n):
for i,b in enumerate(bags):
color_count[c]+= (b[c] * bag_weights[i])
print(color_count)
print(["{0:.0%}".format(c/sum(color_count)) for c in color_count])
else:
print(status)
Related
fd = pd.read_csv('data1.csv', sep=r'\s*,\s*',header=0, encoding='ascii', engine='python')
dv = pd.read_csv('data2.csv', sep=";",header=0, engine='python')
x = fd.iloc[:,1]
print (x)
y = dv.iloc[:,1]
fdmean = x.mean(axis=0)
dvmean = y.mean(axis=0)
multi1list = []
k3list = []
k4list = []
k1list = []
k2list = []
L=-1
i = 0
while i < 97:
x = (fd.iloc[i, 1])
j = i-L
print(j)
y = ( dv.iloc[i-L,1])
print (y)
k1 = x - fdmean
k1list.append(k1)
k2 = y - dvmean
k2list.append(k2)
multi1 = k1*k2
multi1list.append(multi1)
k3 = (x-fdmean)
k3 = k3*2
k3list.append(k3)
k4 = (y-dvmean)
k4 = k4*2
k4list.append(k4)
i = i+1
Summulti = sum(multi1list)
Sumk3 = sum(k3list)
Sumk4 = sum(k4list)
Sumk = Sumk3*Sumk4
Sumk = np.sqrt(Sumk)
r = Summulti/Sumk
print (r)
n = 97 - abs(L)
t = r*(np.sqrt((n-2)/(1-(r**2))))
print (t)
I'm trying to calculate the cross correlation manually after Dawis (1986). I correlated my data with the software Past before and I want to reproduce my results with Python. I have a lot more datasets now so manually correlating them in Past isn't an option any more and I need to use loops. Unfortunately I can't seem to get any plausible results with my code. Can someone spot the error? The t (pvalues) isn't even between 1 and 0.
Thanks a lot!
Disclaimer: It is homework.
I try to implement a k mean cluster function. My problem is the cluster don't converge, it jump between two states. And I don't understand why or can't find the bug in the function.
My data comes from a csv and I push it into a pandas dataframe. I use the pearson correlation coefficient as metric. To calculate the coeffiction the function takes in two list
My only idea what the problem could be is, that the pearson correlation coefficient has negative numbers, so technically it is not a metric.
My code:
def distPearson(para1,para2):
n = len(para1)
p1_med = 0.0
p2_med = 0.0
for i in range(n):
p1_med += para1[i]
p2_med += para2[i]
p1_med = p1_med/n
p2_med = p2_med/n
sum_p1_den = 0.0
sum_p2_den = 0.0
sum_p1p2_num = 0.0
for i in range(n):
delta_p1 = para1[i]-p1_med
delta_p2 = para2[i]-p2_med
sum_p1p2_num += delta_p1*delta_p2
sum_p1_den += delta_p1**2
sum_p2_den += delta_p2**2
den = sqrt(sum_p1_den*sum_p2_den)
if (den == 0):
return 0
return (sum_p1p2_num/den)
def kMeanCluster(data,distance=distPearson,k = 5):
#get range for cluster placement
clusterRanges= [(data.iloc[i].min(),data.iloc[i].max())for i in range(len(data))]
# plase k cluster random
kCluster =[]
for i in range(k):
cluster = [rnd.randint(e[0],e[1]) for e in clusterRanges]
kCluster.append(cluster)
# match data to cluster
cacheMatches = []
for t in range(100):
print("Iter: " + str(t))
bestMatches = []
for e in data.items():
bestmatch = (-1,2)
for i in range(k):
dist = distance(data[e[0]],kCluster[i])
if dist < bestmatch[1]:
bestmatch = (i,dist)
bestMatches.append(bestmatch)
if cacheMatches == bestMatches:
return bestMatches
memberList = [[] for i in range(k)]
for i in range(len(bestMatches)):
memberList[bestMatches[i][0]].append(i)
print("1|" +str(len(memberList[0]))
+ " 2|" +str(len(memberList[1]))
+ " 3|" +str(len(memberList[2]))
+ " 4|" +str(len(memberList[3]))
+ " 5|" +str(len(memberList[4])))
kCluster = []
for i in range(k):
cluster = data[data.columns[memberList[i]]].mean(axis=1).tolist()
kCluster.append(cluster)
cacheMatches = bestMatches
I get the output:
Iter: 0
1|28 2|21 3|17 4|20 5|13
Iter: 1
1|10 2|67 3|8 4|4 5|10
Iter: 2
1|2 2|2 3|11 4|59 5|25
Iter: 3
1|33 2|46 3|12 4|4 5|4
Iter: 4
1|5 2|3 3|9 4|55 5|27
Iter: 5
1|43 2|41 3|10 4|3 5|2
Iter: 6
1|5 2|3 3|5 4|47 5|39
Iter: 7
1|51 2|34 3|10 4|3 5|1
Iter: 8
1|5 2|6 3|2 4|46 5|40
Iter: 9
1|50 2|34 3|12 4|2 5|1
Iter: 10
1|5 2|6 3|2 4|46 5|40
Iter: 11
1|50 2|34 3|12 4|2 5|1
and so on
a = 1541
b = 1575
c = 1512
# I want to ratio the sum of these numbers to 128
total = a + b + c
rounded_a = round(a*128/total) # equals 43
rounded_b = round(b*128/total) # equals 44
rounded_c = round(c*128/total) # equals 42
total_of_rounded = rounded_a + rounded_b + rounded_c # equals 129 NOT 128
# I tried the floor
floor_a = math.floor(a*128/total) # equals 42
floor_b = math.floor(b*128/total) # equals 43
floor_c = math.floor(c*128/total) # equals 41
total_of_floor = floor_a + floor_b + floor_c # equals 126 NOT 128
# The exact values
# a: 42.62057044
# b: 43.56093345
# c: 41,81849611
The question is, how can I reach the total 128?
Note: I should stay at integer, not floating numbers.
Note 2: I can write a correction function which like adding +1 to total but it doesn't seem right to me.
A possibility: round a and b down, then add the missing parts to c.
a = 1541
b = 1575
c = 1512
total = a + b + c # 4628
ra = a * 128 // total
rb = b * 128 // total
rc = (c * 128 + (a * 128)%total + (b*128)%total) // total
print(ra,rb,rc)
# (42, 43, 43)
print(ra+rb+rc)
# 128
This is the way for it:
a = 1541
b = 1575
c = 1512
# I want to ratio the sum of these numbers to 128
total = a + b + c
total_of_round = round((a*128/total)+(b*128/total)+(c*128/total))
print (total_of_round)
Ouput:
128
def compute_qty(self):
prduct = self.env["product.product"]
attribute = self.env["product.attribute.value"]
for line in self.qty_line_id:
stake_meter = line.pipe_size
line_qty = line.pipe_qty
pipe_list = []
qty_list = []
pipe_size_qty_list = []
pipe_size_qty_list_of_list = []
for obj in prduct.search([('product_tmpl_id','=',line.product_id.product_tmpl_id.id),('qty_available','>', 0)]):
for attr in obj.attribute_value_ids.ids:
for name in attribute.search([('id','=', str(attr))]):
pipe_product_size_qty_list = []
if float(str(name.name)) >= line.pipe_size:
pipe_size_qty_list.append(float(str(name.name)))
pipe_size_qty_list.append(obj.qty_available)
pipe_size_qty_list_of_list.append(pipe_size_qty_list)
pipe_size_qty_list = []
pipe_size_qty_list_of_list = sorted(pipe_size_qty_list_of_list)
i = 0
n = line_qty
t = 0
while n !=0 and i < len(pipe_size_qty_list_of_list):
pipe_qty_need = math.floor(float(pipe_size_qty_list_of_list[i][0] / pipe_meter))
if pipe_qty_need == 1 and pipe_size_qty_list_of_list[i][0] > pipe_meter:
if pipe_size_qty_list_of_list[i][1] <= n:
pipe_size = pipe_size_qty_list_of_list[i][0]
pipe_qty = pipe_size_qty_list_of_list[i][1]
pipe_list.append(pipe_size)
qty_list.append(pipe_qty)
if pipe_size_qty_list_of_list[i][1] > n:
pipe_size= pipe_size_qty_list_of_list[i][0]
pipe_qty= n
pipe_list.append(pipe_size)
qty_list.append(pipe_qty)
break
n= n - pipe_qty
t = t + pipe_qty
i += 1
if pipe_qty_need !=1 and pipe_size_qty_list_of_list[i][0] > pipe_meter:
if pipe_qty_need * pipe_size_qty_list_of_list[i][1] <= n:
pipe_size= pipe_size_qty_list_of_list[i][0]
pipe_qty= pipe_size_qty_list_of_list[i][1]
pipe_list.append(pipe_size)
qty_list.append(pipe_qty)
if pipe_qty_need * pipe_size_qty_list_of_list[i][1] > n:
pipe_size= pipe_size_qty_list_of_list[i][0]
pipe_qty=math.ceil(float(n/pipe_qty_need))
pipe_list.append(pipe_size)
qty_list.append(pipe_qty)
break
n= n - pipe_qty
t = t + pipe_qty
i += 1
raise UserError(_("pipe Test list %s")%(qty_list)) #here is the chosen quantity from the suitable size
im going to compute the quantity of possible length of pipe i can use to build a
new object, i had to pick pipes from the stock depends
on the size of the new object, for example:
- suppose i need 5 pipe of size "4.3" meter to build a new object:
- what i realy have in the stock:
- 1 pipe of size 5
- 4 pipe of size 4.1
- 2 pipe of size 4.4
- 10 pipe of size 9
cutting is possible while assembeling is not.
so here i should pick from the available quantity of size >= 4.3 sequentially from the smallest to the largest
until the quatity i need is equal to 5 "the number of needed pipe"
from the exampe above i have to chose the following pipe:
2 of "4.4"
1 of "5"
1 of "9" (here becaue it's sufficeint to produce 2 of (4.3) pipe)
what i actually did is appending pipe's size and quantity in a list of list in the form [[size,qty]] ,sorting and searching on that list.
here is the list:
[[4.4,2],[5,1],[9,10]]
what i should get from that list is the possible size and quantity
[[4.4,2],[5,1][9,1]]
it's work fine but im looking for optimizing my code.
thanks in advance
My script contains a while loop:
import numpy as np
ptf = 200 #profiltiefe
dz = 5
DsD0 = 0.02
D0 = 0.16 #cm2/sec bei 20°C
Ds= D0 * DsD0
eps= 0.3
R= 8.314
Ptot=101300
Te = 20
dt = 120
modellzeit = 86400*3
J=modellzeit/dt
PiA = 0.04
CA = PiA*1000/Ptot
respannual = 10 #t C ha-1 a-1
respmol = respannual/12*10**6/10000/(365*24)
respvol_SI = respmol * R * (Te+273)/(Ptot*3600)
respvol = respvol_SI * 100
I= ptf/dz
S = np.zeros(40)
for i in range(40):
if i <= 4:
S[i] = respvol/(2*4*dz)
if i > 4 and i <= 8:
S[i] = respvol/(4*4*dz)
if i > 8 and i <= 16:
S[i] = respvol/(8*4*dz)
Calt = np.repeat(CA,len(range(int(I+1))))
Cakt = Calt.copy()
res_out = range(1,int(J),1)
Cresult = np.array(Cakt)
faktor = dt*Ds/(dz*dz*eps)
timestep=0
#%%
while timestep <= J:
timestep = timestep+1
for ii in range(int(I)):
if ii == 0:
s1 = Calt[ii+1]
s2 = -3 * Calt[ii]
s3 = 2 * CA
elif ii == int(I-1):
s1 = 0
s2 = -1 * Calt[ii]
s3 = Calt[ii-1]
else:
s1 = Calt[ii+1]
s2 = -2 * Calt[ii]
s3 = Calt[ii-1]
result = Calt[ii]+S[ii]*dt/eps+faktor*(s1+s2+s3)
print(result)
Cakt[ii] = result
Cresult = np.vstack([Cresult,Cakt])
Calt = Cakt.copy()
What is intersting: If I run the complete script print(result) gives me different (and incorrect) values. But if I add all my constants before and run the loop part of the code (shown above) the loop performs well and delivers the output I want.
Any idea why this might happen?
I am on Python 2.7.5 / Mac OS X 10.9.1/ Spyder 2.
You are using python 2.7.5, so division of integers gives integer results. I suspect that is not what you want. For example, the term respannual/12 will be 0, so respmol is 0. Either change your constants to floating point values (e.g. respannual = 10.0), or add from __future__ import division at the top of your script.