1
$\begingroup$

Given an n-by-n matrix A with elements equal to either 0 or 1, I want to replace only nonzero elements (A_ij)'s by (b_ij) and leave 0's intact where (b_ij)'s are themselves elements of another n-by-n matrix B. I do it as following


a[A_, n_] := 
 Table[If[A[[i, j]] == 1, A[[i, j]] = B[[i, j]], 0], {i, 
   n}, {j, n}]

Then by setting n=5, I get the following errors:

Part::partd: Part specification amat[[1,2]] is longer than depth of object. Set::setps: {{0,1,0,0,0},{1,0,1,0,0},{0,1,0,1,0},{0,0,1,0,1},{0,0,0,1,0}} in the part assignment is not a symbol.

How can I get rid of these errors? Is there a better way to do this procedure?

Thanks!

$\endgroup$
3
  • 3
    $\begingroup$ You could do: newMatrix = A B $\endgroup$
    – Carl Woll
    Jan 13, 2022 at 23:38
  • $\begingroup$ well, if you mean the tensor product of A & B, it doesn't do the job. $\endgroup$
    – Irane.Mir
    Jan 13, 2022 at 23:52
  • $\begingroup$ @Bill what you wrote is slightly different than what I have written in my question. But yes, the code I wrote first gives me the mentioned errors but then generates what I want. The problem I guess is the way I call b_ij from matrix B by writing B[[i,j]]. $\endgroup$
    – Irane.Mir
    Jan 14, 2022 at 0:12

2 Answers 2

3
$\begingroup$

Firstly, define the matrices. Below I am doing $(5 \times 5)$ but the dimensions can easily be changed.

n = 5;
A = Table[RandomInteger[], {i, 1, n}, {j, 1, n}];
B = Table[b[i, j], {i, 1, n}, {j, 1, n}];
A // MatrixForm
B // MatrixForm

Then, you do the multiplication like so:

A B // MatrixForm

Comparing to the forms of the matrices A and B ,the result of the multiplication is the right answer.

Are there reasons that you want to use conditions? If, yes the following works fine:

(Table[If[A[[i, j]] == 0, 0, B[[i, j]]], {i, n}, {j, 
    n}]) // MatrixForm

and gives the same answer as the minimal approach which is the vanilla multiplication.

$\endgroup$
3
$\begingroup$

If you want to do in-place modification of A through a function call to a, then you have to tell a that you want to pass the matrix A by reference. You can do that by giving a the attribute HoldFirst (which in this context means call by reference for the first argument only).

So your function could look like this:

ClearAll[a];
SetAttributes[a, HoldFirst];
a[A_, B_] := Table[
   If[A[[i, j]] == 1, A[[i, j]] = B[[i, j]], 0],
   {i, Dimensions[A][[1]]}, {j, Dimensions[A][[2]]}
   ];

Here is a simple test problem:

A = RandomInteger[{0, 1}, {5, 5}]
B = RandomInteger[{1, 10}, {5, 5}]
a[A, B];
A

{{0, 1, 0, 1, 0}, {0, 1, 1, 0, 0}, {1, 0, 0, 0, 1}, {0, 1, 1, 1, 1}, {0, 0, 0, 0, 1}}

{{2, 6, 1, 2, 1}, {1, 2, 3, 2, 8}, {1, 1, 3, 10, 8}, {7, 6, 6, 8, 4}, {8, 9, 8, 2, 4}}

{{0, 6, 0, 2, 0}, {0, 2, 3, 0, 0}, {1, 0, 0, 0, 8}, {0, 6, 6, 8, 4}, {0, 0, 0, 0, 4}}

With Carl Woll's comment, you can also simply use this one:

ClearAll[a];
SetAttributes[a, HoldFirst];
a[A_, B_] := (A*=B);

If A is large and has only few nonzero entries, then you might want to consider to represent A as a SparseArray.

$\endgroup$

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.