I'm not quite sure what you mean. It looks like I could sort of replicate my approach using @anon by just defining an @anon function right below my initial function definition. Then I can use the @anon version elsewhere. For example, function FOC(x,w) return x*w end p_FOC = @anon x -> FOC(x,w) # maybe I should say const p_FOC for performance of global variables?
But this doesn't work because I haven't defined w anywhere. It would work if I set a dummy value for w, like w = 5., but that looks sort of odd. It would basically come down to what I'm doing above anyway. Is that what you meant? On Monday, July 20, 2015 at 10:01:12 PM UTC-4, Tim Holy wrote: > > @anon is supposed to work this way for you under the hood; it's a bit of a > puzzle if it doesn't. Can you file an issue, with test case, with > FastAnonymous? > > --Tim > > On Monday, July 20, 2015 06:14:24 PM Andrew wrote: > > Update: I've found a significantly cleaner way to do this which avoids > > FastAnonymous entirely and runs faster for me. Now in 0.4 arbitrary > objects > > can be overloaded to use the f() syntax using Base.call. I create an > > accessory type for each function that I want to pass to a non-linear > solver > > or optimization routine. This accessory type encapsulates the parameters > of > > the function, Then I define a new method for Base.call which acts like a > > single-variable function, and simply redirects the parameters stored in > my > > type into the function. It looks like this > > > > function > > hoursFOC(UF::UtilityFunction,hours,state::State{IdioState1,AggState1}, > > aprime) > > w = state.as.w > > consump = budget_consump_givenhours(state, aprime, hours) > > w*uc(UF,consump,hours) - ul(UF,consump,hours) # Is w*uc = ul > > end > > > > immutable pars_hoursFOC{TUF <: UtilityFunction, TIS<:IdioState, > > TAS<:AggState} > > UF::TUF > > state::State{TIS,TAS} > > aprime::Float64 > > end > > Base.call(f::pars_hoursFOC, h) = hoursFOC(f.UF, h, f.state, f.aprime) > > > > When I need the nonlinear equation solver, I do > > > > f = pars_hoursFOC(UF,state,aprime) > > j = pars_JACOBhoursFOC(UF, state, aprime) # jacobian, same idea > > hours = myNewton(f, j, hoursguess) > > > > f and j are treated like functions, so this works as expected. > > > > This is much cleaner than my previous method where I was using @anon to > > store an anonymous function, then passing that function around > everywhere. > > Also it's faster for some reason. My new code runs in 14s, the version > > using @anon was about 20s, and a version with nested functions(or > regular > > anonymous functions) would be >30s. > > > > I see mentioned in #8712 <https://github.com/JuliaLang/julia/pull/8712> > that > > there may be a Callable type. That would be useful, since currently > these > > callable types don't work with the Optim functions or anything else that > > asks for a ::Function argument. > > > > On Thursday, July 16, 2015 at 9:20:51 PM UTC-4, Andrew wrote: > > > fzero(f, j, guess) works for me when f and j are functions. f(Af, > guess) > > > works for me now when Af is an @anon function. > > > > > > On Tuesday, July 7, 2015 at 7:34:39 PM UTC-4, j verzani wrote: > > >> Okay, this just got fixed as much as I could with v"0.1.15" (there is > no > > >> fzero(f,j,guess) signature). > > >> > > >> On Tuesday, July 7, 2015 at 4:38:41 PM UTC-4, Andrew wrote: > > >>> Just checked. So, Roots.fzero(f, guess) does work. However, > > >>> Roots.fzero(f, j, guess) doesn't work, and neither does > Roots.newton(f, > > >>> j, > > >>> guess). > > >>> > > >>> I looked at the Roots.jl source and I see ::Function annotations on > the > > >>> methods with the jacobian, but not the regular one. > > >>> > > >>> On Tuesday, July 7, 2015 at 4:22:17 PM UTC-4, j verzani wrote: > > >>>> 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. > >