function sys=double(X)
%DOUBLE Returns current numerical value
%bajs i bajs
% Author Johan Löfberg
% $Id: double.m,v 1.43 2006/09/21 14:34:41 joloef Exp $

solution = yalmip('getsolution');
lmi_variables = X.lmi_variables;
opt_variables = solution.variables;

% Definition of nonlinear variables
[mt,variabletype] = yalmip('monomtable');
nonlinears = lmi_variables(find(variabletype(X.lmi_variables)));

if ~isempty(solution.values)
    if max(lmi_variables) <= length(solution.values) & isempty(nonlinears)
        if ~any(isnan(solution.values(lmi_variables(:))))
            % Yihoo, we can do this really fast by
            % re-using the old values
            sys = X.basis*[1;solution.values(lmi_variables(:))];
            if X.typeflag==10
                sys = eig(full(reshape(sys,X.dim(1),X.dim(2))));
            else
                sys = full(reshape(sys,X.dim(1),X.dim(2)));
            end
            return
        end
    end
end

% Okey, we could not do it really fast...

% Definition of nonlinear variables
allextended   = yalmip('extvariables');
allevaluators = yalmip('evalVariables');
allextended = union(allextended,allevaluators);

if isempty(nonlinears) & isempty(allextended) & all(ismembc(lmi_variables,solution.variables))

    % speed up code for simple linear case
    values = solution.values;
    if isempty(solution.values)
        values = sparse(solution.variables,ones(length(solution.variables),1),solution.optvar,size(mt,1),1);
        %values = zeros(size(mt,1),1);
        %values(solution.variables) = solution.optvar;
        yalmip('setvalues',values);
    else
        if any(isnan(solution.values(lmi_variables(:))))
            values = sparse(solution.variables,ones(length(solution.variables),1),solution.optvar,size(mt,1),1);
            %            values = zeros(size(mt,1),1);
            %            values(solution.variables) = solution.optvar;
            yalmip('setvalues',values);
        end
    end

    sys = X.basis*[1;values(lmi_variables(:))];
    if X.typeflag==10
        sys = eig(full(reshape(sys,X.dim(1),X.dim(2))));
    else
        sys = full(reshape(sys,X.dim(1),X.dim(2)));
    end

    return
end

% All double values
values(size(mt,1),1)=nan;values(:)=nan;
values(solution.variables) = solution.optvar;

% Evaluate the extended operators
if ~isempty(allextended)
    extended_variables = find(ismembc(X.lmi_variables,allextended));
    if ~isempty(extended_variables)
        extstructE = lmi_variables(extended_variables);
        extstructE = yalmip('extstruct',extstructE);
        if ~isa(extstructE,'cell')
            extstructE = {extstructE};
        end
        for i = 1:length(extended_variables)
            extvar = lmi_variables(extended_variables(i));
            %extstruct = yalmip('extstruct',extvar);
            extstruct = extstructE{i};%yalmip('extstruct',extvar);
         %   if ~isequal(extstructE{i},extstruct)
         %       1
         %   end
            for k = 1:length(extstruct.arg)
                if isa(extstruct.arg{k},'sdpvar') | isa(extstruct.arg{k},'constraint')
                    extstruct.arg{k} = double(extstruct.arg{k});
                end
            end

            switch extstruct.fcn
                
                case 'sort'
                    [w,loc] = sort(extstruct.arg{1});
                    if extstruct.arg{2}.isthisloc
                        val = loc(extstruct.arg{2}.i);
                    else
                        val = w(extstruct.arg{2}.i);
                    end
                    
                case 'semivar'
                    % A bit messy, since it not really is a nonlinear
                    % operator. semivar(1) does not return 1, but a new
                    % semivar variable...
                    val = values(getvariables(extstruct.var));

                case 'geomean' % Not 100% MATLAB consistent (Hermitian case differ)
                    val = extstruct.arg{1};
                    if ~any(any(isnan(val)))
                        [n,m] = size(val);
                        if n == m
                            if issymmetric(val)
                                val = max(0,real(det(val)))^(1/n);
                            else
                                val = geomean(val);
                            end
                        else
                            val = geomean(val);
                        end
                    else
                        val = nan;
                    end

                case 'pwf'
                    % Has to be placed here due to the case when
                    % all functions are double, since in this case,
                    % we cannot determine in pwf if we want the double or
                    % create a pw constant function...
                    n = length(extstruct.arg)/2;
                    i = 1;
                    val = nan;
                    while i<=n
                        if min(checkset(extstruct.arg{2*i}))>=0
                            val = extstruct.arg{2*i-1};
                            break
                        end
                        i = i + 1;
                    end

                case 'mpower'      
                    val = extstruct.arg{1};
                case {'max','min'} % Cannot take several inputs, put everything in a vector
                    val = feval(extstruct.fcn,[extstruct.arg{:}]);
                case {'or','and'}
                    try
                        val = feval(extstruct.fcn,extstruct.arg{:});
                    catch
                        val = nan;
                    end

                otherwise 
                    try
                        if ismembc(extvar,allevaluators)
                            % Evaluator variables (used for exp, log, ...)
                            % have an appended argument that we need to
                            % remove. The appended variables is used
                            % internally to convert from general format
                            % f(a'x+c) to f(z), z==a'z+b
                            val = feval(extstruct.fcn,extstruct.arg{1:end-1});
                        else
                            val = feval(extstruct.fcn,extstruct.arg{:});
                        end
                    catch
                        val = nan;
                    end
            end
            values(extvar) = full(val);
        end
    end
end

if ~isempty(nonlinears)
    mt_t = mt'; %Working columnwise is faster
    use_these = find(ismember(lmi_variables,nonlinears));
    all_extended_variables  = yalmip('extvariables');
    all_evaluator_variables = yalmip('evalVariables');
    all_extended_variables = union(all_extended_variables,all_evaluator_variables);

    for i = use_these
        monom_i = mt_t(:,lmi_variables(i));
        used_in_monom = find(monom_i);

        if ~isempty(all_extended_variables)
            extended_variables = find(ismember(used_in_monom,all_extended_variables));
            if ~isempty(extended_variables)
                for ii = 1:length(extended_variables)
                    extvar = used_in_monom(extended_variables(ii));
                    extstruct = yalmip('extstruct',extvar);
                    for k = 1:length(extstruct.arg)
                        if isa(extstruct.arg{k},'sdpvar')
                            extstruct.arg{k} = double(extstruct.arg{k});
                        end
                    end

                    switch extstruct.fcn
                        
                        case 'sort'
                            w = sort(extstruct.arg{1});
                            val = w(extstruct.arg{2});

                        case 'semivar'
                            val = values(getvariables(extstruct.var));

                        case 'mpower'      %
                            val = extstruct.arg{1};
                        case {'max','min'} % Cannot take several inputs, put everything in a vector
                            val = feval(extstruct.fcn,[extstruct.arg{:}]);
                        otherwise          % VAL = OPERATOR(X1,X2,...)
                            if ismembc(extvar,all_evaluator_variables)
                                % Evaluator variables (used for exp, log, ...)
                                % have an appended argument that we need to
                                % remove. The appended variables is used
                                % internally to convert from genreal format
                                % f(a'x+c) to f(z), z==a'z+b
                                val = feval(extstruct.fcn,extstruct.arg{1:end-1});
                            else
                                val = feval(extstruct.fcn,extstruct.arg{:});
                            end
                    end
                    values(extvar) = val;
                end
            end
        end
        % This code is a bit shaky due to the 0^0 bug in linux 6.5
        %the_product = prod(values(used_in_monom).^monom_i(used_in_monom));
        the_product = 1;
        for j = 1:length(used_in_monom)
            the_product = the_product*values(used_in_monom(j))^monom_i(used_in_monom(j));
        end
        values(lmi_variables(i)) = the_product;
    end
end
sys = X.basis*[1;values(lmi_variables(:))];

if X.typeflag==10
    sys = eig(full(reshape(sys,X.dim(1),X.dim(2))));
else
    sys = full(reshape(sys,X.dim(1),X.dim(2)));
end
