Set a default value for a variable if it is not provided by user

I want to make a rule where I have three variables, Input, Compare, Output.
If the user supplies the Compare value, I want it to be run with that. If the user does
not supply a Compare, I want to set it. Does SWI-Prolog have a way to set a variable to
a default value without overriding what the user inputs?

Something like if(x = null) {do y}, else {do z}.

To be more specific, I am trying to create an odd/3 rule so that we can test if a number is odd (without using mod/2), or if we know a number was odd, we can find what that number was (run it in reverse).

I have a functional odd/2 rule that goes like:
odd(Input, Output):-
Input #> 0,
integer(Input),
Input>>1 =:= (Input-1)/2.

The last line gets rid of the final binary 1, so if the user supplied the fact that a number was odd, and perhaps the value of Compare = (Input-1)/2, then the rule could solve for the Input.

Your code for odd/2 doesnā€™t do anything with ā€˜Outputā€™ and I also got a syntax error with it ā€“ which library are you using (for #>)?

Are you trying to write a predicate that can do this?

?- odd(2).
false.
?- odd(3).
true.
?- odd(X).
X = 1 ;
X = 3 ;
X = 5 ;
   ...

->/2 performs that ifā€¦ thenā€¦ else.

1 Like

Sorry, I was messing with it before posting this, so it looks like I hadnā€™t gotten it back to the way it was originally.

It should be an odd/1 function, as far as what works currently:

odd(Input) :-
Input #> 0,
integer(Input),
Input>>1 =:= (Input-1)/2.

The library is clp(fd). I have a couple of other flags set normally, so if you continue to get errors, please let me know, and we can track those down. I think this should be enough though.

But the idea was to make a relation <odd(In, Compare, Out)> so that a rule involving odd-checking could work in reverse. This requires that I modify the odd/1 rule into something like an odd/3, which if I knew the answer (True / False being ā€œOutā€ and what number the bit movement was compared to), I could generate the thing that was tested (In).

It may not be possible, but I figured Iā€™d ask here since Iā€™m relatively inexperienced with Prolog.

As far as I know, ā†’ cannot be used in reverse cases. So like, in the case of a statement like

X + 2 #= 3 ā†’ Z #= 5; Z#= 3

you canā€™t supply Z to find X, precisely because you dont know what X might be if the relation doesnt hold.

In my case, I want to perform different operations based on a truth statement, so Iā€™m unsure if an if statement can be used backwards, since the means of determining the input will be set. Something more like:

X #> 5,
integer(X),
even(X) ā†’ (Bool = true, Y #= X + 3); (Bool = false, Y #= X - 4).

In this case, X must be > 5 and a whole number. If X is an even number, then it is Y - 3 (I could supply Y and the Bool), and if it is odd, X is known to be Y + 4.

Logically I know how to work this in reverse because the conditions are precise enough to force an answer to be available either way. But I dont know how to assign boolean values and I dont know if this last statement is capable of being run in reverse given Bool and Y.

Thatā€™s why Iā€™m looking for another clever way to accomplish the same thing.

Maybe this will do what you want:

odd(Input):-
    Input #> 0,
    freeze(Input, (integer(Input),
                   Input>>1 =:= (Input-1)/2)).
?- odd(X), between(1, 5, X).
X = 1 ;
X = 3 ;
X = 5.

Thatā€™s a strange mix of clpfd and non-clpfd.

Could use e.g.:

?- freeze(X, integer(X)), X mod 2 #= 1, X = 5.
X = 5.

?- freeze(X, integer(X)), X mod 2 #= 1, X = 4.
false.

?- freeze(X, integer(X)), X mod 2 #= 1, X = z.
false.
1 Like

It took a little bit of struggling, but freeze does work. I forgot that #= subsumes both is/2 and =:=/2. Can I ask you two to check my rule for good/ideal syntax?

odd(Input, Compare, Output) :-
	freeze(Input, (Input #> 0, integer(Input), Compare #= (Input-1) rdiv 2, Input>>1 #= Compare -> Output #= 1; Output #= 0)),
	freeze(Output, is(Output, 1) -> Input #= (Compare * 2) + 1; Input #= 2 * Compare).

If you set Input as 7, you do get true (Output has to be 1 or 0, because Iā€™m getting a ā€œArithmetic: true/0 is not a functionā€ error).

Also, for some reason, I canā€™t say that Compare #= (Input-1)/2, I have to say Compare is (Input-1)/2. It seems to be the division symbol throwing things off, but for now I am going with #= ā€¦ div.

Is there a meaningful difference in using ā€œ#= divā€, ā€œ#= rdivā€, or ā€œis /ā€ in terms of the number of calculations being done? The documentation says that div includes a modulo, but I donā€™t know how rdiv is different from div. I do know that by default, / is exact and does not prefer rationals.

Iā€™m too confused. What are you trying to achieve?

What does this mean? Itā€™s trivially easy to count up from 1, incrementing by 2 each time, into infinity. Or use clpfd:

?- I #> 0, I mod 2 #= 1.
I in 1..sup,
I mod 2#=1.

Or use clpBNR:

?- [I, _I1, _I2]::integer(1, _), {_I1 == I + 1, _I2 == _I1 / 2}.
I::integer(1, 72057594037927933),
_I1::integer(2, 72057594037927934),
_I2::integer(1, 36028797018963967).

The two freeze statements allow me to either execute the forward direction (when Input is bound) or the reverse direction (when Output is bound). It is currently working, now Iā€™m curious if this is a fairly good syntax, or if it would be better if it were rearranged / defined differently.

For this situation, you could use var/1 or nonvar/1 instead of freeze/2, even though var/1 and nonvar/1 are ā€œimpureā€ and must be used carefully.
Something like this (untested):

odd(Input, Compare, Output) :-
	(  nonvar(Input),
    -> Input #> 0, integer(Input), Compare #= (Input-1) rdiv 2, Input>>1 #= Compare -> Output #= 1; Output #= 0),
	;  nonvar(Output)
    -> is(Output, 1) -> Input #= (Compare * 2) + 1; Input #= 2 * Compare
    ;  throw(error(...)).

This is a fairly standard way of handling ā€œbidrectionalā€ predicates, if you donā€™t mind a bit more restrictions in the order that you call things (e.g., in this case, you canā€™t have both Input and Output unbound, then bind one of them after the call to odd/3).

1 Like

The integer/1 there is pointless - clpfd ensures integers.

?- X = 1.5, X #> 0.
ERROR: Domain error: `clpfd_expression' expected, found `1.5'

Perhaps put the integer check first, if you want simple failure rather than an error.

1 Like

After reading the whole topic, I believe there is an implicit subject that was not touched on in this thread.

From your initial formulation:

I want to make a rule where I have three variables, Input, Compare, Output.
If the user supplies the Compare value, I want it to be run with that. If the user does
not supply a Compare, I want to set it.

Essentially, your Compare variable represent the mode of the predicate.
Or in your own words, whether the predicate is running in forward or reverse mode.
Usually, in prolog, we qualify the mode of variables. In the documentation, you will see variables annotated with either +, - or ? that respectively means input, output or both.

So to go back to your problem, you actually donā€™t need that third variable Compare to specify the mode of your predicate.
You can use different instantiation pattern of your predicate to evaluate either in forward or backward mode:

?- odd(3, IsOdd). % call the predicate in forward mode, meaning: Is 3 odd ?
?- odd(X, 1). % call the predicate in backward mode, meaning: X is an odd number

Usually, forward mode is, well, straightforward to reason about and implement but you also need to ask yourself what it means to run in backward mode.
In your example, calling odd(X, 1) means X is an odd number. However, since there is an infinity of odd numbers, what would you like prolog to return here ?

Usually, prolog provides two type of solutions:

  1. iterate one solution at a time using backtracking. So calling odd(X, 1) would bind X to values like 1 then 3 then 5 and so on infinitely on backtracking (although this limits the solution to positive integers onlyā€¦)
  2. delay the goal until X is ground. This is what you do when using clpfd or clpBNR or freeze.

PS: here is another lengthy reply of mine about the even/1 predicate : Fully understanding the "intricacies" of the Prolog code design process - #40 by kwon-young

2 Likes

I absolutely love this, my only comment is that Compare would tell the odd function what it should output in the reverse direction.

This is because Compare stores the odd number when its bits were moved to the right. Moving those bits to the left then results by default in an even number which is always 1 less than the odd it came from, if it was originally odd, or the same number if it was originally even.

Thus knowing if it was odd allows you to decide whether or not to add a 1 to get the regenerated number.

Ha, I did not catch what you wanted to do with Compare.

Well, based on this, Compare actually becomes an additional variables that can have different modes.
This complicates the instantiation patterns even further. This is where constraints shines most, since you can just states your constraints and the prolog engine does the rests.
You can actually simplify your implementations with the following two statements:

odd(Input, Compare, Output) :-
    Output in 0..1,
    Input #= Compare * 2 + Output.

So, here:

  1. Input can be any number
  2. Compare is Input // 2
  3. Output is 0 or 1, representing the oddity of Input and luckily it exactly correspond to the rest of Input divided by 2 :slight_smile:

Try to call the predicate in any way, with any instantiation patterns and you will see that it will work both in forward or reverse mode, although with 3 variables, it starts to become foggy what input/output, forward/backward even isā€¦

1 Like