Perhaps there's a better way than using Reduce
three times, but it seems to me that the computations to figure out the range of each variable will have to be done somehow. Reduce
does that. This will work on such simple inequalities as in the OP's example:
And @@ (First@Reduce[a == b + c && a >= 2 && b <= 10 && c == 5, #] & /@
NestList[RotateLeft, {a, b, c}, 2])
(* 2 <= a <= 15 && -3 <= b <= 10 && c == 5 *)
For more complicated cases, one would have to check the Head
of the result to see if there are cases, indicated by a head of Or
. In that case, one would have to take the union of the ranges of each case.
With 100 variables the CylindricalDecomposition
returned by Reduce
will no doubt contain cases.
Here's a more generalized approach.
boundingBox[ineq_, vars_] := And @@ Simplify[
Reduce[ineq, #] & /@ NestList[RotateLeft, vars, 2] //. And[first_, rest_] :> first
]
boundingBox[a == b + c && a >= 12 && b <= 10 && c <= 10 && b >= 1 && c >= 1, {a, b, c}]
(* 12 <= a <= 20 && 2 <= b <= 10 && 2 <= c <= 10 *)
In some fashion, the maximum and minimum values of each variable have to be computed. Reduce
does more than that in computing the cylindrical decomposition, so perhaps some time may be saved. If we can assume that the inequalities are closed, we can try finding the extrema directly.
boundingBox2[ineq_, vars_] :=
And @@ (MinValue[{#, ineq}, vars] <= # <= MaxValue[{#, ineq}, vars] & /@ vars)
boundingBox2[a == b + c && a >= 12 && b <= 10 && c <= 10 && b >= 1 && c >= 1, {a, b, c}]
(* 12 <= a <= 20 && 2 <= b <= 10 && 2 <= c <= 10 *)
It's actually faster on this example.
SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] :=
Do[If[# > 0.3, Return[#/5^i]] & @@ AbsoluteTiming@Do[func, {5^i}], {i, 0, 15}]
boundingBox[
a == b + c && a >= 12 && b <= 10 && c <= 10 && b >= 1 && c >= 1, {a, b, c}] // timeAvg
boundingBox2[
a == b + c && a >= 12 && b <= 10 && c <= 10 && b >= 1 && c >= 1, {a, b, c}] // timeAvg
(* 0.01004385 *)
(* 0.00204969 *)
Reduce
? I'm not sure there's enough information to give a definitive answer. $\endgroup$ – Michael E2 Dec 9 '13 at 4:16Reduce
does not return what I want. For example, I triedReduce[a == b + c && a >= 2 && b <= 10 && c == 5, {a, b, c}]
, it returns2 <= a <= 15 && b == -5 + a && c == a - b
. What I expect to get is2 <= a <= 15 && -3 <= b <= 10 && c == 5
$\endgroup$ – Loi.Luu Dec 9 '13 at 4:21Reduce[.., {a, b, c}]
,Reduce[.., {b, c, a}]
, andReduce[.., {c, a, b}]
-- the first inequality in each is what you're after. Perhaps there's a more efficient way. If this example is typical, you should consider adding it to your question. As it is, it's a bit vague. You could even include a few examples to show the range of problems you wish to deal with. $\endgroup$ – Michael E2 Dec 9 '13 at 4:26Minimize
and Maximize` on the separate variables. $\endgroup$ – Daniel Lichtblau Dec 9 '13 at 14:24