Closed JeanChristopheRohner closed 3 years ago
I would expect this to fail. numbervars
unifies the first argument with a term of the form $VAR(N)
. When X
is an interval, it can only be unified with a numeric value or another interval. So when the option is attvar(bind)
this causes a unification failure. attvar(skip)
should work.
I assume you're trying to assign a more meaningful/simpler name to internal intervals. This has crossed my mind, but couldn't think of any way where the costs outweigh the benefits. Let me know if you have any ideas.
I understand. My goal was to "pretty print" variable names, without the underscore format.
With this:
test1:-
{X * X == 4},
numbervars(X, 0, _, [attvar(skip)]),
Y = someFunctor(this, X, that, _),
writeln(Y).
I get the output:
someFunctor(this,_17060{real(-2,2)},that,_17628)
What i ended up doing to solve my problem was to strip the variable name for any attributed variables only keeping the interval:
test2:-
{X * X == 4},
Y = someFunctor(this, X, that, _),
Y =.. L,
maplist(parse_arg, L, L2),
Y2 =.. L2,
numbervars(Y2, 0, _),
writeln(Y2).
parse_arg(I, O):- attvar(I), I::O.
parse_arg(I, O):- \+attvar(I), I = O.
Which yields:
someFunctor(this,real(-2,2),that,A)
Kind regards, JC
OK. One thing worth considering: by stripping the var you lose the ability to distinguish between two intervals with same domain, e.g., [X,Y]::real(1,10)
would result in X
and Y
both being output as real(1,10)
(which may or may not matter to you).
Yes, i would prefer to be able to have both the variable and interval. I just couldn't figure out how to keep the variable and pretty print its name (i.e. A
instead of _58926395
).
A hack that seems to work to get the variable is to convert to and from a string with term_string/2
. The code in test
below produces uninstantiated named variables (A, B, and so on) when the interval is too large, and a midpoint solution when the interval is small. The code in test2
produces both the interval and var name.
MIDPOINT
:-use_module(library(clpBNR)).
test:-
{X * X == 4}, %here the resulting interval is to large (-2, 2) for a midpoint to say something meaningful
{Y == 1.1 * 1.1}, %the interval is small enough to make a midpoint meaningful
F = someFunctor(this, X, that, _, Y, X, nested(Y, X)), %a compound, where X and Y appear multiple times (to check if numbervars gives them the same name)
F =.. L, %convert compound to list
maplist(parse_arg, L, L1), %parse arg, see below
F2 =.. L1, %convert parsed list back to compound
term_string(F2, F3), %convert compound to string
term_string(F4, F3), %convert string back to compound
numbervars(F4, 0, _), %do numbervars on this compound
writeln(F4).
parse_arg(I, O):- attvar(I), delta(I, D), {D < 0.0001}, midpoint(I, O). % replace with midpoint if the interval is reasonably small
parse_arg(I, O):- attvar(I), delta(I, D), {D >= 0.0001}, O = I. % continue using attvar if the interval is too large
parse_arg(I, O):- \+attvar(I), \+compound(I), I = O. %not attvar and not compound so just use the old argument
parse_arg(I, O):- compound(I), I =.. L, maplist(parse_arg, L, L1), O =.. L1. %term is a compound so apply parse_arg to each argument
Yields:
someFunctor(this,A,that,B,1.2100000000000004,A,nested(1.2100000000000004,A))
BOTH VARNAME and INTEVAL
test2:-
{X * X == 4},
{Y == 1.1 * 1.1},
F = someFunctor(this, X, that, _, Y, X, nested(Y, X)), %a compound, where X and Y appear multiple times (to check if numbervars gives them the same name)
F =.. L, %convert compound to list
maplist(parse_arg2, L, L1), %parse arg
F2 =.. L1, %convert parsed list back to compound
term_string(F2, F3), %convert compound to string
term_string(F4, F3), %convert string back to compound
numbervars(F4, 0, _), %do numbervars on this compound
writeln(F4).
parse_arg2(I, O):- attvar(I), I::DOM, O = I:DOM.
parse_arg2(I, O):- \+attvar(I), \+compound(I), I = O.
parse_arg2(I, O):- compound(I), I =.. L, maplist(parse_arg2, L, L1), O =.. L1.
Yields:
someFunctor(this,A:real(-2,2),that,B,C:real(1.21,1.2100000000000006),A:real(-2,2),nested(C:real(1.21,1.2100000000000006),A:real(-2,2)))
Hi!
Not sure if this a problem or not, but should the code below return the interval (
1.21, 1.2100000000000006
)? The predicate below instead fails.