Standard ML: Backtracking Confusion - functional-programming

I'm confused by an example Harper gives in his Intro to SML on p. 110. He's writing a function to make a certain amount of change from a list of coin values, backtracking when needed.
e.g. If I run change [5, 2] 16, I get [5, 5, 2, 2, 2] (algorithm should be greedy when possible).
exception Change
fun change _ 0 = nil
| change nil _ = raise Change
| change (coin::coins) amt =
if coin > amt then
change coins amt
else
(coin :: change (coin::coins) (amt - coin))
handle Change => change coins amt
A few questions:
1) I'm a bit confused about how this algorithm implements backtracking. It looks like when change is called with an empty list of coin values as its first argument, it raises the Change exception.
But the Change exception handler calls change coins amt. How is this "undoing the most recent greedy decision?
2) Why is the handler placed within the else clause? I would have thought it'd be totally separate...
Thanks for the help,
bclayman

Here's a execution trace for the call change [5,2] 16. The parts to the left
of handle represent what the function has computed thus far, while the part
on the right is the state to continue with when backtracking is requested via a Change signal.
> change [5, 2] 16
> 5 :: change [5, 2] (16 - 5) handle Change: change [2] 16
> 5 :: change [5, 2] 11 handle Change: change [2] 16
> 5 :: 5 :: change [5, 2] (11 - 5) handle Change: 5 :: change [2] 11
> 5 :: 5 :: change [5, 2] 6 handle Change: 5 :: change [2] 11
> 5 :: 5 :: 5 :: change [5, 2] (6 - 5) handle Change: 5 :: 5 :: change [2] 6
> 5 :: 5 :: 5 :: change [5, 2] 1 handle Change: 5 :: 5 :: change [2] 6
> 5 :: 5 :: 5 :: change [2] 1
> 5 :: 5 :: 5 :: change nil 1
> raise Change => 5 :: 5 :: change [2] 6
> 5 :: 5 :: 2 :: change [2] (6 - 2) handle Change
> 5 :: 5 :: 2 :: change [2] 4 handle Change
> 5 :: 5 :: 2 :: 2 :: change [2] (4 - 2) handle Change
> 5 :: 5 :: 2 :: 2 :: change [2] 2 handle Change
> 5 :: 5 :: 2 :: 2 :: 2 :: change [2] (2 - 2) handle Change
> 5 :: 5 :: 2 :: 2 :: 2 :: change [2] 0 handle Change
> 5 :: 5 :: 2 :: 2 :: 2 :: nil
> [5, 5, 2, 2, 2]
As you can see, when the Change exception is caught, the algorithm goes back two
stack frames, drops the third 5 coin from the result list and recurses only with
a 2 coin in the list of coins. The amount is also reset to 6.
The first line, the part before handle tries to use another 5 as a possible
decomposition, while the exception handler represents the backtracking option,
i.e., remove the 5 we've just tried and adjust the coin list and the remaining
amount.
The final line signals the last installed exception handler to backtrack.
> 5 :: 5 :: 5 :: change [5, 2] 1 handle Change: 5 :: 5 :: change [2] 6
> 5 :: 5 :: 5 :: change [2] 1
> 5 :: 5 :: 5 :: change nil 1
> raise Change => 5 :: 5 :: change [2] 6
In other words, the algorithm backtracks when it reaches a state where no more
coin types are available to choose, but the amount is still positive. It's greedy
because the algorithm will use the same coin until it catches an exception.
The exception handler is attached to the else expression because it's where
the greedy choice is made.
Hopefully I've been intelligible with my explanation.

Related

Need help printing the first N numbers in the hofstadter female sequence in OCaml

I'm new here so I apologize in advance if my post is poor.
I'm trying to build a list that contains the first n numbers of the following mutually recursive hofstadter sequence:
F(0) = 1
M(0) = 0
F(n) = n - M(F(n-1)), n > 0
M(n) = n - F(M(n-1)), n > 0
I'm trying to do this in OCaml, which is a new language for me. After struggling all day on this problem I came up with this:
open Printf
let list = [];;
let rec female (n: int) =
if n == 0 then 1::list
else let x = n - male(female(n-1)) in x::list
and male (n:int) =
if n == 0 then 0::list
else let x = n - female(male(n-1)) in x::list
in female 4;; (** test number*)
let () = List.iter (printf "%d ") list
but it keeps producing a type error on line 8 that reads
This pattern matches values of type int
but a pattern was expected which matches values of type int list
Can someone help me understand why I'm getting this error? Functional programming isn't really my strong suit.
You have this subexpression:
male (female (n-1))
From this we can conclude that the parameter of male is the same type as the result of female. But just above we see that female returns this in one case:
1 :: list
This is a list of ints.
So we know that the first parameter of male should be a list of ints. However, when you actually define male you have this:
and male (n:int) =
The compiler is telling you that you have two conflicting requirements for the first parameter of male. In one place it's a list of ints and in another place (the definition of male itself) you say it's an int.
You need to have a consistent plan for what the parameters to male and female should be.
I managed to figure it out, thanks to jeff in the comments. Here's my solution:
let rec female (n: int) =
match n with
| 0 -> 1
| _ -> n - male(female(n-1))
and male (n:int) =
match n with
| 0 -> 0
| _ -> n - female(male(n-1));;
let rec l i =
if i < 10 then female i :: l (i+1)
else []
in
List.iter (fun item -> print_int item; print_newline ()) (l 0)
prints the first 10 numbers in the hofstadter female sequence: 6 5 5 4 3 3 2 2 1 1

How to resolve this type error in my Prolog code for generating the Collatz Sequence?

I am learning Prolog, specifically GNU Prolog, for fun. I thought an interesting challenge would be to generate a sequence of Collatz numbers given a seed, which here is 5. Here's my pseudocode:
collatz(curr, next) -> if even, next is curr / 2
collatz(curr, next) -> if odd, next is curr * 3 + 1
collatz_seq(1, [1]) -> terminate and return 1
collatz_seq(curr, [curr | accum]) -> next = collatz(curr), collatz_seq(next, accum)
I translated that to Prolog like this:
collatz(Curr, Next) :-
0 is Curr mod 2,
Next is Curr / 2.
collatz(Curr, Next) :-
1 is Curr mod 2,
Next is Curr * 3 + 1.
collatz_seq(1, [1]) :- !.
collatz_seq(Curr, [Curr | Accum]) :-
collatz(Curr, Next),
collatz_seq(Next, Accum).
% collatz_seq(3, X).
I first ran my code like this: gprolog --consult-file collatz.pl and tested out 3 with collatz_seq(3, X). in the REPL. uncaught exception: error(type_error(integer,5.0),(is)/2) was the REPL's response. I think that there's a problem here with 5 being misrepresented as 5.0. For 3 as input, the sequence should go 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1, but it terminates at 5. How do I avoid this intermingling of floats and ints when a float's decimal point is just zero?

Rewriting on Infinite Matrices

I've taken a project named with "Symbolic Linear Algebra" which is about doing basic operations on infinite matrices like addition, multiplication, accessing specific element etc. I will be implementing those on Julia.
For specifying those infinite matrices we'll have some mathematical cases like:
So the visual representation of matrix will be like:
For example let's say we want to find A + A' for this example. Here our cases change so we need to rewrite those cases to get desired output right ? I know Mathematica does this but how can I implement this? Yes, this was too general so let me ask some questions;
Let's start with taking cases as input. There can be many cases with different rules like if i % 2 == 0 or i == j like in this example how can I provide a generic input ?
Let's say that I'm done with input and I want to make those simple operations. How can I combine those cases in a programming language like Julia ?
I've wrote some non-generic dumb code to see how things will go so I will provide my code to apply minimum reproducible example but don't take it seriously, I think I'm just looking for a clue or a roadmap to get rid of the question marks in my head.
using Parameters
struct inf_matrix
mod_of :: Integer
mod_value :: Integer
i_coefficient :: Integer
j_coefficient :: Integer
value :: Integer
end
function single_demo(_mod_of :: Integer, _mod_value :: Integer, _i_coefficient :: Integer, _j_coefficient :: Integer, _value :: Integer)
test_matrix = inf_matrix(_mod_of, _mod_value, _i_coefficient, _j_coefficient, _value)
return test_matrix
end
function get_elem(st::inf_matrix ,i :: Integer, j :: Integer)
#This function is not completed yet
if (i % st.mod_of == st.mod_value) && (2 * st.i_coefficient == j)
return st.value;
else
return -1
end
end
demo_1 = single_demo(2, 0 ,1, 2, 1)
println(get_elem(demo_1, 1, 0))
Any help would be appreciated.
Here is how you could do this
import Base: getindex, +, *
abstract type InfiniteMatrix end
struct InfiniteIdentity <: InfiniteMatrix end
getindex(::InfiniteIdentity, i, j) = i .== j'
struct InfiniteConstant <: InfiniteMatrix
c
end
getindex(m::InfiniteConstant, i::Integer, j::Integer) = m.c
getindex(m::InfiniteConstant, i, j) = fill(m.c, size(i)..., size(j)...)
struct InfiniteMatrixFilter <: InfiniteMatrix
condition::Function
iftrue::InfiniteMatrix
iffalse::InfiniteMatrix
end
getindex(m::InfiniteMatrixFilter, i, j) = ifelse.(m.condition.(i,j'), m.iftrue[i,j], m.iffalse[i,j])
struct InfiniteMatrixFunction <: InfiniteMatrix
f::Function
args
end
getindex(m::InfiniteMatrixFunction, i, j) = m.f(getindex.(m.args, Ref(i), Ref(j))...)
+(m1::InfiniteMatrix, m2::InfiniteMatrix) = InfiniteMatrixFunction(+, (m1, m2))
*(n::Number, m::InfiniteMatrix) = InfiniteMatrixFunction(x -> n*x, (m,))
julia> i = InfiniteIdentity()
InfiniteIdentity()
julia> c1 = InfiniteConstant(1)
InfiniteConstant(1)
julia> (2i+3c1)[1:5, 1:5]
5×5 Array{Int64,2}:
5 3 3 3 3
3 5 3 3 3
3 3 5 3 3
3 3 3 5 3
3 3 3 3 5
julia> m = InfiniteMatrixFilter((i,j) -> i%2 == 0, c1, 0c1)
InfiniteMatrixFilter(var"#43#44"(), InfiniteConstant(1), InfiniteMatrixFunction(var"#41#42"{Int64}(0), (InfiniteConstant(1),)))
julia> m[1:5, 1:5]
5×5 Array{Int64,2}:
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
(this is only a proof of concept and it's not optimized or bugfree)

How do I find a list (multiset, size n) of integers where the root-mean-square of the set is an integer?

I already found this one
Brute force is possible of course, but are there any other ways? Is there a way to find all multisets? Is there a way to find out how many combinations exist under a certain limit?
Perhaps this question is too mathy for SO, if that is the case I'll move it.
I created my own version in javascript by generating all possible combinations of a list of numbers, then checking for integer RMS. These are sets though, not multisets.
Edit: I used N for sum value and K for the number of squares.
Number of multi-sets grows fast, so N should have reasonable value. So this problem is equivalent to changing sum N by K coins with nominals 1,4,9,25... (and the number of variants might be calculated using dynamic programming).
The simplest implementation is recursive - we just generate all possible addends. In my Delphi implementation I collect summands in string (instead of list) for simplicity.
Note that such implementation might generate the same sequences again and again - note {5,7} end-sequence in my example. To improve performance (important for rather large values of N and K), it is worth to store generated sequences in table or map (with {N;K;Min} key). In that case generation from large summands to smaller ones would be better, because small summands give a lot of repeating patterns.
procedure FSP(N, K, Minn: Integer; Reslt: string);
var
i: Integer;
begin
if (K = 0) then begin
if (N = 0) then
Memo1.Lines.Add(Reslt); //yield result
Exit;
end;
i := Minn;
while (i * i <= N) do begin
FSP(N - i * i, K - 1, i, Reslt + Format('%d ', [i]));
i := i + 1;
end;
end;
procedure FindSquarePartitions(N, K: integer);
begin
FSP(N, K, 1, '');
end;
FindSquarePartitions(101, 5);
1 1 1 7 7
1 1 3 3 9
1 1 5 5 7
1 2 4 4 8
1 5 5 5 5
2 2 2 5 8
2 3 4 6 6
2 4 4 4 7
3 3 3 5 7

Summing elems of array using binary recursion

I wasn't starting to understand linear recursion and then I thought I practice up on sorting algorithms and then quick sort was where I had trouble with recursion. So I decided to work with a simpler eg, a binary sum that I found online. I understand that recursion, like all function calls, are executed one # a time and not at the same time (which is what multi-threading does but is not of my concern when tracing). So I need to execute all of recursive call A BEFORE recursive call B, but I get lost in the mix. Does anyone mind tracing it completely. The e.g. I have used of size, n = 9 where elems are all 1's to keep it simple.
/**
* Sums an integer array using binary recursion.
* #param arr, an integer array
* #param i starting index
* #param n size of the array
* floor(x) is largest integer <= x
* ceil(x) is smallest integer >= x
*/
public int binarySum(int arr[], int i, int n) {
if (n == 1)
return arr[i];
return binarySum(arr, i, ceil(n/2)) + binarySum(arr,i + ceil(n/2), floor(n/2));
}
What I personally do is start with an array of size 2. There are two elements.
return binarySum(arr, i, ceil(n/2)) + binarySum(arr,i + ceil(n/2), floor(n/2)) will do nothing but split the array into 2 and add the two elements. - case 1
now, this trivial starting point will be the lowest level of the recursion for the higher cases.
now increase n = 4. the array is split into 2 : indices from 0-2 and 2-4.
now the 2 elements inside indices 0 to 2 are added in case 1 and so are the 2 elements added in indices 2-4.
Now these two results are added in this case.
Now we are able to make more sense of the recursion technique, some times understanding bottom up is easier as in this case!
Now to your question consider an array of 9 elements : 1 2 3 4 5 6 7 8 9
n = 9 => ceil(9/2) = 5, floor(9/2) = 4
Now first call (top call) of binarySum(array, 0, 9)
now n = size is not 1
hence the recursive call....
return binarySum(array, 0, 5) + binarySum(array, 5, 4)
now the first binarySum(array, 0 ,5) operates on the first 5 elements of the array and the second binarySum(array,5,4) operates on the last 4 elements of the array
hence the array division can be seen like this: 1 2 3 4 5 | 6 7 8 9
The first function finds the sum of the elements: 1 2 3 4 5
and the second function finds the sum of the elements 6 7 8 9
and these two are added together and returned as the answer to the top call!
now how does this 1+2+3+4+5 and 6+7+8+9 work? we recurse again....
so the tracing will look like
1 2 3 4 5 | 6 7 8 9
1 2 3 | 4 5 6 7 | 8 9
1 2 | 3 4 | 5 6 | 7 8 | 9
[1 | 2]___[3]___[4 5]___[6 7]___[8 9]
Till this we are fine..we are just calling the functions recursively.
But now, we hit the base case!
if (n == 1)
return arr[i];
[1 + 2]____[3]____[4 + 5]____[6 + 7]____[8 + 9]
[3 + 3] ____ [9] ____[13 + 17]
[6 + 9] [30]
[15 + 30]
[45]
which is the sum.
So for understanding see what is done to the major instance of the problem and you can be sure that the same thing is going to happen to the minor instance of the problem.
This example explains binary sum with trace in java
the trace is based on index of array , where 0 - is yours starting index and 8 is length of the array
int sum(int* arr, int p, int k) {
if (p == k)
return arr[k];
int s = (p + k) / 2;
return sum(arr, p, s) + sum(arr, s + 1, k);
}

Resources