mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-25 15:07:57 +00:00
Merge pull request #617 from FSMaxB/implicit-mult-totex
Options for `toTex` and `toString` output of implicit multiplications
This commit is contained in:
commit
f67df0fbfe
@ -197,7 +197,8 @@ The functions `toTex` and `toString` accept an `options` argument to customise o
|
||||
```js
|
||||
{
|
||||
parenthesis: 'keep', // parenthesis option
|
||||
handler: someHandler // handler to change the output
|
||||
handler: someHandler, // handler to change the output
|
||||
implicit: 'hide' // how to treat implicit multiplication
|
||||
}
|
||||
```
|
||||
|
||||
@ -325,3 +326,20 @@ var expression = math.parse('binomial(2,1)');
|
||||
var latex = expression.toTex({handler: customLaTeX});
|
||||
//latex now contains "\binom{2}{1}"
|
||||
```
|
||||
|
||||
### Implicit multiplication
|
||||
|
||||
You can change the way that implicit multiplication is converted to a string or LaTeX. The two options are `hide`, to not show a multiplication operator for implicit multiplication and `show` to show it.
|
||||
|
||||
Example:
|
||||
```js
|
||||
var node = math.parse('2a');
|
||||
|
||||
node.toString(); //'2 a'
|
||||
node.toString({implicit: 'hide'}); //'2 a'
|
||||
node.toString({implicit: 'show'}); //'2 * a'
|
||||
|
||||
node.toTex(); //'2~ a'
|
||||
node.toTex({implicit: 'hide'}); //'2~ a'
|
||||
node.toTex({implicit: 'show'}); //'2\\cdot a'
|
||||
```
|
||||
|
||||
@ -65,13 +65,18 @@
|
||||
<input type="radio" name="parenthesis" value="keep" onclick="parenthesis = 'keep'; expr.oninput();" checked>keep
|
||||
<input type="radio" name="parenthesis" value="auto" onclick="parenthesis = 'auto'; expr.oninput();">auto
|
||||
<input type="radio" name="parenthesis" value="all" onclick="parenthesis = 'all'; expr.oninput();">all
|
||||
<br/>
|
||||
<b>Implicit multiplication:</b>
|
||||
<input type="radio" name="implicit" value="hide" onclick="implicit = 'hide'; expr.oninput();" checked>hide
|
||||
<input type="radio" name="implicit" value="show" onclick="implicit = 'show'; expr.oninput();">show
|
||||
|
||||
|
||||
<script>
|
||||
var expr = document.getElementById('expr'),
|
||||
pretty = document.getElementById('pretty'),
|
||||
result = document.getElementById('result'),
|
||||
parenthesis = 'keep';
|
||||
parenthesis = 'keep',
|
||||
implicit = 'hide';
|
||||
|
||||
// initialize with an example expression
|
||||
expr.value = 'sqrt(75 / 3) + det([[-1, 2], [3, 1]]) - sin(pi / 4)^2';
|
||||
@ -94,7 +99,7 @@
|
||||
|
||||
try {
|
||||
// export the expression to LaTeX
|
||||
var latex = node ? node.toTex({parenthesis: parenthesis}) : '';
|
||||
var latex = node ? node.toTex({parenthesis: parenthesis, implicit: implicit}) : '';
|
||||
console.log('LaTeX expression:', latex);
|
||||
|
||||
// display and re-render the expression
|
||||
|
||||
@ -17,8 +17,9 @@ function factory (type, config, load, typed, math) {
|
||||
* @param {string} op Operator name, for example '+'
|
||||
* @param {string} fn Function name, for example 'add'
|
||||
* @param {Node[]} args Operator arguments
|
||||
* @param {boolean} implicit Is this an implicit multiplication?
|
||||
*/
|
||||
function OperatorNode(op, fn, args) {
|
||||
function OperatorNode(op, fn, args, implicit) {
|
||||
if (!(this instanceof OperatorNode)) {
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
}
|
||||
@ -35,6 +36,7 @@ function factory (type, config, load, typed, math) {
|
||||
throw new TypeError('Array containing Nodes expected for parameter "args"');
|
||||
}
|
||||
|
||||
this.implicit = (implicit === true);
|
||||
this.op = op;
|
||||
this.fn = fn;
|
||||
this.args = args || [];
|
||||
@ -279,6 +281,7 @@ function factory (type, config, load, typed, math) {
|
||||
*/
|
||||
OperatorNode.prototype._toString = function (options) {
|
||||
var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep';
|
||||
var implicit = (options && options.implicit) ? options.implicit : 'hide';
|
||||
var args = this.args;
|
||||
var parens = calculateNecessaryParentheses(this, parenthesis, args, false);
|
||||
|
||||
@ -311,6 +314,10 @@ function factory (type, config, load, typed, math) {
|
||||
rhs = '(' + rhs + ')';
|
||||
}
|
||||
|
||||
if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit == 'hide')) {
|
||||
return lhs + ' ' + rhs;
|
||||
}
|
||||
|
||||
return lhs + ' ' + this.op + ' ' + rhs;
|
||||
|
||||
default:
|
||||
@ -326,6 +333,7 @@ function factory (type, config, load, typed, math) {
|
||||
*/
|
||||
OperatorNode.prototype._toTex = function (options) {
|
||||
var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep';
|
||||
var implicit = (options && options.implicit) ? options.implicit : 'hide';
|
||||
var args = this.args;
|
||||
var parens = calculateNecessaryParentheses(this, parenthesis, args, true);
|
||||
var op = latex.operators[this.fn];
|
||||
@ -384,6 +392,10 @@ function factory (type, config, load, typed, math) {
|
||||
case 'OperatorNode:divide':
|
||||
lhsTex = '\\left(' + lhsTex + '\\right)';
|
||||
}
|
||||
case 'OperatorNode:multiply':
|
||||
if (this.implicit && (implicit === 'hide')) {
|
||||
return lhsTex + '~' + rhsTex;
|
||||
}
|
||||
}
|
||||
return lhsTex + op + rhsTex;
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ function factory (type, config, load, typed) {
|
||||
* @override
|
||||
*/
|
||||
ParenthesisNode.prototype._toString = function(options) {
|
||||
if ((!options) || (options && options.parenthesis === 'keep')) {
|
||||
if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) {
|
||||
return '(' + this.content.toString(options) + ')';
|
||||
}
|
||||
return this.content.toString(options);
|
||||
@ -101,7 +101,7 @@ function factory (type, config, load, typed) {
|
||||
* @override
|
||||
*/
|
||||
ParenthesisNode.prototype._toTex = function(options) {
|
||||
if ((!options) || (options && options.parenthesis === 'keep')) {
|
||||
if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) {
|
||||
return '\\left(' + this.content.toTex(options) + '\\right)';
|
||||
}
|
||||
return this.content.toTex(options);
|
||||
|
||||
@ -896,7 +896,7 @@ function factory (type, config, load, typed) {
|
||||
// number: implicit multiplication like '(2+3)2'
|
||||
// parenthesis: implicit multiplication like '2(3+4)', '2[1,2,3]'
|
||||
last = parseUnary();
|
||||
node = new OperatorNode('*', 'multiply', [node, last]);
|
||||
node = new OperatorNode('*', 'multiply', [node, last], true /*implicit*/);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
|
||||
@ -505,4 +505,89 @@ describe('OperatorNode', function() {
|
||||
assert.equal(math.parse('1+(1+1)').toTex({parenthesis: 'auto'}), '1+1+1');
|
||||
});
|
||||
|
||||
it ('should stringify implicit multiplications', function () {
|
||||
var a = math.parse('4a');
|
||||
var b = math.parse('4 a');
|
||||
var c = math.parse('a b');
|
||||
var d = math.parse('2a b');
|
||||
var e = math.parse('a b c');
|
||||
var f = math.parse('(2+3)a');
|
||||
var g = math.parse('(2+3)2');
|
||||
var h = math.parse('2(3+4)');
|
||||
|
||||
assert.equal(a.toString(), a.toString({implicit: 'hide'}));
|
||||
assert.equal(a.toString({implicit: 'hide'}), '4 a');
|
||||
assert.equal(a.toString({implicit: 'show'}), '4 * a');
|
||||
|
||||
assert.equal(b.toString(), b.toString({implicit: 'hide'}));
|
||||
assert.equal(b.toString({implicit: 'hide'}), '4 a');
|
||||
assert.equal(b.toString({implicit: 'show'}), '4 * a');
|
||||
|
||||
assert.equal(c.toString(), c.toString({implicit: 'hide'}));
|
||||
assert.equal(c.toString({implicit: 'hide'}), 'a b');
|
||||
assert.equal(c.toString({implicit: 'show'}), 'a * b');
|
||||
|
||||
assert.equal(d.toString(), d.toString({implicit: 'hide'}));
|
||||
assert.equal(d.toString({implicit: 'hide'}), '2 a b');
|
||||
assert.equal(d.toString({implicit: 'show'}), '2 * a * b');
|
||||
|
||||
assert.equal(e.toString(), e.toString({implicit: 'hide'}));
|
||||
assert.equal(e.toString({implicit: 'hide'}), 'a b c');
|
||||
assert.equal(e.toString({implicit: 'show'}), 'a * b * c');
|
||||
|
||||
assert.equal(f.toString(), f.toString({implicit: 'hide'}));
|
||||
assert.equal(f.toString({implicit: 'hide'}), '(2 + 3) a');
|
||||
assert.equal(f.toString({implicit: 'show'}), '(2 + 3) * a');
|
||||
|
||||
assert.equal(g.toString(), g.toString({implicit: 'hide'}));
|
||||
assert.equal(g.toString({implicit: 'hide'}), '(2 + 3) 2');
|
||||
assert.equal(g.toString({implicit: 'show'}), '(2 + 3) * 2');
|
||||
|
||||
assert.equal(h.toString(), h.toString({implicit: 'hide'}));
|
||||
assert.equal(h.toString({implicit: 'hide'}), '2 (3 + 4)');
|
||||
assert.equal(h.toString({implicit: 'show'}), '2 * (3 + 4)');
|
||||
});
|
||||
|
||||
it ('should LaTeX implicit multiplications', function () {
|
||||
var a = math.parse('4a');
|
||||
var b = math.parse('4 a');
|
||||
var c = math.parse('a b');
|
||||
var d = math.parse('2a b');
|
||||
var e = math.parse('a b c');
|
||||
var f = math.parse('(2+3)a');
|
||||
var g = math.parse('(2+3)2');
|
||||
var h = math.parse('2(3+4)');
|
||||
|
||||
assert.equal(a.toTex(), a.toTex({implicit: 'hide'}));
|
||||
assert.equal(a.toTex({implicit: 'hide'}), '4~ a');
|
||||
assert.equal(a.toTex({implicit: 'show'}), '4\\cdot a');
|
||||
|
||||
assert.equal(b.toTex(), b.toTex({implicit: 'hide'}));
|
||||
assert.equal(b.toTex({implicit: 'hide'}), '4~ a');
|
||||
assert.equal(b.toTex({implicit: 'show'}), '4\\cdot a');
|
||||
|
||||
assert.equal(c.toTex(), c.toTex({implicit: 'hide'}));
|
||||
assert.equal(c.toTex({implicit: 'hide'}), ' a~\\mathrm{b}');
|
||||
assert.equal(c.toTex({implicit: 'show'}), ' a\\cdot\\mathrm{b}');
|
||||
|
||||
assert.equal(d.toTex(), d.toTex({implicit: 'hide'}));
|
||||
assert.equal(d.toTex({implicit: 'hide'}), '2~ a~\\mathrm{b}');
|
||||
assert.equal(d.toTex({implicit: 'show'}), '2\\cdot a\\cdot\\mathrm{b}');
|
||||
|
||||
assert.equal(e.toTex(), e.toTex({implicit: 'hide'}));
|
||||
assert.equal(e.toTex({implicit: 'hide'}), ' a~\\mathrm{b}~ c');
|
||||
assert.equal(e.toTex({implicit: 'show'}), ' a\\cdot\\mathrm{b}\\cdot c');
|
||||
|
||||
assert.equal(f.toTex(), f.toTex({implicit: 'hide'}));
|
||||
assert.equal(f.toTex({implicit: 'hide'}), '\\left(2+3\\right)~ a');
|
||||
assert.equal(f.toTex({implicit: 'show'}), '\\left(2+3\\right)\\cdot a');
|
||||
|
||||
assert.equal(g.toTex(), g.toTex({implicit: 'hide'}));
|
||||
assert.equal(g.toTex({implicit: 'hide'}), '\\left(2+3\\right)~2');
|
||||
assert.equal(g.toTex({implicit: 'show'}), '\\left(2+3\\right)\\cdot2');
|
||||
|
||||
assert.equal(h.toTex(), h.toTex({implicit: 'hide'}));
|
||||
assert.equal(h.toTex({implicit: 'hide'}), '2~\\left(3+4\\right)');
|
||||
assert.equal(h.toTex({implicit: 'show'}), '2\\cdot\\left(3+4\\right)');
|
||||
});
|
||||
});
|
||||
|
||||
@ -129,6 +129,7 @@ describe('ParenthesisNode', function() {
|
||||
var n = new ParenthesisNode(a);
|
||||
|
||||
assert.equal(n.toString(), '(1)');
|
||||
assert.equal(n.toString({}), '(1)');
|
||||
});
|
||||
|
||||
it ('should stringify a ParenthesisNode when not in keep mode', function () {
|
||||
@ -158,6 +159,7 @@ describe('ParenthesisNode', function() {
|
||||
var n = new ParenthesisNode(a);
|
||||
|
||||
assert.equal(n.toTex(), '\\left(1\\right)');
|
||||
assert.equal(n.toTex({}), '\\left(1\\right)');
|
||||
});
|
||||
|
||||
it ('should LaTeX a ParenthesisNode when not in keep mode', function () {
|
||||
|
||||
@ -1084,9 +1084,21 @@ describe('parse', function() {
|
||||
assert.deepEqual(parseAndEval('[1,2;3,4] [2,2]', {A: [[1,2], [3,4]]}), 4); // index, no multiplication
|
||||
});
|
||||
|
||||
it('should tell the OperatorNode about implicit multiplications', function() {
|
||||
assert.equal(parse('4a').implicit, true);
|
||||
assert.equal(parse('4 a').implicit, true);
|
||||
assert.equal(parse('a b').implicit, true);
|
||||
assert.equal(parse('2a b').implicit, true);
|
||||
assert.equal(parse('a b c').implicit, true);
|
||||
|
||||
assert.equal(parse('(2+3)a').implicit, true);
|
||||
assert.equal(parse('(2+3)2').implicit, true);
|
||||
assert.equal(parse('2(3+4)').implicit, true);
|
||||
});
|
||||
|
||||
it('should correctly order consecutive multiplications and implicit multiplications', function() {
|
||||
var node = parse('9km*3km');
|
||||
assert.equal(node.toString({parenthesis: 'all'}), '((9 * km) * 3) * km');
|
||||
assert.equal(node.toString({parenthesis: 'all'}), '((9 km) * 3) km');
|
||||
});
|
||||
|
||||
it('should throw an error when having an implicit multiplication between two numbers', function() {
|
||||
@ -1849,8 +1861,8 @@ describe('parse', function() {
|
||||
it('should correctly stringify a node tree', function() {
|
||||
assert.equal(parse('0').toString(), '0');
|
||||
assert.equal(parse('"hello"').toString(), '"hello"');
|
||||
assert.equal(parse('[1, 2 + 3i, 4]').toString(), '[1, 2 + 3 * i, 4]');
|
||||
assert.equal(parse('1/2a').toString(), '1 / 2 * a');
|
||||
assert.equal(parse('[1, 2 + 3i, 4]').toString(), '[1, 2 + 3 i, 4]');
|
||||
assert.equal(parse('1/2a').toString(), '1 / 2 a');
|
||||
});
|
||||
|
||||
it('should correctly stringify an index with dot notation', function() {
|
||||
|
||||
@ -83,6 +83,6 @@ describe('to', function() {
|
||||
|
||||
it('should LaTeX to', function () {
|
||||
var expression = math.parse('to(2cm,m)');
|
||||
assert.equal(expression.toTex(), '\\left(2\\cdot\\mathrm{cm}\\rightarrow\\mathrm{m}\\right)');
|
||||
assert.equal(expression.toTex(), '\\left(2~\\mathrm{cm}\\rightarrow\\mathrm{m}\\right)');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user