Constraint is not respected by or-tools - or-tools

I have this simple CP program:
from ortools.sat.python import cp_model
horizon = 5
model = cp_model.CpModel()
A = model.NewIntVar(1, horizon, 'A')
C = model.NewIntVar(1, horizon, 'C')
D = model.NewIntVar(1, horizon, 'D')
E = model.NewIntVar(1, horizon, 'E')
model.Add(max(A+C+D, A+D+E) > max(A+C+E, C+E+D))
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status in (cp_model.FEASIBLE, cp_model.OPTIMAL):
print('status: ', status)
print('A: ', solver.Value(A))
print('C: ', solver.Value(C))
print('D: ', solver.Value(D))
print('E: ', solver.Value(E))
else:
print('Could not solve')
and running it gives me:
status: 4
A: 5
C: 1
D: 1
E: 1
which is incorrect given the constraint provided. Am I doing something wrong?

You can't use min, max, or, and with ortools variables, as they override the __ge__, __lt__ magic methods for creating linear expressions.
In this case you have to create 4 new variables (1 for each sum) and 2 more variables constrained with model.AddMaxEquality. You could also use 2 booleans to set the 2 max variables instead.
Edit:
acd = model.NewIntVar(1, 3 * horizon, "ACD")
model.Add(acd == A + C + D)
ade = model.NewIntVar(1, 3 * horizon, "ADE")
model.Add(ade == A + D + E)
ace = model.NewIntVar(1, 3 * horizon, "ACE")
model.Add(ace == A + C + E)
ced = model.NewIntVar(1, 3 * horizon, "CED")
model.Add(ced == C + E + D)
max1 = model.NewIntVar(1, 3 * horizon, "max1")
max2 = model.NewIntVar(1, 3 * horizon, "max2")
model.AddMaxEquality(max1, [acd, ade])
model.AddMaxEquality(max2, [ace, ced])
model.Add(max1 > max2)

For the record, following Stradivari answer:
#!/usr/bin/env python3
from ortools.sat.python import cp_model
horizon = 5
model = cp_model.CpModel()
A = model.NewIntVar(1, horizon, 'A')
C = model.NewIntVar(1, horizon, 'C')
D = model.NewIntVar(1, horizon, 'D')
E = model.NewIntVar(1, horizon, 'E')
#model.Add(max(A+C+D, A+D+E) > max(A+C+E, C+E+D))
acd = model.NewIntVar(1, 3 * horizon, "ACD")
model.Add(acd == A + C + D)
ade = model.NewIntVar(1, 3 * horizon, "ADE")
model.Add(ade == A + D + E)
ace = model.NewIntVar(1, 3 * horizon, "ACE")
model.Add(ace == A + C + E)
ced = model.NewIntVar(1, 3 * horizon, "CED")
model.Add(ced == C + E + D)
max1 = model.NewIntVar(1, 3 * horizon, "max1")
max2 = model.NewIntVar(1, 3 * horizon, "max2")
model.AddMaxEquality(max1, [acd, ade])
model.AddMaxEquality(max2, [ace, ced])
model.Add(max1 > max2)
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status in (cp_model.FEASIBLE, cp_model.OPTIMAL):
print('status: ', status)
print('A: ', solver.Value(A))
print('C: ', solver.Value(C))
print('D: ', solver.Value(D))
print('E: ', solver.Value(E))
print('ACD: ', solver.Value(acd))
print('ADE: ', solver.Value(ade))
print('max1: ', solver.Value(max1))
print('ACE: ', solver.Value(ace))
print('CED: ', solver.Value(ced))
print('max2: ', solver.Value(max2))
else:
print('Could not solve')
possible output:
%./max.py
status: 4
A: 2
C: 1
D: 2
E: 1
ACD: 5
ADE: 5
max1: 5
ACE: 4
CED: 4
max2: 4

Related

Straighten contours OpenCV

Hello guys I would like to "straighten" some contours using opencv/python. Is there anyway to accomplish this?
I have attached two images:
in the current stage
and how I would like to see it .
Bounding boxes resolve the majority of the problem, but there are some exceptions that do not produce the desired outcome (see the top right contour in the image).
Thank you very much!
Current Contours
Squared Contours
def approximate_contours(image: np.ndarray, eps: float, color=(255, 255, 255)):
contours, _ = cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
image = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
approx_contours = []
for cnt in contours:
epsilon = eps * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)
cv.drawContours(image, [approx], -1, color=color)
approx_contours.append(approx)
return image, approx_contours
def get_angle(pts: np.ndarray):
a = np.array([pts[0][0][0], pts[0][0][1]])
b = np.array([pts[1][0][0], pts[1][0][1]])
c = np.array([pts[2][0][0], pts[2][0][1]])
ba = a - b
bc = c - b
unit_vector_ba = ba / np.linalg.norm(ba)
unit_vector_bc = bc / np.linalg.norm(bc)
dot_product = np.dot(unit_vector_ba, unit_vector_bc)
angle_rad = np.arccos(dot_product)
angle_deg = degrees(angle_rad)
try:
int(angle_deg)
except Exception as e:
raise Exception("nan value detected")
return int(angle_deg)
def move_points(contour:np.ndarray, pts: np.ndarray, angle: int, ext: list, weight=1):
(ext_left, ext_right, ext_bot, ext_top) = ext
a = np.array([pts[0][0][0], pts[0][0][1]])
b = np.array([pts[1][0][0], pts[1][0][1]])
c = np.array([pts[2][0][0], pts[2][0][1]])
right_angle = False
if 45 < angle < 135:
right_angle = True
diff_x_ba = abs(b[0] - a[0])
diff_y_ba = abs(b[1] - a[1])
diff_x_bc = abs(b[0] - c[0])
diff_y_bc = abs(b[1] - c[1])
rap_ba = diff_x_ba / max(diff_y_ba, 1)
rap_bc = diff_x_bc / max(diff_y_bc, 1)
if rap_ba < rap_bc:
a[0] = int((a[0] * weight + b[0]) / (2 + weight - 1))
b[0] = a[0]
c[1] = int((c[1] + b[1]) / 2)
b[1] = c[1]
else:
c[0] = int((c[0] + b[0]) / 2)
b[0] = c[0]
a[1] = int((a[1] * weight + b[1]) / (2 + weight - 1))
b[1] = a[1]
else:
diff_x_ba = abs(b[0] - a[0])
diff_y_ba = abs(b[1] - a[1])
diff_x_bc = abs(b[0] - c[0])
diff_y_bc = abs(b[1] - c[1])
if (diff_x_ba + diff_x_bc) > (diff_y_ba + diff_y_bc):
a[1] = int((a[1] * weight + b[1] + c[1]) / (3 + weight - 1))
b[1] = a[1]
c[1] = a[1]
else:
a[0] = int((a[0] * weight + b[0] + c[0]) / (3 + weight - 1))
b[0] = a[0]
c[0] = a[0]
return a, b, c, right_angle
def straighten_contours(contours: list, image: np.ndarray, color=(255, 255, 255)):
image = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
for cnt in contours:
idx = 0
ext_left = cnt[cnt[:, :, 0].argmin()][0]
ext_right = cnt[cnt[:, :, 0].argmax()][0]
ext_top = cnt[cnt[:, :, 1].argmin()][0]
ext_bot = cnt[cnt[:, :, 1].argmax()][0]
while idx != int(cnt.size / 2):
try:
angle = get_angle(cnt[idx:idx + 3])
except Exception:
idx += 1
continue
(a, b, c, right_angle) = move_points(cnt, cnt[idx:idx + 3], angle, [ext_left, ext_right, ext_bot, ext_top])
cnt[idx][0] = a
cnt[idx + 1][0] = b
cnt[idx + 2][0] = c
idx += 1
if not right_angle:
idx -= 1
cnt = np.delete(cnt, (idx + 1), 0)
if idx == 1:
cnt = np.append(cnt, cnt[:2], axis=0)
cnt = np.delete(cnt, [0, 1], 0)
cv.drawContours(image, [cnt], -1, color=color)
return image
I managed to do some workarounds. The straighten contours function is applied onto the approximate_contours result (the first image in the question). Is not as good as I would have wanted it to be but it works.

Matlab: resize with custom interpolation kernel Mitchell-Netravali

I have seen that there was an interest in custom interpolation kernels for resize (MATLAB imresize with a custom interpolation kernel). Did anyone implemented the parametric Mitchell-Netravali kernel [1] that is used as default in ImageMagick and is willing to share the Matlab code? Thank you very much!
[1] http://developer.download.nvidia.com/books/HTML/gpugems/gpugems_ch24.html
// Mitchell Netravali Reconstruction Filter
// B = 0 C = 0 - Hermite B-Spline interpolator
// B = 1, C = 0 - cubic B-spline
// B = 0, C = 1/2 - Catmull-Rom spline
// B = 1/3, C = 1/3 - recommended
float MitchellNetravali(float x, float B, float C)
{
float ax = fabs(x);
if (ax < 1) {
return ((12 - 9 * B - 6 * C) * ax * ax * ax +
(-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6;
} else if ((ax >= 1) && (ax < 2)) {
return ((-B - 6 * C) * ax * ax * ax +
(6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) *
ax + (8 * B + 24 * C)) / 6;
} else {
return 0;
}
}
Here I got another approach with vectorization; according to my tests with upscaling (1000x1000 -> 3000x3000) this is faster than the standard bicubic even with a large Mitchell radius = 6:
function [outputs] = Mitchell_vect(x,M_B,M_C)
outputs= zeros(size(x,1),size(x,2));
ax = abs(x);
temp = ((12-9*M_B-6*M_C) .* ax.^3 + (-18+12*M_B+6*M_C) .* ax.^2 + (6-2*M_B))./6;
temp2 = ((-M_B-6*M_C) .* ax.^3 + (6*M_B+30*M_C) .* ax.^2 + (-12*M_B-48*M_C) .* ax + (8*M_B + 24*M_C))./6;
index = find(ax<1);
outputs(index)=temp(index);
index = find(ax>=1 & ax<2);
outputs(index)=temp2(index);
end
I got the following proposal for the Mitchel kernel called by imresize with the parameters B and C and a kernel radius using for-loops (and preallocation):
img_resize = imresize(img, [h w], {#(x)Mitchell(x,B,C),radius});
function [outputs] = Mitchell(x,B,C)
outputs= zeros(size(x,1),size(x,2));
for i = 1 : size(x,1)
for j = 1 : size(x,2)
ax = abs(x(i,j));
if ax < 1
outputs(i,j) = ((12-9*B-6*C) * ax^3 + (-18+12*B+6*C) * ax^2 + (6-2*B))/6;
elseif (ax >= 1) && (ax < 2)
outputs(i,j) = ((-B-6*C) * ax^3 + (6*B+30*C) * ax^2 + (-12*B-48*C) * ax + (8*B + 24*C))/6;
else
outputs(i,j) = 0;
end
end
end
end

Boolean expression F = x'y + xyz':

Using DeMorgan's theorem show that:
a. (A + B)'(A' +B)' = 0
b. A + A'B + A'B' = 1
Boolean expression F = x'y + xyz':
Derive an algebraic expression for the complement F'
Show that F·F' = 0
Show that F + F' = 1
Please Help me
Assuming you know how DeMorgan's law works and you understand the basics of AND, OR, NOT operations:
1.a) (A + B)'(A' + B)' = A'B'(A')'B' = A'B'AB' = A'AB'B' = A'AB' = 0 B' = 0.
I used two facts here that hold for any boolean variable A:
AA' = 0 (when A = 0, A' = 1 and when A = 1, A' = 0 so (AA') has to be 0)
0A = 0 (0 AND anything has to be 0)
1.b) A + A'B + A'B' = A + A'(B + B') = A + A' = 1.
I used the following two facts that hold for any boolean variables A, B and C:
AB + AC = A(B + C) - just like you would do with numeric variables and multiplication and addition. Only here we work with boolean variables and AND (multiplication) and OR (addition) operations.
A + A' = 0 (when A = 0, A' = 0 and when A = 1, A' = 0 so (A + A') has to be 1)
2.a) Let's first derive the complement of F:
F' = (x'y + xyz')' = (x'y)'(xyz')' = (x + y')((xy)' + z) = (x + y')(x' + y' + z) = xx' + xy' + xz + x'y' + y'y' + y'z = 0 + xy' + xz + x'y' + y' + y'z = xy' + xz + y'(x + 1) + y'z = xy' + xz + y' + y'z = xy' + xz + y'(z + 1) = xy' + y' + xz = y'(x + 1) = xz + y'.
There is only one additional fact that I used here, that for any boolean variables A and B following holds:
A + AB = A(B + 1) = A - logically, variable A completely determines the output of such an expression and part AB cannot change the output of entire expression (you can check this one with truth tables if it's not clear, but boolean algebra should be enough to understand). And of course, for any boolean variable A + 1 = A.
2.b) FF' = (x'y + xyz')(xz + y') = x'yxz + x'yy' + xyz'xz + xyz'y'.
x'yxz = (xx')yz = 0xz = 0
xyy'= x0 = 0
xyz'xz = xxy(zz') = xy0 = 0
xyz'y' = xz'(yy') = xz'0 = 0
Therefore, FF' = 0.
2.c) F + F' = x'y + xyz' + xz + y'
This one is not so obvious. Let's start with two middle components and see what we can work out:
xyz' + xz = x(yz' + z) = x(yz' + z(y + y')) = x(yz' + yz + y'z) = x(y(z + z') + y'z) = x(y + y'z) = xy + xy'z.
I used the fact that we can write any boolean variable A in the following way:
A = A(B + B') = AB + AB' as (B + B') evaluates to 1 for any boolean variable B, so initial expression is not changed by AND-ing it together with such an expression.
Plugging this back in F + F' expression yields:
x'y + xy + xy'z + y' = y(x + x') + y'(xz + 1) = y + y' = 1.

Is this parallel recursion in Matlab?

What is happening in the function below?
interpreting the output it appears to me that multiple recursions are occurring in parallel. Is that even possible (I didn't write any code to be executed parallely )
How can I fix this?
The top level function call:
for i = 1:n
chNo = cluster.no(i);
%if nodeArch.node(chNo).type ~= 'J'; %if type = J ie its an CH with no path to sink
nodeArch.node(chNo).dest = chNo; %default self loop
packetLength = nodeArch.node(chNo).data;
packetLength = packetLength * roundArch.aggrFactor;
path = num2str(i);
clusterModel= forwardPacket(clusterModel, packetLength, chNo, nodeArch.node(chNo).connections, path);
if nodeArch.node(chNo).dest == chNo
nodeArch.node(chNo).type = 'J'; %set node as isolated CH
end
%end
nodeArch.node(chNo).data = 0 ; %clearing local data
end
the recursive function :
function clusterModel = forwardPacket(clusterModel, packetLength, chNo, connections,path)
nodeArch = clusterModel.nodeArch;
netArch = clusterModel.netArch;
cluster = clusterModel.clusterNode;
zone = nodeArch.node(chNo).zone;
if zone == 1
distance = sqrt((nodeArch.node(chNo).x - netArch.Sink.x)^2 + (nodeArch.node(chNo).y - netArch.Sink.y)^2);
nodeArch.node(chNo).energy = afterTransmissionLoss( packetLength, netArch, distance, nodeArch.node(chNo).energy);
nodeArch.node(chNo).dest = 0; % ie sink
for j = 1:nodeArch.numNode
if connections(j) == 1;
netArch.Sink.connected(j) = 1;
%disp(num2str(j));
end
end
%This is the output block
path = strcat( path , ' > sink');
disp(path);
disp(netArch.Sink.data);
netArch.Sink.data = netArch.Sink.data + 1;
disp(netArch.Sink.data);
%end of output block
nodeArch.node(chNo).dest = 0;
else
n = length(cluster.no); % Number of CHs
for i = 1:n
destChNo = cluster.no(i);
if nodeArch.node(destChNo).zone == zone-1
distance = sqrt((nodeArch.node(chNo).x - nodeArch.node(destChNo).x)^2 + (nodeArch.node(chNo).y - nodeArch.node(destChNo).y)^2);
if distance <= netArch.Yard.nodeRange %check if CH is too far to send data
nodeArch.node(chNo).energy = afterTransmissionLoss( packetLength, netArch, distance, nodeArch.node(chNo).energy);
nodeArch.node(destChNo).energy = afterReceptionLoss( packetLength, netArch, nodeArch.node(destChNo).energy);
nodeArch.node(chNo).dest = destChNo;
%disp(strcat(num2str(destChNo),'>>' , num2str(destChNo) ));
path = strcat( path , ' > ' ,num2str(chNo));
clusterModel = forwardPacket(clusterModel, packetLength, destChNo, connections, path);
nodeArch.node(chNo).dest = destChNo;
break;
end
end
end
nodeArch.node(chNo).type = 'J'; %set node as isolated CH
end
clusterModel.netArch = netArch;
clusterModel.nodeArch = nodeArch;
end
the output:
2 >55 > sink
0
1
6 >72 > sink
0
1
7 >83 > sink
0
1
8 > sink
0
1
10 >106 >55 > sink
1
2
15 >186 > sink
1
2
16 >188 >55 > sink
1
2
17 >192 >330 > sink
1
2
21 > sink
1
2
22 > sink
2
3
26 >268 > sink
3
4
27 >271 > sink
3
4.....and so on
I figured out what's wrong
in Java or C
when we write
a=b; //where b is a structure/class
a is a reference of b.
in Matlab
a is another structure initialized with the values of b.
that was the issue.

How would you vectorize this nested loop in matlab/octave?

I am stuck at vectorizing this tricky loop in MATLAB/Octave:
[nr, nc] = size(R);
P = rand(nr, K);
Q = rand(K, nc);
for i = 1:nr
for j = 1:nc
if R(i,j) > 0
eij = R(i,j) - P(i,:)*Q(:,j);
for k = 1:K
P(i,k) = P(i,k) + alpha * (2 * eij * Q(k,j) - beta * P(i,k));
Q(k,j) = Q(k,j) + alpha * (2 * eij * P(i,k) - beta * Q(k,j));
end
end
end
end
The code tries to factorize R into P and Q, and approaching the nearest P and Q with an update rule. For example, let R = [3 4 0 1 1; 0 1 0 4 4; 5 4 3 1 0; 0 0 5 4 3; 5 3 0 2 1], K=2, alpha=0.01 and beta=0.015. In my real case, I will use a huge sparse matrix R (that's why I need vectorization), and K remain small (less than 10). The goal of the whole script is producing a prediction value for every 0 elements in R, based on the non zero elements. I got this code from here, originally written in Python.
This looks like one of those cases that not all code can be vectorized. Still, you can make it a bit better than it is now.
[nr, nc] = size(R);
P = rand(nr, K);
Q = rand(K, nc);
for i = 1:nr
for j = 1:nc
if R(i,j) > 0
eij = R(i,j) - P(i,:)*Q(:,j);
P(i,:) = P(i,:) + alpha * (2 * eij * Q(:,j)' - beta * P(i,:));
Q(:,j) = Q(:,j) + alpha * (2 * eij * P(i,:)' - beta * Q(:,j));
end
end
end
Since the operations on P and Q are serial in nature (iterative updates) I do not think you can do much better. You can save the if in the loop:
[nr, nc] - size(R);
P = rand(nr, K);
Q = rand(K, nc);
[nzi nzj] = find( R > 0 );
for ii=1:numel(nzi)
i = nzi(ii);
j = nzj(ii);
eij = R(i,j) - P(i,:)*Q(:,j);
P(i,:) = P(i,:) + alpha * (2 * eij * Q(:,j)' - beta * P(i,:));
Q(:,j) = Q(:,j) + alpha * (2 * eij * P(i,:)' - beta * Q(:,j));
end