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$
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$ – anhnha Mar 10 '18 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$ – anhnha Mar 10 '18 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$ – Henrik Schumacher Mar 10 '18 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$ – anhnha Mar 10 '18 at 18:22
  • 1
    $\begingroup$ Ah, I think I got it. See my edit. $\endgroup$ – Henrik Schumacher Mar 10 '18 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$ – anhnha Mar 10 '18 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$ – anhnha Mar 10 '18 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$ – anhnha Mar 10 '18 at 18:23
  • 1
    $\begingroup$ @anhnha, check now $\endgroup$ – J. M.'s torpor Mar 10 '18 at 21:48
  • $\begingroup$ Yeah, it works well now. Thanks! $\endgroup$ – anhnha Mar 10 '18 at 22:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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