9
$\begingroup$

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}} *)
$\endgroup$
17
$\begingroup$

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}}

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

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

$\endgroup$
  • $\begingroup$ 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. ) $\endgroup$ – henry Jan 21 '17 at 10:10
  • 6
    $\begingroup$ 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 $\endgroup$ – Sascha Jan 21 '17 at 10:18
  • 6
    $\begingroup$ (+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. $\endgroup$ – Michael E2 Jan 21 '17 at 14:35
  • 3
    $\begingroup$ 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. $\endgroup$ – Ruslan Jan 21 '17 at 20:23
8
$\begingroup$
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.

$\endgroup$
  • $\begingroup$ ok, but you can only do symbolic calculations this way. m[2 1; 3 4 5] obviously doesn't work. $\endgroup$ – Feyre Jan 21 '17 at 10:41
  • $\begingroup$ @Feyre Are you sure?: i.stack.imgur.com/iw8EM.png Notice the existence of HoldAll. $\endgroup$ – xzczd Jan 21 '17 at 10:44
  • $\begingroup$ You're right, I remember a similar question and this failing, but you're right. It had to do with representing multiple 0's. $\endgroup$ – Feyre Jan 21 '17 at 10:50
  • $\begingroup$ Nice work ! Thanks a lot ! $\endgroup$ – henry Jan 21 '17 at 11:07
  • 2
    $\begingroup$ "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. $\endgroup$ – J. M. will be back soon Jan 21 '17 at 13:20
8
$\begingroup$

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}

$\endgroup$
  • $\begingroup$ (+1) I did, or at least started, something like this, but didn't solve the parsing-expressions-as-entries problem. Given both MATLink` and Control-comma/return, it seemed just an academic exercise, anyway, and I stopped. Still an interesting answer. $\endgroup$ – Michael E2 Jan 22 '17 at 17:45
  • $\begingroup$ BTW don't you want RuleDelayed to localize the pattern name b inside ToExpression[] in the CellEvaluationFunction? $\endgroup$ – Michael E2 Jan 22 '17 at 17:47
  • $\begingroup$ 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. $\endgroup$ – Carl Woll Jan 22 '17 at 18:06
  • $\begingroup$ 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.) $\endgroup$ – Michael E2 Jan 22 '17 at 18:44
5
$\begingroup$

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}} *)
$\endgroup$
  • $\begingroup$ Nice. Thanks a lot! $\endgroup$ – henry Jan 21 '17 at 11:09
3
$\begingroup$

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

$\endgroup$

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.