It isn't your first choice, but `Roots.fzero` can have `@anon` functions 
passed to it, unless I forgot to tag a new version after making that change 
on master not so long ago.

On Tuesday, July 7, 2015 at 2:29:51 PM UTC-4, Andrew wrote:
>
> I'm writing this in case other people are trying to do the same thing I've 
> done, and also to see if anyone has any suggestions.
>
> Recently I have been writing some code that requires solving lots(tens of 
> thousands) of simple non-linear equations. The application is economics, I 
> am solving an intratemporal first order condition for optimal labor supply 
> given the state and a savings decision. This requires solving the same 
> equation many times, but with different parameters.
>
> As far as I know, the standard ways to do this are to either define a 
> nested function which by the lexical scoping rules inherits the parameters 
> of the outer function, or use an anonymous function. Both these methods are 
> slow right now because Julia can't inline those functions. However, the 
> FastAnonymous package lets you define an anonymous "function", which 
> behaves exactly like a function but isn't type ::Function, which is fast. 
> Crucially for me, in Julia 0.4 you can modify the parameters of the 
> function you get out of FastAnonymous. I rewrote some code I had which 
> depended on solving a lot of non-linear equations, and it's now 3 times as 
> fast, running in 2s instead of 6s.
>
> Here I'll describe a simplified version of my setup and point out a few 
> issues.
>
> 1. I store the anonymous function in a type that I will pass along to the 
> function which needs to solve the nonlinear equation. I use a parametric 
> type here since the type of an anonymous function seems to vary with every 
> instance. For example, 
>
> typeof(UF.fhoursFOC)
> FastAnonymous.##Closure#11431{Ptr{Void} 
> @0x00007f2c2eb26e30,0x10e636ff02d85766,(:h,)}
>
>
> To construct the type,
>
> immutable CRRA_labor{T1, T2} <: LaborChoice # <: means "subtype of"
>     sigmac::Float64
>     sigmal::Float64
>     psi::Float64
>     hoursmax::Float64
>     state::State # Encodes info on how to solve itself
>     fhoursFOC::T1
>     fJACOBhoursFOC::T2
> end
>
> To set up the anonymous functions fhoursFOC and fJACOBhoursFOC (the 
> jacobian), I define a constructor 
>
> function CRRA_labor(sigmac,sigmal,psi,hoursmax,state)
>     fhoursFOC = @anon h -> hoursFOC(CRRA_labor(sigmac,sigmal,psi,hoursmax,
> state,0., 0.) , h, state)
>     fJACOBhoursFOC = @anon jh -> JACOBhoursFOC(CRRA_labor(sigmac,sigmal,
> psi,hoursmax,state,0., 0.) , jh, state)
>     CRRA_labor(sigmac,sigmal,psi,hoursmax,state,fhoursFOC, fJACOBhoursFOC)
> end
>
> This looks a bit complicated because the nonlinear equation I need to 
> solve, hoursFOC, relies on the type CRRA_labor, as well as some aggregate 
> and idiosyncratic state info, to set up the problem. To encode this 
> information, I define a dummy instance of CRRA_labor, where I supply 0's in 
> place of the anonymous functions. I tried to make a self-referential type 
> here as described in the documentation, but I couldn't get it to work, so I 
> went with the dummy instance instead.
>
> @anon sets up the anonymous function. This means that code like 
> fhoursFOC(0.5) will return a value.
>
> 2. Now that I have my anonymous function taking only 1 variable, I can use 
> the nonlinear equation solver. Unfortunately, the existing nonlinear 
> equation solvers like Roots.fzero and NLsolve ask the argument to be of 
> type ::Function. Since anonymous functions work like functions but are 
> actually some different type, they wouldn't accept my argument. Instead, I 
> wrote my own Newton method, which is like 5 lines of code, where I don't 
> restrict the argument type.
>
> I think it would be very straightforward to make this a multivariate 
> Newton method.
>
> function myNewton(f, j, x)
>     for n = 1:100
>         fx , jx = f(x), j(x)
>         abs(fx) < 1e-6 && return x
>         d = fx/jx
>         x = x - d
>     end
>     println("Too many iterations")
>     return NaN
> end
>
> 3. The useful thing here in 0.4 is that you can edit the parameters of the 
> anonymous function. The parameters are encoded in a custom type 
> state::State, and I update the state. Then I call my nonlinear equation 
> solver
>
>         UF.fhoursFOC.state, UF.fJACOBhoursFOC.state = state, state
>         f = UF.fhoursFOC
>         j = UF.fJACOBhoursFOC
>         hours = myNewton(f, j, hoursguess)
>
> This runs much faster than my old version which used NLsolve, which itself 
> ran faster than a version using Roots.fzero.
>
> Issues:
>
> 1. Since the type of the anonymous function isn't ::Function, I had to 
> write my own solver. I'm pretty sure a 1-line edit to Roots.fzero where I 
> just remove the ::Function type annotation would let it work there, but I'm 
> not aware of another workaround.
>
> 2. I would rather use NLsolve, which uses in-place updating of its 
> arguments ( f!(input::Array, output::Array) ), but I've tried constructing 
> an anonymous function that does that, and @anon didn't work. Perhaps there 
> is a workaround.
>
> 3. Since I'm using an anonymous function, I have to explicitly pass it 
> around. Encoding it into the type CRRA_labor wasn't really hard though.
>
>
>
>
>
>
>

Reply via email to