bnbfreak
bnbfreak

Reputation: 353

Find gradient from complicated objective function in Matlab

I have a problem in calculating symbolic gradient from the following objective function:

syms x
gradient(@objfun,x)


function f = objfun(x)

N = 4;
I = 3;
fr = 5;

f_temp = 0;
for n=1:N
    sum2 = 0;
    for i=1:I
        sum1 = fr*(1 - x(n+((i-1)*N)));
        sum2 = sum2 + sum1;  
    end
    f_temp = f_temp + sum2;
end

f = 100*f_temp;                
end

However, this error appears "Only anonymous functions and functions without arguments can be converted to sym". How to make this code works?

Upvotes: 1

Views: 352

Answers (1)

jodag
jodag

Reputation: 22194

The gradient function takes a symbolic expression as input, not a function pointer. MATLAB's complaining because it's trying to convert your function pointer to a symbolic expression and it can't.

In this case the following works

N = 4; I = 3;
x = sym('x',[N,I]);     % Define a matrix of symbolic variables
f = objfun(x);          % Get symbolic expression for objfun in terms of x

Disclaimer This works because all the operations in objfun are supported on symbolic variables. For more complex objective functions this approach may not work.

This defines x as a N-by-I matrix of symbolic variables

>> x
x =
[ x1_1, x1_2, x1_3]
[ x2_1, x2_2, x2_3]
[ x3_1, x3_2, x3_3]
[ x4_1, x4_2, x4_3]

and defines f as

>> f
f = 
6000 - 500*x1_2 - 500*x1_3 - 500*x2_1 - 500*x2_2 - 500*x2_3 - 500*x3_1 - 500*x3_2 - 500*x3_3 - 500*x4_1 - 500*x4_2 - 500*x4_3 - 500*x1_1

Then we find the gradient of f with respect x to be

>> g = reshape(gradient(f,x(:)), size(x))
g =
[ -500, -500, -500]
[ -500, -500, -500]
[ -500, -500, -500]
[ -500, -500, -500]

The extra reshape is to conform to the common interpretation for the gradient as a tensor with the same dimensions as x.

Edit To respond to the comment. If you want to use this with fmincon so that you have a function which gives both the objective value and gradient then you can construct such a function handle as follows.

grad_fun = matlabFunction(g,'Vars',x);
obj_with_grad = @(x) deal(objfun(x), grad_fun(x));

Now you can get the objective and gradient at any point. For example at x=ones(N,I);

>> [obj_val, grad_val] = obj_with_grad(ones(N,I))
obj_val =
      0
grad_val =
  -500  -500  -500
  -500  -500  -500
  -500  -500  -500
  -500  -500  -500

I didn't test, but you should be able to use obj_with_grad with fmincon now by setting fmincon's 'SpecifyObjectiveGradient' option to true.

Upvotes: 2

Related Questions