Fix some tests

This commit is contained in:
thepaperpilot 2023-02-14 01:12:11 -06:00
parent b3d61149c4
commit fd925071e5
2 changed files with 61 additions and 26 deletions

View file

@ -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);
} }

View file

@ -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));
}); });