fourier_elim を懐柔する(その2)

前回の qfq では,例えば

(%i1) f:abs(x-a)=abs(x-b)+c;
(%o1)                     abs(x - a) = abs(x - b) + c
(%i2) qfq(f);
(%o2) ((0 < c) %and (a = b - c) %and (x = b))
 %or ((0 < c) %and (b = a - c) %and (x = a - c))
 %or ((a = b) %and (c = 0) %and (x = b))
 %or ((a = b - c) %and (max(b, b - c) < x))
 %or ((a = b - c) %and (c < 0) %and (x = b - c))
 %or ((a = c + b) %and (c < 0) %and (x = c + b))
 %or ((a = c + b) %and (x < min(b, c + b)))
 %or ((a = 2 x - c - b) %and (x < min(b, c + b)))
 %or ((a = 2 x + c - b) %and (max(b, b - c) < x))

のように出力に max,min が入る場合があります.

原因は

(%i3) listofvars(f);
(%o3)                            [a, x, c, b]

として変数を抽出している点,つまり,上の例の場合,fourier_elim が先ず a について解き,次に x について解き,…と進んでしまう点にあります.

そこで,変数の順序を指定できるように

qfq(f):=block([g],
if op(f)="%and" then (g:args(f),f2q(fourier_elim(g,
(if listp(fev) and length(fev)>0 then fev else listofvars(g))
)))
else f2q(fourier_elim(f,
(if listp(fev) and length(fev)>0 then fev else listofvars(f))
)))$

と改め,例えば

(%i4) fev:[c,b,a];
(%o4)                              [c, b, a]

とすれば

(%i5) qfq(f);
(%o5) ((a = x) %and (b = x) %and (c = 0))
 %or ((a = x) %and (b = x - c) %and (c < 0))
 %or ((a = x) %and (b = x + c) %and (c < 0))
 %or ((a < x) %and (b = x) %and (c = x - a))
 %or ((a < x) %and (b < x) %and (c = b - a))
 %or ((a < x) %and (c = 2 x - b - a) %and (x < b))
 %or ((b = x) %and (c = a - x) %and (x < a))
 %or ((b < x) %and (c = (- 2 x) + b + a) %and (x < a))
 %or ((c = a - b) %and (x < a) %and (x < b))

となり,これなら

(%i6) g:fqe([[E,x]],f);fqe([],(g) %eq (abs(c)<=abs(a-b)));
(%o6) ((c - b + a >= 0) %and (c + b - a <= 0))
                                   %or ((c - b + a <= 0) %and (c + b - a >= 0))
(%o7)                                true

と処理できます.