Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLP(ℤ) in multiple files #36

Open
notoria opened this issue Dec 9, 2024 · 1 comment
Open

CLP(ℤ) in multiple files #36

notoria opened this issue Dec 9, 2024 · 1 comment

Comments

@notoria
Copy link

notoria commented Dec 9, 2024

Current clpz is one file of 7.6k lines, I'm having trouble using/understanding it.

Is there a version of clpz in multiple files? If no, any advice on how to split it?

@triska
Copy link
Owner

triska commented Dec 14, 2024

Currently, it is only a single file. Conceptually, we can distinguish at least the following parts, occurring roughly in this order in the source file:

  • domain operations, an essential building block used throughout by the entire library. These may be good candidate operations for Rust-based implementations, if we either manage to generate the Rust code automatically from declarative descriptions, or we benefit from the JIT compilation work of @aarroyoc.
  • labeling and related predicates
  • propagator queue handling, a small kernel that schedules and interprets propagators
  • parsing of arithmetic constraints
  • goal expansion. The reason for the strange location of this is that defined goal expansions affect goals in the file itself, and therefore we must take care to affect only those portions that we want to be affected.
  • parsing of reified constraints
  • constraint propagation, currently the largest part
  • filtering algorithms for global constraints like all_distinct/1, this is the part that may in the future grow to be the largest

Are you interested in any of these portions in particular? Please let me know any time if you have any questions!

Personally, I think the part that would most benefit from improvements is constraint propagation. For instance, we have:

% X + Y = Z
run_propagator(pplus(X,Y,Z,Morph), MState) -->
        (   nonvar(X) ->
            (   X =:= 0 -> kill(MState), Y = Z
            ;   Y == Z -> kill(MState), X =:= 0
            ;   nonvar(Y) -> kill(MState), Z is X + Y
            ;   nonvar(Z) -> kill(MState), Y is Z - X
            ;   { fd_get(Z, ZD, ZPs),
                  fd_get(Y, YD, _),
                  domain_shift(YD, X, Shifted_YD),
                  domains_intersection(ZD, Shifted_YD, ZD1) },
         et cetera

This is really subpar. The code is lengthy and error-prone, and uses impure constructs that are known to be incomplete, a rich source of mistakes that, due to their rarity, can be very hard to find even by exhaustive testing. Can we do better than this? I sure hope so!

Let's stay with propagation of elementary arithmetic constraints, like addition. What must hold for the domains of X, Y and Z such that X + Y #= Z is true? How do we know this? Can we use the definition of addition to derive such propagation, i.e., reasoning about domains or at least their boundaries? What is the best formalism to state this? Indexicals may be a promising route, GNU Prolog and SICStus use them! But they do not let us state everything we may want to state in propagators.

I would much prefer if a lot more of the code were generated from shorter declarative descriptions. This would also simplify it and make it easier to understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants