forked from profectus/Profectus
Support variable anywhere in formula
This commit is contained in:
parent
c8283a7043
commit
5f3dd1162d
2 changed files with 189 additions and 65 deletions
|
@ -27,6 +27,22 @@ function unrefFormulaSource(value: Formula | ProcessedComputable<DecimalSource>)
|
||||||
return value instanceof Formula ? value.evaluate() : unref(value);
|
return value instanceof Formula ? value.evaluate() : unref(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isVariableFormula(value: FormulaSource): value is VariableFormula {
|
||||||
|
return value instanceof Formula && value.hasVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateInvertibility(...inputs: FormulaSource[]) {
|
||||||
|
const invertible = !inputs.some(input => input instanceof Formula && !input.invertible);
|
||||||
|
const hasVariable =
|
||||||
|
invertible &&
|
||||||
|
inputs.filter(input => input instanceof Formula && input.invertible && input.hasVariable)
|
||||||
|
.length === 1;
|
||||||
|
return {
|
||||||
|
invertible,
|
||||||
|
hasVariable
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default class Formula {
|
export default class Formula {
|
||||||
public readonly invertible: boolean;
|
public readonly invertible: boolean;
|
||||||
public readonly hasVariable: boolean;
|
public readonly hasVariable: boolean;
|
||||||
|
@ -533,7 +549,8 @@ export default class Formula {
|
||||||
public neg() {
|
public neg() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().neg(),
|
() => this.evaluate().neg(),
|
||||||
value => Decimal.neg(value)
|
value => Decimal.neg(value),
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,11 +594,17 @@ export default class Formula {
|
||||||
public add(this: Formula, value: FormulaSource): Formula;
|
public add(this: Formula, value: FormulaSource): Formula;
|
||||||
public add(value: FormulaSource) {
|
public add(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().add(unrefFormulaSource(v)),
|
() => this.evaluate().add(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.sub(value, unrefFormulaSource(v))
|
Decimal.sub(
|
||||||
|
value,
|
||||||
|
isVariableFormula(this) ? unrefFormulaSource(v) : this.evaluate()
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,11 +618,17 @@ export default class Formula {
|
||||||
public sub(this: Formula, value: FormulaSource): Formula;
|
public sub(this: Formula, value: FormulaSource): Formula;
|
||||||
public sub(value: FormulaSource) {
|
public sub(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().sub(unrefFormulaSource(v)),
|
() => this.evaluate().sub(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.add(value, unrefFormulaSource(v))
|
Decimal.add(
|
||||||
|
value,
|
||||||
|
isVariableFormula(this) ? unrefFormulaSource(v) : this.evaluate()
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,11 +648,17 @@ export default class Formula {
|
||||||
public mul(this: Formula, value: FormulaSource): Formula;
|
public mul(this: Formula, value: FormulaSource): Formula;
|
||||||
public mul(value: FormulaSource) {
|
public mul(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().mul(unrefFormulaSource(v)),
|
() => this.evaluate().mul(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.div(value, unrefFormulaSource(v))
|
Decimal.div(
|
||||||
|
value,
|
||||||
|
isVariableFormula(this) ? unrefFormulaSource(v) : this.evaluate()
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,11 +678,17 @@ export default class Formula {
|
||||||
public div(this: Formula, value: FormulaSource): Formula;
|
public div(this: Formula, value: FormulaSource): Formula;
|
||||||
public div(value: FormulaSource) {
|
public div(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().div(unrefFormulaSource(v)),
|
() => this.evaluate().div(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.mul(value, unrefFormulaSource(v))
|
Decimal.mul(
|
||||||
|
value,
|
||||||
|
isVariableFormula(this) ? unrefFormulaSource(v) : this.evaluate()
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,7 +715,8 @@ export default class Formula {
|
||||||
public recip() {
|
public recip() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().recip(),
|
() => this.evaluate().recip(),
|
||||||
!this.invertible ? undefined : value => Decimal.recip(value)
|
this.invertible ? value => Decimal.recip(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,7 +787,8 @@ export default class Formula {
|
||||||
public log10() {
|
public log10() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().log10(),
|
() => this.evaluate().log10(),
|
||||||
!this.invertible ? undefined : value => Decimal.pow10(value)
|
this.invertible ? value => Decimal.pow10(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,11 +796,16 @@ export default class Formula {
|
||||||
public log(this: Formula, value: FormulaSource): Formula;
|
public log(this: Formula, value: FormulaSource): Formula;
|
||||||
public log(value: FormulaSource) {
|
public log(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().log(unrefFormulaSource(v)),
|
() => this.evaluate().log(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.pow(unrefFormulaSource(v), value)
|
isVariableFormula(this)
|
||||||
|
? Decimal.pow(unrefFormulaSource(v), value)
|
||||||
|
: Decimal.root(this.evaluate(), value)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +820,8 @@ export default class Formula {
|
||||||
public log2() {
|
public log2() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().log2(),
|
() => this.evaluate().log2(),
|
||||||
!this.invertible ? undefined : value => Decimal.pow(2, value)
|
this.invertible ? value => Decimal.pow(2, value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +830,8 @@ export default class Formula {
|
||||||
public ln() {
|
public ln() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().ln(),
|
() => this.evaluate().ln(),
|
||||||
!this.invertible ? undefined : value => Decimal.exp(value)
|
this.invertible ? value => Decimal.exp(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,11 +839,16 @@ export default class Formula {
|
||||||
public pow(this: Formula, value: FormulaSource): Formula;
|
public pow(this: Formula, value: FormulaSource): Formula;
|
||||||
public pow(value: FormulaSource) {
|
public pow(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().pow(unrefFormulaSource(v)),
|
() => this.evaluate().pow(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.root(value, unrefFormulaSource(v))
|
isVariableFormula(this)
|
||||||
|
? Decimal.root(value, unrefFormulaSource(v))
|
||||||
|
: Decimal.ln(value).div(Decimal.ln(this.evaluate()))
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,7 +857,8 @@ export default class Formula {
|
||||||
public pow10() {
|
public pow10() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().pow10(),
|
() => this.evaluate().pow10(),
|
||||||
!this.invertible ? undefined : value => Decimal.root(value, 10)
|
this.invertible ? value => Decimal.root(value, 10) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,11 +866,16 @@ export default class Formula {
|
||||||
public pow_base(this: Formula, value: FormulaSource): Formula;
|
public pow_base(this: Formula, value: FormulaSource): Formula;
|
||||||
public pow_base(value: FormulaSource) {
|
public pow_base(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().pow_base(unrefFormulaSource(v)),
|
() => this.evaluate().pow_base(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.root(unrefFormulaSource(v), value)
|
isVariableFormula(this)
|
||||||
|
? Decimal.ln(value).div(unrefFormulaSource(v))
|
||||||
|
: Decimal.root(unrefFormulaSource(v), value)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,11 +883,16 @@ export default class Formula {
|
||||||
public root(this: Formula, value: FormulaSource): Formula;
|
public root(this: Formula, value: FormulaSource): Formula;
|
||||||
public root(value: FormulaSource) {
|
public root(value: FormulaSource) {
|
||||||
const v = processFormulaSource(value);
|
const v = processFormulaSource(value);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, value);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().root(unrefFormulaSource(v)),
|
() => this.evaluate().root(unrefFormulaSource(v)),
|
||||||
(v instanceof Formula && !v.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value => Decimal.pow(value, unrefFormulaSource(v))
|
isVariableFormula(this)
|
||||||
|
? Decimal.root(value, Decimal.recip(unrefFormulaSource(v)))
|
||||||
|
: Decimal.ln(value).div(Decimal.ln(this.evaluate()).recip())
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -846,7 +912,8 @@ export default class Formula {
|
||||||
public exp() {
|
public exp() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().exp(),
|
() => this.evaluate().exp(),
|
||||||
!this.invertible ? undefined : value => Decimal.ln(value)
|
this.invertible ? value => Decimal.ln(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,21 +953,21 @@ export default class Formula {
|
||||||
) {
|
) {
|
||||||
const heightValue = processFormulaSource(height);
|
const heightValue = processFormulaSource(height);
|
||||||
const payloadValue = processFormulaSource(payload);
|
const payloadValue = processFormulaSource(payload);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, height, payload);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() =>
|
() =>
|
||||||
this.evaluate().tetrate(
|
this.evaluate().tetrate(
|
||||||
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber(),
|
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber(),
|
||||||
unrefFormulaSource(payloadValue)
|
unrefFormulaSource(payloadValue)
|
||||||
),
|
),
|
||||||
(heightValue instanceof Formula && !heightValue.invertible) ||
|
invertible
|
||||||
(payloadValue instanceof Formula && !payloadValue.invertible) ||
|
? value =>
|
||||||
!this.invertible
|
|
||||||
? undefined
|
|
||||||
: value =>
|
|
||||||
Decimal.slog(
|
Decimal.slog(
|
||||||
value,
|
value,
|
||||||
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber()
|
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber()
|
||||||
)
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,22 +983,22 @@ export default class Formula {
|
||||||
) {
|
) {
|
||||||
const heightValue = processFormulaSource(height);
|
const heightValue = processFormulaSource(height);
|
||||||
const payloadValue = processFormulaSource(payload);
|
const payloadValue = processFormulaSource(payload);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, height, payload);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() =>
|
() =>
|
||||||
this.evaluate().iteratedexp(
|
this.evaluate().iteratedexp(
|
||||||
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber(),
|
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber(),
|
||||||
new Decimal(unrefFormulaSource(payloadValue))
|
new Decimal(unrefFormulaSource(payloadValue))
|
||||||
),
|
),
|
||||||
(heightValue instanceof Formula && !heightValue.invertible) ||
|
invertible
|
||||||
(payloadValue instanceof Formula && !payloadValue.invertible) ||
|
? value =>
|
||||||
!this.invertible
|
|
||||||
? undefined
|
|
||||||
: value =>
|
|
||||||
Decimal.iteratedlog(
|
Decimal.iteratedlog(
|
||||||
value,
|
value,
|
||||||
Math.E,
|
Math.E,
|
||||||
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber()
|
Decimal.min(1e308, unrefFormulaSource(heightValue)).toNumber()
|
||||||
)
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -948,16 +1015,18 @@ export default class Formula {
|
||||||
|
|
||||||
public slog(base: FormulaSource = 10) {
|
public slog(base: FormulaSource = 10) {
|
||||||
const baseValue = processFormulaSource(base);
|
const baseValue = processFormulaSource(base);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, base);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() =>
|
() =>
|
||||||
this.evaluate().slog(Decimal.min(1e308, unrefFormulaSource(baseValue)).toNumber()),
|
this.evaluate().slog(Decimal.min(1e308, unrefFormulaSource(baseValue)).toNumber()),
|
||||||
(baseValue instanceof Formula && !baseValue.invertible) || !this.invertible
|
invertible
|
||||||
? undefined
|
? value =>
|
||||||
: value =>
|
|
||||||
Decimal.tetrate(
|
Decimal.tetrate(
|
||||||
value,
|
value,
|
||||||
Decimal.min(1e308, unrefFormulaSource(baseValue)).toNumber()
|
Decimal.min(1e308, unrefFormulaSource(baseValue)).toNumber()
|
||||||
)
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,22 +1044,22 @@ export default class Formula {
|
||||||
public layeradd(diff: FormulaSource, base: FormulaSource) {
|
public layeradd(diff: FormulaSource, base: FormulaSource) {
|
||||||
const diffValue = processFormulaSource(diff);
|
const diffValue = processFormulaSource(diff);
|
||||||
const baseValue = processFormulaSource(base);
|
const baseValue = processFormulaSource(base);
|
||||||
|
const { invertible, hasVariable } = calculateInvertibility(this, diff, base);
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() =>
|
() =>
|
||||||
this.evaluate().layeradd(
|
this.evaluate().layeradd(
|
||||||
Decimal.min(1e308, unrefFormulaSource(diffValue)).toNumber(),
|
Decimal.min(1e308, unrefFormulaSource(diffValue)).toNumber(),
|
||||||
unrefFormulaSource(baseValue)
|
unrefFormulaSource(baseValue)
|
||||||
),
|
),
|
||||||
(diffValue instanceof Formula && !diffValue.invertible) ||
|
invertible
|
||||||
(diffValue instanceof Formula && !diffValue.invertible) ||
|
? value =>
|
||||||
!this.invertible
|
|
||||||
? undefined
|
|
||||||
: value =>
|
|
||||||
Decimal.layeradd(
|
Decimal.layeradd(
|
||||||
value,
|
value,
|
||||||
Decimal.min(1e308, unrefFormulaSource(diffValue)).negate().toNumber(),
|
Decimal.min(1e308, unrefFormulaSource(diffValue)).negate().toNumber(),
|
||||||
unrefFormulaSource(baseValue)
|
unrefFormulaSource(baseValue)
|
||||||
)
|
)
|
||||||
|
: undefined,
|
||||||
|
hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,7 +1068,8 @@ export default class Formula {
|
||||||
public lambertw() {
|
public lambertw() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().lambertw(),
|
() => this.evaluate().lambertw(),
|
||||||
!this.invertible ? undefined : value => Decimal.pow(Math.E, value).times(value)
|
this.invertible ? value => Decimal.pow(Math.E, value).times(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,7 +1078,8 @@ export default class Formula {
|
||||||
public ssqrt() {
|
public ssqrt() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().ssqrt(),
|
() => this.evaluate().ssqrt(),
|
||||||
!this.invertible ? undefined : value => Decimal.tetrate(value, 2)
|
this.invertible ? value => Decimal.tetrate(value, 2) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1031,7 +1102,8 @@ export default class Formula {
|
||||||
public sin() {
|
public sin() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().sin(),
|
() => this.evaluate().sin(),
|
||||||
!this.invertible ? undefined : value => Decimal.asin(value)
|
this.invertible ? value => Decimal.asin(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,7 +1112,8 @@ export default class Formula {
|
||||||
public cos() {
|
public cos() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().cos(),
|
() => this.evaluate().cos(),
|
||||||
!this.invertible ? undefined : value => Decimal.acos(value)
|
this.invertible ? value => Decimal.acos(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1049,7 +1122,8 @@ export default class Formula {
|
||||||
public tan() {
|
public tan() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().tan(),
|
() => this.evaluate().tan(),
|
||||||
!this.invertible ? undefined : value => Decimal.atan(value)
|
this.invertible ? value => Decimal.atan(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,7 +1132,8 @@ export default class Formula {
|
||||||
public asin() {
|
public asin() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().asin(),
|
() => this.evaluate().asin(),
|
||||||
!this.invertible ? undefined : value => Decimal.sin(value)
|
this.invertible ? value => Decimal.sin(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1067,7 +1142,8 @@ export default class Formula {
|
||||||
public acos() {
|
public acos() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().acos(),
|
() => this.evaluate().acos(),
|
||||||
!this.invertible ? undefined : value => Decimal.cos(value)
|
this.invertible ? value => Decimal.cos(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,7 +1152,8 @@ export default class Formula {
|
||||||
public atan() {
|
public atan() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().atan(),
|
() => this.evaluate().atan(),
|
||||||
!this.invertible ? undefined : value => Decimal.tan(value)
|
this.invertible ? value => Decimal.tan(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1085,7 +1162,8 @@ export default class Formula {
|
||||||
public sinh() {
|
public sinh() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().sinh(),
|
() => this.evaluate().sinh(),
|
||||||
!this.invertible ? undefined : value => Decimal.asinh(value)
|
this.invertible ? value => Decimal.asinh(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,7 +1172,8 @@ export default class Formula {
|
||||||
public cosh() {
|
public cosh() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().cosh(),
|
() => this.evaluate().cosh(),
|
||||||
!this.invertible ? undefined : value => Decimal.acosh(value)
|
this.invertible ? value => Decimal.acosh(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1103,7 +1182,8 @@ export default class Formula {
|
||||||
public tanh() {
|
public tanh() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().tanh(),
|
() => this.evaluate().tanh(),
|
||||||
!this.invertible ? undefined : value => Decimal.atanh(value)
|
this.invertible ? value => Decimal.atanh(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1112,7 +1192,8 @@ export default class Formula {
|
||||||
public asinh() {
|
public asinh() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().asinh(),
|
() => this.evaluate().asinh(),
|
||||||
!this.invertible ? undefined : value => Decimal.sinh(value)
|
this.invertible ? value => Decimal.sinh(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,7 +1202,8 @@ export default class Formula {
|
||||||
public acosh() {
|
public acosh() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().acosh(),
|
() => this.evaluate().acosh(),
|
||||||
!this.invertible ? undefined : value => Decimal.cosh(value)
|
this.invertible ? value => Decimal.cosh(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,7 +1212,8 @@ export default class Formula {
|
||||||
public atanh() {
|
public atanh() {
|
||||||
return new Formula(
|
return new Formula(
|
||||||
() => this.evaluate().atanh(),
|
() => this.evaluate().atanh(),
|
||||||
!this.invertible ? undefined : value => Decimal.tanh(value)
|
this.invertible ? value => Decimal.tanh(value) : undefined,
|
||||||
|
this.hasVariable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,13 +182,12 @@ const nonInvertibleOneParamFunctionNames = [
|
||||||
["layeradd10"]
|
["layeradd10"]
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const invertibleTwoParamFunctionNames = [["tetrate"]] as const;
|
const invertibleTwoParamFunctionNames = [["tetrate"], ["layeradd"]] as const;
|
||||||
|
|
||||||
const nonInvertibleTwoParamFunctionNames = [
|
const nonInvertibleTwoParamFunctionNames = [
|
||||||
["clamp"],
|
["clamp"],
|
||||||
["iteratedexp"],
|
["iteratedexp"],
|
||||||
["iteratedlog"],
|
["iteratedlog"],
|
||||||
["layeradd"],
|
|
||||||
["pentate"]
|
["pentate"]
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
@ -361,5 +360,47 @@ describe("Creating Formulas", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Inverting calculates the value of the variable", () => {
|
||||||
|
let variable: Formula;
|
||||||
|
let constant: Formula;
|
||||||
|
beforeAll(() => {
|
||||||
|
variable = Formula.variable(2);
|
||||||
|
constant = Formula.constant(3);
|
||||||
|
});
|
||||||
|
invertibleOneParamFunctionNames.flat().forEach(name =>
|
||||||
|
describe(name, () => {
|
||||||
|
test(`${name}(var, const).invert()`, () => {
|
||||||
|
const formula = Formula[name](variable, constant);
|
||||||
|
const result = formula.evaluate();
|
||||||
|
expect(formula.invert(result)).toSatisfy(compare_tolerance(2));
|
||||||
|
});
|
||||||
|
test(`${name}(const, var).invert()`, () => {
|
||||||
|
const formula = Formula[name](constant, variable);
|
||||||
|
const result = formula.evaluate();
|
||||||
|
expect(formula.invert(result)).toSatisfy(compare_tolerance(2));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
invertibleTwoParamFunctionNames.flat().forEach(name =>
|
||||||
|
describe(name, () => {
|
||||||
|
test(`${name}(var, const, const).invert()`, () => {
|
||||||
|
const formula = Formula[name](variable, constant, constant);
|
||||||
|
const result = formula.evaluate();
|
||||||
|
expect(formula.invert(result)).toSatisfy(compare_tolerance(2));
|
||||||
|
});
|
||||||
|
test(`${name}(const, var, const).invert()`, () => {
|
||||||
|
const formula = Formula[name](constant, variable, constant);
|
||||||
|
const result = formula.evaluate();
|
||||||
|
expect(formula.invert(result)).toSatisfy(compare_tolerance(2));
|
||||||
|
});
|
||||||
|
test(`${name}(const, const, var).invert()`, () => {
|
||||||
|
const formula = Formula[name](constant, constant, variable);
|
||||||
|
const result = formula.evaluate();
|
||||||
|
expect(formula.invert(result)).toSatisfy(compare_tolerance(2));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue