M2
M2 copied to clipboard
Feature request: cdot or ⋅ as a binary operator
Currently we have a number of unicode synonyms defined in exports.m2. I think it would be useful to introduce the interpuct ($\cdot$) as a binary operator. This could be implemented as a synonym to a binary keyword cdot (similar to and, or, etc. but bound to a top-level method).
However, it would even be more interesting if M2-mode (and other editors) could automatically convert \cdot to $\cdot$ similar to, for instance, in agda-mode, and we could freely type C⋅D (without spaces) and have M2 recognize this.
This would be pretty straightforward, mostly duplicating sections related to and in the interpreter, but there are two tricky things:
- What's the best way to allow installing methods from top-level?
- How do we parse
⋅as a keyword operator in the interpreter so thatC⋅Dworks?
The main applications for this is intersection product and of course dot product of vectors. If this goes well, I think replacing @@ with circ and $\circ$ would be amazing!
This is of course related to #1069 for working with unicode characters. @pzinn have you tried something like this?
What would the precedence be? Maybe between +/-/++ and **?
M-x set-input-method followed by TeX already gives us the ability in Emacs to enter · using \cdot!
Edit: This isn't a good solution because it also changes the behavior of _ and ^ so that they trigger inputting little subscript and superscript characters.
I played around with this and it's pretty straightforward to add:
diff --git a/M2/Macaulay2/d/actors5.d b/M2/Macaulay2/d/actors5.d
index fdde6bcd9a..821f671d57 100644
--- a/M2/Macaulay2/d/actors5.d
+++ b/M2/Macaulay2/d/actors5.d
@@ -198,6 +198,9 @@ setup(AmpersandS,ampersandfun);
hathatfun(lhs:Code,rhs:Code):Expr := binarymethod(lhs,rhs,HatHatS);
setup(HatHatS,hathatfun);
+interpunctfun(lhs:Code, rhs:Code):Expr := binarymethod(lhs, rhs, InterpunctS);
+setup(InterpunctS, interpunctfun);
+
Tildefun(rhs:Code):Expr := unarymethod(rhs,TildeS);
setuppostfix(TildeS,Tildefun);
diff --git a/M2/Macaulay2/d/binding.d b/M2/Macaulay2/d/binding.d
index a561f8249d..9640a02138 100644
--- a/M2/Macaulay2/d/binding.d
+++ b/M2/Macaulay2/d/binding.d
@@ -285,6 +285,8 @@ bumpPrecedence();
export MinusS := makeKeyword(unarybinaryleft("-")); -- also binary
export PlusS := makeKeyword(unarybinaryleft("+")); -- also binary
export PlusPlusS := makeKeyword(binaryleft("++"));
+bumpPrecedence();
+ export InterpunctS := makeKeyword(binaryleft("·"));
bumpPrecedence();
export StarStarS := makeKeyword(binaryleft("**"));
bumpPrecedence();
@@ -510,7 +512,8 @@ export opsWithBinaryMethod := array(SymbolClosure)(
PowerGreaterEqualS, UnderscoreGreaterEqualS,
PowerLessS, UnderscoreLessS,
PowerLessEqualS, UnderscoreLessEqualS,
- PowerStarStarS
+ PowerStarStarS,
+ InterpunctS
);
export opsWithUnaryMethod := array(SymbolClosure)(
StarS, MinusS, PlusS, LessLessS, QuestionQuestionS,
diff --git a/M2/Macaulay2/m2/exports.m2 b/M2/Macaulay2/m2/exports.m2
index c52ac919ae..c28facd05c 100644
--- a/M2/Macaulay2/m2/exports.m2
+++ b/M2/Macaulay2/m2/exports.m2
@@ -57,6 +57,7 @@ export {
"_>=",
"_<",
"_<=",
+ "·",
"Acknowledgement",
"AdditionalPaths",
"Adjacent",
It seems to then work out of the box:
i1 : Vector · Vector := (v, w) -> ((transpose v#0) * w#0)_(0, 0)
o1 = FunctionClosure[stdio:1:20-1:60]
o1 : FunctionClosure
i2 : vector {1,2,3} · vector {4, 5, 6}
o2 = 32
Fantastic! Is u·v (without spaces) parsed correctly? How about things like locate? (e.g. if you look at the pseudocode, is the location of the operator correct and everything after it correct, or is it off because of unicode?)
I think we should still add cdot (e.g. to be used from the terminal). I imagine a couple of other places also need to updated (e.g. for converting to latex or for expressions).
M-x set-input-methodfollowed byTeXalready gives us the ability in Emacs to enter · using\cdot!
This is a great tip! C-\ TeX also seems to work and after the first time C-\ alone will toggle it on and off.
However, it opens a can of worms: should we consider supporting tex input by default? e.g. should $x^2$ work? How about printing this way depending on compactMatrixForm?
Parsing without spaces doesn't work:
i4 : v·w
o4 = v·w
o4 : Symbol
But locate seems to work:
i6 : methods symbol ·
o6 = {0 => ((·, =), Type, Type) }
{1 => ((·, =), Thing, Thing)}
{2 => (·, Thing, Thing) }
{3 => (·, Vector, Vector) }
o6 : NumberedVerticalList
i7 : locate 3
o7 = stdio:1:20-1:60
o7 : FilePosition
i8 : code oo
o8 = stdio:1:20-1:60: --source code:
Vector · Vector := (v, w) -> ((transpose v#0) * w#0)_(0, 0)
That's not what I meant, is this output the same if you replace + with cdot?
i2 : peek locate (pseudocode functionBody(() -> 1 + 1))
o2 = FilePosition{stdio, 2, 45, 2, 58, 2, 51}
It ends at column 59 instead of 58, so I'm guessing that's coming from the extra byte in the Unicode character.
i2 : peek locate (pseudocode functionBody(() -> 1 · 1))
o2 = FilePosition{stdio, 2, 45, 2, 59, 2, 51}
Parsing without spaces doesn't work:
It would be ideal if we could get this to work, for instance A⊗B seems to parse correctly:
i25 : A⊗B
stdio:25:0:(3): error: no method for binary operator ** applied to objects:
A (of class Symbol)
** B (of class Symbol)
the reason ⊗ works (and more generally, a variety of mathematical symbols) is the following commits:
8936f64c85b7eddc83aef6e6c8fa3edff3cf28db
ecde3f8a77d02cef36b0e58352aa5089a8cf76db
Sadly this cdot is not a "mathematical" symbol -- its unicode doesn't start with 226 -- so the code there doesn't immediately apply. one could try to rewrite these commits to allow for general unicode symbols, but that will require some significant changes to the parser.
Thanks! This is very helpful. Taking a brief look, is it not possible to add cdot as an exception? I don't think there are too many of them.
why don't you use ⋅ for \cdot?
i1 : ascii "⋅"
o1 = {226, 139, 133}
Incidentally, if you want to see all characters starting with 226 (which contains a bunch of non mathematical symbols as well -- we could be more selective), try in the browser:
needsPackage "Text"; TABLE table(2^6,2^6,(i,j)->ascii{226,128+i,128+j})
v·w still won't work. This requires a change in the interpreter.
actually in your original post you used ·, not ·. why would you use the latter?
What difference does it make?
⋅ starts with 226 in UTF8, so there's no need to change existing code besides what @d-torrance did.
In emacs, open M2 then enter M-x set-input-method and type TeX. Then type ascii "\cdot". It'll be converted to this:
i1 : ascii "·"
o1 = {194, 183}
We want something that is easily usable.