1
$\begingroup$

I have this function GuessError, here's a plot assuming a single variable x, Plot[GuessError[10^x, etc..], {x, 8, 12}] , being etc some more variables which are previously defined, machine-type numbers. plot of my function, which has a minimum in the given range

It shows that minimum near x=9.

Now if I try NMinimize[{GuessError[10^x, etc..], {8.8 < x < 9.2}}, x], I get this error message:

Nearest::neard: "The default distance function does not give a real numeric distance when applied to the point pair Max[0.23359984866812222`,-(3.23*10^15\10^-x)/(1+<<23>>\10^(<<5>><<1>><<1>>]))^0.5+ ..."

It does not have to do with Real or Complex values, because my function returns always Abs[...]. What could be the problem here?

Here is the function, in the minimization, I use ni = 10^x:

GuessError[IVcurve_,Area_,ni_,mue_,krec_,Jgen_,d_,T_]:=Module[{Vext,q,Vt,Jsim,Vexp,Vsup,Vinf,ninf,nsup,Jexp,Jrange,Vrange,Iexp,Vint,imin,imax,JV},
  Vt = 8.61733238 10^-5 (T + 273.15);
  q = 1.6 10^-19;
  Iexp = Transpose[IVcurve][[2]]/Area;
  Vexp = Transpose[IVcurve][[1]];
  Jexp = Iexp/Area;
  Vint = Vt Log[(Jexp + Jgen)/(q d krec ni^2) + 1]; 
  Vext = Vint + (d Jexp)/(2 q mue ni E^(Vint/(2 Vt)));
  Vinf = Max[First[Vext], First[Vexp]]; 
  ninf = Flatten[Position[Vexp, Nearest[Vexp, Vinf][[1]]]][[1]];
  Vsup = Min[Last[Vext], Last[Vexp]]; 
  nsup = Flatten[Position[Vexp, Nearest[Vexp, Vsup][[1]]]][[1]];

  Vrange = Take[Vext, {ninf, nsup}];

      Abs@Total[(Vrange - Take[Vexp, {ninf, nsup}])^2]]
$\endgroup$
13
  • 3
    $\begingroup$ What is GuessError[ ]? $\endgroup$ Commented May 12, 2015 at 15:04
  • 2
    $\begingroup$ Problems with code usually require the code. My guess is that it's a _?NumericQ problem. $\endgroup$
    – Michael E2
    Commented May 12, 2015 at 15:18
  • $\begingroup$ ok I included it in the original question. The point is that it evaluates to real numbers. If I try an Interpolation of a table of my function as a function of x, NMinimize works. $\endgroup$
    – Kurt
    Commented May 12, 2015 at 15:20
  • $\begingroup$ I think that it would be more helpful to have the code for GuessError, rather than its plot. $\endgroup$
    – MarcoB
    Commented May 12, 2015 at 15:25
  • $\begingroup$ My (guessed) point is that GuessError[.., .., 10^x, etc.] does not itself evaluate to a number at all. (Try GuessError[Table[{t, 10^t + RandomReal[]}, {t, 10}], 1, 10^x, 1, 1, 1, 1, 1].) $\endgroup$
    – Michael E2
    Commented May 12, 2015 at 15:37

1 Answer 1

3
$\begingroup$

I think there is enough information in the question to make a confident guess at the problem. The key clue is in the quoted error message:

Nearest::neard: "The default distance function does not give a real numeric distance when applied to the point pair Max[0.23359984866812222`,-(3.23*10^15\10^-x)/(1+<<23>>\10^(<<5>><<1>><<1>>]))^0.5+ ..."

We can see that there is a 10^x in the message, which shows that the call to GuessError[.., .., 10^x, etc.] was evaluated with a symbolic x. (NMinimize is not HoldAll or HoldFirst.) This is a classic problem solved by _?NumericQ, which is explained in this answer: What are the most common pitfalls awaiting new users?

Indeed both calls below yield a Nearest::neard error:

GuessError[Table[{t, 10^t}, {t, 10}], 1, 10^x, 1, 1, 1, 1, 1]
NMinimize[{GuessError[Table[{t, 10^t}, {t, 10}], 1, 10^x, 1, 1, 1, 1, 1],
  {0.1 < x < 1.5}}, x]

The minimal fix is to add a ?NumericQ to ni:

GuessError[IVcurve_, Area_, ni_?NumericQ, mue_, krec_, Jgen_, d_, T_] := ...

One might add it to other variables except IVcurve, which needs a ?(MatrixQ[#, NumericQ]&) PatternTest.


Gratuitous suggestions

Since NMinimize can be slow, it might be good to speed up GuessError. Depending on how large IVcurve is, since it is static, it would be potentially much faster to construct the NearestFunction just once for the optimization problem.

Next, since it is the position of the nearest point that is desired, it will be more efficient to use the form

Nearest[Vexp -> Automatic]

These two changes speed up NMinimize 35% in a test run on an IVcurve of length 1000, 20% on a curve of length 100.

Further, one can do some more of the construction of the objective function by precomputing Jexp and Vexp which are constant (with respect to ni). With these improvements, the same optimization runs almost 65% faster on a curve of length 1000 (and almost 50% faster on a curve of length 100).

Code:

ClearAll[GuessError, objGuessError];
 (* No pattern tests - Returns an objective function, objGuessError *)
GuessError[IVcurve_, Area_, ni_, mue_, krec_, Jgen_, d_, T_] :=
 objGuessError[
  IVcurve[[All, 1]]/Area^2, IVcurve[[All, 2]],
  Nearest[IVcurve[[All, 1]] -> Automatic],
  Area, ni, mue, krec, Jgen, d, T]; 

objGuessError[Jexp_, Vexp_, iNF_, Area_, ni_?NumericQ, mue_, krec_, Jgen_, d_, T_] := 
 Module[{Vext, q, Vt, Jsim, Vsup, Vinf, ninf, nsup, Jrange, Vrange, 
   Vint, imin, imax, JV}, Vt = 8.61733238 10^-5 (T + 273.15);
  q = 1.6 10^-19;
  Vint = Vt Log[(Jexp + Jgen)/(q d krec ni^2) + 1];
  Vext = Vint + (d Jexp)/(2 q mue ni E^(Vint/(2 Vt)));
  Vinf = Max[First[Vext], First[Vexp]];
  ninf = First[iNF[Vinf]];
  Vsup = Min[Last[Vext], Last[Vexp]];
  nsup = First[iNF[Vsup]];
  Vrange = Take[Vext, {ninf, nsup}];
  Abs@Total[(Vrange - Take[Vexp, {ninf, nsup}])^2]]

Example optimization:

ivcurve = Table[{t, 10^t}, {t, 0, 10, 0.01}];
NMinimize[{GuessError[ivcurve, 1, 10^x, 1, 1, 1, 1, 1], {0.1 < x < 1.5}}, x]
$\endgroup$
4
  • $\begingroup$ Thank you @Michael E2, it works just as you say in the first part of your answer. I am still having trouble finding the minimum with actual values but thats another story. The ?NumberQ as pattern in the definition of the function buffles me, because somehow NMinimize "notices" and prevents evaluation, but it does not with a more simple function like x^2. $\endgroup$
    – Kurt
    Commented May 12, 2015 at 18:21
  • $\begingroup$ More of a hint than an explanation: First ClearAll[f, g]; f[x_?NumericQ] := x^2; g[x_] := x^2. Then consider NMinimize[f[x], x] vs. NMinimize[g[x], x]. Now f[x] evaluates to f[x] - nothing happens because NumericQ[x] is False. This is the standard Mathematica evaluation and has nothing to with NMinimize. But f[2] yields 4. OTOH, g[x] evaluates to the symbolic expression x^2. Execute the the NMinimize commands and you get different answers, because NMinimize has to use a finite difference approximation for f'[x]. See the links in the linked Q above for more. $\endgroup$
    – Michael E2
    Commented May 12, 2015 at 20:02
  • $\begingroup$ If you're having trouble finding the minimum, you could consult the tutorial I linked in my last comment under the main question. Another method or increasing "MaxIterations" may help. Your graph looks ragged. You can monitor the process with Block[{Optimization`NMinimizeDump`dbPrint = Print}, NMinimize[…]], but do it in its own notebook and be prepared for tons and tons of output. If you do it on f or g in my previous comment, look for "Entering KKT" to see where the derivative comes into play. $\endgroup$
    – Michael E2
    Commented May 12, 2015 at 20:08
  • $\begingroup$ Thank you Michael E2!! Really helps! I did take a look at your linked tutorial and found many useful things. I got the NMinimize working now and playing around with the Methods. $\endgroup$
    – Kurt
    Commented May 14, 2015 at 14:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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