1

The documentation says that

copy_term(+Term, -Copy, -Body) makes a copy of Term in which all variables have been replaced by new variables that occur nowhere outside the newly created term. If Term contains attributed variables, Body is unified with a term such that executing Body will reinstate equivalent attributes on the variables in Copy.

I'm previously affirming numerical CLP(R) constraints over some variables, and at some point I collect these constraints using copy_term/3. Later, when I try to reinstate the constraints using 'call(Body)', I get an "Instantiation error" in arguments of the form [nfr:resubmit_eq(...)]

Here's a simplified example that demonstrates the problem:

:-use_module(library(clpr)).
{Old>=0, A>=0,A=<10, NR= Old+Z, Z=Old*(A/D)}, copy_term(Old,New,CTR), call(CTR).

Results in:

Instantiation error in argument 1 of '.'/2
! goal:  [nfr:resubmit_eq([v(-1.0,[_90^ -1,_95^1,_100^1]),v(1.0,[_113^1])])]

My question is: how do I reinstate the constraints in Body over New? I haven't been able to find concrete examples.

false
  • 10,264
  • 13
  • 101
  • 209
vmg
  • 4,176
  • 2
  • 20
  • 33

2 Answers2

3

copy_term/3 is a relatively new built-in predicate, that has been first introduced in SICStus about 2006. Its motivation was to replace the semantically cumbersome call_residue/2 which originated from SICStus 0.6 of 1987 by a cleaner and more efficient interface that splits the functionality in two:

call_residue_vars(Goal, Vars) which is like call(Goal) and upon success unifies Vars with a list variables (in unspecified order) that are attached to constraints and have been created or affected in Goal.

copy_term(Term, Copy, Body) like copy_term/2 and upon success unifies Body with a term to reinstate the actual constraints involved. Originally, Body was a goal that could be executed directly. Many systems that adopted this interface (like SWI, YAP) however, switched to use a list of goals instead. This simplifies frequent operations since you have less defaultyness, but at the expense of making reinstating more complex. You need to use maplist(call,Goals).

Most of the time, these two built-in predicates will be used together. You are using only one which makes me a bit suspicious. You first need to figure out which variables are involved, and only then you can copy them. Typically you will use call_residue_vars/2 for that. If you are copying only a couple of variables (as in your exemple) you are effectively projecting the constraints on these variables. This may or may not be your intention.

false
  • 10,264
  • 13
  • 101
  • 209
  • @j4nbur53: I'd say: Harmless. What is important is that `[]` is given if there is nothing left. – false Oct 31 '15 at 23:17
  • Yes. if you look at the implementation of call_residue/2 (still in YAP), you will see lots of copying going on anyway. But at least this "new" interface (10yrs old) is less costly and maintains certain consistencies - compared to the older interface. – false Oct 31 '15 at 23:28
  • The interface here is the result of ~20 years experience with constraints in SICStus. – false Oct 31 '15 at 23:33
  • Prior to this, `library(clpfd)` had tons of problems. Similarly, with delayed goals. – false Oct 31 '15 at 23:34
  • It is up to you to implement `copy_term(X,X,C)` more efficiently. By the same token, also `copy_term(G+V,G+L)` might be implemented in a more efficient manner. It is all up to you. – false Oct 31 '15 at 23:43
  • Correction: The current YAP version already has an implementation that is very similar to this interface. – false Oct 31 '15 at 23:47
2

This is simply a bug in CLPR, which is unsupported. We lost touch with the CLPR supplier a long time ago.

Mats Carlsson
  • 1,426
  • 7
  • 3