3
$\begingroup$

I'm using NMinimize with Mathematica 7 using an external Fortran program to get the target value to minimize. I'm doing it using RunThrough with the variables as arguments in the command line.

This works, but I have to run the program for every possible candidate of NMinimize and is very slow (the program takes time to run and initialize).

I have made an interactive version of the program that will read the candidates from the standard input and write the resulting value to the standard output, but I cannot make it work in Mathematica. It seems that streams can be Input or Output only, so I cannot read and write to the stream at the same time, or get two different streams from a external execution command.

Documentation suggest using files for exchange but I'm not sure how to do that, not only in Mathematica but also in the Fortran code, to wait for a certain file to have new data instead of just returning EOF.

I've read the answer here: Is it possible to interact with an external program's command-line interface? but it doesn't address an interactive communication.

Any idea how to make Mathematica to open two In/Out streams to a external command?

$\endgroup$
  • 1
    $\begingroup$ Maybe take a look at 'StartProcess' (instead of RunProcess) which can be used to interact with processes while they are running or to run "background tasks" without blocking the Wolfram Engine. $\endgroup$ – SquareOne Feb 9 '15 at 16:29
  • $\begingroup$ @SquareOne, it looks very promising! But it is a new feature of Mathematica 10 and I'm using Mathematica 7 (I've updated the question with the version of Mathematica). $\endgroup$ – siritinga Feb 9 '15 at 16:33
  • $\begingroup$ a linux named pipe approach is given here: stackoverflow.com/a/6468874/1004168. For some reason mathematica throws a noopen error for me however. $\endgroup$ – george2079 Mar 11 '15 at 19:48
4
$\begingroup$

Update -- finally got version 10

StartProcess version:

the fortran:

  program ptest
  real*8 x
  do while(.true.)
     read(*,*)x
     write(*,*)x**2*cos(x)+1.d0
  enddo
  end

this is a simple endless loop, reading from stdin and writing to stdout.

now in mathemaitca:

 pr = StartProcess["ptest"];
 f[x_?NumericQ] := (Write[pr, FortranForm[x]]; Read[pr, Number])
 NMinimize[f[x], x] // AbsoluteTiming
 KillProcess[pr]; (* dont forget to kill it.. remember the endless loop*)

{0.101721, {-10.6378, {x -> -3.6436}}}

Notice this is now comparable to native mathematica code (within a factor of 2 ).. nice!

---original RunThrough new-process-per-call version---

You can use RunThrough to pipe through stdin | fortran | stdout:

here has a minimal fortran example:

       real*8 x
       read(*,*)x
       write(*,*)x**2*cos(x)+1
       end

in mathematica:

      f[v_?NumericQ]:=RunThrough["path/file" , FortranForm[v] ]

      NMinimize[f[x],x]  //AbsoluteTiming

{17.993699, {-10.6378, {x -> -3.6436}}}

There are two essentials here.

  • ?NumericQ is required else we pass a symbolic string "x" to fortran on the first pass
  • FortranForm ( or equivalently CForm ) is needed so any numbers in scientific notation are properly formatted.

native mathematica is a "tad" faster by the way:

      NMinimize[ x^2 Cos[x] + 1  , x] // AbsoluteTiming

{0.062400, {-10.6378, {x -> -3.6436}}}

of course thats not a reflection on the performance of fortran, its slow due to all the overhead of starting up the executable for each eval.

RunThrough seem to need a full path by the way.

$\endgroup$
  • $\begingroup$ Thank you for your answer @george2079 , but that is exactly what I'm doing already :) (second line of my question) but using arguments instead of stdin. $\endgroup$ – siritinga Mar 11 '15 at 19:19
  • $\begingroup$ I think StartProcess is what you need. ( I don't have v10 either to try it ..). $\endgroup$ – george2079 Mar 11 '15 at 19:34
1
$\begingroup$

To call an external command with input parameters like *argv[] in C (I don't know how is it called in Fortran) you can use this Mathematica routine:

    RunProcess[{$SystemShell, "-c", ExecutableFileName <> " " <> arg1 <> " " <> arg2 <> " " <> arg3}, "StandardOutput"]

This will also give back output as a result of the routine. Then you can use this trick inside of the definition of your model function to get a value for some specific parameters of this function that you want to minimise. Then you can use NMinimize[] to find the minimum of this model function and the best values for parameters <=> the value of parameters at position of the minimum.

$\endgroup$
  • $\begingroup$ Thank you for your answer. That is what I'm currently doing. It works, but it is slow to run the program for every candidate that NMinimize wants to try, so was asking how I can interact with the program using standard input and standard output, like a user typing at the keyboard. I can run a program and read from it (as you did or using OpenRead) or I can run a program and write to it (using OpenWrite). But I cannot do both. $\endgroup$ – siritinga Feb 9 '15 at 14:42
  • $\begingroup$ NMinimize needs a lot of candidates to do the job, there is no shortcut, except setting precision of the result. If your function has nice analytic shape, you may also consider using some fitting procedure to fit to that shape. Otherwise NMinimize has to search manually for the minimum, but you can also change the method of the search. Could you be more specific on the problem considering OpenWrite and OpenRead? $\endgroup$ – Vladimir Feb 9 '15 at 14:48
  • 1
    $\begingroup$ I'm not trying to reduce the number of candidates. I'm trying to test each candidate faster. For that, the external program can be run interactively: you type a candidate and the program returns the target function value at that point. I'm trying to get Mathematica talk to the program in this way, instead of running a new execution everytime. I can use OpenRead["!myprogram"] to get an InputStream, or use OpenWrite["!myprogram"] to get an OutputStream, but not both over the same program, to capture standard input and standard output. $\endgroup$ – siritinga Feb 9 '15 at 14:52

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.