10

Every time I want to manually input a matrix in Mathematica, it takes me a while since every new row has to be in a separate pair of curly braces.

For instance:

a = {{1, 2}, {3, 4}}

In MATLAB, this is solved more concisely by using a semicolon to indicate a new row:

a=[1 2; 3 4]

It is much faster to type.

Can one built a function that automatically replaces the semicolon by a bracket, such that typing becomes faster?

[1 2; 3 4] // someFunction
(* {{1, 2}, {3, 4}} *)
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
henry
  • 2,510
  • 14
  • 28
  • More info is needed. Are all elements of the matrix integers?, are all matrices rectangular? – Feyre Jan 21 '17 at 09:15
  • 7
    I assure you its only a question of getting used to it! – Mirko Aveta Jan 21 '17 at 09:24
  • @Feyre For arbitrairy Matrices. Put all that is before the smi-colum into a curly bracet and replace the square bracets also with curly bracets. – henry Jan 21 '17 at 09:36
  • 1
    This also annoys me, even though I use Mathematica very often. – james Jan 21 '17 at 09:37
  • 3
    http://reference.wolfram.com/language/howto/InputAMatrix.html, http://reference.wolfram.com/language/tutorial/TypingMatrices.html, and http://reference.wolfram.com/language/tutorial/EnteringTablesAndMatrices.html – Karsten7 Jan 21 '17 at 10:08
  • 1
  • if it is really easier and you gind enough others which think the same way it is maybe instead of programming such a thing by yourself more worth to ask the developers of mathematica if they can/will change it to fit your needs, if no one else thinks the same way as you do then you should ask yourself why you are the only one having a problem with this – konqui Jan 21 '17 at 17:13
  • I think "faster to code" is often not efficient in terms of code execution. When is a code "efficient"? – vagoberto Jan 21 '17 at 17:33
  • 7
    So far, nothing I've seen here beats Ctrl-comma etc, not even Matlab. Mainly because, one can input Mathematica expression with Ctrl-comma. If you're talking about a large amount of data entry, I'd use something else to enter it other than Mathematica or Matlab. – Michael E2 Jan 21 '17 at 18:40
  • @konqui Do you find it more enjoyable to put those curly bracets around each row ? – henry Jan 22 '17 at 09:32
  • @DoHe to be honest yes the curly braces i use this much so i instinctively know where they are but the square ones i always have to search – konqui Jan 22 '17 at 09:35

6 Answers6

19

Quick-n-dirty. I dispense with open/close bracket, trivial to put in if it matters:

fn = ToExpression/@ImportString[StringReplace[#, ";" -> "\n"], "Table"] &;

mymat = "2 4;  3 4 5 ; 5 6" // fn
mymat2 = "a b;2 c; d 5" // fn

{{2, 4}, {3, 4, 5}, {5, 6}}

{{a, b}, {2, c}, {d, 5}}

ciao
  • 25,774
  • 2
  • 58
  • 139
  • Awesome ! Thanks a lot ! – henry Jan 21 '17 at 11:12
  • 7
    Instead of StringReplace you can use "LineSeparators" option for ImportString: ToExpression@ImportString[#, "Table", "LineSeparators" -> ";"] & – Simon Rochester Jan 21 '17 at 11:50
  • @SimonRochester - ah, nice. I import/export about as often as total solar eclipses, don't know all the options off top-of-head. +1 – ciao Jan 21 '17 at 18:51
10

You can make use of the build-in palettes e.g. the Basic Math Assistant. The major advantages are

  • MatrixForm-esque look for input
  • Tab can be used to fill the matrix from top left to bottom right.
  • 2D-Navigation using arrow keys is also possible.
  • Hotkeys for adding rows and columns

gif

Sascha
  • 8,459
  • 2
  • 32
  • 66
  • Thanks for the answere, but I am afraid, this still takes more time than simply typing [ 1 2 3; 4 5 6; 7 8 9] and it takes a lot of space when the Matrix is very large. (20*20 etc. ) – henry Jan 21 '17 at 10:10
  • 6
    How often does one need to manually input $20 \times 20$ matrices? If I had to do this a significant number of times I would outsource the task to amazon mechanical turk – Sascha Jan 21 '17 at 10:18
  • 6
    (+1) I do this with Ctrl-comma and Ctrl-return and tab between entries. Parentheses are optional. -- Probably what you meant by "Hotkeys," but the palette, imo, is an unnecessary inconvenience once you have the workflow down. – Michael E2 Jan 21 '17 at 14:35
  • 3
    Move-aim-click for each new column and row is even slower than just typing all the braces. And using <Ctrl>-, and <Ctrl>-<Return> is really fast. – Ruslan Jan 21 '17 at 20:23
9
m = Function[expr, Block[{Times = List, CompoundExpression = List}, expr], HoldAll];
m[b a; c d e]
(*{{b, a}, {c, d, e}}*)

Do notice this representation has conspicuous limitation e.g. it can not be used to represent {{a b}, {c, d e}}. It doesn't cause trouble in MATLAB because MATLAB doesn't have implicit time sign.

Also, it can't represent {i = 1; i + 1}. MATLAB suffers this problem, too.

xzczd
  • 65,995
  • 9
  • 163
  • 468
  • ok, but you can only do symbolic calculations this way. m[2 1; 3 4 5] obviously doesn't work. – Feyre Jan 21 '17 at 10:41
  • @Feyre Are you sure?: https://i.stack.imgur.com/iw8EM.png Notice the existence of HoldAll. – xzczd Jan 21 '17 at 10:44
  • You're right, I remember a similar question and this failing, but you're right. It had to do with representing multiple 0's. – Feyre Jan 21 '17 at 10:50
  • Nice work ! Thanks a lot ! – henry Jan 21 '17 at 11:07
  • What is the Trouble exactley ? – henry Jan 21 '17 at 11:19
  • @DoHe Oh my former explanation for the "trouble" is wrong, see my edit. – xzczd Jan 21 '17 at 11:22
  • 2
    "MATLAB doesn't have implicit time sign" - right, it has to explicitly use .* to multiply stuff. That's the thing with language design, it's full of compromises. If you want to allow space as a separator, then you can't multiply two variables with a space; if you want to be able to multiply things like x y, then you need to delimit your arrays differently. – J. M.'s missing motivation Jan 21 '17 at 13:20
  • @J.M Thank a lot for the explenation of the Problem with the space seperator. – henry Jan 21 '17 at 13:31
9

One idea is to use a style sheet to enable MATLAB-type matrix input. The following is an extension of @xzczd's idea. Here is the style sheet:

Notebook[{
    Cell[StyleData[StyleDefinitions->"Default.nb"]],
    Cell[StyleData["MATLAB", StyleDefinitions->StyleData["Input"]],

        (* Use a private context so that $Line doesn't increment during processing *)
        CellContext->Cell,

        (* Add a tag to the evaluation cell, and hence to its generated cells *)
        CellProlog:>SetOptions[EvaluationCell[],CellTags->"MATLAB"],

        (* Clear tags *)
        CellEpilog:>(SetOptions[#1,CellTags->{}]&)/@Cells[CellTags->"MATLAB"],
        CellEvaluationFunction->Function[
            Module[{m},
                ToExpression[
                    # //.  RowBox[{"[", b__}] -> RowBox[{ToString[m],"[",b}],
                    StandardForm,
                    Function[Null,
                        Defer@@(Hold[#1]
                            //.  {
                                m[a_CompoundExpression] :> With[
                                    {tmp = Replace[Defer[a], {CompoundExpression->List,Times->List}, 3, Heads->True]},
                                    tmp/;True
                                ],
                                m[a_]:>With[{tmp=Replace[Defer[a], {Times->List}, 2, Heads->True]}, tmp/;True]
                                }
                            //.  Defer[x_]:>x),
                        HoldAll
                    ]
                ]
            ]
        ],

        (* MATInput style looks like input, but it has a working CellAutoOverwrite option *)
        System`GeneratedCellStyles->{"Output"->"MATInput"},

        (* No need to show In for this cell *)
        ShowCellLabel->False,

        (* Make the cell look like text *)
        FontFamily->"Arial",
        FontSize->14,
        FontWeight->"Plain",
        AutoMultiplicationSymbol->False
    ],
    Cell[StyleData["MATInput", StyleDefinitions->StyleData["Output"]],

        (* Convert to regular Input cell before evaluation *)
        CellProlog:>SetOptions[EvaluationCell[],CellStyle->"Input"],

        (* Disappear if the MATLAB cell generating the MATInput is reevaluated *)
        GeneratedCell->True,
        CellAutoOverwrite->True,

        (* No need to show cell label until after it is converted to an Input cell *)
        ShowCellLabel->False,

        (* Make it look like an Input cell*)
        ShowStringCharacters->True,
        NumberMarks->True,
        FontWeight->"DemiBold"
    ]
    },
    WindowSize->{808,689},
    WindowMargins->{{Automatic,274},{28,Automatic}},
    FrontEndVersion->"10.3 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 10, 2015)",
    StyleDefinitions->"PrivateStylesheetFormatting.nb"
];
NotebookPut @ %;

Here is how it works. The following is a MATLAB-style cell:

a = [1 2 3 4 5 ; 2 3 4 5 6^2]

After evaluation of the above cell, we have the original MATLAB cell and a generated MATInput cell:

a = [1 2 3 4 5 ; 2 3 4 5 6^2]

a={{1,2,3,4,5},{2,3,4,5,6^2}}

If we edit the MATLAB cell, and then reevaluate, the old generated MATInput cell is overwritten by the new MATInput cell. Also, note that the generated cell hasn't evaluated, 6^2 is not 36 yet, and a has no OwnValue:

OwnValues[a]

{}

If we select the generated cell and evaluate it, then everything works as expected:

a = {{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6^2}}

{{1, 2, 3, 4, 5}, {2, 3, 4, 5, 36}}

Note that the above "Input" cell has now become a real Input cell, and will no longer be overwritten when the MATLAB cell that generated it is reevaluated.

So, the work flow is to create a MATLAB cell, populate it with a MATLAB-style matrix, and then evaluate the MATLAB cell to generate the equivalent unevaluated Mathematica Input cell. This Input cell can then be evaluated to generate results.

Some advantages of this approach are that the MATLAB cell can contain arbitrary Mathematica code, and you can use CompoundExpression and Times in the matrix entries since they are only replaced at the top levels. For example, @xzczd's problematic examples can be handled as follows:

[Times[a b] ; c (d e)]

{{a b},{c,d e}}

[Times[i = 1 ; i + 1]]

{i=1;i+1}

Peter Mortensen
  • 759
  • 4
  • 7
Carl Woll
  • 130,679
  • 6
  • 243
  • 355
  • (+1) I did, or at least started, something like this, but didn't solve the parsing-expressions-as-entries problem. Given both [MATLink`](http://mathematica.stackexchange.com/questions/10231/calling-matlab-from-mathematica/24478#24478) and Control-comma/return, it seemed just an academic exercise, anyway, and I stopped. Still an interesting answer. – Michael E2 Jan 22 '17 at 17:45
  • BTW don't you want RuleDelayed to localize the pattern name b inside ToExpression[] in the CellEvaluationFunction? – Michael E2 Jan 22 '17 at 17:47
  • To avoid situations like b=3; 5 /. b_->b returning 3 instead of the expected 5? Using CellContext->Cell prevents the possibility of b having OwnValues, so I think it's a matter of taste whether to use Rule or RuleDelayed here. – Carl Woll Jan 22 '17 at 18:06
  • I see. I missed that. Thanks. It was just the question of b having a global value. So does m need to be localized? Or is it just the Temporary attribute? (I like the m trick, because I struggled with that problem.) – Michael E2 Jan 22 '17 at 18:44
6

An alternative answer to what Feyre suggested using strings:

stringToMatrix[string_] :=
string // StringSplit[#, ";"] & // Map[StringSplit[#, " " ] &] //ToExpression

stringToMatrix["1 2 3; 4 5 6; 7 8 9"]
(* {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} *)
Sascha
  • 8,459
  • 2
  • 32
  • 66
4

Suppose the number of data are a multiple of 4. This is a simple way

m = HoldForm[{1 2 3 4, 5 6 7 8, 9 10 11 12}] /. 
  a_ b_ c_ d_ -> {a, b, c, d}

Try

m//MatrixForm

this doesn't work since the HoldForm must be release.

 mm = ReleaseHold[mm]

and now the precedent command works

If you want a $3 \times 4$ matrix

mmm = Partition[Flatten[mm], 3]

It's the simplest way I can imagine

cyrille.piatecki
  • 4,582
  • 13
  • 26