I have linear systems of inequalities in 3 variables and I'd like to plot these regions.
Ideally, I'd like something that looks like objects in PolyhedronData. I tried RegionPlot3D, but the results are visually poor and too polygon-heavy to rotate in real time
Here's what I mean, the code below generates 10 sets of linear constraints and plots them
randomCons := Module[{},
hadamard = KroneckerProduct ## Table[{{1, 1}, {1, -1}}, {3}];
invHad = Inverse[hadamard];
vs = Range[8];
m = mm /# vs;
sectionAnchors = Subsets[vs, {1, 7}];
randomSection :=
Mean[hadamard[[#]] & /# #] & /#
Prepend[RandomChoice[sectionAnchors, 3], vs]; {p0, p1, p2, p3} =
randomSection;
section =
Thread[m ->
p0 + {x, y, z}.Orthogonalize[{p1 - p0, p2 - p0, p3 - p0}]];
And ## Thread[invHad.m >= 0 /. section]
];
Table[RegionPlot3D ## {randomCons, {x, -3, 3}, {y, -3, 3}, {z, -3,
3}}, {10}]
Any suggestions?
Update: Incorporating suggestions below, here's the version I ended up using to plot feasible region of a system of linear inequalities
(* Plots feasible region of a linear program in 3 variables, \
specified as cons[[1]]>=0,cons[[2]]>=0,...
Each element of cons must \
be an expression of variables x,y,z only *)
plotFeasible3D[cons_] :=
Module[{maxVerts = 20, vcons, vertCons, polyCons},
(* find intersections of all triples of planes and get rid of \
intersections that aren't points *)
vcons = Thread[# == 0] & /# Subsets[cons, {3}];
vcons = Select[vcons, Length[Reduce[#]] == 3 &];
(* Combine vertex constraints with inequality constraints and find \
up to maxVerts feasible points *)
vertCons = Or ## (And ### vcons);
polyCons = And ## Thread[cons >= 0];
verts = {x, y, z} /.
FindInstance[polyCons && vertCons, {x, y, z}, maxVerts];
ComputationalGeometry`Methods`ConvexHull3D[verts,
Graphics`Mesh`FlatFaces -> False]
]
Code for testing
randomCons := Module[{},
hadamard = KroneckerProduct ## Table[{{1, 1}, {1, -1}}, {3}];
invHad = Inverse[hadamard];
vs = Range[8];
m = mm /# vs;
sectionAnchors = Subsets[vs, {1, 7}];
randomSection :=
Mean[hadamard[[#]] & /# #] & /#
Prepend[RandomChoice[sectionAnchors, 3], vs]; {p0, p1, p2, p3} =
randomSection;
section =
Thread[m ->
p0 + {x, y, z}.Orthogonalize[{p1 - p0, p2 - p0, p3 - p0}]];
And ## Thread[invHad.m >= 0 /. section]
];
Table[plotFeasible3D[List ## randomCons[[All, 1]]], {50}];
Here is a small program that seems to do what you want:
rstatic = randomCons; (* Call your function *)
randeq = rstatic /. x_ >= y_ -> x == y; (* make a set of plane equations
replacing the inequalities by == *)
eqset = Subsets[randeq, {3}]; (* Make all possible subsets of 3 planes *)
(* Now find the vertex candidates
Solving the sets of three equations *)
vertexcandidates =
Flatten[Table[Solve[eqset[[i]]], {i, Length[eqset]}], 1];
(* Now select those candidates
satisfying all the original equations *)
vertex = Union[Select[vertexcandidates, rstatic /. # &]];
(* Now use an UNDOCUMENTED Mathematica
function to plot the surface *)
gr1 = ComputationalGeometry`Methods`ConvexHull3D[{x, y, z} /. vertex];
(* Your plot follows *)
gr2 = RegionPlot3D[rstatic,
{x, -3, 3}, {y, -3, 3}, {z, -3, 3},
PerformanceGoal -> "Quality", PlotPoints -> 50]
Show[gr1,gr2] (*Show both Graphs superposed *)
The result is:
Downside: the undocumented function is not perfect. When the face is not a triangle, it will show a triangulation:
Edit
There is an option to get rid of the foul triangulation
ComputationalGeometry`Methods`ConvexHull3D[{x, y, z} /. vertex,
Graphics`Mesh`FlatFaces -> False]
does the magic. Sample:
Edit 2
As I mentioned in a comment, here are two sets of degenerate vertex generated by your randomCons
{{x -> Sqrt[3/5]},
{x -> -Sqrt[(5/3)] + Sqrt[2/3] y},
{x -> -Sqrt[(5/3)], y -> 0},
{y -> -Sqrt[(2/5)], x -> Sqrt[3/5]},
{y -> 4 Sqrt[2/5], x -> Sqrt[3/5]}
}
and
{{x -> -Sqrt[(5/3)] + (2 z)/Sqrt[11]},
{x -> Sqrt[3/5], z -> 0},
{x -> -Sqrt[(5/3)], z -> 0},
{x -> -(13/Sqrt[15]), z -> -4 Sqrt[11/15]},
{x -> -(1/Sqrt[15]), z -> 2 Sqrt[11/15]},
{x -> 17/(3 Sqrt[15]), z -> -((4 Sqrt[11/15])/3)}
}
Still trying to see how to cope gently with those ...
Edit 3
This code is not general enough for the full problem, but eliminates the cylinder degenerancy problem for your sample data generator. I used the fact that the pathogenic cases are always cylinders with their axis paralell to one of the coordinate axis, and then used RegionPlot3D to plot them.
I'm not sure if this will be useful for your general case :(.
For[i = 1, i <= 160, i++,
rstatic = randomCons;
r[i] = rstatic;
s1 = Reduce[r[i], {x, y, z}] /. {x -> var1, y -> var2, z -> var3};
s2 = Union[StringCases[ToString[FullForm[s1]], "var" ~~ DigitCharacter]];
If [Dimensions#s2 == {3},
(randeq = rstatic /. x_ >= y_ -> x == y;
eqset = Subsets[randeq, {3}];
vertexcandidates = Flatten[Table[Solve[eqset[[i]]], {i, Length[eqset]}], 1];
vertex = Union[Select[vertexcandidates, rstatic /. # &]];
a[i] = ComputationalGeometry`Methods`ConvexHull3D[{x, y, z} /. vertex,
Graphics`Mesh`FlatFaces -> False, Axes -> False, PlotLabel -> i])
,
a[i] = RegionPlot3D[s1, {var1, -2, 2}, {var2, -2, 2}, {var3, -2, 2},
Axes -> False, PerformanceGoal -> "Quality", PlotPoints -> 50,
PlotLabel -> i, PlotStyle -> Directive[Yellow, Opacity[0.5]],
Mesh -> None]
];
]
GraphicsGrid[Table[{a[i], a[i + 1], a[i + 2]}, {i, 1, 160, 4}]]
Here you can find an image of the generated output, the degenerated cases (all cylinders) are in transparent yellow
HTH!
A triplet chosen from your set of inequalities will generally determine a point obtained by solving the corresponding triplet of equations. I believe that you want the convex hull of this set of points. You can generate this like so.
cons = randomCons; (* Your function *)
eqs = Apply[Equal, List ### Subsets[cons, {3}], {2}];
sols = Flatten[{x, y, z} /. Table[Solve[eq, {x, y, z}], {eq, eqs}], 1];
pts = Select[sols, And ## (NumericQ /# #) &];
ComputationalGeometry`Methods`ConvexHull3D[pts]
Of course, some triplets might actually be underdetermined and lead to lines or evan a whole plane. Thus the code will issue a complaint in those cases.
This appeared to work in the few random cases that I tried but, as Yaro points out, it doesn't work in all. The following picture will illustrate exactly why:
{p0, p1, p2,
p3} = {{1, 0, 0, 0, 0, 0, 0, 0}, {1, 1/2, -(1/2), 0, -(1/2), 0,
0, -(1/2)}, {1, 0, 1/2, 1/2, 0, 0, -(1/2), 1/2}, {1, -(1/2), 1/2,
0, -(1/2), 0, 0, -(1/2)}};
hadamard = KroneckerProduct ## Table[{{1, 1}, {1, -1}}, {3}];
invHad = Inverse[hadamard];
vs = Range[8];
m = mm /# vs;
section =
Thread[m ->
p0 + {x, y, z}.Orthogonalize[{p1 - p0, p2 - p0, p3 - p0}]];
cons = And ## Thread[invHad.m >= 0 /. section];
eqs = Apply[Equal, List ### Subsets[cons, {3}], {2}];
sols = Flatten[{x, y, z} /. Table[Solve[eq, {x, y, z}], {eq, eqs}],
1]; // Quiet
pts = Select[sols, And ## (NumericQ /# #) &];
ptPic = Graphics3D[{PointSize[Large], Point[pts]}];
regionPic =
RegionPlot3D[cons, {x, -2, 2}, {y, -2, 2}, {z, -2, 2},
PlotPoints -> 40];
Show[{regionPic, ptPic}]
Thus, there are points that are ultimately cut off by the plane defined by some other constraint. Here's one (I'm sure terribly inefficient) way to find the ones you want.
regionPts = regionPic[[1, 1]];
nf = Nearest[regionPts];
trimmedPts = Select[pts, Norm[# - nf[#][[1]]] < 0.2 &];
trimmedPtPic = Graphics3D[{PointSize[Large], Point[trimmedPts]}];
Show[{regionPic, trimmedPtPic}]
Thus, you could use the convex hull of trimmedPts. This ultimately depends on the result of RegionPlot and you might need to ramp of the value of PlotPoints to make it more reliable.
Googling about a bit reveals the concept of a feasibility region in linear programming. This seems to be exactly what you're after.
Mark
Seeing all the previous answers; what is wrong with using the build-in function
RegionPlot3D, e.g.
RegionPlot3D[ 2*y+3*z <= 5 && x+y+2*z <= 4 && x+2*y+3*z <= 7 &&
x >= 0 && y >= 0 && z >= 0,
{x, 0, 4}, {y, 0, 5/2}, {z, 0, 5/3} ]
Related
I am a beginner in Constraint Programming using Minizinc and I need help from experts in the field.
How can I compute all the possible combinations: 6 Rectangles inside the Square (10x10) using Minizinc?
Considering that the RESTRICTIONS of the problem are:
1) No Rectangle Can Overlap
2) The 6 rectangles may be vertical or horizontal
OUTPUT:
0,1,1,0,0, . . . , 0,0,6,6,6
1,1,1,0,0, . . . , 0,0,0,4,4
0,0,5,5,0, . . . , 0,0,1,1,1
0,0,0,2,2, . . . , 0,0,0,0,0
0,0,0,0,2, . . . , 0,0,0,0,0
6,6,6,0,0, . . . , 0,4,4,4,0
Continue Combination...
The following model finds solutions within a couple of seconds:
% Chuffed: 1.6s
% CPLEX: 3.9s
% Gecode: 1.5s
int: noOfRectangles = 6;
int: squareLen = 10;
int: Empty = 0;
set of int: Coords = 1..squareLen;
set of int: Rectangles = 1..noOfRectangles;
% decision variables:
% The square matrix
% Every tile is either empty or belongs to one of the rectangles
array[Coords, Coords] of var Empty .. noOfRectangles: s;
% the edges of the rectangles
array[Rectangles] of var Coords: top;
array[Rectangles] of var Coords: bottom;
array[Rectangles] of var Coords: left;
array[Rectangles] of var Coords: right;
% function
function var Coords: getCoord(Coords: row, Coords: col, Rectangles: r, Coords: coord, Coords: defCoord) =
if s[row, col] == r then coord else defCoord endif;
% ----------------------< constraints >-----------------------------
% Determine rectangle limits as minima/maxima of the rows and columns for the rectangles.
% Note: A non-existing rectangle would have top=squareLen, bottom=1, left=squareLen, right=1
% This leads to a negative size and is thus ruled-out.
constraint forall(r in Rectangles) (
top[r] == min([ getCoord(row, col, r, row, squareLen) | row in Coords, col in Coords])
);
constraint forall(r in Rectangles) (
bottom[r] == max([ getCoord(row, col, r, row, 1) | row in Coords, col in Coords])
);
constraint forall(r in Rectangles) (
left[r] == min([ getCoord(row, col, r, col, squareLen) | row in Coords, col in Coords])
);
constraint forall(r in Rectangles) (
right[r] == max([ getCoord(row, col, r, col, 1) | row in Coords, col in Coords])
);
% all tiles within the limits must belong to the rectangle
constraint forall(r in Rectangles) (
forall(row in top[r]..bottom[r], col in left[r]..right[r])
(s[row, col] == r)
);
% enforce a minimum size per rectangle
constraint forall(r in Rectangles) (
(bottom[r] - top[r] + 1) * (right[r] - left[r] + 1) in 2 .. 9
);
% symmetry breaking:
% order rectangles according to their top/left corners
constraint forall(r1 in Rectangles, r2 in Rectangles where r2 > r1) (
(top[r1]*squareLen + left[r1]) < (top[r2]*squareLen + left[r2])
);
% output solution
output [ if col == 1 then "\n" else "" endif ++
if "\(s[row, col])" == "0" then " " else "\(s[row, col]) " endif
| row in Coords, col in Coords];
The grid positions in the sqare can be empty or assume one of six values. The model determines the top and bottom rows of all rectangles. Together with the left and right columns, it makes sure that all tiles within these limits belong to the same rectangle.
To experiment, it is helpful to start with smaller square dimensions and/or smaller numbers of rectangles. It might also make sense to delimit the size of rectangles. Otherwise, the rectangles tend to become too small (1x1) or too big.
Symmetry breaking to enforce a certain ordering of rectangles, does speed-up the solving process.
Here's another solution using MiniZincs Geost constraint. This solution is heavily based on Patrick Trentins excellent answer here. Also make sure to see his explanation on the model.
I assume using the geost constraint speeds up the process a little. Symmetry breaking might further speed things up as Axel Kemper suggests.
include "geost.mzn";
int: k;
int: nObjects;
int: nRectangles;
int: nShapes;
set of int: DIMENSIONS = 1..k;
set of int: OBJECTS = 1..nObjects;
set of int: RECTANGLES = 1..nRectangles;
set of int: SHAPES = 1..nShapes;
array[DIMENSIONS] of int: l;
array[DIMENSIONS] of int: u;
array[RECTANGLES,DIMENSIONS] of int: rect_size;
array[RECTANGLES,DIMENSIONS] of int: rect_offset;
array[SHAPES] of set of RECTANGLES: shape;
array[OBJECTS,DIMENSIONS] of var int: x;
array[OBJECTS] of var SHAPES: kind;
array[OBJECTS] of set of SHAPES: valid_shapes;
constraint forall (obj in OBJECTS) (
kind[obj] in valid_shapes[obj]
);
constraint geost_bb(k, rect_size, rect_offset, shape, x, kind, l, u);
And the corresponding data:
k = 2; % Number of dimensions
nObjects = 6; % Number of objects
nRectangles = 4; % Number of rectangles
nShapes = 4; % Number of shapes
l = [0, 0]; % Lower bound of our bounding box
u = [10, 10]; % Upper bound of our bounding box
rect_size = [|
2, 3|
3, 2|
3, 5|
5, 3|];
rect_offset = [|
0, 0|
0, 0|
0, 0|
0, 0|];
shape = [{1}, {2}, {3}, {4}];
valid_shapes = [{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {3, 4}];
The output reads a little different. Take this example:
x = array2d(1..6, 1..2, [7, 0, 2, 5, 5, 0, 0, 5, 3, 0, 0, 0]);
kind = array1d(1..6, [1, 1, 1, 1, 1, 3]);
This means rectangle one is placed at [7, 0] and takes the shape [2,3] as seen in this picture:
Building on the answer of #Phonolog, one way to obtain the wanted output format is to use a 2d-array m which is mapped to x through constraints (here size is the bounding box size):
% mapping to a 2d-array output format
set of int: SIDE = 0..size-1;
array[SIDE, SIDE] of var 0..nObjects: m;
constraint forall (i, j in SIDE) ( m[i,j] = sum(o in OBJECTS)(o *
(i >= x[o,1] /\
i <= x[o,1] + rect_size[kind[o],1]-1 /\
j >= x[o,2] /\
j <= x[o,2] + rect_size[kind[o],2]-1)) );
% symmetry breaking between equal objects
array[OBJECTS] of var int: pos = [ size*x[o,1] + x[o,2] | o in OBJECTS ];
constraint increasing([pos[o] | o in 1..nObjects-1]);
solve satisfy;
output ["kind=\(kind)\n"] ++
["x=\(x)\n"] ++
["m="] ++ [show2d(m)]
Edit: Here is the complete code:
include "globals.mzn";
int: k = 2;
int: nObjects = 6;
int: nRectangles = 4;
int: nShapes = 4;
int: size = 10;
set of int: DIMENSIONS = 1..k;
set of int: OBJECTS = 1..nObjects;
set of int: RECTANGLES = 1..nRectangles;
set of int: SHAPES = 1..nShapes;
array[DIMENSIONS] of int: l = [0, 0];
array[DIMENSIONS] of int: u = [size, size];
array[OBJECTS,DIMENSIONS] of var int: x;
array[OBJECTS] of var SHAPES: kind;
array[RECTANGLES,DIMENSIONS] of int: rect_size = [|
3, 2|
2, 3|
5, 3|
3, 5|];
array[RECTANGLES,DIMENSIONS] of int: rect_offset = [|
0, 0|
0, 0|
0, 0|
0, 0|];
array[SHAPES] of set of SHAPES: shape = [
{1}, {2}, {3}, {4}];
array[OBJECTS] of set of SHAPES: valid_shapes =
[{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {3, 4}];
constraint forall (obj in OBJECTS) (
kind[obj] in valid_shapes[obj]
);
constraint
geost_bb(
k,
rect_size,
rect_offset,
shape,
x,
kind,
l,
u
);
% mapping to a 2d-array output format
set of int: SIDE = 0..size-1;
array[SIDE, SIDE] of var 0..nObjects: m;
constraint forall (i, j in SIDE) ( m[i,j] = sum(o in OBJECTS)(o *
(i >= x[o,1] /\
i <= x[o,1] + rect_size[kind[o],1]-1 /\
j >= x[o,2] /\
j <= x[o,2] + rect_size[kind[o],2]-1)) );
% symmetry breaking between equal objects
array[OBJECTS] of var int: pos = [ size*x[o,1] + x[o,2] | o in OBJECTS ];
constraint increasing([pos[o] | o in 1..nObjects-1]);
solve satisfy;
output ["kind=\(kind)\n"] ++
["x=\(x)\n"] ++
["m="] ++ [show2d(m)]
In Python, I've seen two variable values swapped using this syntax:
left, right = right, left
Is this considered the standard way to swap two variable values or is there some other means by which two variables are by convention most usually swapped?
Python evaluates expressions from left to right. Notice that while
evaluating an assignment, the right-hand side is evaluated before the
left-hand side.
Python docs: Evaluation order
That means the following for the expression a,b = b,a :
The right-hand side b,a is evaluated, that is to say, a tuple of two elements is created in the memory. The two elements are the objects designated by the identifiers b and a, that were existing before the instruction is encountered during the execution of the program.
Just after the creation of this tuple, no assignment of this tuple object has still been made, but it doesn't matter, Python internally knows where it is.
Then, the left-hand side is evaluated, that is to say, the tuple is assigned to the left-hand side.
As the left-hand side is composed of two identifiers, the tuple is unpacked in order that the first identifier a be assigned to the first element of the tuple (which is the object that was formerly b before the swap because it had name b)
and the second identifier b is assigned to the second element of the tuple (which is the object that was formerly a before the swap because its identifiers was a)
This mechanism has effectively swapped the objects assigned to the identifiers a and b
So, to answer your question: YES, it's the standard way to swap two identifiers on two objects.
By the way, the objects are not variables, they are objects.
That is the standard way to swap two variables, yes.
I know three ways to swap variables, but a, b = b, a is the simplest. There is
XOR (for integers)
x = x ^ y
y = y ^ x
x = x ^ y
Or concisely,
x ^= y
y ^= x
x ^= y
Temporary variable
w = x
x = y
y = w
del w
Tuple swap
x, y = y, x
I would not say it is a standard way to swap because it will cause some unexpected errors.
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
nums[i] will be modified first and then affect the second variable nums[nums[i] - 1].
Does not work for multidimensional arrays, because references are used here.
import numpy as np
# swaps
data = np.random.random(2)
print(data)
data[0], data[1] = data[1], data[0]
print(data)
# does not swap
data = np.random.random((2, 2))
print(data)
data[0], data[1] = data[1], data[0]
print(data)
See also Swap slices of Numpy arrays
To get around the problems explained by eyquem, you could use the copy module to return a tuple containing (reversed) copies of the values, via a function:
from copy import copy
def swapper(x, y):
return (copy(y), copy(x))
Same function as a lambda:
swapper = lambda x, y: (copy(y), copy(x))
Then, assign those to the desired names, like this:
x, y = swapper(y, x)
NOTE: if you wanted to you could import/use deepcopy instead of copy.
That syntax is a standard way to swap variables. However, we need to be careful of the order when dealing with elements that are modified and then used in subsequent storage elements of the swap.
Using arrays with a direct index is fine. For example:
def swap_indexes(A, i1, i2):
A[i1], A[i2] = A[i2], A[i1]
print('A[i1]=', A[i1], 'A[i2]=', A[i2])
return A
A = [0, 1, 2, 3, 4]
print('For A=', A)
print('swap indexes 1, 3:', swap_indexes(A, 1, 3))
Gives us:
('For A=', [0, 1, 2, 3, 4])
('A[i1]=', 3, 'A[i2]=', 1)
('swap indexes 1, 3:', [0, 3, 2, 1, 4])
However, if we change the left first element and use it in the left second element as an index, this causes a bad swap.
def good_swap(P, i2):
j = P[i2]
#Below is correct, because P[i2] is modified after it is used in P[P[i2]]
print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
P[P[i2]], P[i2] = P[i2], P[P[i2]]
print('Good swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
return P
def bad_swap(P, i2):
j = P[i2]
#Below is wrong, because P[i2] is modified and then used in P[P[i2]]
print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
P[i2], P[P[i2]] = P[P[i2]], P[i2]
print('Bad swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
return P
P = [1, 2, 3, 4, 5]
print('For P=', P)
print('good swap with index 2:', good_swap(P, 2))
print('------')
P = [1, 2, 3, 4, 5]
print('bad swap with index 2:', bad_swap(P, 2))
('For P=', [1, 2, 3, 4, 5])
('Before: P[i2]=', 3, 'P[P[i2]]=', 4)
('Good swap: After P[i2]=', 4, 'P[P[i2]]=', 3)
('good swap with index 2:', [1, 2, 4, 3, 5])
('Before: P[i2]=', 3, 'P[P[i2]]=', 4)
('Bad swap: After P[i2]=', 4, 'P[P[i2]]=', 4)
('bad swap with index 2:', [1, 2, 4, 4, 3])
The bad swap is incorrect because P[i2] is 3 and we expect P[P[i2]] to be P[3]. However, P[i2] is changed to 4 first, so the subsequent P[P[i2]] becomes P[4], which overwrites the 4th element rather than the 3rd element.
The above scenario is used in permutations. A simpler good swap and bad swap would be:
#good swap:
P[j], j = j, P[j]
#bad swap:
j, P[j] = P[j], j
You can combine tuple and XOR swaps: x, y = x ^ x ^ y, x ^ y ^ y
x, y = 10, 20
print('Before swapping: x = %s, y = %s '%(x,y))
x, y = x ^ x ^ y, x ^ y ^ y
print('After swapping: x = %s, y = %s '%(x,y))
or
x, y = 10, 20
print('Before swapping: x = %s, y = %s '%(x,y))
print('After swapping: x = %s, y = %s '%(x ^ x ^ y, x ^ y ^ y))
Using lambda:
x, y = 10, 20
print('Before swapping: x = %s, y = %s' % (x, y))
swapper = lambda x, y : ((x ^ x ^ y), (x ^ y ^ y))
print('After swapping: x = %s, y = %s ' % swapper(x, y))
Output:
Before swapping: x = 10 , y = 20
After swapping: x = 20 , y = 10
after having watched the coursera Basic Modelling course I am trying to categorize my problem so that to choose the suitable Model representation on MiniZinc.
I have a range of 10 products, each of them with its 4 special features/attributes, (a table 4x10). This table has fixed values. The user will give as input 4 parameters.
The constraints will be created in a way that the user input parameters will determine the product's attribute values.
The decision variable will be the subset of the products that match user's input.
from my understanding this is a problem of selecting a subset from a set of Objects, is there any example suggestion available that corresponds to the above Minizinc model description to have a look?
I'm (still) not completely sure about the exact specification of the problem, but here is a model that identifies all the products that are "nearest" the input data. I've defined "nearest" simply as the sum of absolute differences between each feature of a product and the input array (calculated by the score function).
int: k; % number of products
int: n; % number of features
array[1..k, 1..n] of int: data;
array[1..n] of int: input;
% decision variables
array[1..k] of var int: x; % the closeness score for each product
array[1..k] of var 0..1: y; % 1: this products is nearest (as array)
% var set of 1..k: y; % products closest to input (as set)
var int: z; % the minimum score
function var int: score(array[int] of var int: a, array[int] of var int: b) =
let {
var int: t = sum([abs(a[i]-b[i]) | i in index_set(a)])
} in
t
;
solve minimize z;
constraint
forall(i in 1..k) (
x[i] = score(data[i,..], input) /\
(y[i] = 1 <-> z = x[i]) % array
% (i in y <-> x[i] = z) % set
)
/\
minimum(z, x)
;
output [
"input: \(input)\n",
"z: \(z)\n",
"x: \(x)\n",
"y: \(y)\n\n"
]
++
[
% using array representation of y
if fix(y[i]) = 1 then
"nearest: ix:\(i) \(data[i,..])\n" else "" endif
| i in 1..k
];
% data
k = 10;
n = 4;
% random features for the products
data = array2d(1..k,1..n,
[
3,6,7,5,
3,5,6,2,
9,1,2,7,
0,9,3,6,
0,5,2,4, % score 5
1,8,7,9,
2,0,2,3, % score 5
7,5,9,2,
2,8,9,7,
3,6,1,2]);
input = [1,2,3,4];
% input = [7,5,9,2]; % exact match for product 8
The output is:
input: [1, 2, 3, 4]
z: 5
x: [11, 10, 13, 10, 5, 15, 5, 17, 16, 10]
y: [0, 0, 0, 0, 1, 0, 1, 0, 0, 0]
nearest: ix:5 [0, 5, 2, 4]
nearest: ix:7 [2, 0, 2, 3]
I have to find max number of rectangles from a given set of coordinates.
Consider the following coordinates are given in an X Y coordinate system
3 10,
3 8,
3 6,
3 4,
3 0,
6 0,
6 4,
6 8,
6 10,
How can I find if the following coordinates form a rectangle (3,0) (3,4) (6,4) (6,0)
Running time constraint: 0.1 sec
Thank you
Separate your points in lists of 'y' coordinate, grouped by 'x' coordinate. In your case you would have two sorted lists:
3: [0,4,6,8,10]
6: [0,4,8,10]
Doing the intersection of both lists you get: [0,4,8,10]
Any two of those would form a rectangle:
[0,4] => (3,0), (3,4), (6,0), (6,4)
[0,8] => (3,0), (3,8), (6,0), (6,8)
[4,8] => (3,4), (3,8), (6,4), (6,8)
...
This solution only works for orthogonal rectangles, this is, with sides parallel to x,y axis.
For every pair of points, say (x1, y1) and (x2, y2) consider it to be the diagonal of some rectangle. If there exist points (x1, y2) and (x2, y1) in the initial set then we have found our rectangle. It should be noted that there will exist 2 diagonals which will represent the same rectangle so we divide the final answer by 2.
This will work only for rectangles parallel to x-axis or y-axis.
PseudoCode C++:
answer = 0;
set<pair<int, int>> points;
for(auto i=points.begin(); i!=std::prev(points.end()); i++)
{
for(auto j=i+1; j!=points.end(); j++)
{
pair<int, int> p1 = *i;
pair<int, int> p2 = *j;
if(p1.first == p2.first || p1.second == p2.second)
continue;
pair<int, int> p3 = make_pair(p1.first, p2.second);
pair<int, int> p4 = make_pair(p2.first, p1.second);
if(points.find(p3) != points.end() && points.find(p4) != points.end())
++answer;
}
}
return answer/2;
To check if 4 points form a rectangle:
for every two points calculate the distance. store all in array of floats.
sort the array.
you will have a[0] = a[1], a[2] = a[3], a[4] = a[5]
How can I find if the following coordinates form a rectangle
Check whether the difference vectors are orthogonal, i.e. have dot product zero.
This does not check whether these coordinates are included in your list. It also does not check whether the rectangle is aligned with the coordinate axes, which would be a far simpler problem.
If you want to find all rectangles in your input, you could do the above check for all quadruples. If that is inacceptable for performance reasons, then you should update your question, indicating what kind of problem size and performance constrainst you are facing.
My humble submission
I assume number of optimizations is possible.
My approach is to
Traverse over every point
Check which all points are there just above this point and then store Y coordinates of that points which form a line
Next time when I find again the same Y coordinate that means we have found 1 rectangle
Keep traversing all other points again doing the same thing.
My solution runs in O(n^2) but this will only be rectangle which are parallel to X or Y axis.
Here is my code for above approach:
def getRectangleCount(coordinate):
n = len(coordinate)
y_count = dict()
ans = 0
for i in range(n):
x, y = coordinate[i]
for j in range(n):
dx = coordinate[j][0]
dy = coordinate[j][1]
if y < dy and x == dx:
ans += y_count.get((y, dy), 0)
y_count[(y, dy)] = y_count.get((y, dy), 0) + 1
return ans
coordinate = [[3, 10], [3, 8], [3, 6], [3, 4], [3, 0], [6, 0], [6, 4], [6, 8], [6, 10]]
print(getRectangleCount(coordinate))
Here's a solution that finds all unique rectangles (not only those parallel to the x or y-axis) in a given list of coordinate points in O(n^4) time.
Pseudocode:
// checks if two floating point numbers are equal within a given
// error to avoid rounding issues
bool is_equal(double a, double b, double e) {
return abs(a - b) < e;
}
// computes the dot product of the vectors ab and ac
double dot_product(Point a, Point b, Point c) {
return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y);
}
// find all rectangles in a given set of coordinate points
List<Rectangle> find_rectangles(List<Point> points) {
List<Rectangle> rectangles;
// sort points in ascending order by first comparing x than y value
sort(points);
for (int a = 0; a < points.size(); ++a)
for (int b = a + 1; a < points.size(); ++b)
for (int c = b + 1; c < points.size(); ++c)
for (int d = c + 1; d < points.size(); ++d)
// check all angles
if (is_equal(dot_product(points[a], points[b], points[c]), 0.0, 1e-7) &&
is_equal(dot_product(points[b], points[a], points[d]), 0.0, 1e-7) &&
is_equal(dot_product(points[d], points[b], points[c]), 0.0, 1e-7) &&
is_equal(dot_product(points[c], points[a], points[d]), 0.0, 1e-7))
// found rectangle
rectangles.add(new Rectangle(points[a], points[c], points[d], points[b]));
return rectangles;
}
Explanation:
For a given set of points A, B, C, D to define a rectangle we can check if all angles are 90° meaning all non-parallel sides are orthogonal.
Since we can check this property just by the dot product being 0 this is the most efficient way (instead of having to do square-root calculations for computing side lengths).
Sorting the points first avoids checking the same set of points multiple times due to permutations.
Suppose we have a set of points with the restriction that for each point all coordinates are non-negative, and the sum of coordinates is equal to 1. This restricts points to lie in a 3-dimensional simplex so it makes sense to try to map it back into 3 dimensional space for visualization.
The map I'm looking for would take extreme points (1,0,0,0),(0,1,0,0),(0,0,1,0) and (0,0,0,1) to vertices of "nicely positioned" regular tetrahedron. In particular, center of the tetrahedron will be at the origin, one vertex would lie on the z axis, one face to parallel to x,y plane, and one edge to be parallel to x axis.
Here's code that does similar thing for points in 3 dimensions, but it doesn't seem obvious how to extend it to 4. Basically I'm looking for 4-d equivalents of functions tosimplex (which takes 4 dimensions into 3) and it's inverse fromsimplex
A = Sqrt[2/3] {Cos[#], Sin[#], Sqrt[1/2]} & /#
Table[Pi/2 + 2 Pi/3 + 2 k Pi/3, {k, 0, 2}] // Transpose;
B = Inverse[A];
tosimplex[{x_, y_, z_}] := Most[A.{x, y, z}];
fromsimplex[{u_, v_}] := B.{u, v, Sqrt[1/3]};
(* checks *)
extreme = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
Graphics[Polygon[tosimplex /# extreme]]
fromsimplex[tosimplex[#]] == # & /# extreme
Answer:
straightforward reformulation of deinst's answer in terms of matrices gives following. (1/sqrt[4] comes up as 4th coordinate because it's the distance to simplex center)
A = Transpose[{{-(1/2), -(1/(2 Sqrt[3])), -(1/(2 Sqrt[6])),
1/Sqrt[4]}, {1/2, -(1/(2 Sqrt[3])), -(1/(2 Sqrt[6])),
1/Sqrt[4]}, {0, -(1/(2 Sqrt[3])) + Sqrt[3]/2, -(1/(2 Sqrt[6])),
1/Sqrt[4]}, {0, 0, Sqrt[2/3] - 1/(2 Sqrt[6]), 1/Sqrt[4]}}];
B = Inverse[A];
tosimplex[{x_, y_, z_, w_}] := Most[A.{x, y, z, w}];
fromsimplex[{t_, u_, v_}] := B.{t, u, v, 1/Sqrt[4]};
(* Checks *)
extreme = Table[Array[Boole[# == i] &, 4], {i, 1, 4}];
Graphics3D[Sphere[tosimplex[#], .1] & /# extreme]
fromsimplex[tosimplex[#]] == # & /# extreme
You want
(1,0,0,0) -> (0,0,0)
(0,1,0,0) -> (1,0,0)
(0,0,1,0) -> (1/2,sqrt(3)/2,0)
(0,0,0,1) -> (1/2,sqrt(3)/6,sqrt(6)/3))
And it is a linear transformation so you transform
(x,y,z,w) - > (y + 1/2 * (z + w), sqrt(3) * (z / 2 + w / 6), sqrt(6) * w / 3)
Edit You want the center at the origin -- just subtract the average of the four points. Sorry
(1/2, sqrt(3)/6, sqrt(6) / 12)
One possibility:
Generate four (non-orthoganal) 3-vectors, \vec{v}_i from the center of the tetrahedron toward each vertex.
For each four position x = (x_1 .. x_4) form the vector sum \Sum_i x_i*\vec{v}_i.
Of course this mapping is not unique in general, but you condition that the x_i's sum to 1 constrains things.