4
$\begingroup$

I am trying to create a function that returns a matrix as in the description below.

The function has five inputs:

  • M: name of the matrix
  • n: size of the matrix nxn
  • a, b, c: integer numbers with $0 \le a,b, c\le n$

Next I will assign elements of the matrix with both non-zero column and non-zero row indices as below. All the remaining elements are assigned 0 values.

M[[a,a]] = x11;

M[[a,b]] = x12;

M[[a,c]] = x13;

M[[b,a]] = x21;

M[[b,b]] = x22;

M[[b,c]] = x23;

M[[c,a]] = x31;

M[[c,b]] = x32;

M[[c,c]] = x33;

How can I do this? I don't know how to give name M as an input to a function, and also this function is complex to me. I haven't written any function with more many code lines like this.

For now I am just starting something, but I am not sure if it is correct.

    myfunc[M_, n_, a_, b_, c_] := (M = Table[0, {n}, {n}];

        If[a > 0, M[[a,a]] = x11, M[[a,a]] = 0];
        If[a > 0 && b > 0, M[[a,b]] = x12, M[[a,b]] = 0];
        If[a > 0 && c > 0, M[[a,c]] = x13, M[[a,c]] = 0];
        If[b > 0, M[[b,b]] = x22, M[[b,b]] = 0];
        If[b > 0 && a > 0, M[[b,a]] = x21, M[[b,a]] = 0];
        If[b > 0 && c > 0, M[[b,c]] = x23, M[[b,c]] = 0];
        If[b > 0 && a > 0, M[[b,a]] = x21, M[[b,a]] = 0];
        If[b > 0, M[[b,b]] = x22, M[[b,b]] = 0];
        If[b > 0 && c > 0, M[[b,c]] = x23, M[[b,c]] = 0];
        If[c > 0 && a > 0, M[[c,a]]= x31, M[[c,a]] = 0];
        If[c > 0 && b > 0, M[[c,b]] = x32, M[[c,b]] = 0];
        If[c > 0, M[[c,c]] = x33, M[[c,c]] = 0];)
$\endgroup$

2 Answers 2

6
$\begingroup$

Here is another, (more flexible?) way:

f[n_Integer, list_?VectorQ, vals_?MatrixQ] := Module[{M, idx, idx1},
 idx = Pick[Range[Length[list]], UnitStep[list - 1] UnitStep[n - list], 1];
 M = ConstantArray[0, {n, n}];
 idx1 = list[[idx]];
 M[[idx1, idx1]] = vals[[idx, idx]];
 M
 ]

xx = Array[ToExpression[StringJoin["x", IntegerString[{##}]]] &, {3, 3}];
M = f[8, {1, 4, 7}, xx];
M//MatrixForm

$$\left( \begin{array}{cccccccc} \text{x11} & 0 & 0 & \text{x12} & 0 & 0 & \text{x13} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \text{x21} & 0 & 0 & \text{x22} & 0 & 0 & \text{x23} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \text{x31} & 0 & 0 & \text{x32} & 0 & 0 & \text{x33} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \end{array} \right)$$

Edit

Entries $i$ in list will now also be ignored if they do not fullfil $1 \leq i \leq n$.

$\endgroup$
7
  • $\begingroup$ Thanks, short and great too! $\endgroup$
    – emnha
    Commented Mar 10, 2018 at 12:29
  • $\begingroup$ Hi, when one input is zero, the code doesn't work. Assume that a = 0 but b, c are non-zero then elements with bc, cb also should be assigned as above. How can I fix that? $\endgroup$
    – emnha
    Commented Mar 10, 2018 at 17:47
  • $\begingroup$ Mathematica's array are 1-based; index zero makes no sense. But you can enter, e.g., f[8, {4,7}, xx] if want to set only two colums and two rows. In fact, the second argument list can be any list of integers between 1 and n of length at most the length of the matrix vals (which is suppose to be a square matrix). $\endgroup$ Commented Mar 10, 2018 at 18:01
  • $\begingroup$ Maybe you misunderstood a bit. For example, f[4,0,2,3] then only the elements [[2,2]], [[2,3]] [[3,2]], [[3,3]] are set to their x values. Like this: i.imgur.com/SUMOdiC.png $\endgroup$
    – emnha
    Commented Mar 10, 2018 at 18:22
  • 1
    $\begingroup$ Ah, I think I got it. See my edit. $\endgroup$ Commented Mar 10, 2018 at 18:37
6
$\begingroup$

Here's one way:

myfunc[n_Integer?Positive, a_Integer?Positive, b_Integer?Positive, c_Integer?Positive] /;
  Max[a, b, c] <= n := 
  Normal[SparseArray[Thread[Tuples[{a, b, c}, {2}] ->
                            {x11, x12, x13, x21, x22, x23, x31, x32, x33}], {n, n}]]

Test:

myfunc[8, 1, 4, 7] // MatrixForm

$$\begin{pmatrix} \mathtt{x11} & 0 & 0 & \mathtt{x12} & 0 & 0 & \mathtt{x13} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \mathtt{x21} & 0 & 0 & \mathtt{x22} & 0 & 0 & \mathtt{x23} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \mathtt{x31} & 0 & 0 & \mathtt{x32} & 0 & 0 & \mathtt{x33} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \end{pmatrix}$$


If you want to be able to use 0 as an indicator to ignore an entry:

myfunc[n_Integer?Positive, a_Integer?NonNegative,
       b_Integer?NonNegative, c_Integer?NonNegative] /; Max[a, b, c] <= n := 
  Normal[SparseArray[Select[Thread[
 Tuples[{a, b, c}, {2}] ->
 {x11, x12, x13, x21, x22, x23, x31, x32, x33}], FreeQ[First[#], 0] &], {n, n}]]

Test:

myfunc[8, 0, 4, 7] // MatrixForm

$$\begin{pmatrix} 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & \mathtt{x22} & 0 & 0 & \mathtt{x23} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & \mathtt{x32} & 0 & 0 & \mathtt{x33} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \end{pmatrix}$$

Here's a SparseArray[] equivalent of Henrik's routine:

myfuncgen[n_Integer?Positive, idx_List, ent_?SquareMatrixQ] /; 
  Length[idx] <= n && Length[idx] == Length[ent] && 
  VectorQ[idx, IntegerQ] && 0 <= Min[idx] && Max[idx] <= n := 
Normal[SparseArray[Select[Thread[Tuples[idx, {2}] -> Flatten[ent]], 
                          FreeQ[First[#], 0] &], {n, n}]]

Test:

myfuncgen[8, {1, 0, 7},
          Array[Symbol["x" <> IntegerString[#1] <> IntegerString[#2]] &, {3, 3}]]

$$\begin{pmatrix} \mathtt{x11} & 0 & 0 & 0 & 0 & 0 & \mathtt{x13} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \mathtt{x31} & 0 & 0 & 0 & 0 & 0 & \mathtt{x33} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \end{pmatrix}$$

$\endgroup$
5
  • $\begingroup$ Thanks a lot. Look great but that beyond my current lever! I need to practice more! I wrote my code above. It is somewhat long and many errors. $\endgroup$
    – emnha
    Commented Mar 10, 2018 at 12:27
  • $\begingroup$ Hi, I just checked that when one input is zero, the code doesn't work. Assume that a = 0 but b, c are non-zero then elements with bc, cb also should be assigned as above. How can I fix that? $\endgroup$
    – emnha
    Commented Mar 10, 2018 at 14:04
  • $\begingroup$ For example, f[4,0,2,3] then only the elements [[2,2]], [[2,3]] [[3,2]], [[3,3]] are set to their x values. We only set elements with indices non-zero Like this:i.imgur.com/SUMOdiC.png $\endgroup$
    – emnha
    Commented Mar 10, 2018 at 18:23
  • 1
    $\begingroup$ @anhnha, check now $\endgroup$ Commented Mar 10, 2018 at 21:48
  • $\begingroup$ Yeah, it works well now. Thanks! $\endgroup$
    – emnha
    Commented Mar 10, 2018 at 22:59

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.