5
$\begingroup$

Say I have a function FUN defined in Mathemtica notebook:

FUN[{s1_, s2_, s3_, p_}] := 
 Block[{S, V, eigS, eigV, dev1, dev2, dev3, dev4, fun},
  S = {{s1, s2*Cos[p]}, {s2*Sin[p], s3}};
  V = {{s2, s1*Sin[p]}, {s1*Cos[p], s3}};
  eigS = Sqrt@Eigenvalues[S.ConjugateTranspose[S]];
  eigV = Sqrt@Eigenvalues[V.ConjugateTranspose[V]];
  dev1 = (eigS[[1]] - 1.2)/0.1; dev2 = (eigS[[2]] - 2.2)/0.15;
  dev3 = (eigV[[1]] - 0.3)/0.08; dev4 = (eigV[[2]] - 1.9)/0.2;
  fun = dev1^2 + dev2^2 + dev3^2 + dev4^2;
  Return[fun];]

Now, I want to minimize this function FUN using python optimizer (scipy in particular). Question is, how within python IDLE, I import this Mathematica function FUN, and feed it to scipy optimizer to minimize it? I am familiar with how to minimize a function defined in python to be minimized using scipy.optimize solvers.

Please note that the example I am giving here is a trivial function and can be easily minimized within Mathemtica itself. But for practical purpose, I am interested in very complicated function (and I am interested in minimizing using scipy solvers). For several practical reasons, the functions I am interested in are coded within Mathemtica (meaning, rewriting these functions in python is not the option I am interested in).

I appreciate your valuable comments. Thank you in advance.

$\endgroup$
5
  • 1
    $\begingroup$ "For several practical reasons" you prefer not to rewrite these functions in python. Hmm... But you have to consider that mixed approaches require more work in the long run. The function that you provide as an illustration is as easy to implement in python. And reverse is also true, one can do optimization and root finding in MA as well. $\endgroup$
    – yarchik
    Mar 4 at 10:45
  • 1
    $\begingroup$ Hi yarchik, yes. I did not want to specify why I want the function to be defined in Mathematica. The reason is, the functions that I am defining are very complicated and use a few external packages, all written in Mathematica language. So I call several pre-defined functions from several external Mathematica packages. $\endgroup$
    – string
    Mar 4 at 10:52
  • 1
    $\begingroup$ Hi yarchik, the reply to your second part of the query is: yes, I only want to minimize in python. The reason is, my actual functions are so complicated that within Mathemtica, using built-in functions, such as NMinimize / FindRoot fail badly. This is not a new experience for me. This is why I typically run all minimization in python. Unfortunately, now I have a function that must be coded in Mathematica (reason as stated in my last reply). $\endgroup$
    – string
    Mar 4 at 10:56
  • $\begingroup$ Could you use Mathematica C code generator and build a wrapper with python, then optimize the wrapper which calls the C code? $\endgroup$
    – Ben Izd
    Mar 4 at 18:26
  • $\begingroup$ Hi Beny, I haven't used CCodeGenerator before. My understanding is, it will convert the existing code to be used. From Wolfram page I see their examples with simple functions. I cannot say whether this can be done for my original function, which is in fact not just a single function (as mentioned above, it calls several more function from several other external Mathematica packages). But I will explore the possibility, as you mentioned. $\endgroup$
    – string
    Mar 5 at 21:07
3
$\begingroup$

The Wolfram Client For Python allows Mathematica code to be called from Python. Following the strategy explained here start by creating a Mathematica Package (.m file) with the function of interest:

BeginPackage["targetFunctions`"]
FUN::usage = "FUN[{s1,s2,s3,p}]";
Begin["Private`"]
FUN[{s1_, s2_, s3_, p_}] := 
 Block[{S, V, eigS, eigV, dev1, dev2, dev3, dev4, fun}, 
  S = {{s1, s2*Cos[p]}, {s2*Sin[p], s3}};
  V = {{s2, s1*Sin[p]}, {s1*Cos[p], s3}};
  eigS = Sqrt@Eigenvalues[S.ConjugateTranspose[S]];
  eigV = Sqrt@Eigenvalues[V.ConjugateTranspose[V]];
  dev1 = (eigS[[1]] - 1.2)/0.1; dev2 = (eigS[[2]] - 2.2)/0.15;
  dev3 = (eigV[[1]] - 0.3)/0.08; dev4 = (eigV[[2]] - 1.9)/0.2;
  fun = dev1^2 + dev2^2 + dev3^2 + dev4^2;
  Return[fun]]
End[]
EndPackage[]

You can then define a target function in Python in the following way

from wolframclient.evaluation import WolframLanguageSession
from wolframclient.language import wl
    
wolfSession = WolframLanguageSession()
wolfSession.evaluate(wl.Needs("targetFunctions`"))
    
def target(x):
    return wolfSession.evaluate(wl.targetFunctions.FUN((x[0],x[1],x[2],x[3])))

scipy.optimize may be employed in a straightforward way, for example:

from scipy.optimize import minimize
import numpy as np
x0 = np.array([0,0,0,0])
res = minimize(target, x0)
print(res.x)

Finally, terminate the Wolfram session

wolfSession.terminate()
$\endgroup$
2
  • $\begingroup$ Thank you! This is very nice. Though I am a little confused. For this particular example, Mathematica finds much better minimum than Python, which is highly surprising. Do you have any idea why this strange behavior? $\endgroup$
    – string
    Apr 11 at 19:30
  • $\begingroup$ @string, I didn't examine the target function. In which sense is a minimum computed within Mathematica better than one calculated with the Mathematica-Python strategy presented above? $\endgroup$ Apr 14 at 5:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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