Finding all the Combinations - N Rectangles inside the Square - constraint-programming

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)]

Related

Count the subtree - optimise

COUNT THE SUBTREES
Given a tree having N nodes numbered from 1 to N and (N-1) edges where the ith edge is between node Edges [i][0] and node Edges[i][1].
The tree is rooted at node 1 and each node has a colour where the colour of the ith node is given by A[i].
Count the number of subtrees that do not contain any two nodes which have the same color.
Example:
Input:
N = 4
A[] = {1, 1, 2, 3}
Edges[][] = {{1, 2},
{2, 3},
{2, 4}}
Output:
3
Explanation:
The structure of the tree is:
1
|
2
/ \
3 4
There are only three subtrees rooted at node 2, 3 and 4 which do not contain any two
nodes of the same color.
The subtree rooted at node 1 contains two nodes which have the same color
(i.e. node 1 and node 2)
Input:
N = 2
A[] = {5, 2}
Edges[][] = {{2, 1}}
Output:
2
Constraints:
1 <= N <= 10^5
1 <= A[i] <= 10^9
1 <= Edges[i][0], Edges[i][1] <= N
Code:
def countSubtree(self, N, A, edges):
adj = defaultdict(list)
for i in edges:
adj[i[0]].append(i[1])
adj[i[1]].append(i[0])
visited = [0 for i in range(N)]
subtrees = 0
def dfs(node):
sofar = True
colors = set([A[node-1]])
visited[node-1] = 1
for i in adj[node]:
if visited[i-1] == 1:
continue
check,temp = dfs(i)
sofar = sofar and check
if colors&temp:
sofar = False
colors = colors|temp
nonlocal subtrees
if sofar:
subtrees+=1
visited[node-1] = 0
return [sofar,colors]
dfs(1)
return subtrees
The above code resulted in TLE. Is there any better approach to do this? Or can it be optimised?

Automatically round arithmetic operations to eight decimals

I am doing some numerical analysis exercise where I need calculate solution of linear system using a specific algorithm. My answer differs from the answer of the book by some decimal places which I believe is due to rounding errors. Is there a way where I can automatically set arithmetic to round eight decimal places after each arithmetic operation? The following is my python code.
import numpy as np
A1 = [4, -1, 0, 0, -1, 4, -1, 0,\
0, -1, 4, -1, 0, 0, -1, 4]
A1 = np.array(A1).reshape([4,4])
I = -np.identity(4)
O = np.zeros([4,4])
A = np.block([[A1, I, O, O],
[I, A1, I, O],
[O, I, A1, I],
[O, O, I, A1]])
b = np.array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6])
def conj_solve(A, b, pre=False):
n = len(A)
C = np.identity(n)
if pre == True:
for i in range(n):
C[i, i] = np.sqrt(A[i, i])
Ci = np.linalg.inv(C)
Ct = np.transpose(Ci)
x = np.zeros(n)
r = b - np.matmul(A, x)
w = np.matmul(Ci, r)
v = np.matmul(Ct, w)
alpha = np.dot(w, w)
for i in range(MAX_ITER):
if np.linalg.norm(v, np.infty) < TOL:
print(i+1, "steps")
print(x)
print(r)
return
u = np.matmul(A, v)
t = alpha/np.dot(v, u)
x = x + t*v
r = r - t*u
w = np.matmul(Ci, r)
beta = np.dot(w, w)
if np.abs(beta) < TOL:
if np.linalg.norm(r, np.infty) < TOL:
print(i+1, "steps")
print(x)
print(r)
return
s = beta/alpha
v = np.matmul(Ct, w) + s*v
alpha = beta
print("Max iteration exceeded")
return x
MAX_ITER = 1000
TOL = 0.05
sol = conj_solve(A, b, pre=True)
Using this, I get 2.55516527 as first element of array which should be 2.55613420.
OR, is there a language/program where I can specify the precision of arithmetic?
Precision/rounding during the calculation is unlikely to be the issue.
To test this I ran the calculation with precisions that bracket the precision you are aiming for: once with np.float64, and once with np.float32. Here is a table of the printed results, their approximate decimal precision, and the result of the calculation (ie, the first printed array value).
numpy type decimal places result
-------------------------------------------------
np.float64 15 2.55516527
np.float32 6 2.5551653
Given that these are so much in agreement, I doubt an intermediate precision of 8 decimal places is going to give an answer that's not between these two results (ie, 2.55613420 that's off in the 4th digit).
This isn't part isn't part of my answer, but is a comment on using mpmath. The questioner suggested it in the comments, and it was my first thought too, so I ran a quick test to see if it behaved how I expected with low precision calculations. It didn't, so I abandoned it (but I'm not an expert with it).
Here's my test function, basically multiplying 1/N by N and 1/N repeatedly to emphasise the error in 1/N.
def precision_test(dps=100, N=19, t=mpmath.mpf):
with mpmath.workdps(dps):
x = t(1)/t(N)
print(x)
y = x
for i in range(10000):
y *= x
y *= N
print(y)
This works as expected with, eg, np.float32:
precision_test(dps=2, N=3, t=np.float32)
# 0.33333334
# 0.3334327041164994
Note that the error has propagated into more significant digits, as expected.
But with mpmath, I could never get that to happen (testing with a range of dps and a various prime N values):
precision_test(dps=2, N=3)
# 0.33
# 0.33
Because of this test, I decided mpmath is not going to give normal results for low precision calculations.
TL;DR:
mpmath didn't behave how I expected at low precision so I abandoned it.

MiniZinc select a subset of products -problem category

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]

Find number of rectangles from a given set of coordinates

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.

Plotting linear inequalities in Mathematica

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} ]

Resources