4
$\begingroup$

I'm trying to write a script that will minimize a given set of functions. The homework problem I've been given lists a set of dietary information, and I'm supposed to build the optimal salad based on those parameters.

What I can't figure out is how to use the data returned by the Minimize function. The documentation for the Minimize function doesn't specify anything about it.

cost[tomatoe_, lettuce_, spinach_, carrot_, sunflower_, tofu_, chickpea_, oil_] := 1*tomatoe + .75*lettuce +
        .5*spinach + .5*carrot + .45*sunflower + 2.15*tofu + .95*chickpea + 2*oil

energy[tomatoe_, lettuce_, spinach_, carrot_, sunflower_, tofu_, chickpea_, oil_] := 21*tomatoe + 16*lettuce +
        40*spinach + 41*carrot + 585*sunflower + 120*tofu + 164*chickpea + 884*oil

protein[tomatoe_, lettuce_, spinach_, carrot_, sunflower_, tofu_, chickpea_, oil_] := .85*tomatoe + 1.62*lettuce +
        2.86*spinach + 0.93*carrot + 23.4*sunflower + 16.00*tofu + 9.0*chickpea + 0*oil

fat[tomatoe_, lettuce_, spinach_, carrot_, sunflower_, tofu_, chickpea_, oil_] := 0.33*tomatoe + 0.20*lettuce +
        0.39*spinach + 0.24*carrot + 48.7*sunflower + 5*tofu + 2.6*chickpea + 100.00*oil

carbs[tomatoe_, lettuce_, spinach_, carrot_, sunflower_, tofu_, chickpea_, oil_] := 4.64*tomatoe + 2.37*lettuce +
        3.63*spinach + 9.58*carrot + 15.00*sunflower + 3.00*tofu + 27.0*chickpea + 0*oil

sodium[tomatoe_, lettuce_, spinach_, carrot_, sunflower_, tofu_, chickpea_, oil_] := 9.00*tomatoe + 28.00*lettuce +
        65.00*spinach + 69.00*carrot + 3.80*sunflower + 120.00*tofu + 78.00*chickpea + 0*oil

data = Minimize[{energy[tomatoe,lettuce,spinach,carrot,sunflower,tofu,chickpea,oil],
        tomatoe >= 0
        && lettuce >= 0
        && spinach >= 0
        && carrot >= 0
        && sunflower >= 0
        && tofu >= 0
        && chickpea >= 0
        && oil >= 0
        && protein[tomatoe,lettuce,spinach,carrot,sunflower,tofu,chickpea,oil] >= 15
        && 2 <= fat[tomatoe,lettuce,spinach,carrot,sunflower,tofu,chickpea,oil] <= 8
        && sodium[tomatoe,lettuce,spinach,carrot,sunflower,tofu,chickpea,oil] <= 200
        && carbs[tomatoe,lettuce,spinach,carrot,sunflower,tofu,chickpea,oil] >= 4
        && ((lettuce + spinach)/(tomatoe+lettuce+spinach+carrot+sunflower+tofu+chickpea+oil)) >= .40
        },
        {tomatoe,lettuce,spinach,carrot,sunflower,tofu,chickpea,oil}
]

Print[cost[data["tomato"], data["lettuce"], data["spinach"], data["carrot"], data["sunflower"], data["tofu"], data["chickpea"], data["oil"]]]

Export["out.csv", data, "csv"]
$\endgroup$
5
  • $\begingroup$ Welcome to Mathematica.SE! I suggest that: 1) You take the introductory Tour now! 2) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! 3) As you receive help, try to give it too, by answering questions in your area of expertise. $\endgroup$
    – bbgodfrey
    Commented May 20, 2015 at 18:37
  • 4
    $\begingroup$ The first time I read the expression "the optimal salad" in the question, I thought you were using some obscure jargon, or you had a weird typo :-) That's a fun problem. $\endgroup$
    – MarcoB
    Commented May 20, 2015 at 18:54
  • $\begingroup$ @MarcoB: I edited the question so it's more clear... I see why you were confused at first. :P $\endgroup$
    – Jacobm001
    Commented May 20, 2015 at 19:03
  • 3
    $\begingroup$ I would think "The Optimal Salad" could be a rock and roll band. Or possibly the name of some super-villain in a Spiderman movie. $\endgroup$ Commented May 20, 2015 at 19:05
  • 2
    $\begingroup$ Aww, the optimal salad (said in an ominous voice) was great! Too bad, you edited it out... $\endgroup$
    – LLlAMnYP
    Commented May 20, 2015 at 19:07

3 Answers 3

1
$\begingroup$

Just use the following instead of your print statement:

Print[cost[tomatoe, lettuce, spinach, carrot, sunflower, tofu, chickpea, oil] /. data[[2]] ]

(* Out: 2.32728 *)

The Minimize function returns the following data structure:

{114.754, {tomatoe -> 1.72651*10^-8, lettuce -> 0.58548, spinach -> 3.53893*10^-8, carrot -> 8.48321*10^-9, sunflower -> 9.69807*10^-10, tofu -> 0.87822, chickpea -> 3.3596*10^-9, oil -> 4.43666*10^-10}}

The first value in the list is the value of the function you minimized at the minimum. The second part is a list of the variable values at that minimum, provided as a replacement list. data[[2]] extracts that replacement list. With that, lettuce /. data[[2]] gives you for instance the value of the lettuce variable.


By the way, if all you need is to show the value, you don't need Print. The expression

cost[tomatoe, lettuce, spinach, carrot, sunflower, tofu, chickpea, oil] /. data[[2]]

will be evaluated to its value and that value will be returned. You may still need Print, however, if you intend to put this code e.g. inside a Module, or a function, etc. where it is not the last evaluated expression.

$\endgroup$
1
  • $\begingroup$ Thank you. I've been struggling to figure out how to handle the return value. I assumed I needed the Print[] function to handle formatting the type or something :-/. $\endgroup$
    – Jacobm001
    Commented May 20, 2015 at 18:54
3
$\begingroup$

data returns:

{114.754, {tomatoe -> 1.72651*10^-8, lettuce -> 0.58548, 
           spinach -> 3.53893*10^-8, carrot -> 8.48321*10^-9, 
           sunflower -> 9.69807*10^-10, tofu -> 0.87822,
           chickpea -> 3.3596*10^-9, oil -> 4.43666*10^-10}}

Where 114.754 is the minimum total energy with the constraints you have given. And the values (quantities, I guess) of each individual food are listed as replacement rules.

In other words, Minimize returns the minimized value, as well as a list of rules to actually minimize whatever you were minimizing. Not a dataset or a function or anything like that. Just a list of rules.

You should note that data is not a function, but merely the output listed above.

In any case, you want the replacement rules without the total energy. The second (last) part of data. For example:

rules = Last[data];
tomatoe /. rules
(* 1.72651*10^-8 *)

cost[tomatoe, lettuce, spinach, carrot, sunflower, tofu, chickpea, oil] /. rules
(* 2.32728 *)

For bedtime reading:
1;

2.

$\endgroup$
8
  • 1
    $\begingroup$ They could probably do with some bedtime reading on LinearProgramming too. Their minimize takes around 6 seconds on my machine, the corresponding canonical matrix form LP problem should be practically instantaneous. $\endgroup$
    – Histograms
    Commented May 20, 2015 at 18:54
  • $\begingroup$ Yeah, but teaching math as well as mathematica is way too much work :) $\endgroup$
    – LLlAMnYP
    Commented May 20, 2015 at 18:55
  • $\begingroup$ Thank you for the bedtime reading, I will certainly go through it. $\endgroup$
    – Jacobm001
    Commented May 20, 2015 at 18:55
  • $\begingroup$ @Histograms: I'm sure I'll get there, my course just started LP, so this is my first introduction to it. $\endgroup$
    – Jacobm001
    Commented May 20, 2015 at 18:56
  • 1
    $\begingroup$ @Jacobm001 done the LP solution. Interestingly my solution gives an ever so slightly smaller value, but that may be because I simplified some minor constraints or everyone else's Minimize is bigger, who knows. $\endgroup$
    – Histograms
    Commented May 20, 2015 at 20:19
2
$\begingroup$

The LinearProgramming[...] solution. Recall the canonical minimization form for linear programming:

\begin{align} \mathrm{minimize}\ \mathbf{c}^\mathrm{T}\mathbf{x} \ \mathrm{subj\ to:\\} \mathbf{Ax}\ge \mathbf{b} \mathrm{\ and \ } \mathbf{x\ge0} \end{align}

In the interest of keeping this answer simple and informative, we can throw out the nonlinear constraint on (lettuce + spinach)/(...rest...) >= 0.4 because it has a very small effect on the answer except to spread tiny quantities like 10^-8 around (this constraint is what made Minimize slow).

First we have to get the constraint matrix in its minimization form; whenever a $\le$ constraint appears we multiply the row and constraint by -1. In the case of the $2\le(\dots)\le8$ constraint we can ignore the 8 and just write this as $(\dots)\ge 2$ (we could add another constraint if we wanted but it makes little difference in this case). The matrix $\mathbf{A}$ (referred to as m in the LinearProgramming documentation), energy $\mathbf{c}$ and constraint vector $\mathbf{b}$ are now:

c = {21, 16, 40, 41, 585, 120, 164, 884}; (* energy objective*)
(* constraint matrix A, called m here*)
m = {{0.85, 1.62, 2.86, 0.93, 23.4, 16.0, 9.0, 0}, (*protein*)
     {0.33, 0.2, 0.39, 0.24, 48.7, 5, 2.6, 100}, (*fat*)
    -{9, 28, 65, 69, 3.8, 120, 78, 0}, (*sodium*)
     {4.64, 2.37, 3.63, 9.58, 15, 3, 27, 0}}; (*carbs*)
b = {15, 2, -200, 4}; (* constraint values *)
quantities = LinearProgramming[c, m, b];
bestEnergy = quantities.c;
Print["Cost: ", cost @@ quantities]
(* result 2.32155
  for quantities: 
  0.5747126436781611` lettuce
  0.8793103448275861` tofu *)

The result is lower by a tiny amount probably because we chucked out the nonlinear constraint.

$\endgroup$
1
  • 1
    $\begingroup$ LP was the first thing that came to mind, too. If the nonlinear constraint has to be enforced, the output of LinearProgramming[] could then be used in FindMinimum[] as a starting point, with the nonlinear constraint already included in the first argument. $\endgroup$ Commented May 20, 2015 at 23:14

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.