Replies: 7 comments 10 replies
-
|
We can discuss how to improve on this. Let's do that in the discussions section. |
Beta Was this translation helpful? Give feedback.
-
|
The upcoming journey seems to be long, very long... Then, let us state that some operations on integers are absolutely safe. These are: addition, division, multiplication. Then the corresponding simplification rules are: safeIntegerSimplification = [
{ l: "m1+m2", r: "forceSimplifyConstants(m1+m2)" },
{ l: "m1-m2", r: "forceSimplifyConstants(m1-m2)" },
{ l: "m1*m2", r: "forceSimplifyConstants(m1*m2)" },
];
function forceSimplifyConstantsInNode(node){
if(node.fn && node.fn.name === 'forceSimplifyConstants'){
return math.simplifyConstant(node.args[0]);
}
for(let i = 0; node.args && i < node.args.length; i++){
node.args[i] = forceSimplifyConstantsInNode(node.args[i]);
}
return node;
}Now we can deal with fractions, e.g. The problem sounds classic and should have been solved somehow - e.g. in Maxima. |
Beta Was this translation helpful? Give feedback.
-
|
I did a completely other attempt, my it didn't work for me (it runs forever). Maybe someone can find anything useful in it :) let mathjsRules = {};
mathjsRules.simplifyCarefully = [
{ l: 'ce1', r: 'carefullySimplifyConstants(ce1)', repeat: false },
mathjs_helpers.carefullySimplifyConstantsInNode,
];
let mathjs_helpers = {
carefullySimplifyConstantsInNode : function(node){
if(node.fn && node.fn.name === 'carefullySimplifyConstants'){
let simp = math.simplifyConstant(node.args[0]/*,{exactFractions:true}*/);
if (simp.toTex().length < 10){
return simp;
}
//Failure!
}
for(let i = 0; node.args && i < node.args.length; i++){
node.args[i] = mathjs_helpers.carefullySimplifyConstantsInNode(node.args[i]);
}
return node;
},
};
let e1 = math.parse('1+2+sqrt(3)+sqrt(4)');
math.simplify(e1).toTex();
math.simplify(e1,mathjsRules.simplifyCarefully, {repeat:false}).toTex(); |
Beta Was this translation helpful? Give feedback.
-
|
At this point, what's the best way to achieve the initial goal : do not simplify sqrt(2) but keep all other simplifications ? I saw the rule named I'm wondering about implementing a custom simplify with my own parser and
and after all, replace all symbols with their value Is there a better way ? making a customSimplifyConstant wrapper of simplifyConstant to replace it in rules (with perhaps two different wrappers for first call and second call, because simplifyConstant appears twice in rules list) ? |
Beta Was this translation helpful? Give feedback.
-
|
I tried something like import { fraction, isConstantNode, isFunctionNode, parse, simplify, ConstantNode } from 'mathjs'
import { almostEqual } from 'src/lib/utils/comparators'
let areRulesPatched = false
const squares = []
while (squares.length < 21) {
const n = squares.length
squares.push(n * n)
}
function simplifySqrt (node) {
try {
// On regarde si l’argument est un carré parfait après simplification/évaluation
const sqrtArg = node.args[0]
if (isConstantNode(sqrtArg)) {
const value = sqrtArg.evaluate()
if (typeof value === 'number' && value > 0) {
const n = Math.round(value)
const r = Math.round(Math.sqrt(n))
if (almostEqual(value, n)) {
// n est entier
if (almostEqual(r * r, n)) {
// carré parfait
return new ConstantNode(r)
}
let a = 1
let b = n
for (let i = Math.max(squares.length - 1, r); i > -1; i--) {
const i2 = squares[i]
if (b % i2 === 0) {
b = b / i2
a = a * i
}
}
if (a > 1) {
return parse(`${a}sqrt(${b})`)
}
// l'entier ne peut pas être simplifié, on laisse intact
return node
}
// test p/q avec p & q entiers
const frac = fraction(value)
const p = Number(frac.n)
const q = Number(frac.d)
if (p >= 0 && Number.isInteger(p) && Number.isInteger(q)) {
const rp = Math.round(Math.sqrt(p))
const rq = Math.round(Math.sqrt(q))
if (rq * rq === q) {
if (rp * rp === p) {
return parse(`${rp}/${rq}`)
}
// reste un radical au numérateur
return parse(`sqrt(${p})/${rq}`)
}
}
}
}
} catch (error) {
console.error(error)
}
// pas de simplification
return node
}
function patchSimplifyConstant () {
if (areRulesPatched) return console.error(Error('rules have been already patched'))
areRulesPatched = true
const rules = simplify.rules
const simplifyConstant = rules.find(r => typeof r === 'function' && r.name === 'simplifyConstant')
if (!simplifyConstant) {
console.warn('Rule simplifyConstant not found, rules patch ignored')
return
}
const customSimplifyConstant = function customSimplifyConstant (node) {
if (isFunctionNode(node) && node.fn.name === 'sqrt') {
const sqrtArg = node.args[0]
if (isConstantNode(sqrtArg)) {
return simplifySqrt(node)
}
// sinon il faut simplifier l'argument
const simplifiedArg = simplifyConstant(sqrtArg)
if (simplifiedArg !== sqrtArg) {
const clone = node.clone()
clone.args = [simplifiedArg]
if (isConstantNode(simplifiedArg)) {
return simplifySqrt(clone)
}
// sinon y'a rien à faire de plus
return clone
}
}
return simplifyConstant(node)
}
simplify.rules = simplify.rules.map(r => {
return typeof r === 'function' && r.name === 'simplifyConstant'
? customSimplifyConstant
: r
})
}
function customSimplify (expr, simplifyOptions) {
if (!areRulesPatched) {
patchSimplifyConstant()
}
return simplify(parse(expr), {}, simplifyOptions)
}It works to preserve There is two uses of simplifyConstant in simplify.rules, is it possible to replace the sqrt arg by a symbol on the first use (of my customSimplifyConstant) and then replace the symbol by the original node on the second one ? |
Beta Was this translation helpful? Give feedback.
-
|
One thought on the specific case of sqrt:
More general thoughts on function-specific simplification in general:
Now, none of the above principles then allows things like Hope these ideas help a future implementor here. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for all your suggestions. I finally had what I wanted, but it's really complicated
You can see it there, but it's probably still buggy ! it works with this unit test, feel free to suggest more complicated expression to test. I did others tries before, as you can see on this history But all this is a really complicated workaround, an implementation of your suggesion (property |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
The function
simplifyalways evaluatessqrtinstead of leaving some forms such assqrt(2)unchanged.To Reproduce
Simplify the following:
The result is a
ConstantNodewith value1.4142135623730951, but I expected aFunctionNodewhere thesqrtfunction was not applied.When its argument is an exact, it feels like
sqrtshould only simplify to a constant if the result is an exact integer. This would be akin todividethat simplifies fractions, but does not apply division if the result is not an integer.Beta Was this translation helpful? Give feedback.
All reactions