How to fix this recursive multiplication? - recursion

I am new to logic programming and Prolog. The following Prolog program defines a predicate mul/3 for multiplying the first argument to the second argument, which results in the third argument, based on the equation x * y = z which is equivalent to (x − 1) * y + y = z:
mul(0, _, 0).
mul(X, Y, Z) :-
ground(X),
succ(U, X),
add(V, Y, Z),
mul(U, Y, V).
mul(X, Y, Z) :-
var(X),
add(V, Y, Z),
mul(U, Y, V),
succ(U, X).
add(0, Y, Y).
add(X, Y, Z) :-
ground(X),
ground(Z),
succ(U, X),
succ(V, Z),
add(U, Y, V).
add(X, Y, Z) :-
ground(X),
var(Z),
succ(U, X),
add(U, Y, V),
succ(V, Z).
add(X, Y, Z) :-
ground(Z),
var(X),
succ(V, Z),
add(U, Y, V),
succ(U, X).
But it exhausts resources with queries in this argument mode:
?- mul(X, Y, 2).
X = 1, Y = 2
; X = 2, Y = 1
;
Stack limit (0.2Gb) exceeded
Stack sizes: local: 0.2Gb, global: 20.8Mb, trail: 10.4Mb
Stack depth: 452,739, last-call: 0%, Choice points: 452,716
In:
[452,739] add(_1326, 0, 0)
[452,738] add(_1354, 0, 1)
[452,737] add(_1382, 0, 2)
[452,736] mul(_1410, 0, 2)
[452,735] mul(_1438, 0, 2)
How to fix this recursive multiplication?

The program works okay in the sense that it gives the two solutions, X = 1, Y = 2 and X = 2, Y = 1. It then goes into an infinite search for other solutions.
The problem is with this rule:
mul(X, Y, Z) :-
var(X),
add(V, Y, Z),
mul(U, Y, V),
succ(U, X).
Here mul(U, Y, V) recurses in a way that the first argument is not ground, but the previous rules assume that it is (when V is not zero). Simply swapping the first two arguments solves the problem.
It is still not perfect though, consider
?- mul(2, 3, X).
false.
Here the problem is in the previous rule:
mul(X, Y, Z) :-
ground(X),
succ(U, X),
add(V, Y, Z),
mul(U, Y, V).
The call to add(V, Y, Z) becomes add(V, 3, Z), which is under-defined. Swapping it with the next mul solves this:
mul(X, Y, Z) :-
ground(X),
succ(U, X),
mul(U, Y, V),
add(V, Y, Z).
So is it okay now? Not really, e.g.
?- mul(X, 3, 6).
false.
Try to go through it with
?- trace, mul(X,3,6).
and find where the problem lies.
--- EDIT ---
Okay, so let's try this from scratch.
To simplify things, first look at the case when the first two arguments are not variables:
% add1(+X, +Y, ?Z) [semidet]
add1(0, Y, Y) :-
!.
add1(X, Y, Z) :-
succ(X1, X),
add1(X1, Y, Z1),
succ(Z1, Z).
% mul1(+X, +Y, ?Z) [semidet]
mul1(0, _, 0) :-
!.
mul1(X, Y, Z) :-
succ(X1, X),
mul1(X1, Y, Z1),
add1(Z1, Y, Z).
Then the other case, when the sum/product is known:
% add2(?X, ?Y, +Z) [nondet]
add2(0, Y, Y).
add2(X, Y, Z) :-
succ(Z1, Z),
add2(X1, Y, Z1),
succ(X1, X).
% mul2(?X, ?Y, +Z) [nondet]
mul2(X, Y, 0) :-
!,
(X = 0; Y = 0).
mul2(X, Y, Z) :-
nonvar(Y),
!,
succ(Y1, Y),
add2(Z1, X, Z),
mul2(X, Y1, Z1).
mul2(X, Y, Z) :-
add2(Z1, Y, Z),
mul2(X1, Y, Z1),
succ(X1, X).
Note that when the third rule in mul2 recurses, its second argument will be known, and that is used by the second rule. This is very similar to what you have written originally.
Finally, you can create a rule to choose the one you need:
add(X, Y, Z) :-
nonvar(Z) -> add2(X, Y, Z); add1(X, Y, Z).
mul(X, Y, Z) :-
nonvar(Z) -> mul2(X, Y, Z); mul1(X, Y, Z).
(Of course, you can unite these rules using var(X) etc., but I think it is much clearer this way.)

Related

Proving termination of Takeuchi function in Isabelle

Here is my try at proving that Takeuchi function does terminate:
function moore :: "(int ⇒ int ⇒ int) ⇒ (int ⇒ int ⇒ int)" where
"moore x y z = ((if (x ≤ y) then 0 else 1) (max(x,y,z) - min(x,y,z)) (x - min(x,y,z)))"
fun tk :: "int ⇒ int ⇒ int ⇒ int" where
"tk x y z = ( if x ≤ y then y else tk (tk (x-1) y z) (tk (y-1) z x) (tk (z-1) x y) )"
there are several problems here. First I should return a triple in the function moore. Right now, the system is complaining with error:
Type unification failed: Clash of types "int" and "_ ⇒ _"
Type error in application: incompatible operand type
Operator: op ≤ x :: (int ⇒ int ⇒ int) ⇒ bool Operand: y :: int
Then, of course the termination proof does not succeed since I didn't apply the termination function above (the way to this should be similar to here).
How can I fix this?
First of all, your moore function currently does not return a triple but a function taking two ints and returning an int. For a triple, you would have to write int × int × int. Also, tuples are constructed as (x, y, z), not as x y z like you did.
Also, there is no reason to use fun (let alone function) to define the moore function, since it is not recursive. definition works fine. For tk, on the other hand, you will need to use function since there is no obvious lexicographic termination measure.
Also, functions returning triple are usually a bit ugly to handle in Isabelle; it makes more sense to define three individual functions. Putting all this together, you can then define your functions like this:
definition m1 where "m1 = (λ(x,y,z). if x ≤ y then 0 else 1)"
definition m2 where "m2 = (λ(x,y,z). nat (Max {x, y, z} - Min {x, y, z}))"
definition m3 where "m3 = (λ(x,y,z). nat (x - Min {x, y, z}))"
function tk :: "int ⇒ int ⇒ int ⇒ int" where
"tk x y z = ( if x ≤ y then y else tk (tk (x-1) y z) (tk (y-1) z x) (tk (z-1) x y))"
by auto
You can then easily prove a partial correctness theorem for the tk function using the partial induction rule tk.pinduct:
lemma tk_altdef:
assumes "tk_dom (x, y, z)"
shows "tk x y z = (if x ≤ y then y else if y ≤ z then z else x)"
using assms by (induction rule: tk.pinduct) (simp_all add: tk.psimps)
The tk_dom (x, y, z) assumption says that tk terminates on the values (x, y, z).
Now, if I read the paper you linked correctly, the template for the termination proof looks like this:
termination proof (relation "m1 <*mlex*> m2 <*mlex*> m3 <*mlex*> {}", goal_cases)
case 1
show "wf (m1 <*mlex*> m2 <*mlex*> m3 <*mlex*> {})"
by (auto intro: wf_mlex)
next
case (2 x y z)
thus ?case sorry
next
case (3 x y z)
thus ?case sorry
next
case (4 x y z)
thus ?case sorry
next
case (5 x y z)
thus ?case sorry
qed
In the last four cases here, you will have to do the actual work of showing that the measure decreases. The <*mlex*> operator combines several measures into a single lexicographic measure. The relevant rules for showing that something is in contained in that measure are mlex_less and mlex_le.

"Curry" from tuple in SML

I am trying to define a function wrapper that curries a tuple in SML.
fun curry f = fn (x, y) z => f x y z;
Gives me the error
Non-identifier applied to a pattern.
I am new to ML and not sure why the pattern matching in fn doesn't work.
How could I make this work?
I am trying to define a function wrapper that curries a tuple in SML.
fun curry f = fn (x, y) z => f x y z;
How could I make this work?
Closures in SML don't allow for multiple arguments, but you can nest them instead.
What curry usually does is take a function f that normally accepts a tuple (x, y) and instead returns a modified function that takes x and y separately. Here is a number of equivalent ways to define curry:
fun curry f x y = f (x, y)
fun curry f x = fn y => f (x, y)
fun curry f = fn x => fn y => f (x, y)
val curry = fn f => fn x => fn y => f (x, y)
Its opposite, uncurry instead takes a function f that takes x and y separately and returns a modified function that takes (x, y). Here is one way to write uncurry:
fun uncurry f (x, y) = f x y
It's easy to mix up the two.
One way to fix the function you've written so that it compiles is insert an extra => fn:
fun what_is_this f = fn (x, y) => fn z => f x y z
(* ^- there *)
Before giving it a name, let's analyse what it does. It has the type signature:
fn : ('a -> 'b -> 'c -> 'd) -> 'a * 'b -> 'c -> 'd
(* now a tuple -^ ^- still curried *)
meaning that it takes a function of three curried arguments (x, y and z) and returns a modified function where the first two arguments are now in a tuple (uncurried) and the third is still curried. This is really a less generic version of uncurry. A more clear way of writing it would be:
fun what_is_this f (x, y) z = f x y z
If you use uncurry on a function of three arguments, you get the same effect, but you can't use what_is_this on anything with two curried arguments. So I'd say that this is a less useful variant of uncurry.
There are however other more useful variants of curry/uncurry. For example, you could make an uncurry_twice that converts f x y z into (uncurry_twice f) ((x, y), z), or an uncurry3 that converts f x y z into (uncurry3 f) (x, y, z):
fun uncurry_twice f = uncurry (uncurry f)
fun uncurry3 f (x, y, z) = f x y z

Pattern matching with logic?

I wonder if there is a way to do something like this (x, y < 0, z)
with y < 0
There are three cases in my example y = 0, y < 0 and else.
I know how to implement this function with different approaches, but
I just like this way and want to know if this is possible in some way.
let rec f = function
| (x, 0, y) -> x
| (x, y < 0, z) -> f (x y z)
| (x, y, z) -> f (z y x)
Just that you know, I removed the complexity of the tuple in the recursive call, so the function has no purpose right now.
You can add a condition after a pattern using the when keyword. With that, you can do what you want like this:
let rec f = function
| (x, 0, y) -> x
| (x, y, z) when y < 0 -> f (x, y, z)
| (x, y, z) -> f (z, y, x)
This will cause infinite recursion because f (x, y, z) doesn't change anything about the arguments, but I assume that problem does not exist in your real code.

Find all Pairs definition

I want to make a definition in Isabelle which returns all the pairs of a map function.
I have the following definition in Z
\begin{schema}[X, Y, Z]
allPairs: (X \pfun (Y \rel Z)) \fun (Y \rel Z)
where
\<forall f: (X \<pfun (Y \rel Z)) #
allPairs f == \<bigcup{x:X | x \in \dom f # fx}
\end{schema}
Therefore I want to make a definition which takes an element of type
(X \<rightharpoonup> ((Y * Z) set))) or (X \<rightharpoonup> (Y \<rightharpoonup> Z)) in isabelle and return ((Y * Z) set) for both.
I have the following so far
definition allPairs ::
"('X \<rightharpoonup ('Y * 'Z) set) => ('Y * 'Z) set"
where
"allPairs f == ⋃{yz. yz ∈ ran f}"

How to do an addition on a list with a condition?

I have a university course about functional programming, where I use SML. As a preparation for the exam, I am working on some of the older exam sets without solutions.
One of the only questions I really have problems with is the following question using foldl:
Consider the program skeleton: fun
addGt k xs = List.foldl (...) ... xs;
Fill in the two missing pieces
(represented by the dots ...), so that
addGt k xs is the sum of those
elements in xs, which are greater than
k. For example, addGt 4 [1, 5, 2, 7,
4, 8] = 5 + 7 + 8 = 20
I am sure this is really easy, but I have a very hard time understanding the foldl and foldr functions.
What I have now is the following (which seems to be very wrong if you ask my compiler!):
fun addGt(k,xs) = List.foldl ( fn x => if x > k then op+ else 0) 0 xs;
I would really appreciate some help with this question, and maybe a very short comment which would cast some light on the foldl and foldr functions!
A solution that I just though of is the following:
fun addGt(k, xs) = List.foldl (fn (x, y) => if x >= 5 then x + y else y) 0 xs;
But let me explain. First of all check the type of the List.foldl function, it's:
('a * 'b -> 'b) -> 'b -> 'a list -> 'b
So List.foldl is a curried function that takes as first parameter another function of type ('a * 'b -> 'b). You used (fn x => if x > k then op+ else 0) which has type int -> int. You should instead provide List.foldl with a function that takes a tuple of type int * int and returns an int, so something like this: (fn (x, y) => do stuff). That's why your code didn't compile, you passed a wrong type of function in foldl.
Now you can think of foldl this way:
foldl f b [x_1, x_2, ..., x_(n - 1), x_n] = f(x_n, f(x_(n - 1), ..., f(x2, f(x1, b)) ...)) where f is a function of type ('a * 'b -> 'b), b is something of type 'b and the list [x_1, x_2, ..., x_(n - 1), x_n] is of type 'a list.
And similar for foldr you can think it in this way:
foldr f b [x_1, x_2, ..., x_(n - 1), x_n] = f(x_1, f(x_2, ..., f(x_(n - 1), f(x_ n, b))
If you call foldl f s ls on a list, ls = [x1, x2, ..., xn], then you get the result:
f(xn, ... f(x2, f(x1, s)))
That is, it starts by finding
a1 = f(x1, s)
Then
a2 = f(x2, a1)
and so on, until it's through the list.
When it's done, it returns an.
You can think of the a-values as being a sort of accumulator, that is, ai is the result as it would be if the list was only [x1, x2, ..., xi] (or rather, the first i elements of the list).
Your function will usually have the form:
fn (x, a) => ...
What you then need to do is think: Okay, if I have the next element in the list, x(i+1), and the value ai, which is the result for the list [x1, x2, ..., xi], what do I need to do to find the value a(i+1), which is the result for the list [x1, x2, ..., xi, x(i+1)].
s can be thought of as the value given to the empty list.
foldr works the same way, only you start from the back of the list instead of from the front.

Resources