## 2 argument
function map!{F}(f::F, dest::AbstractArray, A::AbstractArray, B::
AbstractArray)
    for i = 1:length(A)
        dest[i] = f(A[i], B[i])
    end
    return dest
end

The above is the map!() implementation in abstractarray.jl. Should it 
return "dest" if it is an in-place function ? Is there any fundamental 
difference between my mape4a() and map!() in abstractarray.jl ?

Thanks,
Jan

Dňa piatok, 23. októbra 2015 9:30:36 UTC+2 Ján Dolinský napísal(-a):
>
> Hi Glen,
>
> Thanks for the investigation. I am afraid the for loop in map!() is not 
> the source of the issue. Consider the folowing:
>
> _f(a,f) = (a - f) / a
>
> function mape4(A, F)
> # A - actual target values
> # F - forecasts (model estimations)
>
>   tmp = similar(A)
>   map!(_f, tmp, A, F)
>   100 * sumabs(tmp) / length(A)
>
> end
>
> function mape4a(A, F)
>
>     tmp = similar(A)
>     for i in eachindex(A)
>         tmp[i] = _f(A[i], F[i])
>     end
>     100 * sumabs(tmp) / length(A)
> end
>
> @time mape4(A,F)
>   0.452273 seconds (20.00 M allocations: 343.323 MB, 9.80% gc time)
> 832.852597807525
>
> @time mape4a(A,F)
>   0.040240 seconds (7 allocations: 38.147 MB, 1.93% gc time)
> 832.852597807525
>
> The for loop in mape4a() does not do 4 * 5 milion allocations, neither 
> should do the loop in map!(). Is this possibly a bug ?
>
> Thanks,
> Jan
>
> Dňa štvrtok, 22. októbra 2015 19:43:31 UTC+2 Glen O napísal(-a):
>>
>> I'm uncertain, but I think I may have figured out what's going on.
>>
>> The hint lies in the number of allocations - map! has 20 million 
>> allocations, while broadcast! has just 5. So I had a look at how the two 
>> functions are implemented.
>>
>> map! is implemented in perhaps the simplest way you can think of - for 
>> i=1:length(A) dest[i]=f(A[i],B[i]); end - which means that it has to store 
>> four values per iteration - i, A[i], B[i], and f(A[i],B[i]). Thus, 4 times 
>> 5 million allocations.
>>
>> broadcast! is using a cache to store values, instead, and I believe it's 
>> generating instructions using a macro instead of a regular loop, thus 
>> avoiding the assignments for i. As such, it doesn't need to store anything 
>> except for the initial caches, and after that it just overwrites the 
>> existing values. Unfortunately, that's as much as I can figure out from 
>> broadcast!, because it uses a lot of macros and a lot of relatively opaque 
>> structure.
>>
>> I'm also not entirely sure how it avoids the assignments necessary in the 
>> function call.
>>
>> On Friday, 23 October 2015 01:54:14 UTC+10, Ján Dolinský wrote:
>>>
>>> Hi,
>>>
>>> I am exploring Julia's map() and broadcast() functions. I did a simple 
>>> implementation of MAPE (mean absolute percentage error) using broadcast() 
>>> and map(). Interestingly, the difference in performance was huge.
>>>
>>> A = rand(5_000_000)
>>> F = rand(5_000_000)
>>>
>>> _f(a,f) = (a - f) / a
>>>
>>> function mape3(A, F)
>>> # A - actual target values
>>> # F - forecasts (model estimations)
>>>
>>>   tmp = similar(A)
>>>   broadcast!(_f, tmp, A, F)
>>>   100 * sumabs(tmp) / length(A)
>>>
>>> end
>>>
>>> function mape4(A, F)
>>> # A - actual target values
>>> # F - forecasts (model estimations)
>>>
>>>   tmp = similar(A)
>>>   map!(_f, tmp, A, F)
>>>   100 * sumabs(tmp) / length(A)
>>>
>>> end
>>>
>>> @time mape3(A,F) # after JIT warm-up
>>>   0.038686 seconds (8 allocations: 38.147 MB, 2.25% gc time)
>>> 876.4813057521973
>>>
>>> @time mape4(A,F) # after JIT warm-up
>>>   0.457771 seconds (20.00 M allocations: 343.323 MB, 11.29% gc time)
>>> 876.4813057521973
>>>
>>> I wonder why map() is so much slower ?
>>>
>>> Thanks,
>>> Jan
>>>
>>

Reply via email to