7

CLPFD-systems are not primarily targeted to handle quadratic equations efficiently, nevertheless, are there better ways to formulate problems like the following?

It seems the problem boils down to equations like the following. SWI with library(clpfd) gave:

?- time( ((L+7)^2#=L^2+189, L in 0..10000000) ).
% 252,169,718 inferences, 87208.554 CPU in 87445.038 seconds (100% CPU, 2892 Lips)
ERROR: Out of local stack

But now the latest version in SWI gives

?- time( ((L+7)^2#=L^2+189, L in 0..10000000) ).
% 3,805,545,940 inferences, 868.635 CPU in 870.311 seconds (100% CPU, 4381063 Lips)
L = 10.

and in SICStus 4.3beta7 I get:

| ?- statistics(runtime,_).
yes
| ?- (L+7)*(L+7)#=L*L+189, L in 0..10000000.
L = 10 ? ;
no
| ?- statistics(runtime,[_,T_ms]).
T_ms = 2550 ? ;
no
false
  • 10,182
  • 12
  • 93
  • 182
  • I also noticed - solving some Project Euler problem - that plain arithmetic can be much faster than CLP(FD). Seems that Markus has got an interesting problem to solve... BTW the time to find the first solution to `(L+7)*(L+7)#=L*L+189, L in 0..10000, label([L])` is much smaller than the time required when the ^2 operator is used... – CapelliC Mar 25 '14 at 18:40
  • 1
    @CapelliC: `*` in place of ^2 leads to less consistency. Also, the cost is proportional to the size of the domain for L. – false Mar 25 '14 at 19:26
  • 1
    Is actually solving the equation out of the question? What is your use case exactly? I am asking because it feels maybe a bit wasteful to not try to simplify before doing anything else. –  Mar 26 '14 at 07:23
  • @Boris: Solving the equation is always an option but at what price? – false Mar 26 '14 at 18:46
  • It's difficult to know the "price" when the use case is not known. If those are indeed just quadratic equations, it's fairly trivial to simplify them (or solve them) programmatically. –  Mar 26 '14 at 19:37
  • 2
    @Boris one might not use this in the quadratic case since there are precise algebraic solutions, but (I think) Ulrich is offering this by way of example. I played with it a bit in GNU and also saw the huge inconsistency between using `X^2` versus `X*X` (in GNU, the `X^2` was far better behaved. I think in general, for algebraic equations, one might need to apply some maths to prune the search tree a bit. Otherwise, the Prolog FD implementation(s) will struggle. – lurker Mar 27 '14 at 15:29
  • @repeat That was a year ago! :p I can't say I really remember what I did. I'm thinking I probably ran Ulrich's equation, but I don't recall how I measured it. I just tried it again and couldn't get the function to run more than once in the `X * X` case without resulting in a segfault (gprolog V 1.4.2). – lurker Mar 26 '15 at 20:32

1 Answers1

0

To solve this quickly, a constraint solver that has already a primitive X #= Y^2 constraint, might also implement the following rules:

Rule #1:

X #= (Y+C)^2 --> H #= Y^2, X #= H + 2*C*Y + C^2
% where C is an integer and X,Y variables

Rule #2:

X #= Z^2, Y #= Z^2 --> X #= Z^2, X #= Y.
% where X,Y,Z are variables

The above rules will reduce the equation to a linear equation, which is anyway directly solved by a decent CLP(FD) system. Here you see the difference between a system with and without rule #2:

Without Rule #2:

?- (L+7)*(L+7) #= L*L+189, stored.
_C #= 140+_B-14*L.
_B #>= 0.
_C #>= 0.
_B #= L*L.
_C #= L*L.
Yes

With Rule #2:

?- (L+7)*(L+7) #= L*L+189, stored.
L = 10
?- statistics(time, S), (L+7)*(L+7) #= L*L+189, statistics(time, T), U is T-S.
U = 3

But rule #2 looks a little ad hoc to me. Not yet sure whether one should keep it.

Bye

Mostowski Collapse
  • 12,118
  • 3
  • 34
  • 78