forked from profectus/Profectus
Fix some tests
This commit is contained in:
parent
b3d61149c4
commit
fd925071e5
2 changed files with 61 additions and 26 deletions
|
@ -829,7 +829,9 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.internalInvertIntegral =
|
this.internalInvertIntegral =
|
||||||
this.internalHasVariable && variable?.isIntegralInvertible() ? invert : undefined;
|
this.internalHasVariable && variable?.isIntegralInvertible()
|
||||||
|
? invertIntegral
|
||||||
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Type predicate that this formula can be inverted. */
|
/** Type predicate that this formula can be inverted. */
|
||||||
|
@ -847,7 +849,10 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
|
|
||||||
/** Type predicate that this formula has an integral function that can be inverted. */
|
/** Type predicate that this formula has an integral function that can be inverted. */
|
||||||
isIntegralInvertible(): this is InvertibleIntegralFormula {
|
isIntegralInvertible(): this is InvertibleIntegralFormula {
|
||||||
return this.internalHasVariable && this.internalInvertIntegral != null;
|
return (
|
||||||
|
this.internalHasVariable &&
|
||||||
|
(this.internalInvertIntegral != null || this.internalEvaluate == null)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether or not this formula has a singular variable inside it, which can be accessed via {@link innermostVariable}. */
|
/** Whether or not this formula has a singular variable inside it, which can be accessed via {@link innermostVariable}. */
|
||||||
|
@ -892,11 +897,12 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
* @see {@link isIntegrable}
|
* @see {@link isIntegrable}
|
||||||
*/
|
*/
|
||||||
evaluateIntegral(variable?: DecimalSource): DecimalSource {
|
evaluateIntegral(variable?: DecimalSource): DecimalSource {
|
||||||
return (
|
if (this.internalIntegrate) {
|
||||||
this.internalIntegrate?.call(this, variable, ...this.inputs) ??
|
return this.internalIntegrate.call(this, variable, ...this.inputs);
|
||||||
variable ??
|
} else if (this.inputs.length === 1 && this.internalHasVariable) {
|
||||||
unrefFormulaSource(this.inputs[0])
|
return variable ?? unrefFormulaSource(this.inputs[0]);
|
||||||
);
|
}
|
||||||
|
throw "Cannot integrate formula without variable";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -907,7 +913,12 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
invertIntegral(value: DecimalSource): DecimalSource {
|
invertIntegral(value: DecimalSource): DecimalSource {
|
||||||
// This is nearly completely non-functional
|
// This is nearly completely non-functional
|
||||||
// Proper nesting will require somehow using integration by substitution or integration by parts
|
// Proper nesting will require somehow using integration by substitution or integration by parts
|
||||||
return this.internalInvertIntegral?.call(this, value, ...this.inputs) ?? value;
|
if (this.internalInvertIntegral) {
|
||||||
|
return this.internalInvertIntegral.call(this, value, ...this.inputs);
|
||||||
|
} else if (this.inputs.length === 1 && this.internalHasVariable) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
throw "Cannot invert integral of formula without invertible integral";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -962,10 +973,12 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
public static step(
|
public static step(
|
||||||
value: FormulaSource,
|
value: FormulaSource,
|
||||||
start: Computable<DecimalSource>,
|
start: Computable<DecimalSource>,
|
||||||
formulaModifier: (value: Ref<DecimalSource>) => GenericFormula
|
formulaModifier: (
|
||||||
|
value: InvertibleFormula & IntegrableFormula & InvertibleIntegralFormula
|
||||||
|
) => GenericFormula
|
||||||
): GenericFormula {
|
): GenericFormula {
|
||||||
const lhsRef = ref<DecimalSource>(0);
|
const lhsRef = ref<DecimalSource>(0);
|
||||||
const formula = formulaModifier(lhsRef);
|
const formula = formulaModifier(Formula.variable(lhsRef));
|
||||||
const processedStart = convertComputable(start);
|
const processedStart = convertComputable(start);
|
||||||
function evalStep(lhs: DecimalSource) {
|
function evalStep(lhs: DecimalSource) {
|
||||||
if (Decimal.lt(lhs, unref(processedStart))) {
|
if (Decimal.lt(lhs, unref(processedStart))) {
|
||||||
|
@ -1002,10 +1015,12 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
public static if(
|
public static if(
|
||||||
value: FormulaSource,
|
value: FormulaSource,
|
||||||
condition: Computable<boolean>,
|
condition: Computable<boolean>,
|
||||||
formulaModifier: (value: Ref<DecimalSource>) => GenericFormula
|
formulaModifier: (
|
||||||
|
value: InvertibleFormula & IntegrableFormula & InvertibleIntegralFormula
|
||||||
|
) => GenericFormula
|
||||||
): GenericFormula {
|
): GenericFormula {
|
||||||
const lhsRef = ref<DecimalSource>(0);
|
const lhsRef = ref<DecimalSource>(0);
|
||||||
const formula = formulaModifier(lhsRef);
|
const formula = formulaModifier(Formula.variable(lhsRef));
|
||||||
const processedCondition = convertComputable(condition);
|
const processedCondition = convertComputable(condition);
|
||||||
function evalStep(lhs: DecimalSource) {
|
function evalStep(lhs: DecimalSource) {
|
||||||
if (unref(processedCondition)) {
|
if (unref(processedCondition)) {
|
||||||
|
@ -1035,7 +1050,9 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
public static conditional(
|
public static conditional(
|
||||||
value: FormulaSource,
|
value: FormulaSource,
|
||||||
condition: Computable<boolean>,
|
condition: Computable<boolean>,
|
||||||
formulaModifier: (value: Ref<DecimalSource>) => GenericFormula
|
formulaModifier: (
|
||||||
|
value: InvertibleFormula & IntegrableFormula & InvertibleIntegralFormula
|
||||||
|
) => GenericFormula
|
||||||
) {
|
) {
|
||||||
return Formula.if(value, condition, formulaModifier);
|
return Formula.if(value, condition, formulaModifier);
|
||||||
}
|
}
|
||||||
|
@ -1632,20 +1649,26 @@ export default class Formula<T extends [FormulaSource] | FormulaSource[]> {
|
||||||
|
|
||||||
public step(
|
public step(
|
||||||
start: Computable<DecimalSource>,
|
start: Computable<DecimalSource>,
|
||||||
formulaModifier: (value: Ref<DecimalSource>) => GenericFormula
|
formulaModifier: (
|
||||||
|
value: InvertibleFormula & IntegrableFormula & InvertibleIntegralFormula
|
||||||
|
) => GenericFormula
|
||||||
) {
|
) {
|
||||||
return Formula.step(this, start, formulaModifier);
|
return Formula.step(this, start, formulaModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public if(
|
public if(
|
||||||
condition: Computable<boolean>,
|
condition: Computable<boolean>,
|
||||||
formulaModifier: (value: Ref<DecimalSource>) => GenericFormula
|
formulaModifier: (
|
||||||
|
value: InvertibleFormula & IntegrableFormula & InvertibleIntegralFormula
|
||||||
|
) => GenericFormula
|
||||||
) {
|
) {
|
||||||
return Formula.if(this, condition, formulaModifier);
|
return Formula.if(this, condition, formulaModifier);
|
||||||
}
|
}
|
||||||
public conditional(
|
public conditional(
|
||||||
condition: Computable<boolean>,
|
condition: Computable<boolean>,
|
||||||
formulaModifier: (value: Ref<DecimalSource>) => GenericFormula
|
formulaModifier: (
|
||||||
|
value: InvertibleFormula & IntegrableFormula & InvertibleIntegralFormula
|
||||||
|
) => GenericFormula
|
||||||
) {
|
) {
|
||||||
return Formula.if(this, condition, formulaModifier);
|
return Formula.if(this, condition, formulaModifier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,8 +569,8 @@ describe("Integrating", () => {
|
||||||
checkFormula(Formula[name](variable, constant)));
|
checkFormula(Formula[name](variable, constant)));
|
||||||
test(`${name}(const, var) is marked as integrable`, () =>
|
test(`${name}(const, var) is marked as integrable`, () =>
|
||||||
checkFormula(Formula[name](constant, variable)));
|
checkFormula(Formula[name](constant, variable)));
|
||||||
test(`${name}(var, var) is marked as integrable`, () =>
|
test(`${name}(var, var) is marked as not integrable`, () =>
|
||||||
checkFormula(Formula[name](variable, variable)));
|
expect(Formula[name](variable, variable).isIntegrable()).toBe(false));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -872,20 +872,29 @@ describe("Custom Formulas", () => {
|
||||||
describe("Formula with invert", () => {
|
describe("Formula with invert", () => {
|
||||||
test("Zero input inverts correctly", () =>
|
test("Zero input inverts correctly", () =>
|
||||||
expect(
|
expect(
|
||||||
new Formula({ inputs: [], evaluate: () => 6, invert: value => value }).invert(10)
|
new Formula({
|
||||||
|
inputs: [],
|
||||||
|
evaluate: () => 6,
|
||||||
|
invert: value => value,
|
||||||
|
variable: ref(10)
|
||||||
|
}).invert(10)
|
||||||
).compare_tolerance(10));
|
).compare_tolerance(10));
|
||||||
test("One input inverts correctly", () =>
|
test("One input inverts correctly", () =>
|
||||||
expect(
|
expect(
|
||||||
new Formula({ inputs: [1], evaluate: () => 10, invert: (value, v1) => v1 }).invert(
|
new Formula({
|
||||||
10
|
inputs: [1],
|
||||||
)
|
evaluate: () => 10,
|
||||||
|
invert: (value, v1) => v1,
|
||||||
|
variable: ref(10)
|
||||||
|
}).invert(10)
|
||||||
).compare_tolerance(1));
|
).compare_tolerance(1));
|
||||||
test("Two inputs inverts correctly", () =>
|
test("Two inputs inverts correctly", () =>
|
||||||
expect(
|
expect(
|
||||||
new Formula({
|
new Formula({
|
||||||
inputs: [1, 2],
|
inputs: [1, 2],
|
||||||
evaluate: () => 10,
|
evaluate: () => 10,
|
||||||
invert: (value, v1, v2) => v2
|
invert: (value, v1, v2) => v2,
|
||||||
|
variable: ref(10)
|
||||||
}).invert(10)
|
}).invert(10)
|
||||||
).compare_tolerance(2));
|
).compare_tolerance(2));
|
||||||
});
|
});
|
||||||
|
@ -923,7 +932,8 @@ describe("Custom Formulas", () => {
|
||||||
new Formula({
|
new Formula({
|
||||||
inputs: [],
|
inputs: [],
|
||||||
evaluate: () => 10,
|
evaluate: () => 10,
|
||||||
invertIntegral: () => 1
|
invertIntegral: () => 1,
|
||||||
|
variable: ref(10)
|
||||||
}).invertIntegral(8)
|
}).invertIntegral(8)
|
||||||
).compare_tolerance(1));
|
).compare_tolerance(1));
|
||||||
test("One input inverts integral correctly", () =>
|
test("One input inverts integral correctly", () =>
|
||||||
|
@ -931,7 +941,8 @@ describe("Custom Formulas", () => {
|
||||||
new Formula({
|
new Formula({
|
||||||
inputs: [1],
|
inputs: [1],
|
||||||
evaluate: () => 10,
|
evaluate: () => 10,
|
||||||
invertIntegral: val => 1
|
invertIntegral: val => 1,
|
||||||
|
variable: ref(10)
|
||||||
}).invertIntegral(8)
|
}).invertIntegral(8)
|
||||||
).compare_tolerance(1));
|
).compare_tolerance(1));
|
||||||
test("Two inputs inverts integral correctly", () =>
|
test("Two inputs inverts integral correctly", () =>
|
||||||
|
@ -939,7 +950,8 @@ describe("Custom Formulas", () => {
|
||||||
new Formula({
|
new Formula({
|
||||||
inputs: [1, 2],
|
inputs: [1, 2],
|
||||||
evaluate: (v1, v2) => 10,
|
evaluate: (v1, v2) => 10,
|
||||||
invertIntegral: (v1, v2) => 1
|
invertIntegral: (v1, v2) => 1,
|
||||||
|
variable: ref(10)
|
||||||
}).invertIntegral(8)
|
}).invertIntegral(8)
|
||||||
).compare_tolerance(1));
|
).compare_tolerance(1));
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue