Skip to main content
added 1796 characters in body
Source Link
xzczd
  • 71.6k
  • 10
  • 184
  • 524

Update

Aha, 8 years passed and now I'm able to figure out what's wrong with OP's original attempt. The problem can be boiled down to the following:

Why does an a[21] appear in the warning message?

This is actually a matter of evaluation order. Just observe the output of the following sample:

Clear[a, i]; i = 1; If[a[i] > 0, 1, If[a[i] < 2, 4]] (* If[a[1] > 0, 1, If[a[i] < 2, 4]] *) 

As we can see, there's an a[i] in 2nd If[…], this is because If owns HoldRest attribute, so the a[i] inside 2nd If[…] is never evaluated.

"So what? This won't cause any problem, because a[i] will finally evaluate to a[1] at sometime! " Yes, if only the value of i never changes afterwards, but sadly it's not the case for OP's f: the value of i is changing in the For loop, which finally becomes 21!

So, how to fix? Using PiecewiseExpand as shown below is of course a solution, but a more on-target solution is to adjust the evaluation order to make the a[i]s evaluate at proper timings, which can be done with With:

f[a_] := Module[{i},(*Set initial condition as clean*) CurrentCapacity[1] = InitialCapacity; For[i = 2, i < Periods + 1, i++, CurrentCapacity[i] =(*PiecewiseExpand@*) With[{i = i}, If[a[i] == 0 && a[i - 1] == 0, CurrentCapacity[i - 1] - PeriodCapacityLoss, If[a[i] == 1, OOSCapacity, InitialCapacity]]];]; Return[Total[Map[CurrentCapacity, Range[Periods]]]];] 

You'll see some of the i becomes red, it's merely for warning. If you don't like it, just change the With[…] to With[{ii = i}, If[a[ii] == 0 && a[ii - 1] == 0, CurrentCapacity[ii - 1] - PeriodCapacityLoss, If[a[ii] == 1, OOSCapacity, InitialCapacity]]].


Update

Aha, 8 years passed and now I'm able to figure out what's wrong with OP's original attempt. The problem can be boiled down to the following:

Why does an a[21] appear in the warning message?

This is actually a matter of evaluation order. Just observe the output of the following sample:

Clear[a, i]; i = 1; If[a[i] > 0, 1, If[a[i] < 2, 4]] (* If[a[1] > 0, 1, If[a[i] < 2, 4]] *) 

As we can see, there's an a[i] in 2nd If[…], this is because If owns HoldRest attribute, so the a[i] inside 2nd If[…] is never evaluated.

"So what? This won't cause any problem, because a[i] will finally evaluate to a[1] at sometime! " Yes, if only the value of i never changes afterwards, but sadly it's not the case for OP's f: the value of i is changing in the For loop, which finally becomes 21!

So, how to fix? Using PiecewiseExpand as shown below is of course a solution, but a more on-target solution is to adjust the evaluation order to make the a[i]s evaluate at proper timings, which can be done with With:

f[a_] := Module[{i},(*Set initial condition as clean*) CurrentCapacity[1] = InitialCapacity; For[i = 2, i < Periods + 1, i++, CurrentCapacity[i] =(*PiecewiseExpand@*) With[{i = i}, If[a[i] == 0 && a[i - 1] == 0, CurrentCapacity[i - 1] - PeriodCapacityLoss, If[a[i] == 1, OOSCapacity, InitialCapacity]]];]; Return[Total[Map[CurrentCapacity, Range[Periods]]]];] 

You'll see some of the i becomes red, it's merely for warning. If you don't like it, just change the With[…] to With[{ii = i}, If[a[ii] == 0 && a[ii - 1] == 0, CurrentCapacity[ii - 1] - PeriodCapacityLoss, If[a[ii] == 1, OOSCapacity, InitialCapacity]]].


Source Link
xzczd
  • 71.6k
  • 10
  • 184
  • 524

Maybe there're deeper reasons, but I can't figure it out right now: it seems that NMinimize doesn't like If. Add a PiecewiseExpand to the definition of f will fix the problem:

f[a_] := Module[{i},(*Set initial condition as clean*) CurrentCapacity[1] = InitialCapacity; For[i = 2, i < Periods + 1, i++, CurrentCapacity[i] = PiecewiseExpand@ If[a[i] == 0 && a[i - 1] == 0, CurrentCapacity[i - 1] - PeriodCapacityLoss, If[a[i] == 1, OOSCapacity, InitialCapacity]];]; Return[Total[Map[CurrentCapacity, Range[Periods]]]];]; vars = Array[a, Periods]; realconstraints = And @@ Map[Greater[2, #, 0] &, vars]; integerconstraints = Append[realconstraints, Element[vars, Integers]]; NMaximize[{f[a], integerconstraints}, vars, Method -> {"DifferentialEvolution"}] 

{10500., {a[1] -> 1, a[2] -> 1, a[3] -> 1, a[4] -> 1, a[5] -> 1,
a[6] -> 1, a[7] -> 1, a[8] -> 1, a[9] -> 1, a[10] -> 1, a[11] -> 1,
a[12] -> 1, a[13] -> 1, a[14] -> 1, a[15] -> 1, a[16] -> 1, a[17] -> 1, a[18] -> 1, a[19] -> 1, a[20] -> 1}}