1
$\begingroup$

I have a problem I am attempting to solve with NMinimize.

I have a scoring function, which will give me a final score. The problem has many variables, so instead of having them as parameters, they are assembled by variable name. Here is a simple example:

scoreResults = Function[
Module[{temp, i},
 temp = 0;
 Print["Checkpoint 0: " <> ToString[temp]];
 For[i = 0, i < 2, i++,
  temp = temp + ToExpression["aaa" <> ToString[i]];
  If[ToExpression["aaa" <> ToString[i]] > 300,
   temp = temp + 100000;
   ];
  Print["Checkpoint 1: " <> ToString[Evaluate[temp]]];
  ];
 Return[temp, Module];
 ]
];

Notice the If condition. Now, when I evaluate with a ReplaceAll, I get the following:

scoreResults[] /. {aaa0 -> 123, aaa1 -> 456}
Checkpoint 0: 0
Checkpoint 1: aaa0
Checkpoint 1: aaa0 + aaa1
579

That is not correct! I believe what's happening is the function is being evaluated before the ReplaceAll. Is it possible to get around this without having input parameters? My problem has many variables, and the scoring function will have many nested for loops, so assembling variable names on the fly inside the scoring function is key. Even if I do use input parameters for the function, I'm finding that my ToExpression["aaa"<>ToString[i]] is not effective.

Ultimately, I would like to use this scoring function with NMinimize like such:

NMinimize[{scoreResults[], {aaa0 > 222, aaa1 > 333}}, {aaa0, aaa1}]

Currently the answer it gives me is wrong:

{555., {aaa0 -> 222., aaa1 -> 333.}}

Thank you in advance for your help, I have been trying to figure this out for a while now. I understand that when I get to the NMinimize part, I'll probably have to use NumericQ, but for now, I just need to get past the initial problem I'm having just getting the function to produce the correct value, including the If statement.

$\endgroup$
0
$\begingroup$

Here is some code which I think should do what you are after:

ClearAll@scoreResults;
scoreResults[a_ /; NumericQ[a[0]]] := Module[{temp, i},
  temp = 0;
  For[i = 0, i < 2, i++,
    temp = temp + a[i];
    If[a[i] > 300,
      temp = temp + 100000
    ]
  ];
  temp
]

NMinimize[{scoreResults[a], {a[0] > 222, a[1] > 333}}, {a[0], a[1]}]

note that it generally is not a good idea to generate variable from strings. Using other approaches is usually more efficient and results in clearer code. In your case you can take advantage of the fact that NMinimize as many similar functions accepts indexed variables. This is not really documented but has worked since all versions I know of. The second trick to make things work as intended is the use of NumericQ which will make scoreResults only evaluate when numeric values are given for the indexed variables. If you find this does what you want, here is another version which is how you typically would formulate the problem in Mathematica:

ClearAll@scoreResults;
scoreResults[a_ /; NumericQ[a[1]]] := Sum[
  a[i] + If[a[i] > 300, 100000, 0],
  {i, 2}
];
NMinimize[{scoreResults[a], {a[1] > 222, a[2] > 333}}, {a[1], a[2]}]
$\endgroup$
  • $\begingroup$ Thank you very much, that is perfect! For the longest time, I just couldn't figure it out, this helps a lot. $\endgroup$ – Helix888 Sep 17 at 19:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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