GithubHelp home page GithubHelp logo

triska / clpz Goto Github PK

View Code? Open in Web Editor NEW
175.0 11.0 14.0 1.04 MB

Constraint Logic Programming over Integers

Home Page: https://www.metalevel.at/prolog/clpz

Prolog 100.00%
clp constraints integer-arithmetic prolog sicstus-prolog constraint-programming

clpz's People

Contributors

triska avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clpz's Issues

Sum propagation in clp(fd)

If I have

A #= B + C + D, A #< 300, B #> 0, C #>0, D #> 0

A stronger propagation should be added stating that

B #< 300, C #< 300, D #< 300

Bug multiple sat/1 combined with weighted_maximum/3

Should weighted_maximum/3 work together with multiple sat/1
constraints. I get the following result:

/* SWI-Prolog (threaded, 64 bits, version 8.3.20) */
ฬ€?- sat(~(Y*X)), sat(Z=:=Y), weighted_maximum([7,2,5],[X,Y,Z],W).
false.

But was rather expecting:

?- sat(~(Y*X)), sat(Z=:=Y), weighted_maximum([7,2,5],[X,Y,Z],W).
Y = 1, X = 0, Z = 1, W = 7 ;
Y = 0, X = 1, Z = 0, W = 7

Verify propagation

Verify the following propagation:

?- M #= 10^150, [B,E,P]ins 0..M, P #= B^E, B #>= 2, P #< E.
M = 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
clpz:(B^E#=P),
clpz:(P#=<E+ -1),
clpz:(P in 512..999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999),
clpz:(E in 513..1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000),
clpz:(B in 2..1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) ? 
yes

Is this correct? Can it be made stronger?

addition example is slow to fail

In this Sicstus example,

pred(A, B, C) :-
    Max = 10000,
    [A, B] ins 0..Max,
    B #= C+A-Max,
    B #= C+1.

The predicate correctly fails since C+1 does not fit B's Max supremum (but C+0 would fit).
However, it is very slow to terminate (due to Max being big).
What can be done to fasten this seemingly simple kind of code? (In practice, these constraints come from more complex predicates that are hard to relate)

nvalue/2 non-monotonic

(i3a#372)

| ?- B=1, B in 1..2, C in 1..2, #(A)#> #(B),nvalue(A,[B,B,C]),labeling([],[B,C]).
B = 1,
C = 2,
A = 2 ? ;
no
| ?-      B in 1..2, C in 1..2, #(A)#> #(B),nvalue(A,[B,B,C]),labeling([],[B,C]).
no

It's not the labeling:

| ?- B=1, B in 1..2, C in 1..2, #(A)#> #(B),nvalue(A,[B,B,C]), A = 2, B = 1, C = 2.
B = 1,
C = 2,
A = 2 ? ;
no
| ?-      B in 1..2, C in 1..2, #(A)#> #(B),nvalue(A,[B,B,C]), A = 2, B = 1, C = 2.
no

In fact, both can be generalized to:

| ?-       B in 1..2, C in 1..2, #(A)#> #(B),nvalue(A,[B,B,C]).
no

Unification may fail with user attributes

I've found that we have a situation where unification could fail if a custom attribute is added before a clpz constraint is posted.

Consider this code

:- use_module(library(atts)).
:- use_module(library(clpz)).

:- attribute some_attr/0.


verify_attributes(_Var1, _Var2, []). % to satisfy pred3

pred1 :- % fails
    put_atts(A, some_attr),
    B #= _,
    A = B.

pred2 :- % works (but pointless)
    B #= _,
    _A = B.

pred3 :- % works
    B #= _,
    put_atts(A, some_attr),
    A = B.

pred4 :- % works
    A #= _,
    put_atts(A, some_attr),
    B #= _,
    A = B.

Running this on sicstus, we see that only pred1 fails. However swapping a goal (like pred3) or declare the var as a clpz constraint first (like pred4) works!

Output:

[jeshan@pc ~]$ sicstus --nologo --noinfo -l hello.pl --goal pred1.
* user:pred1 - goal failed
| ?- [jeshan@pc ~]$ sicstus --nologo --noinfo -l hello.pl --goal pred2.
| ?- [jeshan@pc ~]$ sicstus --nologo --noinfo -l hello.pl --goal pred3.
| ?- [jeshan@pc ~]$ sicstus --nologo --noinfo -l hello.pl --goal pred4.
| ?- [jeshan@pc ~]$ 

I'm not familiar with the clpz code but could it be because you assumed that variables_same_queue([Var,Other]) would always hold here?

clpz/clpz.pl

Lines 7385 to 7388 in 281aaf0

variables_same_queue([Var,Other]),
phrase((fd_put(Other,Dom1,Ps1),
trigger_props(Ps1)), [Q0], _),
Gs = [phrase(do_queue, [Q0], _)]

Am I reading this correctly or should the bug be fixed in my code?

Update: I've found that it makes a difference if the clpz var is either on left-hand side of X#=Y or right-hand side. If I have a specific example, I'll add it but I think you'll know that it's about verify_attributes implementation which may not have been tested for if Var and Other have been swapped in verify_attributes(Var, Other, Gs).

Goal expansion for (#\=)/2

This was raised by @JCumin:

X #\= Y

should become faster for ground X or Y, so that we can write for example:

R #\= N mod D

with acceptable performance.

Test cases

Is there any available list of test cases to check changes made to CLPZ?

Domain error after some level of backtracking with clpz: error(domain_error(clpz_expression,[]),unknown([])-1)

I am sure this is completely my fault, but it is not entirely clear to me what this error means. Am I mixing clpz expressions in some non-compatible way?

I have a very "naive" implementation of the following predicate to detect what numeric position (0-based) an element is within a list which I have run using scryer prolog and clpz:

:- use_module(library(lists)).
:- use_module(library(clpz)).

member_at_position(L, [L|_], 0).
member_at_position(L, [_|Ls], N) :-
    N #> 0,
    length(Ls, Length),
    Limit #= Length + 1,
    N #< Limit,
    member_at_position(L, Ls, M),
    N #= M+1.

Here is some interaction with the console which shows this issue:

?- member_at_position(a, [a,b,c,a,d], P).
   P = 0
;  caught: error(domain_error(clpz_expression,[]),unknown([])-1)
?- member_at_position(a, L, P).
   L = [a|_A], P = 0
;  L = [_A,a], P = 1
;  L = [_A,a,_B], P = 1
;  L = [_A,_B,a], P = 2
;  L = [_A,a,_B,_C], P = 1
;  caught: error(domain_error(clpz_expression,[]),unknown([])-1)
?- member_at_position(E, L, P).
   L = [E|_A], P = 0
;  L = [_A,E], P = 1
;  L = [_A,E,_B], P = 1
;  L = [_A,_B,E], P = 2
;  L = [_A,E,_B,_C], P = 1
;  caught: error(domain_error(clpz_expression,[]),unknown([])-1)

I am sure I am at fault here, but could you explain what is wrong please?

Stronger propagation for exponentiation

Enhance propagation in the following cases, if possible:

?-  X^Y #= 0.
X^Y#=0.

and:

?- X in 0..100, 2^I #= X.
X in 0..100,
2^I#=X.

Suggested by @JCumin. These cases must be checked carefully.

clpz: lots of unexpected constraints

?- B = 0, B in -2..0, 0#<==>0#=0/(B*B),labeling([],[B]).
   B = 0.
?- B in -2..0, 0#<==>0#=0/(B*B),labeling([],[B]).
   B = 0, clpz:(_A in 0..1), clpz:(2#=0#<==>_A), clpz:(0/_A#=_B), clpz:(_C#/\0#=_B#<==>0), unexpected.

Faraway bug

It seems this bug is caused by:

clpz/clpz.pl

Line 5126 in 78fcfe1

( { YInf cis_gt YSup } -> kill(MState), queue_goal(Z = Y)

It should be { YInf cis_gt XSup }.

Assert domain from set of values

I see from your knight's tour example , you wrote a small utility to convert a list of values to a domain:

foldl(num_to_dom, Nexts, Next, Dom)

where:

num_to_dom(N, D0, D0\/N).

I think this should be part of the library itself. Something like:

Var in_set [1, 2, 3, 4]
Vars ins_set [1, 2, 3, 4]

Integration with `library(reif)`?

Hello there! After watching/reading part of 'the Power of Prolog' (amazing material by the way!), I wanted to get some experience with using clpz.

As challenge, I attempted to implement a variant of FizzBuzz that uses CLP(Z) rather than the builtin arithmetic predicates, as well as if_ (of library(reif)), both with the idea in mind to write as 'logicaly pure' code as possible.

The issue arose that I tried to use (#=)/2 inside if_, which did not work. After reading up on its definition in Scryer-Prolog's standard library as well as the 'indexing dif'-paper, I realized that if_ uses an arity-3 version of the predicate that is passed as first argument.

I was able to adapt the example of (=)/3 given in the paper to (#=) although I am not 100% if my implementation is correct.
To be precise, a call like ?- number_fizzbuzz(5, Res). still produces a choicepoint:

?- number_fizzbuzz(5, Res).
Res = 'Buzz' ;
false.

Am I using clpz and reif correctly together here? Or am I making a mistake?
Is providing a reif-compatible implementation of (#=)/3 (and maybe of the other similar predicates) something that would be worthwhile to add to clpz, or not?

Thank you for your consideration,

~Qqwy/Marten


:- module(fizz_buzz, [main/0, number_fizzbuzz_below_100/2, number_fizzbuzz/2]).
:- use_module(library(reif)).

% for Scryer-Prolog:
:- use_module(library(clpz)).

:- use_module(library(between)).
:- use_module(library(iso_ext)).

% for SWI-Prolog:
% :- use_module(library(clpfd)).

% Prints all solutions to `number_fizzbuzz_below_100` each on a separate line, in order.
% Logically-impure shell.
main :-
    forall(number_fizzbuzz_below_100(_, FizzBuzz), (write(FizzBuzz), write('\n'))).

% Constrains FizzBuzz results to the range 1 <= X <= 100,
% and (for the 'most general query' where neither X or FizzBuzz is concrete)
% ensures results are traversed in order low -> high X (with concrete X).
number_fizzbuzz_below_100(X, FizzBuzz) :-
    between(1, 100, X),
    number_fizzbuzz(X, FizzBuzz).

% States the relationship between a number
% and its FizzBuzz representation.
number_fizzbuzz(Num, FizzBuzz) :-
    if_((Num mod 15 #= 0), FizzBuzz = 'FizzBuzz',
        if_((Num mod 5 #= 0), FizzBuzz = 'Buzz',
            if_((Num mod 3 #= 0), FizzBuzz = 'Fizz',
                Num = FizzBuzz)
           )
       ).

% Reifiable `#=`.
% Is this implementation correct?
% Can this implementation be improved to reduce useless choicepoints?
#=(X, Y, T) :-
      (X #= Y,  T = true)
    ; (X #\= Y, T = false).

tuples_in/2 misses tuple_domain/2

Trying SWI-Prolog/swipl-devel#1160 in SICStus:

| ?- tuples_in([[A,B]],[[11,0],[12,1]]).
! Existence error in clpz:tuple_domain/2
! procedure clpz:tuple_domain/2 does not exist
! goal:  clpz:tuple_domain([_229,_233],[[11,0],[12,1]])
| ?- X in 1..2.
clpz:(X in 1..2) ? 
yes

Documentation: unnecessary functional notation.

The documentation reads:

?- assertz(clpz:monotonic).
true.

?- #(X) #= #(Y) + #(Z).
#(Y)+ #(Z)#= #(X).    % inaccurate answer, given the operator definition for `(#)/1`

Yet, the functional notation is superfluous and the example is a bit irritating. E.g. in Scryer:

?- assertz(clpz:monotonic).
   true.
?- #(X) #= #(Y) + #(Z).
   clpz:(#Y+ #Z#= #X).
?- #X + #Y #= #Z.
   clpz:(#X+ #Y#= #Z).       % this example is preferable as the answer is not reformulated

sign/1 lacking

?- X #= sign(-10).
caught: error(domain_error(clpz_expression,sign(-10)),unknown(sign(-10))-1)

Expected: X = -1.

See also this comment.

leaking constraints

In SICStus:

| ?- call_residue_vars(X in 1..2,Vs).
Vs = [X,_A,_B,_C,_D,_E,_F],
clpz:(X in 1..2) ? ;
no
| ?- [user].
% compiling user...
| l :- X in 1..2, X = 1, l.
| 
% compiled user in module user, 4 msec 2752 bytes
yes
| ?- catch(l,error(E,_),true).
   E = resource_error(memory), unexpected.
$ ulimit -v
500000

Possible improvements to abs/1

(Tested on SWI's CLP(FD), though I assume the same problem exists in CLP(Z))

Weak propagation

?- X #= abs(X) + 1.
X in 2..sup,
_G2048+1#=X,
_G2048#=abs(X),
_G2048 in 2..sup.

This could directly fail. As a result it takes a long time for this to fail, even though it is obvious that it will:

?- time((X #= abs(X) + 1, X in 1..100000, indomain(X))).
% 17,551,054 inferences, 65.037 CPU in 65.061 seconds (100% CPU, 269863 Lips)
false.

Redundant constraint

?- X #= abs(X).
X in 0..sup,
X#=abs(X).

This correctly constrains X to 0..sup from inf..sup, but then the X#=abs(X) constraint is completely unnecessary.

Bug CLP(B) and CLP(FD) dont work together

I am not assuming that CLP(B) from SWI-Prolog uses branch and bound
for weighted_maximum/2. But theoreticall CLP(B) branch and bound should
work for any constraints, given as freeze/2, when/2, CLP(FD) etc..

I tried this theoretical claim. In my system I get:

/* Jekejeke Prolog 1.5.0 */
?- List = [Alice, Bob, Carla, David], weighted_maximum([5,-3,7,-9], List, Max).
List = [1, 0, 1, 0],
Max = 12 ;
No

?- List = [Alice, Bob, Carla, David], Alice*5-Bob*3+Carla*7-David*9 #<10, 
   weighted_maximum([5,-3,7,-9], List, Max).
List = [1, 1, 1, 0],
Max = 9 ;
No

But in SWI-Prolog I get:

/* SWI-Prolog 8.3.20 */
?- List = [Alice, Bob, Carla, David], weighted_maximum([5,-3,7,-9], List, Max).
List = [1, 0, 1, 0],
Max = 12.

?- List = [Alice, Bob, Carla, David], Alice*5-Bob*3+Carla*7-David*9 #<10, 
   weighted_maximum([5,-3,7,-9], List, Max).
false.

Is this unavoidable in SWI-Prolog? Does CLP(Z) fare better?

More general global_cardinality/3

It would be nice if global_cardinality/3 supported CLP(Z) variables as keys. This would allow one to express more general permutations without needing to know the values of the list (e.g. two of one number and three of another).

Compatibility with SWI

If this cannot be done ATM because of missing libraries or open issues, then we can at least assemble a list of requirements SWI should meet in order to add compatibility in the future.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.