VBA if else doesn't return correct values - vba

Trying to return a L, M, H value based on the values of two inputs. Here is what I have:
If (80 <= x <= 120 And y > 120) Or (x > 120 And y > 120) Or (x > 120 And 80 <= y <= 120) Then
CDI = "H"
ElseIf (x < 80 And y <= 120) Or (x < 120 And y < 80) Then
CDI = "L"
ElseIf (x < 80 And y > 120) Or (80 <= x <= 120 And 80 <= y <= 120) Or (x > 120 And y < 80) Then
CDI = "M"
End If
The values being returned aren't what I need. For example, (0,291) returns H when it should clearly be M. Why?

The conditions with the variable in the middle (even if they are acceptable to the VBA interpreter) are almost certainly not going to produce the result you expect. Change all such conditions to the equivalent of the form:
variable condition constant
Example: Change
80 <= x <= 120
to
x >= 80 and x <= 120

Try this:
If (x >= 80 And x <= 120 And y > 120) Or (x > 120 And y > 120) Or (x > 120 And y >= 80 And y <= 120) Then
CDI = "H"
ElseIf (x < 80 And y <= 120) Or (x < 120 And y < 80) Then
CDI = "L"
ElseIf (x < 80 And y > 120) Or (x >= 80 And x <= 120 And y >= 80 And y <= 120) Or (x > 120 And y < 80) Then
CDI = "M"
End If

Related

Updating constraint set rhs in docplex

I am trying to update the rhs of a constraint iteratively under a while loop in docplex, however, it does not work properly. As I analyze the output text file, while some constraints are updated as I want, others are not.
z_bar is a list consists of y+1 elements and is updated at each iteration. Constraint set I want to change the RHS of consists of (x+1)*(y+1) constraints. z_bar is related to the j indice, however since each constraint involves i and j indices, I have to update all. What do you think I am doing wrong?
Original constraint set:
for i in range(1, x + 1):
for j in range(1, y + 1):
sub_cbd.add_constraint(x_cbd[i, j] <= z_bar[j], ctname='constraint_name{0}{1}'.format(i, j))
Updating constraint set rhs attempt:
for i in range(1, x + 1):
for j in range(1, y + 1):
sub_cbd.get_constraint_by_name('constraint_name{0}{1}'.format(i, j)).rhs = z_bar[j]
For the updated z_bar: [0, 0, 0, 0, 1, 1, 0...0], 15 elements in total, two 1s and 13 0s.
How it looks now:
constraint11: x_1_1 <= 0
constraint12: x_1_2 <= 0
constraint13: x_1_3 <= 0
constraint14: x_1_4 <= 0
constraint15: x_1_5 <= 1
constraint16: x_1_6 <= 1
constraint17: x_1_7 <= 0
constraint18: x_1_8 <= 0
constraint19: x_1_9 <= 0
constraint110: x_1_10 <= 0
constraint111: x_1_11 <= 1
constraint112: x_1_12 <= 1
constraint113: x_1_13 <= 1
constraint114: x_1_14 <= 1
constraint115: x_1_15 <= 1
constraint21: x_2_1 <= 0
constraint22: x_2_2 <= 0
constraint23: x_2_3 <= 0
constraint24: x_2_4 <= 0
constraint25: x_2_5 <= 1
constraint26: x_2_6 <= 1
constraint27: x_2_7 <= 0
constraint28: x_2_8 <= 0
constraint29: x_2_9 <= 0
constraint210: x_2_10 <= 0
constraint211: x_2_11 <= 1
constraint212: x_2_12 <= 1
constraint213: x_2_13 <= 1
constraint214: x_2_14 <= 1
constraint215: x_2_15 <= 1
How it should look:
constraint11: x_1_1 <= 0
constraint12: x_1_2 <= 0
constraint13: x_1_3 <= 0
constraint14: x_1_4 <= 0
constraint15: x_1_5 <= 1
constraint16: x_1_6 <= 1
constraint17: x_1_7 <= 0
constraint18: x_1_8 <= 0
constraint19: x_1_9 <= 0
constraint110: x_1_10 <= 0
constraint111: x_1_11 <= 0
constraint112: x_1_12 <= 0
constraint113: x_1_13 <= 0
constraint114: x_1_14 <= 0
constraint115: x_1_15 <= 0
constraint21: x_2_1 <= 0
constraint22: x_2_2 <= 0
constraint23: x_2_3 <= 0
constraint24: x_2_4 <= 0
constraint25: x_2_5 <= 1
constraint26: x_2_6 <= 1
constraint27: x_2_7 <= 0
constraint28: x_2_8 <= 0
constraint29: x_2_9 <= 0
constraint210: x_2_10 <= 0
constraint211: x_2_11 <= 0
constraint212: x_2_12 <= 0
constraint213: x_2_13 <= 0
constraint214: x_2_14 <= 0
constraint215: x_2_15 <= 0
Full working example in https://github.com/AlexFleischerParis/zoodocplex/blob/master/zooincremental.py
from docplex.mp.model import Model
# original model
mdl = Model(name='buses')
nbbus40 = mdl.integer_var(name='nbBus40')
nbbus30 = mdl.integer_var(name='nbBus30')
mdl.add_constraint(nbbus40*40 + nbbus30*30 >= 300, 'kids')
mdl.minimize(nbbus40*500 + nbbus30*400)
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
#now 350 kids instead of 300
print()
print("now 350 kids instead of 300")
mdl.get_constraint_by_name("kids").rhs=350;
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
# no more than 4 buses 40 seats
print()
print("no more than 4 buses 40 seats")
mdl.get_var_by_name("nbBus40").ub=4
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
#change the objective so that cost for 40 seats is 450
#and remove the limit on the number of buses 40 seats
print()
print("change the objective so that cost for 40 seats is 450")
print("and remove the limit on the number of buses 40 seats ")
mdl.get_var_by_name("nbBus40").ub=1000
mdl.set_objective("min",nbbus40*450 + nbbus30*400);
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
Now let me change this into a loop:
from docplex.mp.model import Model
# original model
mdl = Model(name='buses')
nbbus40 = mdl.integer_var(name='nbBus40')
nbbus30 = mdl.integer_var(name='nbBus30')
for i in range(0,10):
mdl.add_constraint(nbbus40*40 + nbbus30*30*i >= 300+i,'kids'+str(i))
mdl.minimize(nbbus40*500 + nbbus30*400)
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
#now 350 kids instead of 300
for i in range(0,10):
mdl.get_constraint_by_name("kids"+str(i)).rhs=350+i;
mdl.export("zoo.lp")
mdl.solve()
and then in zoo.lp I get
Minimize
obj: 500 nbBus40 + 400 nbBus30
Subject To
kids0: 40 nbBus40 >= 350
kids1: 40 nbBus40 + 30 nbBus30 >= 351
kids2: 40 nbBus40 + 60 nbBus30 >= 352
kids3: 40 nbBus40 + 90 nbBus30 >= 353
kids4: 40 nbBus40 + 120 nbBus30 >= 354
kids5: 40 nbBus40 + 150 nbBus30 >= 355
kids6: 40 nbBus40 + 180 nbBus30 >= 356
kids7: 40 nbBus40 + 210 nbBus30 >= 357
kids8: 40 nbBus40 + 240 nbBus30 >= 358
kids9: 40 nbBus40 + 270 nbBus30 >= 359
Bounds
Generals
nbBus40 nbBus30
End

How to maximise an function in vb.net?

I have a function T which I'm wanting to maximise:
T = (B((A + 1.646) + 0.583 w) + 311)((1 + ((R + 0.553) + 0.0389 x)((D) + 0.0389 y)
with the constraints
w + x + y + z = 25
w >= 0
x >= 0
y >= 0
z >= 0
B, A, R, D are all constants.
How would I go about doing this?

Rounding Non-LinearExpr with google or-tools SAT solver

Using CP-SAT of google or-tools I'm trying to write this constraint:
q >= (50x + 100y + 150z + 200k + 250p + 300v) / (x + y + z + k + p + v)
Where q is a simple integer.
The thing is I need to round the right side of the equation (let's call it expression) as follows:
if(expression < 75) {
expression = 50;
} else if(expression < 125) {
expression = 100;
} else if(expression < 175) {
expression = 150;
} else if(expression < 225) {
expression = 200;
} else if(expression < 275) {
expression = 250;
} else {
expression = 300;
}
So I need to round the expression
(50x + 100y + 150z + 200k + 250p + 300v) / (x + y + z + k + p + v)
So that it gets one of the following values:
{50, 100, 150, 200, 250, 300}
Let's review 2 cases:
Case 1
q = 180 and expression = 176.
Although the condition 180 >= 176 is true, after rounding up 176 to 200 the tested condition should be 180 >= 200 which is false.
So for q = 180 and expression = 176 I would like the condition to return false.
Case 2
q = 210 and expression = 218.
Although the condition 210 >= 218 is false, after rounding down 218 to 200 the tested condition should be 210 >= 200 which is true.
So for q = 210 and expression = 218 I would like the condition to return true.
I got a great answer here for resolving this challenge over a linear expression but now I need to resolve it for a non-linear expression.
Any suggestions?
Let's rephrase
you have an integer variable e with a value between 0 and 300.
You want to round it to the nearest multiple of 50
if you do:
(e div 50) * 50
you will get the max multiple of 50 less or equal to e
(70 / 50) * 50 -> 50
(99 / 50) * 50 -> 50
(102 / 50) * 50 -> 100
To get a round to nearest, you need to add 25 to e before the division
((e + 25) div 50) * 50
Which will do the correct rounding
((70 + 25) / 50) * 50 -> 50
((99 + 25) / 50) * 50 -> 100
((102 + 25) / 50) * 50 -> 100
with the correct or-tools CP-SAT python code:
numerator = model.NewIntVar(...)
model.Add(numerator == 50x + 100y + 150z + 200k + 250p + 300v)
denom = model.NewIntVar(...)
model.Add(denom == 50x + 100y + 150z + 200k + 250p + 300v)
e = model.NewIntVar(0, 300, 'e')
model.AddDivisionEquality(e, numerator, denom)
shifted_e = model.NewIntVar(25, 325, 'shifted_e')
model.Add(shifted_e == e + 25)
multiple_of_fifty = model.NewIntVar(0, 6, 'multiple_of_fifty')
model.AddDivisionEquality(multiple_of_fifty, shifted_e, 50)
result = model.NewIntVar(0, 300, 'result')
model.Add(result = multiple_of_fifty * 50)
if a and b are positive then
a div b >= q
is equivalent to
a >= q * b
now, your example does not specify how to round (nearest or down)
if you want to round down
q * (x + y + z + k + p + v) <= (50x + 100y + 150z + 200k + 250p + 300v)
If you want to round to nearest, you need to add q / 2 in the right place
q * (x + y + z + k + p + v) <= (50x + 100y + 150z + 200k + 250p + 300v + q / 2)
Now, if you want the other direction
a div b <= q
is equivalent to
a <= q * b + q - 1
The rest of the transformation is the same.

algorithm to deal with series of values

With a series with a START, INCREMENT, and MAX:
START = 100
INCREMENT = 30
MAX = 315
e.g. 100, 130, 160, 190, 220, 250, 280, 310
Given an arbitrary number X return:
the values remaining in the series where the first value is >= X
the offset Y (catch up amount needed to get from X to first value of the series).
Example
In:
START = 100
INCREMENT = 30
MAX = 315
X = 210
Out:
Y = 10
S = 220, 250, 280, 310
UPDATE -- From MBo answer:
float max = 315.0;
float inc = 30.0;
float start = 100.0;
float x = 210.0;
float k0 = ceil( (x-start) / inc) ;
float k1 = floor( (max - start) / inc) ;
for (int i=k0; i<=k1; i++)
{
NSLog(#" output: %d: %f", i, start + i * inc);
}
output: 4: 220.000000
output: 5: 250.000000
output: 6: 280.000000
output: 7: 310.000000
MBo integer approach will be nicer.
School math:
Start + k0 * Inc >= X
k0 * Inc >= X - Start
k0 >= (X - Start) / Inc
Programming math:
k0 = Ceil(1.0 * (X - Start) / Inc)
k1 = Floor(1.0 * (Max - Start) / Inc)
for i = k0 to k1 (including both ends)
output Start + i * Inc
Integer math:
k0 = (X - Start + Inc - 1) / Inc //such integer division makes ceiling
k1 = (Max - Start) / Inc //integer division makes flooring
for i = k0 to k1 (including both ends)
output Start + i * Inc
Example:
START = 100
INCREMENT = 30
MAX = 315
X = 210
k0 = Ceil((210 - 100) / 30) = Ceil(3.7) = 4
k1 = Floor((315 - 100) / 30) = Floor(7.2) = 7
first 100 + 4 * 30 = 220
last 100 + 7 * 30 = 310
Solve the inequation
X <= S + K.I <= M
This is equivalent to
K0 = Ceil((X - S) / I) <= K <= Floor((M - S) / I) = K1
and
Y = X - (S + K0.I).
Note that it is possible to have K0 > K1, and there is no solution.

Conditional ELSEIF does not work

Not sure how to solve this. "a" was meant to start from 1 to NumData, but I have deliberately change the start from 44200 to check the ELSEIF. For NumData = 117,350,
I would expect the 3rd ELSEIF to be activated. Instead throughout the whole run, it only step-into the first ELSEIF even though the "a" value does not meet the conditions.
What should I do?
For a = 44200 To NumData 'Int1
If a > 1 Then
If UCase(Trim(Range1(a, 3))) = UCase(Trim(Range1(a - 1, 3))) Then
GoTo Line1 'Next count loop if next Platform name the same
End If
End If
For b = 1 To NumData
lat1 = Range1(a, 5)
lat2 = Range1(b, 5)
long1 = Range1(a, 6)
long2 = Range1(b, 6)
CompRad = Dist(lat1, lat2, long1, long2)
If (CompRad <= Radius And CompRad >= 0) Then
z = CLng(NumData / 8)
If a <= CLng(NumData / 8) Then
For c = 1 To 6
Range2(d, c) = Range1(b, c)
Next c
Acc_Sum2 = Acc_Sum2 + Range2(d, 4)
d = d + 1
ElseIf CLng(NumData / 8) < a <= 2 * CLng(NumData / 8) Then
z = 2 * CLng(NumData / 8)
For c = 1 To 6
Range3(e, c) = Range1(b, c)
Next c
Acc_Sum3 = Acc_Sum3 + Range3(e, 4)
e = e + 1
ElseIf 2 * CLng(NumData / 8) < a <= 3 * CLng(NumData / 8) Then
For c = 1 To 6
Range4(f, c) = Range1(b, c)
Next c
Acc_Sum4 = Acc_Sum4 + Range4(f, 4)
f = f + 1
ElseIf 3 * CLng(NumData / 8) < a <= 4 * CLng(NumData / 8) Then
z = 3 * CLng(NumData / 8)
For c = 1 To 6
Range5(g, c) = Range1(b, c)
Next c
Acc_Sum5 = Acc_Sum5 + Range5(g, 4)
g = g + 1
ElseIf 4 * CLng(NumData / 8) < a <= 5 * CLng(NumData / 8) Then
For c = 1 To 6
Range6(h, c) = Range1(b, c)
Next c
Acc_Sum6 = Acc_Sum6 + Range6(h, 4)
h = h + 1
ElseIf 5 * CLng(NumData / 8) < a <= 6 * CLng(NumData / 8) Then
For c = 1 To 6
Range7(i, c) = Range1(b, c)
Next c
Acc_Sum7 = Acc_Sum7 + Range7(i, 4)
i = i + 1
ElseIf 6 * CLng(NumData / 8) < a <= 7 * CLng(NumData / 8) Then
For c = 1 To 6
Range8(j, c) = Range1(b, c)
Next c
Acc_Sum8 = Acc_Sum8 + Range8(j, 4)
j = j + 1
ElseIf 7 * CLng(NumData / 8) < a <= NumData Then
For c = 1 To 6
Range9(k, c) = Range1(b, c)
Next c
Acc_Sum9 = Acc_Sum9 + Range9(k, 4)
k = k + 1
End If
End If
Next b
Line1:
Next a
Your conditions like:
1 < a <= 10
are always true. First part (1 < a) evaluates to True or False and then it is converted to integer (True = 1, False = 0). Both values are <=10.
You should change thes conditions to:
(1 < a) And (a <= 10)
Brackets are optional, comparison operators have higher precedence.
user3964075 nailed the core issue. I think making the code a little bit more readable will help to filter out other possible trouble areas. Why do you set the value of 'z' and then not use it?
z = CLng(NumData / 8)
Where are the variables d, e, f...; Range2, Range3, Range4...; Acc_Sum2, Acc_Sum3... assigned, and what are they doing? Can each group be replaced by a single variable?
You may also want to create a simple Between function
to clean up a lot of your conditional statements.
Public Function Between(x As Integer, min As Integer, max As Integer) As Boolean
Between = x <= max And x >= min
End Function
Thanks, user3964075 & Carl for your prompt response. It's worked! Carl, the z variable was slotted in when I was trying to figure out the problem. I thought it would be too much to post the whole code. It does require a lot of cleaning up. Appreciate your tips.