function [A,b] = generate_kernel_representation_data(N,N_unique,exponent_m2,exponent_p,p,options,p_base_parametric,ParametricIndicies,MonomIndicies,FirstRun)

persistent saveData

exponent_p_parametric = exponent_p(:,ParametricIndicies);
exponent_p_monoms = exponent_p(:,MonomIndicies);
pcoeffs = getbase(p);
if any(exponent_p_monoms(1,:))
    pcoeffs=pcoeffs(:,2:end); % No constant term in p
end
b = [];

parametric = full((~isempty(ParametricIndicies) & any(any(exponent_p_parametric))));

% For problems with a lot of similar cones, this saves some time
reuse = 0;
if ~isempty(saveData) & isequal(saveData.N,N) & ~FirstRun
    n = saveData.n;
    ind = saveData.ind;
    if  isequal(saveData.N_unique,N_unique) & isequal(saveData.exponent_m2,exponent_m2)% & isequal(saveData.epm,exponent_p_monoms)
        reuse = 1;
    end
else
    % Congruence partition sizes
    for k = 1:size(N,1)
        n(k) = size(N{k},1);
    end
    % Save old SOS definition
    saveData.N = N;
    saveData.n = n;
    saveData.N_unique = N_unique;
    saveData.exponent_m2 = exponent_m2;
    saveData.N_unique = N_unique;
end

if reuse & options.sos.reuse
    % Get old stuff
    if size(exponent_m2{1},2)==2 % Stupid set(sos(parametric)) case
        ind = spalloc(1,1,0);
        ind(1)=1;
        allj = 1:size(exponent_p_monoms,1);
        used_in_p = ones(size(exponent_p_monoms,1),1);
    else
        allj = [];
        used_in_p = zeros(size(exponent_p_monoms,1),1);
        hash = randn(size(exponent_p_monoms,2),1);
        p_hash = exponent_p_monoms*hash;
        exponent_p_monoms_hash = exponent_p_monoms*hash;
        for i = 1:size(N_unique,1)
            monom = sparse(N_unique(i,3:end));
            j = find(exponent_p_monoms_hash == (monom*hash));
          
            if isempty(j)
                b = [b 0];
                allj(end+1,1) = 0;
            else
                used_in_p(j) = 1;
                allj(end+1,1:length(j)) = j(:)';
            end
        end
        ind = saveData.ind;
    end
else
    allj = [];
    used_in_p = zeros(size(exponent_p_monoms,1),1);
    if size(exponent_m2{1},2)==2 % Stupid set(sos(parametric)) case
        ind = spalloc(1,1,0);
        ind(1)=1;
        allj = 1:size(exponent_p_monoms,1);
        used_in_p = ones(size(exponent_p_monoms,1),1);
    else
        % To speed up some searching, we random-hash data
        hash = randn(size(exponent_p_monoms,2),1);
        for k = 1:length(exponent_m2)
            if isempty(exponent_m2{k})
                exp_hash{k}=[];
            else
                exp_hash{k} = sparse((exponent_m2{k}(:,3:end)))*hash; % SPARSE NEEDED DUE TO STRANGE NUMERICS IN MATLAB ON 0s (the stuff will differ on last bit in hex format)
            end
        end

        p_hash = exponent_p_monoms*hash;
        ind = spalloc(size(N_unique,1),sum(n.^2),0);       

        for i = 1:size(N_unique,1)
            monom = N_unique(i,3:end);
            monom_hash = sparse(monom)*hash;
            LHS = 0;
            start = 0;
            for k = 1:size(N,1)
                j = find(exp_hash{k} == monom_hash);
                if ~isempty(j)
                    pos=exponent_m2{k}(j,1:2);
                    nss = pos(:,1);
                    mss = pos(:,2);
                    indicies = nss+(mss-1)*n(k);
                    ind(i,indicies+start) = ind(i,indicies+start) + 1;                                                                 
                end
                start = start + (n(k))^2;
                %                start = start + (matrixSOSsize*n(k))^2;
            end

            j = find(p_hash == monom_hash);

            if isempty(j)
                allj(end+1,1) = 0;
            else
                used_in_p(j) = 1;
                allj(end+1,1:length(j)) = j(:)';
            end
        end                     
    end
end
saveData.ind = ind;

% Some parametric terms in p(x,t) do not appear in v'Qv
% So these have to be added 0*Q = b
not_dealt_with  = find(used_in_p==0);
while ~isempty(not_dealt_with)
    %j = findrows(exponent_p_monoms,exponent_p_monoms(not_dealt_with(1),:));
    j = find(p_hash == p_hash(not_dealt_with(1)));
    allj(end+1,1:length(j)) = j(:)';
    used_in_p(j) = 1;
    not_dealt_with  = find(used_in_p==0);
    ind(end+1,1)=0;
end

matrixSOSsize = length(p);
if parametric
    % Inconsistent behaviour in MATLAB
    if size(allj,1)==1
        uu = [0;p_base_parametric];
        b = sum(uu(allj+1))';
    else
        b = [];
        for i = 1:matrixSOSsize
            for j = i:matrixSOSsize
                if i~=j
                    uu = [0;2*p_base_parametric(:,(i-1)*matrixSOSsize+j)];
                else
                    uu = [0;p_base_parametric(:,(i-1)*matrixSOSsize+j)];
                end
                b = [b sum(uu(allj+1),2)'];
            end
        end
    end
else
    if matrixSOSsize == 1
        uu = [zeros(size(pcoeffs,1),1) pcoeffs]';
        b = sum(uu(allj+1,:),2)';
    else
        b = [];
        for i = 1:matrixSOSsize
            for j = i:matrixSOSsize
                if i~=j
                    uu = [0;2*pcoeffs((i-1)*matrixSOSsize+j,:)'];
                else
                    uu = [0;pcoeffs((i-1)*matrixSOSsize+j,:)'];
                end
                b = [b;sum(uu(allj+1,:),2)'];
            end
        end
    end
    % uu = [0;pcoeffs(:)];
    % b = sum(uu(allj+1),2)';
end

b = b';
dualbase = ind;

j = 1;
A = cell(size(N,1),1);
for k = 1:size(N,1)
    if matrixSOSsize==1
        A{k} = dualbase(:,j:j+n(k)^2-1);
    else
        % Quick fix for matrix SOS case, should be optimized
        A{k} = inflate(dualbase(:,j:j+n(k)^2-1),matrixSOSsize,n(k));
    end
    j = j + n(k)^2;
end
b = b(:);



function newAi = inflate(Ai,matrixSOSsize,n);
% Quick fix for matrix SOS case, should be optimized
newAi = [];
newAi = [];
newAj = [];
newAk = [];
top = 1;
for i = 1:matrixSOSsize
    for r = i:matrixSOSsize
        for m = 1:size(Ai,1)
            ai = reshape(Ai(m,:),n,n);
            
            if 1
              %  V = spalloc(matrixSOSsize,matrixSOSsize,2);
              %  V(i,r)=1;
              %  V(r,i)=1;
              %  aii = kron(V,ai);
              %  aii = aii(:);
              %  [ii,jj,kk] = find(aii);
              % newAj = [newAj ii(:)'];
              %  newAi = [newAi repmat(top,1,length(ii))];
              %  newAk = [newAk kk(:)'];
                [dnewAj,dnewAi,dnewAk] = inflatelocal(ai,matrixSOSsize,r,i,top);
                newAj = [newAj dnewAj];
                newAi = [newAi dnewAi];
                newAk = [newAk dnewAk];
                % newAi = [newAi;ai(:)'];
            else
                 [dnewAjC,dnewAiC,dnewAkC] = inflatelocal(ai,matrixSOSsize,r,i,top);
                 [dnewAj,dnewAi,dnewAk] = inflatelocalnew(ai,matrixSOSsize,r,i,top,n);
                 AA=reshape(full(sparse(dnewAi*0+1,dnewAj,dnewAk,1,(matrixSOSsize*n)^2)),n*matrixSOSsize,[]);
                 AA2=reshape(full(sparse(dnewAiC*0+1,dnewAjC,dnewAkC,1,(matrixSOSsize*n)^2)),n*matrixSOSsize,[]);
                 
                 if norm(AA-AA2)>0
                     1
                 end
              
              
                newAj = [newAj dnewAj];
                newAi = [newAi dnewAi];
                newAk = [newAk dnewAk];
%                 
%                 [ii,jj,kk] = find(ai-diag(diag(ai)));
%                 iii = [(i-1)*n+ii;(r-1)*n+jj]
%                 jjj = [(r-1)*n+jj;(i-1)*n+ii]
%                 kkk = [kk;kk];
%                 indexi = repmat(top,1,length(iii));
%                 index = iii+(jjj-1)*matrixSOSsize*n
%                 newAj = [newAj index(:)'];
%                 newAi = [newAi indexi];
%                 newAk = [newAk kkk(:)'];
%                 
%                 [ii,jj,kk] = find(diag(diag(ai)));
%                 iii = [(i-1)*n+ii]
%                 jjj = [(r-1)*n+jj]
%                 kkk = [kk];
%                 indexi = repmat(top,1,length(iii));
%                 index = iii+(jjj-1)*matrixSOSsize*n
%                 newAj = [newAj index(:)'];
%                 newAi = [newAi indexi];
%                 newAk = [newAk kkk(:)'];
            end
            
            %sparse(indexi,index,kkk,1,(n*nA)^2)
            
            top = top+1;
        end
    end
end
newAi = sparse(newAi,newAj,newAk,top-1,(matrixSOSsize*n)^2);


function [Z,Q1,R] = sparsenull(A)

[Q,R] = qr(A');
n = max(find(sum(abs(R),2)));
Q1 = Q(:,1:n);
R = R(1:n,:);
Z = Q(:,n+1:end); % New basis


 function [dnewAj,dnewAi,dnewAk] = inflatelocal(ai,matrixSOSsize,r,i,top)
        V = spalloc(matrixSOSsize,matrixSOSsize,2);
        V(i,r)=1;
        V(r,i)=1;
        aii = kron(V,ai);
        aii = aii(:);
        [ii,jj,kk] = find(aii);
        
        dnewAj = ii(:)';
        dnewAi = repmat(top,1,length(ii));
        dnewAk = kk(:)';
        % newAi = [newAi;ai(:)'];
        
        
        
     function [dnewAj,dnewAi,dnewAk] = inflatelocalnew(ai,matrixSOSsize,r,i,top,n)
         
         if r==i
             [ii,jj,kk] = find(ai-diag(diag(ai)));
         else
             [ii,jj,kk] = find(ai);
         end               
         iii = [(i-1)*n+ii;(r-1)*n+jj];
         jjj = [(r-1)*n+jj;(i-1)*n+ii];
         kkk = [kk;kk];
         indexi = repmat(top,1,length(iii));
         index = iii+(jjj-1)*matrixSOSsize*n;
         dnewAj = [ index(:)'];
         dnewAi = [ indexi];
         dnewAk = [ kkk(:)'];
         
         [ii,jj,kk] = find(diag(diag(ai)));
         iii = [(i-1)*n+ii];
         jjj = [(r-1)*n+jj];
         kkk = [kk];
         indexi = repmat(top,1,length(iii));
         index = iii+(jjj-1)*matrixSOSsize*n;
         dnewAj = [dnewAj index(:)'];
         dnewAi = [dnewAi indexi];
         dnewAk = [dnewAk kkk(:)'];