From: John on
FindMaximum/NMaximize vs. Excel Solver

I am looking at a simple model that calculates the best wagers to
place on a set of 20 horses, where the goal is to maximize reward vs.
risk. Since the bets need to be constrained, I can't use NMaximize.
The probabilities are the "real" probabilities of the horses winning;
odds are what would be available at the track.

I have working versions in Excel and Mathematica, but the Mathematica
implementation runs twice as slowly, and it seems that there must be a
more elegant way to do it. The examples I've seen for FindMaximum use
3 or fewer variables and list them explicitly.

I am mostly interested in understanding if this is the Mathematica way
of doing this problem (as opposed to finding a really fast way to bet
on horses).

solveHorse[]:=Module
[{probabilities,odds,totalWager=100,vars,f,inRange,sol},
probabilities={0.2,0.2,0.2,0.2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.1,0.1};
odds={7,5,5,5,5,5,5,5,5,5,5,5,5,5,1,1,2,2,2,2};
inRange[x_]:=0<=x<=totalWager;
f[a__Symbol]:=Module[{ep,var,ws,sp},
ws=List[a];
ep=MapThread[(#1*(1+#2)-totalWager)&,{ws,odds}];
sp= Dot[probabilities,ep];
var=((#-sp)^2)&/@ep;
sp/Sqrt[Dot[probabilities,var]]
];

(* 23.08,25.64,25.64,25.64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0 <--
Excel answer*)
vars=Table[ToExpression["x"<>ToString[i]],{i,1,20}];
sol=FindMaximum[{f[vars]/.List->Sequence,
(And@@inRange/@vars) && Total[vars]==totalWager },
vars,AccuracyGoal->6,PrecisionGoal->9,MaxIterations->1000];
Print["Final Rtn/SD: ",First[sol]];
If[#<10^-6,0,#]&/@vars/.Last[sol]
];
Timing[solveHorse[]]
Final Rtn/SD: 0.444878
{5.28921,
{23.0767,25.6411,25.6411,25.6411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}

From: Bill Rowe on
On 1/21/10 at 4:57 AM, jhurley13(a)gmail.com (John) wrote:

>I am looking at a simple model that calculates the best wagers to
>place on a set of 20 horses, where the goal is to maximize reward
>vs. risk. Since the bets need to be constrained, I can't use
>NMaximize.

NMaximize allows constraints. For example consider the function
x + 5 Sin[x] which has no global maximum and an infinite number
of local maxima. To obtain a maximum for x between say 5 and 10

In[4]:= NMaximize[{x + 5 Sin[x], 5 < x < 10}, x]

Out[4]= {12.9543,{x->8.05534}}

Or for x between 20 and 25

In[5]:= NMaximize[{x + 5 Sin[x], 20 < x < 25}, x]

Out[5]= {25.5207,{x->20.6217}}

No constraints on x results in the following

In[7]:= NMaximize[x + 5 Sin[x], x]

Out[7]= {6.67113,{x->1.77215}}


From: John on
I received an answer from Daniel Lichtblau at Wolfram, and posed this
additional question:

Stepping back, what would be the right syntax for NMaximize for this
problem:
w is the list of wagers to optimize, a list of 20 elements;
each wager must be between 0 and 100;
the sum of the wagers is 100
It seems gross to list out individual variables when Mathematica is so
powerful at list processing.
Thanks,
John

--------


His response was as follows, and was just what I was looking for,
since I wanted the "Mathematica" way of doing it:

It can be set up as below. Notice I do not explicitly list variables.

probabilities = {0.2,0.2,0.2,0.2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.1,0.1};
len = Length[probabilities];
odds = {7,5,5,5,5,5,5,5,5,5,5,5,5,5,1,1,2,2,2,2};
vars = Array[w,len];
tot = 100;
c1 = Map[#>=0&, vars];

ep = (vars(1+odds)-tot);
sp = ep.probabilities;
var = (ep-sp)^2;

obj = sp / Sqrt[Dot[probabilities,var]];

Timing[NMaximize[{obj,Flatten[{c1,Total[vars]==tot}]}, vars]]

That works, but takes around four times longer than FindMaximum. The
speed of NMaximize is not troubling to me, but FindMaximum might be
slow for this. That is, I'm not sure whether the timing is expected or
indicates a speed bump.

Daniel


--------

In a later message, we were looking at timings:

Daniel,
Thank you so much for your reply. It not only answers my question, but
reminds me how much I still need to learn about Mathematica. If
nothing else, I have to take a long look at "a = b" vs. "a:=b".
I was still curious about why it took so long, and found that
simplifying obj helped speed things up by 20% or so:
obj = sp/Sqrt[Dot[probabilities, var]] // Simplify;
Timing[NMaximize[{obj, Flatten[{Total[vars] == tot, c1}]}, vars,
AccuracyGoal -> 6, PrecisionGoal -> 9]]
Just for fun, I tried the different methods available from NMaximize,
and found:
SimulatedAnnealing 19.2039
RandomSearch 1329.74
DifferentialEvolution 18.9437
NelderMead 99.743
Default 23.7308
FindMaximum 5.43854
If it is OK with you, I'd like to post your response back to the group
since it helped me so much; I can attribute it to you or to an
anonymous helper. Thanks again.
John
[...]

That's fine with me. Possibly someone will get competitive and maybe
figure out a tweak that makes FindMaximum or NMaximize handle this
faster. For FindMaximum, I doubt it will be method-related because I
believe that function has but one choice (interior point) when given
constraints (unless everything is linear or, at worst, objective is
quadratic).

One possible improvement would be to maximize the square, since (I
think) everything is nonnegative. Could use obj2, given as below.

obj2 = Simplify[Rationalize[obj]^2,
Assumptions -> Map[0 <= # <= 100 &, vars]]


Daniel

One other thing. If you get rid of variables that correspond to zero
probability, the timings become tremendously faster. I do not think
this type of smarts could be automated (in NMaximize or Findmaximum),
unfortunately.

Daniel

----------

I was still curious about why it took so long, and found that
simplifying obj helped speed things up by 20% or so:

obj = sp/Sqrt[Dot[probabilities, var]] // Simplify;
Timing[NMaximize[{obj, Flatten[{Total[vars] == tot, c1}]}, vars,
AccuracyGoal -> 6, PrecisionGoal -> 9]]

Just for fun, I tried the different methods available from NMaximize,
and found:

SimulatedAnnealing 19.2039
RandomSearch 1329.74
DifferentialEvolution 18.9437
NelderMead 99.743
Default 23.7308
FindMaximum 5.43854

Thanks for the replies.

From: John on
Bill,

Thanks for the reply. I saw how to use NMaximize itself, but ran into
problems with 20 variables and constraints. Daniel's answer showed me
the syntax that I had not understood just from documentation.

John