1

Is there a way to generate a random n by n strictly diagonally dominant in Mathematica? I use the following code to generate a random square matrix:

A = RandomReal[{-100, 100}, {1000, 1000}]

EDIT: I just need a way to generate a large strictly diagonally dominant matrix, row randomness is not crucial.

Szabolcs
  • 24,728
  • 9
  • 85
  • 174
1osmi
  • 276
  • 3
  • 12
  • if it IS truly random, then how you can specify that the matrix should come out to have a special property as you are asking for? are you not asking for 2 conflicting things at the same time? – Nasser Jan 09 '12 at 22:05
  • 1
    @Nasser Not really. Example: I want a random dice roll `n <= 3`. You could say "that's not random because there's the restriction that it must be `n <= 3`. A truly random dice roll can be between `1 <= n <= 6`." What "random dice roll <= 3" means here is that all the *allowed* (after the restriction of <= 3) outcomes (i.e. `{1,2,3}`) must be *equally* likely. "More random" or "truly random" are not precise terms, but I wanted to show with this example that what you did in you answer is equivalent to ensuring that 1. there are no unneeded restrictions (with the previous example, ... – Szabolcs Jan 10 '12 at 13:03
  • ... all of `{1,2,3}` are allowed, not just a subset of them), which could be called "more random", but 2. you also changed the distribution of the matrix elements, making them non-uniform (with the dice example, `1`, `2` and `3` are not *equally* likely), which might be interpreted as "less random". Of course if the set of possible outcomes is infinite and "continuous" like in the case of matrices, these things are a little more difficult to define, and the OP didn't specify precisely what distribution he needs. But claiming that you're making the matrix *more random* could be misinterpreted – Szabolcs Jan 10 '12 at 13:07

2 Answers2

7

You could sum the absolute values of each row, and add sign of corresponding diagonal entry times its row sum to that diagonal entry.

In[457]:= SeedRandom[11111];
n = 5;

In[465]:= mat1 = RandomReal[{-100, 100}, {n, n}]

Out[465]= {{-47.2529, 53.4377, 28.6267, 
  69.098, -66.3035}, {71.5837, -38.9932, 66.885, -35.7296, 
  38.6584}, {-55.4822, -45.8442, 52.9929, 55.1683, 
  18.8236}, {12.2189, -47.5637, 36.1517, 88.7082, 
  95.101}, {-87.9987, -44.2326, -7.09374, -16.7852, 42.521}}

In[466]:= mat = 
 mat1 + DiagonalMatrix[(Total /@ Abs[mat1])*Sign[Diagonal[mat1]]]

Out[466]= {{-311.972, 53.4377, 28.6267, 
  69.098, -66.3035}, {71.5837, -290.843, 66.885, -35.7296, 
  38.6584}, {-55.4822, -45.8442, 281.304, 55.1683, 
  18.8236}, {12.2189, -47.5637, 36.1517, 368.452, 
  95.101}, {-87.9987, -44.2326, -7.09374, -16.7852, 241.152}}

Whether this suffices for your purposes perhaps depends on what you want in terms of "randomness".

Daniel Lichtblau
  • 6,854
  • 1
  • 23
  • 30
  • A small change could be to use Total[Abs[mat1], {2}], which does not unpack. –  Jan 10 '12 at 08:00
1

how about:

n = 5;
(a = Table[Random[], {n}, {n}]) // MatrixForm
Table[If[i == j, 
   a[[i, j]] = Total[Abs[a[[i, All]]]] - Abs[a[[i, j]]]], {i, 5}, {j, 
   5}];
a // MatrixForm

edit(1)

I was thinking to myself that to make the above more random, I should multiply the generated elements on the diagonal by another random number > 1. Else, the way it is, the matrix is not really random, as one can figure what the element on the diagonal is by summing all the other elements on the row.

So, here is version 2 of the above

  n = 5;
  (a = Table[Random[], {n}, {n}]) // MatrixForm

  Do[
    Do[If[i == j, 
          a[[i, j]] = 
               RandomReal[{1, 10}]*(Total[Abs[a[[i, All]]]]-Abs[a[[i, j]]])
         ], 
      {i, 5}], 
    {j, 5}
   ];

 a // MatrixForm

The matrix is still not exactly random, but at least a little more random than before :)

edit(2)

after having coffee, I thought that I should make the above more functional ! So I rewrote the above in what I think is a more Mathematica/functional style (no explicit Do loops).

here it is

scale = 2;
A = Table[RandomReal[], {3}, {3}]
A = ReplacePart[
  A, {{i_, i_}}:> RandomReal[{1, scale}]*(Total@Abs@A[[i, All]]-Abs@A[[i, i]])]

hence, before mat was

 {{0.577887, 0.825449, 0.085029}, 
 {0.68226, 0.81484,0.903905}, 
 {0.289007, 0.642185, 0.598648}}

after mat becomes

 {{1.74871, 0.825449, 0.085029}, 
  {0.68226, 2.15998,0.903905}, 
  {0.289007, 0.642185, 1.58928}}

I am really starting to like this functional programming way. It also seems to make the code shorter, which is a good thing I think. Less code means less chance of a bug.

Nasser
  • 12,849
  • 6
  • 52
  • 104
  • 1
    Define "more random." I ask because the statement is hard to quantify, especially in view of this [answer](http://stackoverflow.com/a/3956538/198315). – rcollyer Jan 10 '12 at 02:22
  • I agree that the statement is hard to quantify, and that is why I put a smiley face when I said it. But at least, multiplying the dominant diagonal element by a random number at the end, will make it more random that otherwise. In the later case, it would had the exact sum of the row it is on( just meeting the DD condition), which does not make it really random, while in the former case, it will be less likely to have that sum. It will have a sum more than the absolute sum of the row, most of the times, based on the distribution of the RandomReal[] used to 'randomize' it at the end. – Nasser Jan 10 '12 at 03:15
  • Obviously, a structured matrix will in some sense be less random than a non-structured one, but the structure usually just reduces the degrees of freedom available. But, within the remaining space, randomness can be obtained. For a Symmetric/Hermitian matrix, a random version, would not be difficult to generate, necessarily. An SDD, beyond what you did, though, I'm not so sure. Something to think about. – rcollyer Jan 10 '12 at 03:22