Search code examples
matlabnonlinear-optimizationnon-linear-regression

MATLAB - writing objective function for fmincon()


I need to minimize following function

nDOF, nprocs and T are taken from the first two columns of this table

enter image description here

So I have following vectors in MATLAB

nDOF =
        3993
        3993
        3993
        3993
        3993
        3993
        3993
        3993
        7623
        7623
        7623
        7623
        7623
        7623
        7623
        7623

nprocs =
     1
     2
     3
     4
     6
     8
    12
    24
     1
     2
     3
     4
     6
     8
    12
    24

vals = 
    0.6564
    0.2569
    0.2719
    0.1743
    0.1305
    0.1230
    0.1739
    0.1147
    1.1998
    0.5088
    0.6419
    0.2899
    0.2192
    0.2033
    0.2126
    0.1821

And I wanted to minimize the function $F$ with function fmincon like this:

fmincon(@(theta) objFunctionMatAssemble(theta(1), theta(2), theta(3), theta(4), ndofIN, nprocsIN, vals), [0 0 0 0]', [], [], [], [], [0 0 0 0], [+inf +inf +inf +inf] )

Code of objFunctionMatAssemble:

function [t] = objFunctionMatAssemble(alpha, beta, gamma, delta, ndofIN, nprocsIN, vals)
    t = 0;
    for i=1:length(nprocsIN)
        t = t + alpha*ndofIN^beta + gamma*((ndofIN(i)^delta)/nprocsIN(i) - vals(i))^2;
    end
end

The problem is, I'm getting following error:

>> fmincon(@(theta) objFunctionMatAssemble(theta(1), theta(2), theta(3), theta(4), ndofIN, nprocsIN, vals), [0 0 0 0]', [], [], [], [], [0 0 0 0], [+inf +inf +inf +inf] )
Error using  ^ 
Inputs must be a scalar and a square matrix.
To compute elementwise POWER, use POWER (.^) instead.

Error in objFunctionMatAssemble (line 4)
        t = t + alpha*ndofIN^beta + gamma*((ndofIN(i)^delta)/nprocsIN(i) - vals(i))^2;

Error in @(theta)objFunctionMatAssemble(theta(1),theta(2),theta(3),theta(4),ndofIN,nprocsIN,vals)

Error in fmincon (line 535)
      initVals.f = feval(funfcn{3},X,varargin{:});

Caused by:
    Failure in initial objective function evaluation. FMINCON cannot continue.

The problem is apparently in my objective function, but I'm not able to write it correctly despite trying several times. I've seen some solution here on SO, but even if my "closure function" takes only one argument and calls the other one, still its format is not correct.

Could you, please, help me with this?


Solution

  • You forgot to index ndofIN in the loop (you write ndofIN^beta, which should be ndofIN(i)^beta).

    Now, the operator ^ in MATLAB means matrix power. For scalar/scalar input, this operation is the same as normal exponentiation, but for matrix/scalar inputs, it is not quite the same. In your case, MATLAB tries to exponentiate the vector ndofIN with beta -- this is not allowed, since matrix power is only defined for square matrices. That's why you get that error.

    Obviously, this is not quite what you intend to do -- you want element wise exponentiation (.^). Using this, you can simplify and speed up your objective function tremendously -- just write that objective function like this:

    function t = objFunctionMatAssemble(alpha, ...
                                        beta, ...
                                        gamma, ...
                                        delta, ...
                                        ndofIN, ...
                                        nprocsIN, ...
                                        vals) 
    
        t = alpha *  ndofIN.^beta + ...
            gamma * (ndofIN.^delta)./nprocsIN - vals;
    
        t = t.' * t;
    
    end
    

    NOTE in your original function there is also a parenthesis inconsistency. That is, your parenthesis make your objective function something else than what you've shown in the question:

    % your version
    t = t +  alpha*ndofIN^beta + gamma*((ndofIN(i)^delta)/nprocsIN(i) - vals(i))^2;
    
    % what's in the image
    t = t + (alpha*ndofIN^beta + gamma* (ndofIN(i)^delta)/nprocsIN(i) - vals(i))^2;
    

    NB2: You can also write your objective function like this:

    function t = objFunctionMatAssemble2(theta, ...
                                         ndofIN, ...
                                         nprocsIN, ...
                                         TIN)                                      
    
        N = bsxfun(@power, ndofIN, theta([2 4]).');        
        t = [N(:,1) N(:,2)./nprocsIN] * theta([1 3]) - TIN;        
        t = t.' * t;
    
    end
    

    so that your objective function does not need so many arguments. But well, that depends on your tastes.