My goal is to minimize a real valued multi-variable function averageFreeEnergyDensity
. The function accepts an integer argument n
, a set of real parameters j,d,a,h,dx
and two real matrices th,ph
. I want to find matrices th,ph
which minimize the function. FindMinimum
minimizes the function well enough but it is too slow at the moment. I am trying to compile the function to accelerate FindMinimum
. If I compile the function for arbitrary n
it is at least an order of magnitude more slow than if I make a set of functions each of which is defined for a particular n
. My current fastest solution is
averageFreeEnergyDensityCompiled["square",n_]:=
averageFreeEnergyDensityCompiled["square", n]=
Compile[{{j, _Real}, {d, _Real}, {a, _Real}, {h, _Real}, {dx,
_Real}, {th, _Real, 2}, {ph, _Real, 2}}, Evaluate[
(*apply boundary conditions*)
s[i1_, i2_] := Which[
i1 == n + 1 && i2 == n + 1, s[1, 1],
i1 == n + 1, s[1, i2],
i2 == n + 1, s[i1, 1],
True, {Cos[ph[[i1, i2]]] Sin[th[[i1, i2]]],
Sin[ph[[i1, i2]]] Sin[th[[i1, i2]]], Cos[th[[i1, i2]]]}
];
(*define finite difference functions*)
dsdx[i1_, i2_] := (s[i1 + 1, i2] - s[i1, i2])/dx;
dsdy[i1_, i2_] := (s[i1, i2 + 1] - s[i1, i2])/dx;
(*return average free energy density function*)
Sum[j (dsdx[i1, i2].dsdx[i1, i2] + dsdy[i1, i2].dsdy[i1, i2]) +
a s[i1, i2][[3]]^2 - h s[i1, i2][[3]], {i1, 1, n}, {i2, 1, n}]/
n^2
]]
I need to delay evaluation because the expression being compiled can only be evaluated for particular n
. I store the function because I will evaluate it for many values of j,d,a,h,dx
. This solution is fast but it throws an error the first time the function is evaluated
Block[{n = 100},
AbsoluteTiming[
averageFreeEnergyDensityCompiled["square", n][1, 1, 1, 0, 0.1,
Array[0 &, {n, n}], RandomReal[2 Pi, {n, n}]]]]
Part::partd: Part specification ph$[[2,1]] is longer than depth of object. >>
Part::partd: Part specification th$[[2,1]] is longer than depth of object. >>
Part::partd: Part specification ph$[[2,1]] is longer than depth of object. >>
General::stop: Further output of Part::partd will be suppressed during this calculation. >>
After several attempts to evaluate the Part
function Mathematica gives up and evaluates the expression ignoring Part
. The final expression can then be compiled. I want to manually tell Mathematica to ignore Part
. I have tried using Inactive,Activate
but this slows down the final compiled function by orders of magnitude. I would ideally give an option to Evaluate
like Evaluate["insert expression here",Holding->Part]
but Evaluate
has no options that I know of.
Note: The boundary condition I have used here is simple and can be taken out of compile, but I will be using more complicated boundary conditions once I solve this problem. I do not need to use finite difference steps of order greater than 1. I will also be using this code on a triangular grid which will further change the finite difference.