function [yc,y] = ChainMultProg(x,idx)
%ChainMultProg Print a MATLAB program that will simulate
%   the optimal chain multiply result, including
%   explicit usage of temporary matrices and possible
%   re-use of output storage area.
%
%   EXAMPLE: The matrix multiplication chain representation
%       {[4 5 -1] [3 -1 -2] [2 -2 -1] [1 -1 0]}
%    is in the input argument field x.Best.ChainRep, and
%    x.Best.tempOverOutputIdx = 2.  Based on this, the 
%    following program code is generated:
%
%    function y = mtrxmult(A,B,C,D,E)
%    %MTRXMULT Compute y = A * (B * (C*(D*E)));
%    %   using primitive 2-argument matrix multiplies.
%    %
%    %   This requires 496 flops and 8 temporary
%    %   storage locations given the following matrix sizes:
%    %    [5 8], [8 6], [6 8], [8 5], [5 8]
%    %
%    %   Note: the output is used for a temporary
%    %   (intermediate computation) result.
%    %
%    %   Generated: 11-Jun-1999 17:29:17.
%
%    temp1 = D * E;
%    temp2 = C * temp1;
%    temp1 = B * temp2;
%    y = A * temp1;
%
%    % [EOF] mtrxmult.m
%
% See also CHAINMULT, CHAINGUI.

% Author: D. Orofino
% Copyright 1984-2000 The MathWorks, Inc.
% $Revision: 1.5 $ $Date: 2000/05/02 13:52:55 $

tempIdx  = x.All.Metrics(idx).tempOverOutputIdx;
flops    = x.All.Metrics(idx).flopCount;
mem      = x.All.Metrics(idx).temp_ele;
chain     = x.All.Chain{idx};
ppv       = x.All.ChainStr{idx};
inputSize = prettyPrintSizes(x.Input.Sizes);
inputCplx = mat2str(x.Input.Complexity);

% Get # of variables and # temporaries in problem
[numVars, numTemps, allVars, csvars] = generateVarLists(x,idx);

% Write out header info:
if any(x.Input.Complexity),
   mstr = '(real) ';
else
   mstr = '';
end
y = {['function y = mtrxmult(' csvars ')'];
     ['%MTRXMULT Compute ' ppv];
     ['%    using primitive 2-argument matrix multiplies.'];
     ['%    This requires ' num2str(flops) ' flops and ' ...
             num2str(mem) ' temporary ' mstr];
       ['%    storage elements given the following matrix sizes:']};
    
  
  if any(x.Input.Complexity),
     for i=1:length(x.Input.Sizes),
        xi=x.Input.Sizes{i};
        cplx=x.Input.Complexity(i);
        if cplx, cplxStr='Complex'; else cplxStr='Real'; end
        z = {['%    Input ' num2str(i) ': ' mat2str(xi)  ' (' cplxStr ')']};
        y=[y;z];
     end
  else
     % All purely real:
     z = {['%    ' inputSize];
          ['%    with all real inputs.']};
     y=[y;z];
  end
 
% List of matrix sizes:

% Time/date stampe for final portion of initial comment line:
z = {'%';
   ['%   Generated: ' datestr(now) '.']};
y = [y; z];

% Enumerate computational steps:
k=numTemps+1;
for i=1:length(chain),
    x1 = chain{i}(1);
    x2 = chain{i}(2);
    x12 = chain{i}(3);
    if (tempIdx>0) & (-x12 == tempIdx),
        % Writing into a temp matrix that is being 
        %   stored in the output matrix area for optimization.
        %
        % Indicate that we're doing this:
        comment='  % Using output for temp matrix';
    else
        comment = '';
    end
    y = [y; {[allVars{x12+k} ' = ' ...
              allVars{x1+k} ' * ' allVars{x2+k} ';' comment]}];
end

% Write out program footer:
y = [y;
    {'';
     '% [EOF] mtrxmult.m';
	}];

% Convert from cell to string:
yc = char(y);


% ------------------------------------------------------------
function [numVars, numTemps, allVars, csvars] = generateVarLists(x,idx)
% getVarLists

numVars  = 0;
numTemps = 0;
chain    = x.All.Chain{idx};
tempIdx  = x.All.Metrics(idx).tempOverOutputIdx;
tempList = {};

for i=1:length(chain),
    for j=1:3,
        var = chain{i}(j);
        if var>0,     % input var
            numVars = max(numVars, var);
        elseif var<0,  % temp var
           	numTemps = max(numTemps,-var);
        end	
    end
end

% Comma-separated string of vars:
varStr = char('A' + (0:numVars-1));
csvars = [varStr; ones(1,numVars)*','];
csvars = csvars(1:end-1);

% Main Variable and Temp Variable cell-array lists:
varList = cellstr(char('A' + (0:numVars-1)'))';
for i=1:numTemps,
    tempList{i}=sprintf('temp%d',i);
end

% Replace the specified temp variable name with the
% output variable name, if the output was used in
% place of this temporary storage area:
if tempIdx>0,
    tempList(tempIdx) = {'Y'};
end	

% Concatenate temp, output, and main vars into an
% indexed list of all vars.
%
% order of variable names is [flipped_tempList output mainVars]
% e.g., indices are [-N, -N+1, ..., -2, -1, 0, 1, 2, ..., M],
% where N = # temp vars, 0=index of output var, M=# main vars
%
allVars = [fliplr(tempList) {'Y'} varList];


% -----------------------------------------------------------
function str = prettyPrintSizes(x)
% prettyPrintSizes Print the chain multiply sizes

N=length(x);
str = '';
for i=1:N,
    if i<N, t=', '; else t=''; end
   str = [str mat2str(x{i}) t];
end
%str=str(1:end-2);  % remove trailing comma/space

% [EOF] ChainMultProg.m
