yosimitsu kodanuri
yosimitsu kodanuri

Reputation: 177

Applying a list of functions on a list of argument lists

I have a list of anonymous functions that I need to map over a list of argument lists. My desire is to obtain a list containing lists whose elements are the functions in the functions list, evaluated at each argument list.

My first thought was to map the functions list over the argument lists and then apply the functions in the functions list on each element in the arguments list.

;; definitions for k functions
let fj [ [x1 x2 ... xn ] -> <body j> ]
...

let args [ [ ... ] [ ... ] ... [ ... ] ] ;; list of arguments

let f-list ( list f1 f2 ... fk )

map [ [ arg ] -> map [ [ f ] -> ( runresult f arg ) f-list ] ]  args

There is one two problem with this code:

  1. Mapping the f-list on list arg does not behave the way I expected it to behave. Namely, running the code produces run-time errors because the functions in f-list are not defined over a list but are instead defined over a number of arguments.

In order to overcome this latter difficulty, I have redefined the functions in f-list so as to receive a list as an argument and use item in the body of the functions in order to retrieve individual parameters.

This solution, apart from the fact that, it too, feels like a hack, it is also highly impractical because it increases the code needed to obtain a given result, in a way that is highly error prone, not to mention extremely tedious ( consider having to redefine a modest number of functions with a moderate number of arguments ).

In Mathematica it is possible to transform a list of arguments to a function into a sequence ( or tuple ) of arguments by using Apply as in Apply[f, args] where args is a list of argument values.

This facilitates the application of functions on lists of argument ( lists ). Practically, one can write f @@@ { args1, args2, ..., argsm } and obtain a list { f[x11, x12, ..., x1n], f[x21, x22, ..., x2n], ..., f[xm1, xm2, ..., xmn] } ( where @@@ is just the infix notation that corresponds to Apply[f, args, 1] ).

I guess what I'm looking for is how to achieve the same result in native NetLogo code without having to resort to hacks like the one reported in the former part of this question.

some actual code

globals [ f-list args ]

to setup

  let f1 [ [ arg ] -> ( ( item 0 arg ) - 5 ) ^ 2 + ( ( item 1 arg ) - 5 ) ^ 2 + 0 * ( ( item 2 arg ) - 5 ) ^ 2 ]

  let f2 [ [ arg ] -> 4 * ( item 1 arg ) ^ 2 + 4 * ( item 0 arg ) ^ 2 + 0 * ( item 2 arg ) ^ 2 ]

  let f3 [ [ arg ] -> 2 + ( ( item 1 arg ) - 2 ) ^ 2 + ( ( item 2 arg ) - 1 ) ^ 2 + 0 * ( item 0 arg ) ]

  let f4 [ [ arg ] -> 9 * ( item 0 arg ) - ( ( item 2 arg ) - 1 ) ^ 2 + 0 * ( item 1 arg ) ]


  set f-list ( list f1 f2 f3 f4 )


  set args [ [ 2.04 3.09 -1.32 ] [ 5.57 -3.9 4.0 ] [ -1.1 -0.432 8.0 ] [ 1.32 -2.3 -9.103 ] ]


  show map [ [ arg ] -> ( map [ [ f ] -> ( runresult f arg ) ] f-list ) ] args

end

using a setup button that calls the procedure above produces the following output:

observer: [[12.4097 54.8388 8.570500000000001 12.977599999999999] [79.53490000000001 184.9396 45.81 41.13] [66.716624 5.586496 56.914624 -58.9] [66.83239999999999 28.129599999999996 122.56060899999999 -90.190609]]

Upvotes: 1

Views: 127

Answers (1)

Nicolas Payette
Nicolas Payette

Reputation: 14972

Thanks to Bryan Head, NetLogo now offers this functionality via the (experimental and undocumented) __apply and __apply-result primitives.

In your case, __apply-result is the one you need:

globals [ f-list args ]

to setup

  let f1 [ [x y z] -> (x - 5) ^ 2 + (y - 5) ^ 2 + 0 * (z - 5) ^ 2 ]
  let f2 [ [x y z] -> 4 * y ^ 2 + 4 * x ^ 2 + 0 * z ^ 2 ]
  let f3 [ [x y z] -> 2 + (y - 2) ^ 2 + (x - 1) ^ 2 + 0 * x ]
  let f4 [ [x y z] -> 9 * x - (z - 1) ^ 2 + 0 * y ]

  set f-list (list f1 f2 f3 f4)
  set args [[2.04 3.09 -1.32] [5.57 -3.9 4.0] [-1.1 -0.432 8.0] [1.32 -2.3 -9.103]]

  print map [ arg -> map [ f -> __apply-result f arg ] f-list ] args

end

As you can see, __apply-result takes two arguments, an anonymous reporter and a list, and automatically passes the items in the list as arguments to the anonymous reporter. The __apply primitive is similar, but takes an anonymous command instead of an anonymous reporter.

Upvotes: 2

Related Questions