Yes, that is pretty much how I would do it, although, as I said in my previous post, I would set `UtilityFunction` to an abstract type, and then define my actual utility function immutable, say `MyCustomUtilityFunc`, as a subtype of `UtilityFunction`. That way you can easily add different types of utility functions later without having to change your existing code. By the way, just for the record, a fair test between the two approaches would be as follows:
abstract UtilityFunction immutable MyCustomUtilityFunction <: UtilityFunction sigmac::Float64 sigmal::Float64 psi::Float64 end u4(sigmac, sigmal, psi, consump,labor) = consump.^(1-sigmac)/(1-sigmac) + psi*(1-labor).^(1-sigmal)/(1-sigmal) u(UF::MyCustomUtilityFunctionconsump,labor) = consump.^(1-UF.sigmac)/(1-UF.sigmac) + UF.psi*(1-labor).^(1-UF.sigmal)/(1-UF.sigmal) function test1(sigmac, sigmal, psi) for i = 1:1000000 u4(sigmac, sigmal, psi, 1.0 + 1/i, 0.5) end end function test2(UF::UtilityFunction) for i = 1:1000000 u(UF, 1.0 + 1/i , 0.5) end end UF = MyCustomUtilityFunction(4,2,1) test1(4.0, 2.0, 1.0) test2(UF) On my machine that returns: elapsed time: 0.090409383 seconds (80 bytes allocated) elapsed time: 0.091065473 seconds (80 bytes allocated) ie, no significant performance difference On 24 June 2015 at 00:56, Andrew <owen...@gmail.com> wrote: > Thanks, this is all very useful. I think I am going to back away from > using the @anon functions at the moment, so I'll postpone my idea to > encapsulate the functions into a type. Instead, I will just pass a > parameter type to an externally defined(not nested) function. I had thought > this would be slow (see my question here > https://groups.google.com/forum/#!topic/julia-users/6U-otLSx7B0 ), but I > did a little testing. > > immutable UtilityFunction > sigmac::Float64 > sigmal::Float64 > psi::Float64 > end > function u(UF::UtilityFunction,consump,labor) > sigmac = UF.sigmac > sigmal = UF.sigmal > psi = UF.psi > consump.^(1-sigmac)/(1-sigmac) + psi*(1-labor).^(1-sigmal)/(1-sigmal) > end > function u4(consump,labor) > consump.^(1-4)/(1-4) + 1*(1-labor).^(1-2)/(1-2) > end > > function test1(UF) > for i = 1:1000000 > u4(1. + 1/i, .5) > end > end > function test2(UF) > for i = 1:1000000 > u(UF,1. + 1/i ,.5) > end > end > UF = UtilityFunction(4,2,1) > > @time test1(UF) > @time test2(UF) > > elapsed time: 0.068562617 seconds (80 bytes allocated) > elapsed time: 0.139422608 seconds (80 bytes allocated) > > > So, even versus the extreme case where I built the constants into the > function, the slowdown is not huge. I asume @anon would have similar > performance to the constants built in case, which is nice. However, I want > to be able to share my Julia code with others who aren't very experienced > with the language, so I'd be uncomfortable asking them to understand the > workings of FastAnonymous. It's useful to know about in case I need the > speedup in my own personal code though. > > > On Tuesday, June 23, 2015 at 8:51:25 AM UTC-4, colint...@gmail.com wrote: >> >> Yes, this proves to be an issue for me sometimes too. I asked a >> StackOverflow question on this topic a few months ago and got a very >> interesting response, as well as some interesting links. See here: >> >> >> http://stackoverflow.com/questions/28356437/julia-compiler-does-not-appear-to-optimize-when-a-function-is-passed-a-function >> >> As a general rule, if the function you are passing round is very simple >> and gets called a lot, then you will really notice the performance >> overhead. In other cases where the function is more complicated, or is not >> called that often, the overhead will be barely measurable. >> >> If the number of functions that you want to pass around is not that >> large, one way around this is to use types and multiple dispatch instead of >> functions, eg >> >> abstract UtilityFunctions >> type QuadraticUtility <: UtilityFunctions >> a::Float64 >> b::Float64 >> c::Float64 >> end >> evaluate(x::Number, f::QuadraticUtility) = f.a*x^2 + f.b*x + f.c >> >> Now your function would be something like: >> >> function solveModel(f::UtilityFunctions, ...) >> >> and you would call evaluate at the appropriate place in the function body >> and multiple dispatch will take care of the rest. There is no performance >> overhead with this approach. >> >> Of course, if you want to be able to just pass in any arbitrary function >> that a user might think up, then this approach is not tenable. >> >> On Tuesday, 23 June 2015 01:07:25 UTC+10, Andrew wrote: >>> >>> >>> >>> I'm trying to write some abstract Julia code to solve a variety of >>> economics models. Julia provides powerful abstraction tools which I think >>> makes it very well-suited to this; however, I've read in several places >>> that Julia doesn't yet know how to inline functions passed as arguments, >>> hence code like >>> >>> function SolveModel(Utility::Function, ProductionTechnology::Function >>> ,...) >>> ... >>> >>> will be slow. I performed this very simple test. >>> >>> function ftest1() >>> u(x) = log(x) >>> function hello(fun::Function) >>> for i = 1:1000000 >>> fun(i.^(1/2)) >>> end >>> end >>> end >>> >>> function ftest2() >>> function hello() >>> for i = 1:1000000 >>> log(i.^(1/2)) >>> end >>> end >>> end >>> >>> @time ftest1() >>> @time ftest2() >>> >>> elapsed time: 6.065e-6 seconds (496 bytes allocated) >>> elapsed time: 3.784e-6 seconds (264 bytes allocated) >>> >>> >>> The inlined version is about twice as fast, which isn't all that bad, >>> although I'm not sure if it would be worse in a more complicated example. >>> Perhaps I shouldn't worry about this, and should code how I want. I was >>> wondering though, if anybody knows when this is going to change. I've read >>> about functors, which I don't really understand, but it sounds like people >>> are working on this problem. >>> >>