9
$\begingroup$

I am hoping that this isn't a stupid question so feel free to vote it for closure. Google failed somehow.

I want to define a custom function (more complicated than the usual f[x_] := someExpression) that performs several tasks (taking elements of a set, performing computations, etc.) before giving an output. I don't want to run the whole bunch of codes repeatedly.

Is there a way of defining such a function?

What I have in mind is, say a program in R, which goes like

function_name <- function(arg1, arg2, ..., argn){
    routine 1
    routine 2
    routine 3
    ...
    Output to be returned
}

EDIT: In view of the comment that this question is somewhat vague, I am posting part of the code below:

Final = {{1}};
For[hn = 0, hn < 7, hn++;
 rp = {0}; fn = hn;
 For[fk = 0, fk < fn, fk++;
   Clear[r, v, w, p, q, z, x, n, k, t, res, pt];
   v[z_] := Sum[q^d, {d, 0, z - 1}];
   n = fn; k = fk; t = {}; For[i = 0, i < (n - k), i++;
     For[j = -1, j < k, j++; t = Join[t, {j}];]];
   t = KSubsets[t, (n - k)];
   For[i = 0, i < Length[t], i++;
     t[[i]] = Sort[t[[i]]]];
   t = Union[t];

The code is quite long (sloppy programming). I just want the whole thing to be given a name so that I can just type that name of that function and vary the arguments.

$\endgroup$
8
  • $\begingroup$ Maybe if you could say something more definite about the function you want to see, we could be a little more helpful... in short, what's your actual problem? $\endgroup$ Commented Jul 7, 2012 at 6:50
  • $\begingroup$ Multiple statements, exactly. $\endgroup$ Commented Jul 7, 2012 at 6:51
  • 3
    $\begingroup$ You should read the docs for Module and come back with a more concrete question $\endgroup$
    – rm -rf
    Commented Jul 7, 2012 at 6:52
  • 1
    $\begingroup$ Hope this clarifies things up. I want to write a program (this might be the appropriate word for it), which is like a function in the sense that it takes arguments and returns an output. The program performs tasks (computations, assigning variables, etc) and I would like to find a way of writing such a program, and by running the program by simply typing the name and the arguments. The usual method of defining a function f[x_]:= doesnt seem to work for my purpose. $\endgroup$ Commented Jul 7, 2012 at 6:54
  • 1
    $\begingroup$ Also, try to use more functional-style for coding instead of procedural routines and For loops, as it is really rewarding in Mathematica. $\endgroup$ Commented Jul 7, 2012 at 6:56

2 Answers 2

17
$\begingroup$

The original question asked how to do something like the following in Mathematica

function_name < - function (arg1, arg2, ..., argn) {
  routine 1 
  routine 2 
  routine 3 
  ... 
  Output to be returned}

So, yes! You could do something like this:

functionName[arg1_, arg2_, arg3_ (* '_' following a name identifies a function argument *)] := 
 Module[{local1, local2, local3 (* Local variables *)},

  local1 = Join[arg1, {a, a, c, a, e, b, d}];
  local2 = Sort /@ local1;
  local3 = local2 + arg1 * arg3; 

  {local1, local2, local3} (* Output to be returned *)
  ]

So again, yes you can define a function that has:

  • any number of arguments,
  • any number of local variables,
  • routines that set local variables, and
  • return any, all, or any combination of the local variables.

Note one can also define local functions inside a function then use them just as you would any other. A simple if kind of silly example follows:

functionName[arg1,arg2]:= 
  Module[{loca1,local2,localFunction}, 
  localFunction[localAgr1_,localArg2_]:=localAgr1^localArg2;
  local1=localFunction[arg1,arg2];
  local2=local1 * 2;
  local2]

Simply put Mathematica gives you extensive flexibility.

As others have commented look up functions, Module, Block, and functional programming. It will reward you with precise, elegant, and powerful code.

$\endgroup$
2
  • $\begingroup$ This is exactly the structure of the code that I was looking for. $\endgroup$ Commented Jul 8, 2012 at 8:09
  • 3
    $\begingroup$ Thanks for the acceptance. Welcome to the site. Stick around if you can. The real experts on this site have serious chops and they contribute lots of time and attention. I learn new things everyday. I don't know of a better learning community anywhere. $\endgroup$
    – Jagra
    Commented Jul 8, 2012 at 13:27
14
$\begingroup$

You've already had a lot of feedback suggesting that some time with a basic introduction to programming would be useful. I'm going to provide an answer anyway, in the hope of providing a “teachable moment” for other beginning Mathematica users.

My first comment is that the code you have posted is not complete: the two outermost For loops do not have closing square brackets. This will be clear from the pink syntax highlighting in the Mathematica front end. Even after I fixed this and a few other things up, your version of the code doesn’t actually return anything. The definition of a function v[z_] isn't used elsewhere in your code, so it is hard to work out what you are trying to do. And since you are using KSubsets, don’t forget you need to evaluate the following first.

Needs["Combinatorica`"]

My second comment echoes those of others: you almost never need loops in Mathematica. There is usually another, more efficient and concise way. (The exception is if you are going to compile the code using a C compiler, but you are not at that stage.) István’s suggestion to explore the tag is a good one. In particular, have a look at this summary of alternatives to looping constructions.

Now, to the specifics of your code. The commenters who suggested wrapping your multiple statements in Module were exactly right. This is a scoping construct which will allow you to localize your intermediate variables so their definitions don’t leak out to affect other calculations. You then don’t need that Clear statement. The last line is indeed returned, as long as there is no semicolon suppressing output.

I am now going to go through some obvious issues with the code. Take this line:

For[i = 0, i < Length[t], i++;  t[[i]] = Sort[ t[[i]] ] ]

What you mean is, “I want every sublist in t to be sorted”. You would be much better off just using Map, which “maps” a function onto each element of a list. The shorthand version of Map is /@, so:

t = Sort /@ t

Here’s another example.

For[j = -1, j < k, j++; t = Join[t, {j}]

All this is doing is creating a vector from -1 to k. So just kill that loop and try:

t = Range[-1,k-1]

Another issue in your code is that, at the point that you invoke KSubsets, you are outside the two inner For loops. So $n = k$, and you are finding KSubsets of length zero, i.e. empty sets.

A final point I’d make is that you are defining variables like n and k that are just mirroring the iterators in your For loops. This is a waste of time in a language like Mathematica and just makes your code harder to read.

Making all the above changes results in something like the following:

KenjosFunction[kk_Integer?Positive] := 
 Module[{r, v, w, p, q, z, x, n, k, result = {}},
  For[n = 0, n < kk, n++;
   For[k = 0, k < n, k++;
    For[i = 0, i < (n - k), i++;
     result = 
      Join[result, 
       Union[Sort /@ KSubsets[Range[-1, k - 1], (n - k)]]]];
    ]];
  result 
   ]

There are still three nested For loops which I haven’t cleaned up, but it is much cleaner and easier to read. It also actually gives a result, though I have no idea if it is the one you want:

KenjosFunction[4]
(* {{-1}, {0}, {-1, 0}, {-1, 0}, {-1}, {0}, {1}, {-1, 0}, {-1, 1}, {0, 
  1}, {-1, 0}, {-1, 1}, {0, 1}, {-1}, {0}, {1}, {2}} *)

Further simplifications you could consider, depending on your real code, includ eliminating the For loops by defining a single nested Table and using Flatten to get the right dimensions. I leave this as an exercise for you.

$\endgroup$
1
  • $\begingroup$ Sorry for posting an incomplete code (the one I posted was even less than half the code I wrote). I never thought you would actually dissect the code I posted, since all I really needed is a way of creating a function with multiple statements. As a beginner in Mathematica with background in C, my tendency is to use LOOPs and IFs and I'm surprised there are actually shorter (and I believe) quicker alternatives. $\endgroup$ Commented Jul 7, 2012 at 9:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.