# Assigning restrictions to rational solutions from Solve/Reduce/FindInstance

I want to restrict the outputs of Solve/Reduce/FindInstance, etc. to "simple" rationals, which I define as rationals of the form:

$$\pm \dfrac{a}{b}\; \text{ where } \; a, b \in \{1, 2, 3, 4, 5, 6\},$$

e.g., $$\tfrac{3}{5}$$, $$5$$, $$-\tfrac{4}{3}$$, etc.

Since MMA associates the sign with the numerator, e.g.:

g = -3/4;
Numerator@g
Denominator@g


-3

4

... I believe restrictions on rationals can be represented as follows:

g = -3/4;
h = 5;
-6 <= Numerator@g <= 6 && 1 <= Denominator@g <= 6
0 <= Numerator@g <= 6 && 1 <= Denominator@g <= 6
0 <= Numerator@h <= 6 && Denominator@h == 1
-6 <= Numerator@h <= 6 && 2 <= Denominator@h <= 6


True

False

True

False

However, Solve, Reduce, and FindInstance don't recognize this. For example:

exprA = p + ρ + σ == 0 && -p + r + 2 ν - 3 ρ ==
0 && -2 p - ν - 2 σ == 1


FindInstance[
exprA && -6 <= Numerator@σ <= 6 &&  1 <= Denominator@σ <= 6
&& -6 <= Numerator@ν <= 6 &&  1 <= Denominator@ν <= 6
&& -6 <= Numerator@r <= 6 && 1 <= Denominator@r <= 6
&& -6 <= Numerator@p <= 6 && 1 <= Denominator@p <= 6
&& -6 <= Numerator@ρ <= 6 && 1 <= Denominator@ρ <= 6,
{σ, ν, r, p, ρ}, Rationals, 2]


With fewer variables (say, 3 instead of 5), I could instead brute-force the restriction by explicitly reformatting each variable as the ratio of sub-variables, applying value and domain restrictions to each—e.g., replacing the variable $$r$$ with $$\frac{r_1}{r_2}$$, where $$-6 \leq r_1 \leq 6$$, $$1 \leq r_2 \leq 6$$, $$r_1\in \mathbb{Z}$$ and $$r_2\in \mathbb{Z}$$. One can then use Table or Map to recombine the sub-variables in the output into rational solutions for the variables, and delete the duplicates. E.g.:

exprB = -((3 r1)/r2) - ν1/ν2 + σ1/σ2 == 0 &&
r1/r2 + ν1/ν2 == 0 && -((2 ν1)/ν2) == 1


soln = Solve[
exprB && {σ1, σ2, ν1, ν2, r1, r2} ∈ Integers &&
And @@ Thread[-6 <= {σ1, σ2, ν1, ν2, r1,
r2} <= 6], {σ1, σ2, ν1, ν2, r1, r2}];
tab = DeleteDuplicates@
Table[soln[[j, i, 2]]/soln[[j, i + 1, 2]], {j, 1, Length@soln}, {i,
1, Length@soln[[1]] - 1, 2}];
TableForm[tab, TableHeadings -> {None, {"σ", "ν", "r"}}]


However, this method doesn't work with exprA, since its five variables become 10, making the calculation take too long. [I stopped the following after it ran for 24 hours on my 2019 i9 iMac without producing a result.] Thus it would be nice if there were a way to apply the restrictions directly to the original rational-valued variables, rather than transforming them to ratios of integer-valued variables and thus doubling their number:

exprC = exprA /. {σ -> (σ1/σ2), ν -> (ν1/ν2),
r -> (r1/r2), p -> (p1/p2), ρ -> (ρ1/ρ2)}


soln = Solve[
exprC &&
And @@ Thread[-6 <= {σ1, σ2, ν1, ν2, r1, r2,
p1, p2, ρ1, ρ2} <=
6] && {σ1, σ2, ν1, ν2, r1, r2, p1,
p2, ρ1, ρ2} ∈
Integers, {σ1, σ2, ν1, ν2, r1, r2, p1,
p2, ρ1, ρ2}]
tab = DeleteDuplicates@
Table[soln[[j, i, 2]]/soln[[j, i + 1, 2]], {j, 1, Length@soln}, {i,
1, Length@soln[[1]] - 1, 2}];
TableForm[tab,
TableHeadings -> {None, {"σ", "ν", "r", "p", "ρ"}}]

• Why you not simply solve FindInstance[exprA, {\[Sigma], \[Nu], r, p, \[Rho]}, Rationals, 2]and then pick the solutions you want? Commented Jul 25, 2023 at 7:27
• @DanielHuber I want all solutions that satisfy my constraints: All numbers are of of the form: $\pm \dfrac{a}{b}$, where a, b = {1, 2, 3, 4, 5, 6}. If you try runningFindInstance[exprA, {\[Sigma], \[Nu], r, p, \[Rho]}, Rationals, 2], you'll see it gives two solutions, neither of which satisfy my constraints: {{[Sigma] -> -(67/29), [Nu] -> 6, r -> -(78/29), p -> -(69/58), [Rho] -> 7/2}, {[Sigma] -> 101/34, [Nu] -> 137/34, r -> -6, p -> -(373/68), [Rho] -> 171/68}} Commented Jul 25, 2023 at 16:36

## Why Numerator and Denominator do not work in Solve or FindInstance?

Because for symbolic input, they get immediately evaluated:

Numerator[x]
(* x *)

Denominator[x]
(* 1 *)


Therefore, Solve and FindInstance don't even see them:

Solve[Numerator[x] == 3, x] // Trace // Column
(* {{Numerator[x],x},x==3}
Solve[x==3,x]
{{x->3}}
{{x->3,x->3},{x->3}}
{{x->3}} *)


This explains why some solutions may seem wrong at first sight:

FindInstance[Numerator[x] > 1 && Numerator[x] < 20, x, Rationals]
(* {{x -> 21/2}} *)


Given my explanation above (or using Trace), you can convince yourself that the code is actually equivalent to

FindInstance[x > 1 && x < 20, x, Rationals]


and the corresponding result $$21/2$$ is correct.

## Alternative solution

Using Solve (or Reduce):

Solve[exprA]
(* {{ν -> 3 + 2 p - 2 r, ρ -> 2 + p - r, σ -> -2 - 2 p + r}} *)


we determine that there are only two independent variables ($$p$$ and $$r$$). Therefore, we can enumerate all possible $$p$$ and $$r$$, and then perform filtering on the other three variables:

sol1 = First@Solve[exprA];
fracs = DeleteDuplicates@Flatten@Table[m a/b, {m, {1, -1}}, {a, 1, 6}, {b, 1, 6}];
pqs = {p -> #1, r -> #2} & @@@ Tuples[fracs, {2}];
sols = {ν, ρ, σ, p, r} /. sol1 /. # & /@ pqs;

solsFiltered = Select[sols, ContainsAll[fracs, #] &]
(* {{3, 2, -3, 1, 1}, {1, 1, -2, 1, 2}, {2, 3/2, -(5/2), 1, 3/2}, ...} *)

Length[solsFiltered]
(* 234 *)

• Nice use of algebra to make the problem tractable for MMA. Any idea why Solve, etc., don't accept Numerator or Denominator constraints as restrictions in equalities or inequalities? As I mentioned above, MMA does return True or False when those restrictions are applied outside of those functions. Commented Jul 29, 2023 at 23:35
• @theorist, please see my edit. Commented Jul 30, 2023 at 11:25