I was thinking about CLP (FD) and the limits of how it can be used (I.E., why can’t it be used on floats?) and I realised something I didn’t know before: obviously constraint processing over rationals and complex rationals exists, since these are just pairs of integers (or rationals) (this is how they teach it in real analysis), so you get them for free with the integers. You can’t really do the same efficiently for irrationals since whilst you can identify limits with dedekind cuts and you might try to do interval sets with these, you need to basically know them with infinite precision to prevent overlap, and there are a whole boatload of irrational numbers (more than rationals) rendering that method quite inefficient. Not sure how CLP QR attempts to get around that problem, but very interesting thought! Moral of the story: You can manage to encode most things with integers.
Thanks for your insight! Wow, I didn’t know those old LISP algebra systems were still around and kicking. I wish I were less busy with other projects, or I’d be diving down that rabbit hole right now. I did wonder if maybe there was some way to represent the algebraics, being able to do that in SWI-PL would be really nice for all kinds of applications.
By the way, I was having a play around with implementing CLP(Q) myself from CLP(FD) because I think it would be neat to show how trivial it is, but since mod is seemingly not perfectly bidirectional (nor is gcd) I’m having issues with bidirectional rational multiplication/division. Any recommendations on this? Am I missing another nuance? Or simply not approaching the issue correctly?
I support add-on pack(clpBNR) which is a CLP over the extended set of reals, including rationals and irrationals (which I define as including algebraics). Also now available on SWISH (see clpBNR_quickstart).
If you think it’s trivial, I don’t understand what you’re trying to do. While rationals are “just pairs of integers” (numerator and denominator), I don’t think they come “for free”. That SWIP additionally includes the GMP library to support arithmetic for rationals (and extended integers) would suggest otherwise. Similarly I don’t think a CLP over rationals comes for free because you have CLP(FD), but perhaps I’m wrong.
As an aside, floats are a subset of rationals with some interesting properties. They are compact (SWIP floats are 64 bits + cell overhead) but can represent a large range of values. And they are efficient as all commonly used CPU hardware support the IEEE standard. The downside is that arithmetic operations on floats may be imprecise, so you need rounding control to ensure overall correctness of interval enclosures (sets of reals).
Sorry, it’s not really relevant to your goal, but I have recently made a pack for unit aware computation that is compatible with clpBNR, meaning you can do this:
?- qeval({A == 5000*gram / 2 * gram}). % wrong equation, see below
A = 2500.
Here is the original post: Units: a new pack for units and quantities
edit:
the correct equation was this:
?- qeval({A == 5000*gram / (2 * gram)}).
A = 2500.
By the way, I don’t really understand that sentence.
Isn’t the model building in clp* explicitly the encoding of facts and relations into constraints ?
Sorry, I have recently made a lot of change to the library.
I have pushed a new version 0.4. I believe you can update and test again ?
Ah, I made a classic syntax error and I wrongly retyped the equation in my previous message.
It should have been:
?- qeval({A == 5000*gram / (2 * gram)}).
multiplication operator * has lower priority than the division / operation.
Although the error is a bit cryptic, you can see that the quantity equation is not right:
5000/2 * kind(isq:mass)^2[si:gram^2]. this means that you have the number 5000/2 with the quantity mass^2 and unit gram^2.
The correct equation should have been a dimensionless quantity 1 and no unit 1, which you can see when evaluation the expression with the private predicate eval_/2:
?- units:eval_({A == 5000*gram / (2 * gram)}, E).
E = {A==5000/2} * 1[1].
Yeah, since clpBNR does not have an assignment operator, we need to specify the units for both side of the equation.
The best we can do for now is to infer the unit before hand:
?- units:eval_(5*gram + 1000*gram, E), qeval({A*E.u == E}).
E = 5+1000 * isq:mass[si:gram],
A = 1005.
The units:eval_/2 predicate is the internal units library expression parser predicate.
Unfortunately, we have to evaluate the expression 5*gram + 1000*gram first, because swi-prolog dict functional notation is eager and will expand before qeval has done it’s job.
It can ![]()
?- units:eval_(5*gram + 1*kilogram, E), qeval({A*E.u == E}).
E = 5+10^3 * isq:mass[si:gram],
A = 1005.
And by the way, you don’t need clpBNR for the examples you gave:
?- qeval(X is 5*gram + 1*kilogram).
X = 1005 * isq:mass[si:gram].
Crazy, it turns out you can just do this:
?- qeval({Z is X*gram + Y*kilogram}), X = 1, Z.v = 1001.
Z = 1001 * isq:mass[si:gram],
X = Y, Y = 1.