Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I met a strange problem when trying to do an optimization.

Initialization code,

goal = 2.;
vector = {1.0, 1.1, 1.2, 1.3, 1.4, 1.5};

f[m1_Real, m2_Real] := Block[{v},
   v = Map[# + m1*Sin[Norm[{m1, m2}]] &, vector];
   Clip[v, {0, goal}]];

g[m1_Real, m2_Real] := Max[(goal - f[m1, m2])/goal] + Norm[{m1, m2}];

where f is a vector function and g is a scaler function. I want to minimize g[m1,m2] with constrains 0.8 <= Min[f[m1,m2]] <= 1.0 and 0 <= m1 <= 2 && 0 <= m2 <=2. Despite this seems straightforward, a direct implementation is problematic,

counter = 0;
NMinimize[{
  g[m1, m2],
  And[0.8 <= Min[f[m1, m2]]/goal <= 1.0, 0 <= m1 <= 2, 0 <= m2 <= 2]
  }, {m1, m2},
  Method -> {"NelderMead", "Tolerance" -> .001},
  StepMonitor :> (Print[++counter, ":\t", {m1, m2}])]

If we execute the code, an error message NMinimize::bcons will be shown, which tells us that the constrains are not in the valid format.

After a few tests I found out that the the problem is related to the command Min used in the first constrain 0.8 <= Min[f[m1, m2]]/goal <= 1.0. If we do not use Min then there will be no problem, i.e., 0.8 <= Evaluate[Norm[f[m1, m2]/goal]] <= 1.0 can be evaluated without any problem.

So it seems that Min is not valid for using as constrains with NMizimize (yet we can use Norm, Plus, etc.). But this is really inconvenient because I do need to use Min as part of the constrains. I wonder if we can fix this problem?

share|improve this question
    
Since the first entry in the function result is always the minimum, why not just use it? –  rasher Jan 20 at 7:05
    
@rasher, the math used in this code is just an easy example, my real problem is much more complex than it :) –  saturasl Jan 20 at 8:14

1 Answer 1

up vote 8 down vote accepted

To solve your problem, let's first take a good look at the warning generated by your code:

NMinimize::bcons: The following constraints are not valid:
{0 <= m1, 0 <= m2, 0.8 <= 0.5 f[m1, m2], m1 <= 2, m2 <= 2, 0.5 f[m1, m2] <= 1.}.
Constraints should be equalities, inequalities, or domain
specifications involving the variables. >>

What have you found? Our constraints are not valid, yeah, we know that, but what else? Oh, we see the constraints have been displayed by Mathematica and the form of them have been slightly changed, um, that's understandable, and we can easily find the correspondence between them and their original, 0 <= m1 and 0 <= m2 and m1 <= 2 and m2 <= 2 are for 0 <= m1 <= 2 and 0 <= m2 <= 2, 0.8 <= 0.5 f[m1, m2] and 0.5 f[m1, m2] <= 1. are…… wait, where's the Min? Where did it go? Mathematica don't like it so she deleted it?

Of course not, Min disappeared because it has been calculated before f[m1, m2] become number lists. What happened here is just same as:

Clear[m1, m2]
Min@f[m1, m2]
f[m1, m2]

This can be approved by Trace:

NMinimize[{g[m1, m2], 
           And[0.8 <= Min@f[m1, m2]/goal <= 1.0, 0 <= m1 <= 2, 0 <= m2 <= 2]}, 
          {m1, m2}, 
          Method -> {"NelderMead", "Tolerance" -> .001}] // Trace
{{{0.8 <= Min[f[m1, m2]]/goal <= 1. && 0 <= m1 <= 2 && 
   0 <= m2 <= 2, {{{Min[f[m1, m2]], f[m1, m2]}…………

To fix your code, you can definite a new function that calculates only if its argument is a list:

min[x_List] := Min[x]

counter = 0;
(* I removed your Method option since it seems to be unnecessary. *)
NMinimize[{g[m1, m2], 
           And[0.8 <= min@f[m1, m2]/goal <= 1.0, 0 <= m1 <= 2, 0 <= m2 <= 2]}, 
          {m1, m2},  
          StepMonitor :> (Print[++counter, ":\t", {m1, m2}])]
 {1.02036, {m1 -> 0.820357, m2 -> 2.34313*10^-8}}
share|improve this answer
    
+1 - nice sleuthing. –  rasher Jan 20 at 10:57
    
@rasher Frankly speaking, warnings of Mathematica are usually discouraging at first sight, but it's really helpful for debugging if we read carefully. –  xzczd Jan 20 at 11:09
    
@xzczd, Your definition of min[x_List] subtly postpones the evaluation of min@f[m1, m2] until the desired state is reached. This is a very nice trick. I was thinking something like to use Hold and ReleaseHold to do the same, but faild to find a way to actually insert these command inside NMinimize... Thank you for your answer! And you have my gratitude for showing the subtle trick. –  saturasl Jan 21 at 3:06

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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