1
$\begingroup$

This code works when it is not in a for loop, but as soon as I put it in a loop it stops assigning the variable q.

fdotf[x_, y_, z_,w_] = (4*x - 2*y + 3*z - 5*w)^2 + (3*x + 3*y + 5*z - 
  8*w)^2 + (-6*x - 1*y + 4*z + 3*w)^2 + (-4*x + 2*y - 3*z + 5*w)^2;
ClearAll[q]
gradfdotf = Grad[fdotf[x, y, z, w], {x, y, z, w}]
gradfdotf = Simplify[gradfdotf];
gradfdotf = gradfdotf /. {x -> x0[[1]], y -> x0[[2]], z -> x0[[3]],w -> x0[[4]]};
x1 = x0 - q*gradfdotf;
Solve[D[fdotf[x1[[1]], x1[[2]], x1[[3]], x1[[4]]], q] == 0, q];
q2 = q /. %[[1]];
q = q2;(**learning rate **)
x0 = x0 - q*gradfdotf;
N[x0]

The above code works, but if I put it in a loop all of the sudden it stops!If I try to print q now, it just prints q as opposed to the solution of Solve.

    ClearAll[q]
x0 = {5, 5, 5, 5};
For[i = 1, i <= 4, i++, Print[N[x0]];
ClearAll[q, q2];
gradfdotf = Grad[fdotf[x, y, z, w], {x, y, z, w}];
gradfdotf = Simplify[gradfdotf];
gradfdotf =   gradfdotf /. {x -> x0[[1]], y -> x0[[2]], z -> x0[[3]], 
w -> x0[[4]]};
Print[gradfdotf];
x1 = x0 - q*gradfdotf;
Print[x1];
q /. Solve[D[fdotf[x1[[1]], x1[[2]], x1[[3]], x1[[4]]], q] == 0, q];
Print[q];
]
$\endgroup$
1
  • 3
    $\begingroup$ Welcome to Mathematica Stackexchange Frank :) The line q /. Solve[D[fdotf[x1[[1]], x1[[2]], x1[[3]], x1[[4]]], q] == 0, q];inside your For loop takes the expression q and replaces it according to the replacement rule produced by Solve. Nowhere do you assign anything to q. $\endgroup$ Commented Nov 7, 2018 at 11:58

1 Answer 1

2
$\begingroup$

Given

fdotf[x_, y_, z_, w_] = 
  (4*x - 2*y + 3*z - 5*w)^2 + (3*x + 3*y + 5*z - 8*w)^2 + 
  (-6*x - 1*y + 4*z + 3*w)^2 + (-4*x + 2*y - 3*z + 5*w)^2;
x0 = {5, 5, 5, 5};

then the following code will do what you want.

Clear[q]
Do[
  Print[x0];
  gradfdotf = Grad[fdotf[x, y, z, w], {x, y, z, w}];
  gradfdotf = Simplify[gradfdotf];
  gradfdotf = 
    gradfdotf /. {x -> x0[[1]], y -> x0[[2]], z -> x0[[3]], w -> x0[[4]]};
  Print[gradfdotf];
  x1 = x0 - q*gradfdotf;
  sol =
    Solve[D[fdotf[x1[[1]], x1[[2]], x1[[3]], x1[[4]]], q] == 0, q][[1, 1]] // N;
  Print[sol];
  Print[x1 /. sol],
  4]
{5, 5, 5, 5}
{90, 90, 150, -240}
q -> 0.00274134
{4.75328, 4.75328, 4.5888, 5.65792}
...
{5, 5, 5, 5}
{90, 90, 150, -240}
q -> 0.00274134
{4.75328, 4.75328, 4.5888, 5.65792}

Notes

  1. Do is easier to write than For and runs faster. Note not index is needed as none is referred in the code.
  2. It is not necessary make an assignment to q, but it is necessary to substitute it into x1.

Update

The above solution to your problem works and maintains the basic structure of your code, but is far from optimal. For one thing, no loop, For or Do, seems necessary nor desirable. For another, it does seem very desirable to implement a solution where all variables are localized and which works for any input x0 which is a vector of four numeric quantities.

Here is a such a solution.

gradfdotf[x_, y_, z_, w_] = Grad[fdotf[x, y, z, w], {x, y, z, w}];
solver[x0 : {Repeated[_?NumericQ, {4}]}] :=
  Module[{q, gradfdotv, x1, sol},
    Print[x0];
    gradfdotv = gradfdotf @@ x0;
    Print[gradfdotv];
    x1 = x0 - q*gradfdotv;
    sol =
     Solve[D[fdotf[x1[[1]], x1[[2]], x1[[3]], x1[[4]]], q] == 0, q][[1, 1]] // N;
    Print[sol[[2]]];
    x1 /. sol]

This also has the advantage that it returns the vector x1 so it can used in further computations.

Examples

solver[ConstantArray[5, 4]]
{5, 5, 5, 5}
{90, 90, 150, -240}
0.00274134
{4.75328, 4.75328, 4.5888, 5.65792}
solver[Range[4]]
{1, 2, 3, 4}
{-416, 8, -84, 444}
0.00256274
{2.0661, 1.9795, 3.21527, 2.86214}
$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.