0
$\begingroup$

I am translating my code from Python to Mathematica. I am trying to define a matrix, whose values depend on a variable chosen by the user, called kappa. In Python the code looked like that:

def getA(kappa):

    matrix = zeros((n, n), float)
    for i in range(n):
        for j in range(n):
            matrix[i][j] = 2*math.cos((2*math.pi/n)*(abs(j-i))*kappa)
    n = 5
    return matrix

What I have done so far in Mathematica is the following piece of code:

n = 5

getA[kappa_] :=
A = Table[0.0, {n}, {n}];
For[i = 0, i < n, i++, 
  For[ j = 0, j < n, j++, 
   A[[i, j]] = 2*Cos[(2*pi/n)*(abs (j - i))*kappa]]]; 

b = getA[3]

But when I try to evaluate this matrix for a value of kappa equal to 3, I get the following error:

Set::partd: "Part specification A[[i,j]] is longer than depth of object.

How can I fix it?

$\endgroup$
10
  • $\begingroup$ Unlike Python mathematica's lists go from 1 to n $\endgroup$ Apr 11 '15 at 14:54
  • $\begingroup$ BTW you could have filled your table directly without initialization and without For loops using Table. $\endgroup$ Apr 11 '15 at 14:56
  • $\begingroup$ I have changed my code into: $\endgroup$
    – johnhenry
    Apr 11 '15 at 15:01
  • $\begingroup$ n = 5 getA[kappa_] := A = Table[0.0, {n}, {n}]; For[i = 1, i <= n, i++, For[ j = 1, j <= n, j++, A[[i, j]] = 2*Cos[(2*pi/n)*(Abs[j - i])*kappa]]]; b = getA[3] $\endgroup$
    – johnhenry
    Apr 11 '15 at 15:02
  • $\begingroup$ but I get a matrix of 0.0 elements only. How is it possible? $\endgroup$
    – johnhenry
    Apr 11 '15 at 15:03
3
$\begingroup$

Do you mean this ?

n = 5;
getA[kappa_] :=
 Table[2*Cos[(2*π/n)*(Abs @(i - j))*kappa], {i, 0, n-1}, {j, 0, n-1}] 
getA[3] //MatrixForm 

enter image description here

You may post the expected result from your Python code in order to make it easier finding a functional programming equivalent.

EDIT, clean up:

getA[n_,kappa_] :=
 Table[2*Cos[(2*π/n)*(Abs @(i - j))*kappa], {i, 0, n-1}, {j, 0, n-1}] 
getA[5,3] //MatrixForm 
$\endgroup$
1
$\begingroup$

For highest efficiency, you should use the Listability of built-in functions in order to construct lists. Using this, you can do the following one-liner:

a[n_, kappa_] := 2 Cos[(2 Pi/n) kappa Abs[Array[Subtract, {n, n}]]]

a[5, 3] // MatrixForm

$$\left(\begin{array}{ccccc} 2 & \frac{1}{2} \left(-1-\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1-\sqrt{5}\right) \\ \frac{1}{2} \left(-1-\sqrt{5}\right) & 2 & \frac{1}{2} \left(-1-\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) \\ \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1-\sqrt{5}\right) & 2 & \frac{1}{2} \left(-1-\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) \\ \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1-\sqrt{5}\right) & 2 & \frac{1}{2} \left(-1-\sqrt{5}\right) \\ \frac{1}{2} \left(-1-\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1+\sqrt{5}\right) & \frac{1}{2} \left(-1-\sqrt{5}\right) & 2 \\\end{array}\right)$$

The important thing here is that the Array which makes the matrix is actually deep inside all the actual functions from which the matrix elements are built. By doing this, each time a new function is applied to the list we get the speed advantage of the compiled listability of that function, instead of having to call the function for each individual matrix element.

$\endgroup$
0
$\begingroup$
  1. As written your definition stops after the first "line" ending with ;
  2. You should use Module to localize your variables.
  3. Mathematica is case-sensitive and System Symbols will always start with capitals
  4. Function application uses square brackets: Abs[j - i]
  5. Indexing begins from one
  6. generally you should pass n as a parameter

These issues corrected:

getA[n_, kappa_] :=
 Module[{A, i, j},
   A = Table[0.0, {n}, {n}];
   For[i = 1, i <= n, i++, 
    For[j = 1, j <= n, j++, A[[i, j]] = 2 Cos[2 Pi/n*Abs[j - i]*kappa]]
   ];
   A
 ]

getA[5, 3]

However as penguin77 already showed there are better ways to write this in Mathematica. Usually For should be avoided. See:

For example:

fn[n_, kappa_][i_, j_] := 2 Cos[2 Pi/n*Abs[j - i]*kappa]

Array[fn[5, 3], {5, 5}]

This uses a SubValues definition; see: Define parameterized function

$\endgroup$
1
  • $\begingroup$ @user27673, Indeed once getting used to functional programming, For loops appear awkward. Can only encourage all M users to use functional programming for it's efficiency, readability and last and not least, elegance $\endgroup$
    – penguin77
    Apr 11 '15 at 17:24

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