				%RODCUT, 30-jan-2014
% Employ pragma declaration.

%rodcut 487>uname -a
%Darwin luke-immess-imac-2.local 13.0.0 Darwin Kernel Version 13.0.0: Thu Sep 19 22:22:27 PDT 2013; root:xnu-2422.1.72~6/RELEASE_X86_64 x86_64

%rodcut 485>gcc --version
%i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646)
%Copyright (C) 2007 Free Software Foundation, Inc.
%This is free software; see the source for copying conditions.  There is NO
%warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
%

%rodcut 483>mmc -version
%mercury_compile: invalid grade `ion'
%Mercury Compiler, version 13.05, configured for x86_64-apple-darwin12.5.0
%Copyright (C) 1993-2013 The University of Melbourne
%Usage: mmc [<options>] <arguments>
%Use `mmc --help' for more information.

%BUILD
% mmc --make --fully-strict -E -v -O 0 --use-subdirs rodcut


% RUN: no memo statements (commented out). Output is correct.
% rodcut 494>./rodcut 
% Rod Cutting. Input length rod n: 1, 2, 3, 4..., output max cut value.
% 1
% rn(1)=1.

% 2
% rn(2)=5.

% 3
% rn(3)=8.

% 4
% rn(4)=10.

% хорошо́ EOF, Quit
% rodcut 494>

%%%%%%%% If we put memo statement in, which is desirable, then following error is
% Produced.
%
% Rod Cutting. Input length rod n: 1, 2, 3, 4..., output max cut value.
% 1
% rn(1)=1.
%
% 2
% Uncaught Mercury exception:
% Software Error: detected need for minimal model in pred rodcut.r_n/3
% rodcut 493>
%%% Removing both pragma statements: no problem, functions work, and with correct output.

:- module rodcut. % name of file, for now
:- interface.
:- import_module io.

:- pred main(io, io).
:- mode main(di, uo) is cc_multi.

:- implementation.
:- import_module array, int, list, string.

:- pred main1(io, io).
:- mode main1(di, uo) is cc_multi.

:- func getRevenue(int, array(int)) = int. 
:- mode getRevenue(in, in) = out is det.
getRevenue(K, P) = array.lookup(P, K-1). % K-1 because 0 based counting
		
% Implement rn, bottom of page 362 Dynamic programming, Cormen text.
% Should be implementing 15.2 rn = max (p_i + r_n-i)
%                                                  1 <= i <= n, r0=0
%%%% Cannot use multi mode on functions, use pred, and declare main to be cc_multi.

:- pred r_n(int, array(int), int). 
:- mode r_n(in, in, out) is multi.
%:- pragma memo(r_n/3).
r_n(1, P, Mx) :-
	Mx = getRevenue(1, P).
r_n(N, P, Mx) :-
	r_nAux(getRevenue(N, P), 1, N-1, P, Mx).

:- pred r_nAux(int, int, int, array(int), int). 
:- mode r_nAux(in, in, in, in, out) is multi.
%:- pragma memo(r_nAux/5).
r_nAux(Mx, LowIndx, HighIndx, P, Max) :-
	(
	 if LowIndx > HighIndx then
	   Max = Mx
	else
	   r_n(LowIndx, P, Lw),
	   r_n(HighIndx, P, Hg),
	    NewMax = int.max(Mx, Lw + Hg),
	    r_nAux(NewMax, LowIndx + 1, HighIndx -1, P, Max)
	).

% Start with N=1, then N=2, up to N=4
:- pred doRodCut(int, int).
:- mode doRodCut(in, out) is multi.
doRodCut(N, Max) :-
	P = array.array([1, 5, 8, 9]), % array might be larger than N
	r_n(N, P, Max).

main(In, Out) :-
	write_string("Rod Cutting. Input length rod n: 1, 2, 3, 4..., output max cut value.\n", In, Out1),
	main1(Out1, Out).
	
main1(In, Out) :-
     read_line_as_string(Result, In, Out0), % blank line, wait for input from console
     (
	 Result = eof,		% c^d
	format("хорошо́ EOF, Quit\n", [], Out0, Out)
	;  

	 Result = error(Error),
	 format("IO error: %s\n", [s(io.error_message(Error))], Out0, Out) % IO error from readLine
	; 
	
	Result = ok(Nstr),
	(if string.to_int(string.strip(Nstr), N)
	then
	  doRodCut(N, Mx),
	  format("rn(%d)=%d.\n\n", [i(N), i(Mx) ], Out0, Out1)
	
	 else
	format("Input is not a number.\n", [], Out0, Out1)  % e.g.: letter, a
	),
	main1(Out1, Out)  % tail recursive
     ).