FlatPlusOperation for future simplifications!
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
80d0dad63a
commit
64d5f11ff9
1 changed files with 176 additions and 0 deletions
|
@ -38,6 +38,7 @@ enum ASEType {
|
||||||
UNARY_OPERATION,
|
UNARY_OPERATION,
|
||||||
BINARY_OPERATION,
|
BINARY_OPERATION,
|
||||||
TERTIARY_OPERATION,
|
TERTIARY_OPERATION,
|
||||||
|
FLAT_PLUS_OPERATIONS
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -826,6 +827,170 @@ class BinaryOperation extends AbstractSyntaxElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to contain chains of + and - operations for simplification purposes
|
||||||
|
*/
|
||||||
|
class FlatPlusOperations extends AbstractSyntaxElement {
|
||||||
|
type = ASEType.FLAT_PLUS_OPERATIONS
|
||||||
|
|
||||||
|
constructor(elements, operators) {
|
||||||
|
if(this.operators.some(ope => ope != '+' && ope != '-'))
|
||||||
|
throw new Error(`Unallowed operators in flat plus operation: ${this.operators.filter(ope => ope != '+' && ope != '-').join(',')}.`)
|
||||||
|
if(this.operators.length != this.elements.length+1)
|
||||||
|
throw new Error(`Unmatched elements and error count.`)
|
||||||
|
this.elements = elements
|
||||||
|
this.operators = operators
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
evaluate(variables) {
|
||||||
|
let result = this.elements[0].evaluate(variables);
|
||||||
|
for(let i = 0; i < this.operators.length; i++)
|
||||||
|
if(this.operators[i] == '+')
|
||||||
|
result += this.elements[i+1].evaluate(variables)
|
||||||
|
else
|
||||||
|
result -= this.elements[i+1].evaluate(variables)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
simplify() {
|
||||||
|
let elements = this.elements.map(elem => elem.simplify())
|
||||||
|
let units = 0
|
||||||
|
let variablesNoms = {} // Polynom elements for each variable.
|
||||||
|
let others = {'-': [], '+': []}
|
||||||
|
let nome
|
||||||
|
for(let i = 0; i < elements.length; i++)
|
||||||
|
if(elements[i].isConstant())
|
||||||
|
if(i == 0 || this.operators[i-1] == '+')
|
||||||
|
units += elements[i].evaluate({})
|
||||||
|
else
|
||||||
|
units -= elements[i].evaluate({})
|
||||||
|
else if((nome = isNome(elements[i]))[0]) {
|
||||||
|
let [nom, variable, power] = nome
|
||||||
|
if(!(variable in variablesNoms))
|
||||||
|
variablesNoms[variable] = {}
|
||||||
|
if(variablesNoms[variable][power] == undefined)
|
||||||
|
variablesNoms[variable][power] = 0
|
||||||
|
if(i == 0 || this.operators[i-1] == '+')
|
||||||
|
variablesNoms[variable][power]++
|
||||||
|
else
|
||||||
|
variablesNoms[varName][power]--
|
||||||
|
} else if(elements[i] instanceof BinaryOperation && elements[i].ope == '*' &&
|
||||||
|
elements[i].leftHand.isConstant() && (nome = isNome(elements[i].rightHand instanceof Variable))[0]) {
|
||||||
|
// Simple constant by variable product
|
||||||
|
let number = elements[i].leftHand.evaluate({})
|
||||||
|
let [nom, variable, power] = nome
|
||||||
|
// Add to counter
|
||||||
|
if(!(variable in variablesNoms))
|
||||||
|
variablesNoms[variable] = {}
|
||||||
|
if(variablesNoms[variable][power] == undefined)
|
||||||
|
variablesNoms[variable][power] = 0
|
||||||
|
if(i == 0 || this.operators[i-1] == '+')
|
||||||
|
variablesNoms[variable][power] += number
|
||||||
|
else
|
||||||
|
variablesNoms[variable][power] -= number
|
||||||
|
} else if(elements[i] instanceof BinaryOperation && elements[i].ope == '*' &&
|
||||||
|
(nome = isNome(elements[i].leftHand))[0] && elements[i].rightHand.isConstant()) {
|
||||||
|
// Simple constant by variable product
|
||||||
|
let number = elements[i].rightHand.evaluate({})
|
||||||
|
let [nom, variable, power] = nome
|
||||||
|
// Add to counter
|
||||||
|
if(!(variable in variablesNoms))
|
||||||
|
variablesNoms[variable] = {}
|
||||||
|
if(variablesNoms[variable][power] == undefined)
|
||||||
|
variablesNoms[variable][power] = 0
|
||||||
|
if(i == 0 || this.operators[i-1] == '+')
|
||||||
|
variablesNoms[variable][power] += number
|
||||||
|
else
|
||||||
|
variablesNoms[variable][power] -= number
|
||||||
|
} else if(elements[i] instanceof BinaryOperation && elements[i].ope == '/' &&
|
||||||
|
(nome = isNome(elements[i].leftHand))[0] && elements[i].rightHand.isConstant()) {
|
||||||
|
// Simple constant by variable divided by constant
|
||||||
|
let number = elements[i].rightHand.evaluate({})
|
||||||
|
let [nom, variable, power] = nome
|
||||||
|
// Register in counter
|
||||||
|
if(!(variable in variablesNoms))
|
||||||
|
variablesNoms[variable] = {}
|
||||||
|
if(variablesNoms[variable][power] == undefined)
|
||||||
|
variablesNoms[variable][power] = 0
|
||||||
|
// Division so we remove from count
|
||||||
|
if(i == 0 || this.operators[i-1] == '+')
|
||||||
|
variablesNoms[variable][power] -= number.evaluate({})
|
||||||
|
else
|
||||||
|
variablesNoms[variable][power] += number.evaluate({})
|
||||||
|
} else {
|
||||||
|
let sign = this.operators[i-1]
|
||||||
|
let element = elements[i]
|
||||||
|
if(element instanceof UnaryOperation && element.ope == '-') {
|
||||||
|
// Negation, inverse signs
|
||||||
|
sign = sign == '+' ? '-' : '+'
|
||||||
|
element = element.element
|
||||||
|
}
|
||||||
|
others[sign] = element
|
||||||
|
}
|
||||||
|
// Creating new flat operation.
|
||||||
|
let newElements = [new NumberElement(units)] // Yes, I know units should be in last, but this simplifies the implementation a lot.
|
||||||
|
let newOperators = []
|
||||||
|
for(let variable in variablesNoms)
|
||||||
|
for(let power in Object.keys(variablesNoms[variable]).reverse()) {
|
||||||
|
power = parseFloat(power)
|
||||||
|
let times = variablesNoms[variable][nom]
|
||||||
|
if(power < 0) {
|
||||||
|
power = -power
|
||||||
|
newOperators.push('-')
|
||||||
|
} else
|
||||||
|
newOperators.push('+')
|
||||||
|
newElements.push(new Variable(variable))
|
||||||
|
if(power != 1)
|
||||||
|
newElements.push(new BinaryOperation(newElements.pop(), '^', new NumberElement(power)))
|
||||||
|
if(times != 1)
|
||||||
|
newElements.push(new BinaryOperation(new NumberElement(times), '*', newElements.pop()))
|
||||||
|
}
|
||||||
|
for(let sign in others)
|
||||||
|
for(let element of others[sign]) {
|
||||||
|
newOperators.push(sign)
|
||||||
|
newElements.push(element)
|
||||||
|
}
|
||||||
|
return new FlatPlusOperations(newElements, newOperators)
|
||||||
|
}
|
||||||
|
|
||||||
|
derivation(variable) {
|
||||||
|
return new FlatPlusOperations(this.elements.map(elem => elem.derivation(variable)), this.operators)
|
||||||
|
}
|
||||||
|
|
||||||
|
integral(variable) {
|
||||||
|
return new FlatPlusOperations(this.elements.map(elem => elem.integral(variable)), this.operators)
|
||||||
|
}
|
||||||
|
|
||||||
|
toEditableString() {
|
||||||
|
let ret = this.elements[0].toEditableString()
|
||||||
|
for(let i = 0; i < this.operators.length; i++) {
|
||||||
|
ret += ' ' + this.operators[i] + ' '
|
||||||
|
if(this.elements[i+1] instanceof BinaryOperation && Reference.BINARY_OPERATION_PRIORITY[this.elements[i+1].ope] < Reference.BINARY_OPERATION_PRIORITY['+'])
|
||||||
|
ret += `(${this.elements[i+1].toEditableString()})`
|
||||||
|
else
|
||||||
|
ret += this.elements[i+1].toEditableString()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
toLatex() {
|
||||||
|
let ret = this.elements[0].toLatex()
|
||||||
|
for(let i = 0; i < this.operators.length; i++) {
|
||||||
|
ret += ' ' + this.operators[i] + ' '
|
||||||
|
if(this.elements[i+1] instanceof BinaryOperation && Reference.BINARY_OPERATION_PRIORITY[this.elements[i+1].ope] < Reference.BINARY_OPERATION_PRIORITY['+'])
|
||||||
|
ret += `\\left(${this.elements[i+1].toLatex()}\\right)`
|
||||||
|
else
|
||||||
|
ret += this.elements[i+1].toLatex()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
isConstant() {
|
||||||
|
return this.elements.every(elem => elem.isConstant())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function simplifyFraction(num,den) {
|
function simplifyFraction(num,den) {
|
||||||
// More than gcd because it allows decimals fractions.
|
// More than gcd because it allows decimals fractions.
|
||||||
let mult = 1
|
let mult = 1
|
||||||
|
@ -846,6 +1011,17 @@ function simplifyFraction(num,den) {
|
||||||
return [num*mult/gcd, den*mult/gcd]
|
return [num*mult/gcd, den*mult/gcd]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isNome(element) {
|
||||||
|
// Checks if the elements is a part of a polynomial, which variable, and to which degree
|
||||||
|
if(element instanceof Variable)
|
||||||
|
return [true, element.variableName, 1]
|
||||||
|
else if(element instanceof BinaryOperation && element.ope == '^' && element.leftHand instanceof Variable && element.rightHand.isConstant())
|
||||||
|
return [true, element.leftHand.variableName, element.rightHand.evaluate({})]
|
||||||
|
else
|
||||||
|
return [false, '', 0]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Negation extends AbstractSyntaxElement {
|
class Negation extends AbstractSyntaxElement {
|
||||||
type = ASEType.NEGATION
|
type = ASEType.NEGATION
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue