function [vtable,F] = BR_KB2F_gen(KB,fname)
% BR_KB2F_gen - produce error function for gradient descent
% On input:
%     KB (KB struct): CNF KB
%     fname (string): name of error function
% On output:
%     vtable (kxw array): variable table; identifies conditional variables
%     F (string): text of error function
% Call:
%     [vt,F] = BR_KB2F_gen(KB,'MP');
% Author:
%     T. Henderson
%     UU
%     Fall 2017
%

OP_AND = 1;
OP_OR = 2;

vtable = [];
F = [];
len_KB = length(KB);
if len_KB==0
    return
end

len_vtable = 0;
n = length(BR_vars(KB,[]));
num_x = n;

fd = fopen([fname,'.m'],'w');
fprintf(fd,'function F = %s(x)\n',fname);
fprintf(fd,'%%\n\n');

vtable = BR_create_vtable(n);

for c = 1:len_KB
    clause = KB(c).clauses;
    p = KB(c).prob;
    switch length(clause)
        case 1  % [L1]
            L1 = clause(1);
            if L1<1
                F(c).f = ['F(',num2str(c),') = -',num2str(p),...
                    ' + (1-x(',num2str(abs(L1)),'));'];
            else
                F(c).f = ['F(',num2str(c),') = -',num2str(p),...
                    ' + (x(',num2str(abs(L1)),'));'];
            end
        case 2  % [L1,L2]
            L1 = clause(1);
            L2 = clause(2);
            parity = BR_parity(L1,L2,0);
            index = BR_get_vtable(vtable,L1,L2,0,0,parity,0);
            if isempty(index)
                [vtable,index,ne] = BR_put_vtable(vtable,L1,L2,0,c,0);
            end
            if L1<1
                s1 = ['(1-x(',num2str(abs(L1)),'))'];
            else
                s1 = ['x(',num2str(abs(L1)),')'];
            end
            if L2<1
                s2 = ['(1-x(',num2str(abs(L2)),'))'];
            else
                s2 = ['x(',num2str(abs(L2)),')'];
            end
            F(c).f = ['F(',num2str(c),') = -',num2str(p),...
                ' + ',s1,' + ',s2,' - x(',num2str(index),')*',s2,';'];
        case 3  % [L1,L2,L3]
            L1 = clause(1);
            L2 = clause(2);
            L3 = clause(3);
            p12 = BR_parity(L1,L2,0);
            index12 = BR_get_vtable(vtable,L1,L2,0,0,p12,0);
            if isempty(index12)
                [vtable,index12,ne] = BR_put_vtable(vtable,L1,L2,0,c,0);
            end
            p13 = BR_parity(L1,L3,0);
            index13 = BR_get_vtable(vtable,L1,L3,0,0,p13,0);
            if isempty(index13)
                [vtable,index13,ne] = BR_put_vtable(vtable,L1,L3,0,c,0);
            end
            p23 = BR_parity(L2,L3,0);
            index23 = BR_get_vtable(vtable,L2,L3,0,0,p23,0);
            if isempty(index23)
                [vtable,index23,ne] = BR_put_vtable(vtable,L2,L3,0,c,0);
            end
            p123 = BR_parity(L1,L2,L3);
            index123 = BR_get_vtable(vtable,L1,L2,L3,0,p123,OP_AND);
            if isempty(index123)
                [vtable,index123,ne] = BR_put_vtable(vtable,L1,L2,L3,c,...
                    OP_AND);
            end
            if L1<1
                s1 = ['(1-x(',num2str(abs(L1)),'))'];
            else
                s1 = ['x(',num2str(abs(L1)),')'];
            end
            if L2<1
                s2 = ['(1-x(',num2str(abs(L2)),'))'];
            else
                s2 = ['x(',num2str(abs(L2)),')'];
            end
            if L3<1
                s3 = ['(1-x(',num2str(abs(L3)),'))'];
            else
                s3 = ['x(',num2str(abs(L3)),')'];
            end
            F(c).f = ['F(',num2str(c),') = -',num2str(p),...
                ' + ',s1,' + ',s2,' + ',s3,' - x(',num2str(index12),...
                ')*',s2,' - x(',num2str(index13),')*',s3,...
                ' - x(',num2str(index23),')*',s3,' + x(',...
                num2str(index123),')*x(',num2str(index23),')*',s3,';'];
    end
end

num_eqn = len_KB;
%------   Add Constraints --------------
num_x = length(vtable(:,1));
ca = zeros(num_x,1);
ca(1:n) = 1;
for k = n+1:num_x
    if ca(k)==0
        if vtable(k,3)==0&vtable(2)~=0
            L1 = vtable(k,1);
            L2 = vtable(k,2);
            c = vtable(k,4);
            indexes = zeros(4,1);
            pp = BR_parity(-abs(L1),-abs(L2),0);
            index = BR_get_vtable(vtable,-abs(L1),-abs(L2),0,0,pp,0);
            if isempty(index)
                [vtable,index,ne] = BR_put_vtable(vtable,-abs(L1),...
                    -abs(L2),0,vtable(k,4),0);
            end
            indexes(1) = index;
            pp = BR_parity(-abs(L1),abs(L2),0);
            index = BR_get_vtable(vtable,-abs(L1),abs(L2),0,0,pp,0);
            if isempty(index)
                [vtable,index,ne] = BR_put_vtable(vtable,-abs(L1),...
                    abs(L2),0,vtable(k,4),0);
            end
            indexes(2) = index;
            pp = BR_parity(abs(L1),-abs(L2),0);
            index = BR_get_vtable(vtable,abs(L1),-abs(L2),0,0,pp,0);
            if isempty(index)
                [vtable,index,ne] = BR_put_vtable(vtable,abs(L1),...
                    -abs(L2),0,vtable(k,4),0);
            end
            indexes(3) = index;
            pp = BR_parity(abs(L1),abs(L2),0);
            index = BR_get_vtable(vtable,abs(L1),abs(L2),0,0,pp,0);
            if isempty(index)
                [vtable,index,ne] = BR_put_vtable(vtable,abs(L1),...
                    abs(L2),0,vtable(k,4),0);
            end
            indexes(4) = index;
            indexa1 = abs(L1);
            indexa2 = abs(L2);
            indexp0 = indexes(1);
            indexp1 = indexes(2);
            indexp2 = indexes(3);
            indexp3 = indexes(4);
            if vtable(k,5)==0
                % Equation 1
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                    num2str(indexp0),')*(1-x(',num2str(indexa2),...
                    '))-1+(1-x(',num2str(indexa1),'))+(1-x(',...
                    num2str(indexa2),'))-x(',num2str(indexp3),...
                    ')*(1-x(',num2str(indexa2),'));'];
                % Equation 2
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp2),') + 1 - x(',num2str(indexp0),');'];
                % Equation 3
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp1),') + 1 - x(',num2str(indexp3),');'];
            end
            if vtable(k,5)==1
                % Equation 1
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp3),') + 1 - x(',num2str(indexp1),');'];
                % Equation 2
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp2),') + 1 - x(',num2str(indexp0),');'];
                % Equation 3
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp0),') + (1-(x(',num2str(indexa1),...
                    ') + x(',num2str(indexa2),') - x(',num2str(indexp3),...
                    ')*x(',num2str(indexa2),')))/(1-x(',num2str(indexa2),...
                    '));'];
            end
            if vtable(k,5)==2
                % Equation 1
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp2),') + 1 - x(',num2str(indexp0),');'];
                % Equation 2
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp3),') + (x(',num2str(indexp0),...
                    ')*(-x(',num2str(indexa2),') - 1 + x(',...
                    num2str(indexa1),') + x(',num2str(indexa2),')))/x('...
                    num2str(indexa2),');'];
                % Equation 3
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp1),') + 1 - x(',num2str(indexp3),');'];
            end
            if vtable(k,5)==3
                % Equation 1
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp1),') + 1 - x(',num2str(indexp3),');'];
                % Equation 2
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp0),') + (1-(x(',num2str(indexa1),...
                    ') + x(',num2str(indexa2),') - x(',num2str(indexp3),...
                    ')*x(',num2str(indexa2),')))/(1-x(',num2str(indexa2),...
                    '));'];
                % Equation 3
                num_eqn = num_eqn + 1;
                F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                    num2str(indexp2),') + 1 - x(',num2str(indexp0),');'];
            end
         elseif vtable(k,3)~=0
             L1 = vtable(k,1);
             L2 = vtable(k,2);
             L3 = vtable(k,3);
             c = vtable(k,4);
             indexes = zeros(4,1);
             pp = BR_parity(-L1,-L2,-L3);
             index = BR_get_vtable(vtable,-L1,-L2,-L3,0,pp,OP_OR);
             if isempty(index)
                 [vtable,index,ne] = BR_put_vtable(vtable,-L1,-L2,-L3,...
                     vtable(k,4),OP_OR);
             end
             indexes(1) = index;
             pp = BR_parity(-L1,L2,L3);
             index = BR_get_vtable(vtable,-L1,L2,L3,0,pp,OP_AND);
             if isempty(index)
                 [vtable,index,ne] = BR_put_vtable(vtable,-L1,L2,L3,...
                     vtable(k,4),OP_AND);
             end
             indexes(2) = index;
             pp = BR_parity(L1,-L2,-L3);
             index = BR_get_vtable(vtable,L1,-L2,-L3,0,pp,OP_OR);
             if isempty(index)
                 [vtable,index,ne] = BR_put_vtable(vtable,L1,-L2,-L3,...
                     vtable(k,4),OP_OR);
             end
             indexes(3) = index;
             pp = BR_parity(L1,L2,L3);
             index = BR_get_vtable(vtable,L1,L2,L3,0,pp,OP_AND);
             if isempty(index)
                 [vtable,index,ne] = BR_put_vtable(vtable,L1,L2,L3,...
                     vtable(k,4),OP_AND);
             end
             indexes(4) = index;
             indexa1 = abs(L1);
             indexa2 = abs(L2);
             indexa3 = abs(L3);
             [vv,index23,ne] = BR_vtable(vtable,L2,L3,0,-1,0);
             indexp0 = indexes(1);
             indexp1 = indexes(2);
             indexp2 = indexes(3);
             indexp3 = indexes(4);
             if vtable(k,5)==0
                 % Equation 1
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp0),')*(1-x(',num2str(index23),...
                     ')*(1-x(',num2str(indexa3),')))-1+(1-x(',...
                     num2str(indexa1),'))+x(',num2str(index23),')*(1-x(',...
                     num2str(indexa3),'))-x(',num2str(indexp3),')*x(',...
                     num2str(index23),')*(1-x(',num2str(indexa3),'));'];
                 % Equation 2
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                     num2str(indexp2),') + 1 - x(',num2str(indexp0),');'];
                 % Equation 3
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                     num2str(indexp1),') + 1 - x(',num2str(indexp3),');'];
             end
             if vtable(k,5)==3
                 % Equation 1
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp1),') - 1 + x(',num2str(indexp3),');'];
                 % Equation 2
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp0),')*(1-x(',num2str(index23),...
                     ')*x(',num2str(indexa3),'))-1+(1-x(',...
                     num2str(indexa1),'))+x(',num2str(index23),')*x(',...
                     num2str(indexa3),')-x(',num2str(indexp3),')*x(',...
                     num2str(index23),')*x(',num2str(indexa3),');'];
                 % Equation 3
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = -x(',...
                     num2str(indexp2),') + 1 - x(',num2str(indexp0),');'];
             end
             if vtable(k,5)==4  % P(A|~B)
                 % Equation 1
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp0),') - 1 + x(',num2str(indexp2),');'];
                 % Equation 2
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp0),')*(1-x(',num2str(index23),...
                     ')*x(',num2str(indexa3),'))-1+x(',...
                     num2str(indexa1),')+x(',num2str(index23),')*x(',...
                     num2str(indexa3),')+x(',num2str(indexp3),')*x(',...
                     num2str(index23),')*x(',num2str(indexa3),');'];
                 % Equation 3
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp1),') - 1 + x(',num2str(indexp3),');'];
             end
             if vtable(k,5)==7  % P(A|B)
                 % Equation 1
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp1),') - 1 + x(',num2str(indexp3),');'];
                 % Equation 2
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp0),')*(1-x(',num2str(index23),...
                     ')*x(',num2str(indexa3),'))-1+x(',...
                     num2str(indexa1),')+x(',num2str(index23),')*x(',...
                     num2str(indexa3),')+x(',num2str(indexp3),')*x(',...
                     num2str(index23),')*x(',num2str(indexa3),');'];
                 % Equation 3
                 num_eqn = num_eqn + 1;
                 F(num_eqn).f = ['F(',num2str(num_eqn),') = x(',...
                     num2str(indexp2),') - 1 + x(',num2str(indexp0),');'];
             end
             tch = 0;
         end
    end
end

%---------------------------------------
for c = 1:num_eqn
    fprintf(fd,'%s\n',F(c).f);
end
fclose(fd);

return

%--------------------------------------------------------------------
function vars = BR_vars(KB,sentence)
% BR_vars - find list of variables in logical sentences
% On input:
%     KB (nx1 conjunctive normal form vector): conjunctive clauses
%       (i).clauses (1xm vector): disjunctive clause
%     sentence (1x1 conjunctive normal form vector): conjunctive clause
%       (1).clauses (1xk vector): disjunctive clause
% On output:
%     vars (1xp vector): list of variables in KB and sentence
% Call:
%     vars = BR_vars(KB,thm);
% Author:
%     T. Henderson
%     UU
%     Spring 2017
%

vars = [];

for s = 1:length(KB)
    vars = unique([vars,abs(KB(s).clauses)]);
end
for s = 1:length(sentence)
    vars = unique([vars,abs(sentence(s).clauses)]);
end
vars = sort(vars);

