clpBNR: difference constraint on reals

Sorry, still too hypothetical and keeps changing.

So which is it? Why disjoint ranges (from previous post) if the functions “depend on the specific (real number) lat/long.”? If you have a Lat/Long range, the constraint functions will provide a range of energy values for that (approximate) location. If the position is refined further, so will the energy range.

Because the trucks can only be in certain geographic areas (disjoint areas, specified by real intervals of lat/long) and within these areas the functions for cost, speed, energy, etc are used and the problem needs to take into account both the disjoint areas and the other constraints at the same time.

It has not changed from the original problem I posted, you narrowed the problem to mapping areas to integers and I was trying to explain why this narrowing would not be useful.

I don’t think I’m suggesting anything that contradicts this. I’ve just defined regions (“certain geographic areas”) and constraints associated with those regions - currently just location, but could be extended with cost, speed, etc. Other constraints may include mutual constraints between truck instances. But I can’t say much more than that because the problem isn’t sufficiently defined.

All considered, I think your enumerate_domains proposal above would be useful to solve these kinds of problems. I also can’t think of a good name, but I think it would be useful.

That’s interesting, because there’s really no semantic difference between enumerate_domains and standard enumerate used with an explicit integer, as in the “regions” example.

So with the helper predicate:

subDomains(R,S) :-
	S::integer(1,2),
	{(S==1, 1=<R,R=<3) or (S==2, 8=<R,R=<10)}.

the initial simple example (used to demonstrate enumerate_domains ) becomes:

?- subDomains(X,SX),subDomains(Y,SY),{SX<>SY},enumerate([SX,SY]).
SX = 1,
SY = 2,
X::real(1, 3),
Y::real(8, 10) ;
SX = 2,
SY = 1,
X::real(8, 10),
Y::real(1, 3).

So I had come to the conclusion that enumerate_domains was redundant, not to mention that it can be expensive. (It has to scan the cyclic constraint network looking for “implicit” booleans to enumerate.)

How can you use it for reals?

Don’t understand the question; X and Y are reals. And it makes no sense to represent a (finite) set of subdomains by a real.

ooops, my mind wasn’t working. Thanks.

Back to the early proposal for a “declaration” of disjoint intervals, consider a predicate disjoint_union/3 which takes some variable A , the subdomains definition Type(Subs) (Subs is a sequence of sub-ranges), and a sub-domain selector variable As. If it succeeds, the effect of disjoint_union is to apply all the necessary mutual constraints. Example:

?- disjoint_union(X,real((1,3),(8,10)),SX).
SX::integer(1, 2),
X::real(1, 10).

To support labelling, the selector can be used to enumerate the sub-domains. Or if X is narrowed, SX will narrow accordingly, which may constrain other dependant values (cost, speed, …):

?- disjoint_union(X,real((1,3),(8,10)),SX), enumerate(SX).
SX = 1,
X::real(1, 3) ;
SX = 2,
X::real(8, 10).

?- disjoint_union(X,real((1,3),(8,10)),SX), {X>=5}.
SX = 2,
X::real(8, 10).

Note these are all just constraints, not declarations that impose an execution order so:

?- {X>=5}, disjoint_union(X,real((1,3),(8,10)),SX).
SX = 2,
X::real(8, 10).

Subdomain selectors can be used to enforce mutual constraints:

?- disjoint_union(X,real((1,3),(8,10)),SX), disjoint_union(Y,real((1,3),(8,10)),SY), {SX<>SY}, enumerate([SX,SY]).
SX = 1,
SY = 2,
X::real(1, 3),
Y::real(8, 10) ;
SX = 2,
SY = 1,
X::real(8, 10),
Y::real(1, 3).

The implementation of disjoint_union/3 is pretty simple (uses “,” as synonym for “and” - will be available in v0.9.9):

disjoint_union(A,Doms,As) :-
	Doms=..[Type|Subs],
	dj_constraints(Subs,A,As, 1,Len, 1.0Inf,-1.0Inf,Min,Max, Cs),
	As::integer(1,Len),
	Dom=..[Type,Min,Max], A::Dom,
	{Cs}.
	
dj_constraints([R],A,As, N,N,  MinIn,MaxIn, Min,Max, C) :-               % last in `or`
	dj_constraint(R,A,As, N,  MinIn,MaxIn, Min,Max, C),
	!.
dj_constraints([R|Subs],A,As, N,Len, MinIn,MaxIn, Min,Max, C or Cs) :-   % `or` sequence
	dj_constraint(R,A,As, N,  MinIn,MaxIn, NxtMin,NxtMax, C),
	!,
	NxtN is N+1,
	dj_constraints(Subs,A,As, NxtN,Len, NxtMin,NxtMax, Min,Max, Cs).
dj_constraints([L,H],A,As, N,N,  MinIn,MaxIn, Min,Max, C) :-    % in case of naked bounds
	dj_constraint((L,H),A,As, N,  MinIn,MaxIn, Min,Max, C).

dj_constraint((L,H),A,As, N, MinIn,MaxIn, Min,Max, (As==N, L=<A,A=<H)) :- 
	Min is min(MinIn,L),  Max is max(MaxIn,H).

This is an interesting application of mixed mode constraints that should be added to the clpBNR User Guide, but I’d like to find a simple concrete problem example, e.g., in a text book or academic paper. Any suggestions welcome.

This is much better, and I think it completely solves the use case I was talking about before. Thanks! Will it be in 0.9.9?

Unfortunately I don’t know of any textbook or paper with this kind of example. I think this kind of usage is somewhat new in the clp domain.

At the moment, no. I’ve tried to keep the module interface to a minimum so just those utility predicates that require (or can take advantage of) the low level implementation are included. Things like numerical integration (for solving differential equations), meta-contractors, cardinality, etc. are not included but their implementation and usage are covered by the User Guide. And I think disjoint_union fits in that category (which is why I’m searching for a relevant simple example). In the meantime, the implementation is in this thread. (Change ","s to “and” in the last dj_constraintargument for use in current release.)

OK, I’ll keep looking (and thinking).

1 Like