3

I am trying to create a function that returns Arnold's Cat Map of size n iterated k times. I can get something out of the Function command, but I can't figure out how to use that output as a function.

The non-iterated version of the problem is trivial. I define my mapping function:

G[x_, y_, n_] := Mod[{{2, 1}, {1, 1}}.{x, y}, n];

I want it to work with ImageTransformation, so I define an appropriate function for that:

CatMapStep[{x_, y_}] := G[x, y, side];

where side is calculated somewhere earlier. Now I can call ImageTransformation (let's say I have an image kitty):

ImageTransformation[kitty, CatMapStep]

Done. But what do I do if you want to iterate CatMap k times? Well, I can hard-code k:

CatMapFiveTimes[u_] := Nest[CatMapStep[u], u, 5];

And I discovered the `Function' command, but I can't figure out how to use it. What I would really like to do is create a function that takes k as an argument, and returns a function of u. Such is the sentiment of the following incorrect snippet:

IteratedCatMap[k_] := Function[u, Nest[CatMapStep[u], u, k];   <--- DOESN'T WORK

In my fantasy world, I would then be able to define CatMapFiveTimes by invoking the following line:

CatMapFiveTimes[u_] = IteratedCatMap[5];     <--- HYPOTHETICAL

And then using it as I would the previous definition.

How can I create this function that returns a function?

Thanks, David

PS: Note that I am using Mathematica 8, although my officemate has Mathematica 9 and she couldn't get it, either.

PPS: I am completely open to a totally different approach to this problem. Ultimately, my only goal is to use Manipulate to let my students specify how many iterations of the cat map they want to see. I will be doing similar things for the Mandelbrot set, as well.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Define "doesn't work." What happens when you run it? The reason I ask is I've run your code, and I've seen what happens. But, you don't give enough info for the casual reader to know what the issue is. – rcollyer Aug 13 '13 at 01:49
  • Related or possible duplicate: (7999) – Mr.Wizard Aug 13 '13 at 17:29

2 Answers2

6

Perhaps just a syntax problem:

side = 1;
kitty = ExampleData[{"TestImage", "Lena"}];
G[x_, y_, n_] := Mod[{{2, 1}, {1, 1}}.{x, y}, n];
CatMapStep[{x_, y_}] := G[x, y, side];
CatMapFiveTimes[u_] := Nest[CatMapStep, u, 5];
it5 = ImageTransformation[kitty, CatMapFiveTimes];

IteratedCatMap[k_] := Function[u, Nest[CatMapStep, u, k]];
itt5 = ImageTransformation[kitty, IteratedCatMap[5]];

GraphicsRow@{it5, itt5}

Mathematica graphics

Dr. belisarius
  • 115,881
  • 13
  • 203
  • 453
3

This question is related to and possibly a duplicate of: Define parameterized function

First there appears to be a mistake in your code; I believe you wanted:

CatMapFiveTimes[u_] := Nest[CatMapStep, u, 5]

To realize your IteratedCatMap we do not need to generate a function, merely to use a SubValues pattern definition (as discussed in the link above).

IteratedCatMap[n_][u_] := NestList[CatMapStep, u, n]

I have used NestList above in place of Nest simply to make the operation of the function visible.

With our supporting definitions in place:

G[x_, y_, n_] := Mod[{{2, 1}, {1, 1}}.{x, y}, n];
CatMapStep[{x_, y_}] := G[x, y, side];
side = Prime @ 50;

To use this you simply write:

IteratedCatMap[5][{62, 35}]
{{62, 35}, {159, 97}, {186, 27}, {170, 213}, {95, 154}, {115, 20}}  (* five + original *)

You can define your "function" like this:

CatMapThreeTimes = IteratedCatMap[3];

CatMapThreeTimes[{62, 35}]
{{62, 35}, {159, 97}, {186, 27}, {170, 213}} (* three + original *)

Note that the value of CatMapThreeTimes is not a function, it is simply a head waiting to be completed before the SubValues rule triggers.

You can use Function as also discussed in the linked question:

IteratedCatMapAlt[n_] := NestList[CatMapStep, #, n] &

CatMapTwoTimes = IteratedCatMapAlt[2];

The value of CatMapTwoTimes is a function (a pure function, specifically).


Notes

  • It is generally a good idea to avoid starting user Symbol names with capital letter, especially short or generic names like G because these may conflict with System` Symbols now or in the future.

  • Beware creating function that rely on a global definition such as side. It is often better to include such a parameter as an argument, possibly using SubValues as discussed above.

To illustrate the second point you might write your functions like this:

ClearAll["Global`*"]

G[side_][{x_, y_}] := Mod[{{2, 1}, {1, 1}}.{x, y}, side]

catMap[side_, n_][u : {_, _}] := Nest[G[side], u, n]

You can then create a particular version of the "function" simply with:

catMap4 = catMap[229, 4];

And use it:

catMap4[{62, 35}]
{95, 154}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Thank you! So would this be more computationally efficient than the Nest approach, because the new function is not actually generated? I don't have a very good sense of how Mathematica evaluates things. The function was actually named \Gamma, but I couldn't paste the Greek letter, so I decided to change it to G. I will keep that in mind about the global parameters. Is there a book on Mathematica programming that's reasonably concise and informative? – David Bruce Borenstein Aug 14 '13 at 12:51