From 12291ffa01c43bd8be030819c1c325e391fc474d Mon Sep 17 00:00:00 2001 From: Charles Nykamp Date: Fri, 29 Nov 2024 14:24:51 -0600 Subject: [PATCH] Convert tests to vitest and fix component so it works with updated math.js --- .../linearAlgebra/EigenDecomposition.js | 2 +- .../linearAlgebra/eigenDecomposition.test.ts | 609 ++++++++++++++++++ .../linearAlgebra/eigenDecomposition.cy.js | 503 --------------- 3 files changed, 610 insertions(+), 504 deletions(-) create mode 100644 packages/doenetml-worker/src/test/linearAlgebra/eigenDecomposition.test.ts delete mode 100644 packages/test-cypress/cypress/e2e/linearAlgebra/eigenDecomposition.cy.js diff --git a/packages/doenetml-worker/src/components/linearAlgebra/EigenDecomposition.js b/packages/doenetml-worker/src/components/linearAlgebra/EigenDecomposition.js index c8f31d870..cb0d757fa 100644 --- a/packages/doenetml-worker/src/components/linearAlgebra/EigenDecomposition.js +++ b/packages/doenetml-worker/src/components/linearAlgebra/EigenDecomposition.js @@ -307,7 +307,7 @@ export default class EigenDecomposition extends BaseComponent { let vectorMag = 0; for (let j = 0; j < arraySize[0]; j++) { let val = - globalDependencyValues.decomposition.vectors[j][i]; + globalDependencyValues.decomposition.eigenvectors[i].vector[j]; vector.push(val); vectorMag += me.math.square(me.math.abs(val)); } diff --git a/packages/doenetml-worker/src/test/linearAlgebra/eigenDecomposition.test.ts b/packages/doenetml-worker/src/test/linearAlgebra/eigenDecomposition.test.ts new file mode 100644 index 000000000..3dd5b22c3 --- /dev/null +++ b/packages/doenetml-worker/src/test/linearAlgebra/eigenDecomposition.test.ts @@ -0,0 +1,609 @@ +import { describe, expect, it, vi } from "vitest"; +import { createTestCore, returnAllStateVariables } from "../utils/test-core"; +import me from "math-expressions"; +import Core from "../../Core"; + +const Mock = vi.fn(); +vi.stubGlobal("postMessage", Mock); +vi.mock("hyperformula"); + +describe("EigenDecomposition Tag Tests", async () => { + function reviveComplex(num: number | { re: number; im: number }) { + if (typeof num === "number") { + return me.math.complex({ re: num, im: 0 }); + } else { + return me.math.complex({ re: num.re, im: num.im }); + } + } + + it("2x2 matrices", async () => { + let core = await createTestCore({ + doenetML: ` +

A = + \\begin{pmatrix} + 1 & 2\\\\ + 2 & 1 + \\end{pmatrix} +

+

B = + \\begin{pmatrix} + 1 & 2\\\\ + -2 & 1 + \\end{pmatrix} +

+ + + $A + + + $B + + +

Eigenvalues of A:

+

1st eigenvalue of A:

+

2nd eigenvalue of A:

+ +

Eigenvectors of A:

+

1st eigenvector of A:

+

2nd eigenvector of A:

+

1st component of 1st eigenvector of A:

+

2nd component of 1st eigenvector of A:

+ +

Eigenvalues of B:

+

1st eigenvalue of B:

+

2nd eigenvalue of B:

+ +

Eigenvectors of B:

+

1st eigenvector of B:

+

2nd eigenvector of B:

+

1st component of 1st eigenvector of B:

+

2nd component of 1st eigenvector of B:

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/pAevs"].stateValues.text).eqls( + "Eigenvalues of A: -1, 3", + ); + expect(stateVariables["/Aev1"].stateValues.value).eqls(-1); + expect(stateVariables["/Aev2"].stateValues.value).eqls(3); + + expect(stateVariables["/pBevs"].stateValues.text).eqls( + "Eigenvalues of B: 1 + 2 i, 1 - 2 i", + ); + expect(stateVariables["/Bev1"].stateValues.text).eqls("1 + 2 i"); + expect(stateVariables["/Bev2"].stateValues.text).eqls("1 - 2 i"); + + expect(stateVariables["/Ad"].stateValues.eigenvalues).eqls([-1, 3]); + expect(stateVariables["/Aev1"].stateValues.value).eq(-1); + expect(stateVariables["/Aev1a"].stateValues.value).eq(-1); + expect(stateVariables["/Aev2"].stateValues.value).eq(3); + expect(stateVariables["/Aev2a"].stateValues.value).eq(3); + + expect( + stateVariables["/Ad"].stateValues.eigenvectors[0][1] / + stateVariables["/Ad"].stateValues.eigenvectors[0][0], + ).closeTo(-1, 1e-14); + expect( + stateVariables["/Ad"].stateValues.eigenvectors[1][1] / + stateVariables["/Ad"].stateValues.eigenvectors[1][0], + ).closeTo(1, 1e-14); + + expect( + stateVariables["/Aevec1"].stateValues.displacement[1] / + stateVariables["/Aevec1"].stateValues.displacement[0], + ).closeTo(-1, 1e-14); + expect( + stateVariables["/Aevec1a"].stateValues.displacement[1] / + stateVariables["/Aevec1a"].stateValues.displacement[0], + ).closeTo(-1, 1e-14); + expect( + stateVariables["/Aevec2"].stateValues.displacement[1] / + stateVariables["/Aevec2"].stateValues.displacement[0], + ).closeTo(1, 1e-14); + expect( + stateVariables["/Aevec2a"].stateValues.displacement[1] / + stateVariables["/Aevec2a"].stateValues.displacement[0], + ).closeTo(1, 1e-14); + expect( + stateVariables["/Aevec1y"].stateValues.value / + stateVariables["/Aevec1x"].stateValues.value, + ).closeTo(-1, 1e-14); + + expect(stateVariables["/Bd"].stateValues.eigenvalues[0].re).closeTo( + 1, + 1e-14, + ); + expect(stateVariables["/Bd"].stateValues.eigenvalues[0].im).closeTo( + 2, + 1e-14, + ); + expect(stateVariables["/Bd"].stateValues.eigenvalues[1].re).closeTo( + 1, + 1e-14, + ); + expect(stateVariables["/Bd"].stateValues.eigenvalues[1].im).closeTo( + -2, + 1e-14, + ); + expect(stateVariables["/Bev1"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev1"].stateValues.value.im).closeTo(2, 1e-14); + expect(stateVariables["/Bev1a"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev1a"].stateValues.value.im).closeTo(2, 1e-14); + expect(stateVariables["/Bev2"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev2"].stateValues.value.im).closeTo(-2, 1e-14); + expect(stateVariables["/Bev2a"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev2a"].stateValues.value.im).closeTo( + -2, + 1e-14, + ); + + let ratio = me.math.divide( + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[0][1]), + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[0][0]), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + ratio = me.math.divide( + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[1][1]), + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[1][0]), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(-1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec1"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec1"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec1a"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec1a"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec2"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec2"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(-1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec2a"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec2a"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(-1, 1e-14); + + ratio = me.math.divide( + reviveComplex(stateVariables["/Bevec1y"].stateValues.value), + reviveComplex(stateVariables["/Bevec1x"].stateValues.value), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + }); + + it("2x2 matrices, fractions", async () => { + let core = await createTestCore({ + doenetML: ` +

A = + \\begin{pmatrix} + 2/2 & 6/3\\\\ + 8/4 & 5/5 + \\end{pmatrix} +

+

B = + \\begin{pmatrix} + 2/2 & 6/3\\\\ + -8/4 & 5/5 + \\end{pmatrix} +

+ + + $A + + + $B + + +

Eigenvalues of A:

+

1st eigenvalue of A:

+

2nd eigenvalue of A:

+ +

Eigenvectors of A:

+

1st eigenvector of A:

+

2nd eigenvector of A:

+

1st component of 1st eigenvector of A:

+

2nd component of 1st eigenvector of A:

+ +

Eigenvalues of B:

+

1st eigenvalue of B:

+

2nd eigenvalue of B:

+ +

Eigenvectors of B:

+

1st eigenvector of B:

+

2nd eigenvector of B:

+

1st component of 1st eigenvector of B:

+

2nd component of 1st eigenvector of B:

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/pAevs"].stateValues.text).eqls( + "Eigenvalues of A: -1, 3", + ); + expect(stateVariables["/Aev1"].stateValues.value).eqls(-1); + expect(stateVariables["/Aev2"].stateValues.value).eqls(3); + + expect(stateVariables["/pBevs"].stateValues.text).eqls( + "Eigenvalues of B: 1 + 2 i, 1 - 2 i", + ); + expect(stateVariables["/Bev1"].stateValues.text).eqls("1 + 2 i"); + expect(stateVariables["/Bev2"].stateValues.text).eqls("1 - 2 i"); + + expect(stateVariables["/Ad"].stateValues.eigenvalues).eqls([-1, 3]); + expect(stateVariables["/Aev1"].stateValues.value).eq(-1); + expect(stateVariables["/Aev1a"].stateValues.value).eq(-1); + expect(stateVariables["/Aev2"].stateValues.value).eq(3); + expect(stateVariables["/Aev2a"].stateValues.value).eq(3); + + expect( + stateVariables["/Ad"].stateValues.eigenvectors[0][1] / + stateVariables["/Ad"].stateValues.eigenvectors[0][0], + ).closeTo(-1, 1e-14); + expect( + stateVariables["/Ad"].stateValues.eigenvectors[1][1] / + stateVariables["/Ad"].stateValues.eigenvectors[1][0], + ).closeTo(1, 1e-14); + + expect( + stateVariables["/Aevec1"].stateValues.displacement[1] / + stateVariables["/Aevec1"].stateValues.displacement[0], + ).closeTo(-1, 1e-14); + expect( + stateVariables["/Aevec1a"].stateValues.displacement[1] / + stateVariables["/Aevec1a"].stateValues.displacement[0], + ).closeTo(-1, 1e-14); + expect( + stateVariables["/Aevec2"].stateValues.displacement[1] / + stateVariables["/Aevec2"].stateValues.displacement[0], + ).closeTo(1, 1e-14); + expect( + stateVariables["/Aevec2a"].stateValues.displacement[1] / + stateVariables["/Aevec2a"].stateValues.displacement[0], + ).closeTo(1, 1e-14); + expect( + stateVariables["/Aevec1y"].stateValues.value / + stateVariables["/Aevec1x"].stateValues.value, + ).closeTo(-1, 1e-14); + + expect(stateVariables["/Bd"].stateValues.eigenvalues[0].re).closeTo( + 1, + 1e-14, + ); + expect(stateVariables["/Bd"].stateValues.eigenvalues[0].im).closeTo( + 2, + 1e-14, + ); + expect(stateVariables["/Bd"].stateValues.eigenvalues[1].re).closeTo( + 1, + 1e-14, + ); + expect(stateVariables["/Bd"].stateValues.eigenvalues[1].im).closeTo( + -2, + 1e-14, + ); + expect(stateVariables["/Bev1"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev1"].stateValues.value.im).closeTo(2, 1e-14); + expect(stateVariables["/Bev1a"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev1a"].stateValues.value.im).closeTo(2, 1e-14); + expect(stateVariables["/Bev2"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev2"].stateValues.value.im).closeTo(-2, 1e-14); + expect(stateVariables["/Bev2a"].stateValues.value.re).closeTo(1, 1e-14); + expect(stateVariables["/Bev2a"].stateValues.value.im).closeTo( + -2, + 1e-14, + ); + + let ratio = me.math.divide( + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[0][1]), + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[0][0]), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + ratio = me.math.divide( + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[1][1]), + reviveComplex(stateVariables["/Bd"].stateValues.eigenvectors[1][0]), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(-1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec1"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec1"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec1a"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec1a"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec2"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec2"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(-1, 1e-14); + + ratio = me.math.divide( + me + .fromAst(stateVariables["/Bevec2a"].stateValues.displacement[1]) + .evaluate_to_constant(), + me + .fromAst(stateVariables["/Bevec2a"].stateValues.displacement[0]) + .evaluate_to_constant(), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(-1, 1e-14); + + ratio = me.math.divide( + reviveComplex(stateVariables["/Bevec1y"].stateValues.value), + reviveComplex(stateVariables["/Bevec1x"].stateValues.value), + ); + expect(ratio.re).closeTo(0, 1e-14); + expect(ratio.im).closeTo(1, 1e-14); + }); + + it("3x3 matrices with real eigenvectors", async () => { + let core = await createTestCore({ + doenetML: ` + + 1 2 3 + 4 5 6 + 7 8 9 + +$A + `, + }); + + const stateVariables = await returnAllStateVariables(core); + const eigvals = stateVariables["/eig"].stateValues.eigenvalues; + const eigvecs = stateVariables["/eig"].stateValues.eigenvectors; + expect(eigvals[0]).closeTo(0, 1e-14); + const ev0x = 1; + const ev0y = -2; + const ev0z = 1; + expect(eigvecs[0][0] / eigvecs[0][1]).closeTo(ev0x / ev0y, 1e-13); + expect(eigvecs[0][0] / eigvecs[0][2]).closeTo(ev0x / ev0z, 1e-13); + + expect(eigvals[1]).closeTo((-3 / 2) * (Math.sqrt(33) - 5), 1e-14); + const ev1x = (1 / 22) * (-11 - 3 * Math.sqrt(33)); + const ev1y = (1 / 44) * (11 - 3 * Math.sqrt(33)); + const ev1z = 1; + expect(eigvecs[1][0] / eigvecs[1][1]).closeTo(ev1x / ev1y, 1e-13); + expect(eigvecs[1][0] / eigvecs[1][2]).closeTo(ev1x / ev1z, 1e-13); + + expect(eigvals[2]).closeTo((3 / 2) * (5 + Math.sqrt(33)), 1e-14); + const ev2x = (1 / 22) * (-11 + 3 * Math.sqrt(33)); + const ev2y = (1 / 44) * (11 + 3 * Math.sqrt(33)); + const ev2z = 1; + expect(eigvecs[2][0] / eigvecs[2][1]).closeTo(ev2x / ev2y, 1e-13); + expect(eigvecs[2][0] / eigvecs[2][2]).closeTo(ev2x / ev2z, 1e-13); + }); + + async function check_eigendecomposition({ + evecs, + evals, + core, + decompositionName, + }: { + evecs: any[][]; + evals: any[]; + core: Core; + decompositionName: string; + }) { + const stateVariables = await returnAllStateVariables(core); + const actualEvals = + stateVariables[decompositionName].stateValues.eigenvalues.map( + reviveComplex, + ); + const actualEvecs = stateVariables[ + decompositionName + ].stateValues.eigenvectors.map((v) => v.map(reviveComplex)); + const n = evecs.length; + expect(actualEvals.length).eqls(n); + expect(actualEvecs.length).eqls(n); + + for (let i = 0; i < n; i++) { + expect(actualEvals[i].re).closeTo(evals[i].re, 1e-12); + expect(actualEvals[i].im).closeTo(evals[i].im, 1e-12); + + for (let j = 1; j < n; j++) { + let ratio = me.math.divide(evecs[i][0], evecs[i][j]); + let actualRatio = me.math.divide( + actualEvecs[i][0], + actualEvecs[i][j], + ); + expect(actualRatio.re).closeTo(ratio.re, 1e-12); + expect(actualRatio.im).closeTo(ratio.im, 1e-12); + } + } + } + + it("3x3 matrix, center and spirals", async () => { + let core = await createTestCore({ + doenetML: ` + +-9 +-4 +-8 +9 +-1 +-5 + +-(2*$a11 *$a22 *$a33 +$a11 *$a22 *($a11 +$a22 )+$a11 *$a33 *($a11 +$a33 )+$a22 *$a33 *($a22 +$a33 ) - $a12 *$a23 *$a31 ) +$a31 *($a11 +$a33 )+$a12 *($a11 +$a22 )+$a23 *($a22 +$a33 ) +$b **3/27 + $c **2/4 +$b /(3*($c /2 + sqrt($sqrt_arg ))**(1/3)) - ($c /2 + sqrt($sqrt_arg ))**(1/3) + +$parCenter + 0.1 +$parCenter - 0.1 + +\\begin{pmatrix} + $a11 & $a12 & $parCenter\\\\ + $parCenter & $a22 & $a23\\\\ + $a31 & $parCenter & $a33 +\\end{pmatrix} +$A_center + +\\begin{pmatrix} + $a11 & $a12 & $parStableSpiral\\\\ + $parStableSpiral & $a22 & $a23\\\\ + $a31 & $parStableSpiral & $a33 +\\end{pmatrix} +$A_stableSpiral + + +\\begin{pmatrix} + $a11 & $a12 & $parUnstableSpiral\\\\ + $parUnstableSpiral & $a22 & $a23\\\\ + $a31 & $parUnstableSpiral & $a33 +\\end{pmatrix} +$A_unstableSpiral + + `, + }); + + // Center + let evals = [me.math.complex({ re: 0, im: 14.78846823004614 })]; + evals.push(me.math.conj(evals[0])); + evals.push(me.math.complex({ re: -22, im: 0 })); + + let evecs = [ + [ + me.math.complex({ + re: -0.426486035260864, + im: -0.270682079730474, + }), + me.math.complex({ re: 0.627291349345459, im: 0 }), + me.math.complex({ + re: -0.173343062597144, + im: 0.566832090769437, + }), + ], + ]; + evecs.push(evecs[0].map((v) => me.math.conj(v))); + evecs.push( + [-0.725759948499824, -0.487701621853287, -0.485200603044974].map( + (v) => me.math.complex({ re: v, im: 0 }), + ), + ); + await check_eigendecomposition({ + evecs, + evals, + core, + decompositionName: "/Ad_center", + }); + + // Stable spiral + evals = [ + me.math.complex({ re: -0.048287227932923, im: 14.703099997319454 }), + me.math.complex({ + re: -0.048287227932923, + im: -14.703099997319454, + }), + me.math.complex({ re: -21.903425544134173, im: 0 }), + ]; + evecs = [ + [ + me.math.complex({ + re: -0.427048386266709, + im: -0.269189626634008, + }), + me.math.complex({ re: 0.627621340142377, im: 0 }), + me.math.complex({ + re: -0.172635887510845, + im: 0.566969950209772, + }), + ], + ]; + evecs.push(evecs[0].map((v) => me.math.conj(v))); + evecs.push( + [-0.726546459838247, -0.48712036969194, -0.484607044034337].map( + (v) => me.math.complex({ re: v, im: 0 }), + ), + ); + + await check_eigendecomposition({ + evecs, + evals, + core, + decompositionName: "/Ad_stable", + }); + + // Unstable spiral + evals = [ + me.math.complex({re: 0.048306535292557, im: 14.873845525216694 }), + me.math.complex({re: 0.048306535292557, im: -14.873845525216694 }), + me.math.complex({re: -22.096613070585100, im: 0}), + ] + evecs = [ + [ + me.math.complex({re: -0.425927192657446, im: -0.272156678632516 }), + me.math.complex({re: 0.626965239909586, im: 0 }), + me.math.complex({re: -0.174042517907594, im: 0.566692649269571 }), + ] + ]; + evecs.push(evecs[0].map((v) => me.math.conj(v))); + evecs.push( + [-0.724981295406814, -0.488275620239871, -0.485787031516515].map( + (v) => me.math.complex({ re: v, im: 0 }), + ), + ); + + await check_eigendecomposition({ + evecs, + evals, + core, + decompositionName: "/Ad_unstable", + }); + + }); +}); diff --git a/packages/test-cypress/cypress/e2e/linearAlgebra/eigenDecomposition.cy.js b/packages/test-cypress/cypress/e2e/linearAlgebra/eigenDecomposition.cy.js deleted file mode 100644 index d46fd850a..000000000 --- a/packages/test-cypress/cypress/e2e/linearAlgebra/eigenDecomposition.cy.js +++ /dev/null @@ -1,503 +0,0 @@ -import me from "math-expressions"; -import { cesc } from "@doenet/utils"; - -describe("EigenDecomposition Tag Tests", function () { - beforeEach(() => { - cy.clearIndexedDB(); - cy.visit("/"); - }); - - it("2x2 matrices", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

A = - \\begin{pmatrix} - 1 & 2\\\\ - 2 & 1 - \\end{pmatrix} -

-

B = - \\begin{pmatrix} - 1 & 2\\\\ - -2 & 1 - \\end{pmatrix} -

- - - $A - - - $B - - -

Eigenvalues of A:

-

1st eigenvalue of A:

-

2nd eigenvalue of A:

- -

Eigenvectors of A:

-

1st eigenvector of A:

-

2nd eigenvector of A:

-

1st component of 1st eigenvector of A:

-

2nd component of 1st eigenvector of A:

- -

Eigenvalues of B:

-

1st eigenvalue of B:

-

2nd eigenvalue of B:

- -

Eigenvectors of B:

-

1st eigenvector of B:

-

2nd eigenvector of B:

-

1st component of 1st eigenvector of B:

-

2nd component of 1st eigenvector of B:

- - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.get(cesc("#\\/pAevs")).should( - "have.text", - "Eigenvalues of A: -1, 3", - ); - cy.get(cesc("#\\/Aev1")).should("have.text", "-1"); - cy.get(cesc("#\\/Aev2")).should("have.text", "3"); - - cy.get(cesc("#\\/pBevs")).should( - "have.text", - "Eigenvalues of B: 1 + 2 i, 1 - 2 i", - ); - cy.get(cesc("#\\/Bev1")).should("have.text", "1 + 2 i"); - cy.get(cesc("#\\/Bev2")).should("have.text", "1 - 2 i"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - expect(stateVariables["/Ad"].stateValues.eigenvalues).eqls([-1, 3]); - expect(stateVariables["/Aev1"].stateValues.value).eq(-1); - expect(stateVariables["/Aev1a"].stateValues.value).eq(-1); - expect(stateVariables["/Aev2"].stateValues.value).eq(3); - expect(stateVariables["/Aev2a"].stateValues.value).eq(3); - - expect( - stateVariables["/Ad"].stateValues.eigenvectors[0][1] / - stateVariables["/Ad"].stateValues.eigenvectors[0][0], - ).closeTo(-1, 1e-14); - expect( - stateVariables["/Ad"].stateValues.eigenvectors[1][1] / - stateVariables["/Ad"].stateValues.eigenvectors[1][0], - ).closeTo(1, 1e-14); - - expect( - stateVariables["/Aevec1"].stateValues.displacement[1] / - stateVariables["/Aevec1"].stateValues.displacement[0], - ).closeTo(-1, 1e-14); - expect( - stateVariables["/Aevec1a"].stateValues.displacement[1] / - stateVariables["/Aevec1a"].stateValues.displacement[0], - ).closeTo(-1, 1e-14); - expect( - stateVariables["/Aevec2"].stateValues.displacement[1] / - stateVariables["/Aevec2"].stateValues.displacement[0], - ).closeTo(1, 1e-14); - expect( - stateVariables["/Aevec2a"].stateValues.displacement[1] / - stateVariables["/Aevec2a"].stateValues.displacement[0], - ).closeTo(1, 1e-14); - expect( - stateVariables["/Aevec1y"].stateValues.value / - stateVariables["/Aevec1x"].stateValues.value, - ).closeTo(-1, 1e-14); - - expect(stateVariables["/Bd"].stateValues.eigenvalues[0].re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bd"].stateValues.eigenvalues[0].im).closeTo( - 2, - 1e-14, - ); - expect(stateVariables["/Bd"].stateValues.eigenvalues[1].re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bd"].stateValues.eigenvalues[1].im).closeTo( - -2, - 1e-14, - ); - expect(stateVariables["/Bev1"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev1"].stateValues.value.im).closeTo( - 2, - 1e-14, - ); - expect(stateVariables["/Bev1a"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev1a"].stateValues.value.im).closeTo( - 2, - 1e-14, - ); - expect(stateVariables["/Bev2"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev2"].stateValues.value.im).closeTo( - -2, - 1e-14, - ); - expect(stateVariables["/Bev2a"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev2a"].stateValues.value.im).closeTo( - -2, - 1e-14, - ); - - let ratio = me.math.divide( - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[0][1], - ), - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[0][0], - ), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - ratio = me.math.divide( - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[1][1], - ), - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[1][0], - ), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(-1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec1"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec1"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec1a"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec1a"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec2"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec2"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(-1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec2a"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec2a"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(-1, 1e-14); - - ratio = me.math.divide( - reviveComplex(stateVariables["/Bevec1y"].stateValues.value), - reviveComplex(stateVariables["/Bevec1x"].stateValues.value), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - }); - }); - - it("2x2 matrices, fractions", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

A = - \\begin{pmatrix} - 2/2 & 6/3\\\\ - 8/4 & 5/5 - \\end{pmatrix} -

-

B = - \\begin{pmatrix} - 2/2 & 6/3\\\\ - -8/4 & 5/5 - \\end{pmatrix} -

- - - $A - - - $B - - -

Eigenvalues of A:

-

1st eigenvalue of A:

-

2nd eigenvalue of A:

- -

Eigenvectors of A:

-

1st eigenvector of A:

-

2nd eigenvector of A:

-

1st component of 1st eigenvector of A:

-

2nd component of 1st eigenvector of A:

- -

Eigenvalues of B:

-

1st eigenvalue of B:

-

2nd eigenvalue of B:

- -

Eigenvectors of B:

-

1st eigenvector of B:

-

2nd eigenvector of B:

-

1st component of 1st eigenvector of B:

-

2nd component of 1st eigenvector of B:

- - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.get(cesc("#\\/pAevs")).should( - "have.text", - "Eigenvalues of A: -1, 3", - ); - cy.get(cesc("#\\/Aev1")).should("have.text", "-1"); - cy.get(cesc("#\\/Aev2")).should("have.text", "3"); - - cy.get(cesc("#\\/pBevs")).should( - "have.text", - "Eigenvalues of B: 1 + 2 i, 1 - 2 i", - ); - cy.get(cesc("#\\/Bev1")).should("have.text", "1 + 2 i"); - cy.get(cesc("#\\/Bev2")).should("have.text", "1 - 2 i"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - expect(stateVariables["/Ad"].stateValues.eigenvalues).eqls([-1, 3]); - expect(stateVariables["/Aev1"].stateValues.value).eq(-1); - expect(stateVariables["/Aev1a"].stateValues.value).eq(-1); - expect(stateVariables["/Aev2"].stateValues.value).eq(3); - expect(stateVariables["/Aev2a"].stateValues.value).eq(3); - - expect( - stateVariables["/Ad"].stateValues.eigenvectors[0][1] / - stateVariables["/Ad"].stateValues.eigenvectors[0][0], - ).closeTo(-1, 1e-14); - expect( - stateVariables["/Ad"].stateValues.eigenvectors[1][1] / - stateVariables["/Ad"].stateValues.eigenvectors[1][0], - ).closeTo(1, 1e-14); - - expect( - stateVariables["/Aevec1"].stateValues.displacement[1] / - stateVariables["/Aevec1"].stateValues.displacement[0], - ).closeTo(-1, 1e-14); - expect( - stateVariables["/Aevec1a"].stateValues.displacement[1] / - stateVariables["/Aevec1a"].stateValues.displacement[0], - ).closeTo(-1, 1e-14); - expect( - stateVariables["/Aevec2"].stateValues.displacement[1] / - stateVariables["/Aevec2"].stateValues.displacement[0], - ).closeTo(1, 1e-14); - expect( - stateVariables["/Aevec2a"].stateValues.displacement[1] / - stateVariables["/Aevec2a"].stateValues.displacement[0], - ).closeTo(1, 1e-14); - expect( - stateVariables["/Aevec1y"].stateValues.value / - stateVariables["/Aevec1x"].stateValues.value, - ).closeTo(-1, 1e-14); - - expect(stateVariables["/Bd"].stateValues.eigenvalues[0].re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bd"].stateValues.eigenvalues[0].im).closeTo( - 2, - 1e-14, - ); - expect(stateVariables["/Bd"].stateValues.eigenvalues[1].re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bd"].stateValues.eigenvalues[1].im).closeTo( - -2, - 1e-14, - ); - expect(stateVariables["/Bev1"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev1"].stateValues.value.im).closeTo( - 2, - 1e-14, - ); - expect(stateVariables["/Bev1a"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev1a"].stateValues.value.im).closeTo( - 2, - 1e-14, - ); - expect(stateVariables["/Bev2"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev2"].stateValues.value.im).closeTo( - -2, - 1e-14, - ); - expect(stateVariables["/Bev2a"].stateValues.value.re).closeTo( - 1, - 1e-14, - ); - expect(stateVariables["/Bev2a"].stateValues.value.im).closeTo( - -2, - 1e-14, - ); - - let ratio = me.math.divide( - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[0][1], - ), - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[0][0], - ), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - ratio = me.math.divide( - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[1][1], - ), - reviveComplex( - stateVariables["/Bd"].stateValues.eigenvectors[1][0], - ), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(-1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec1"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec1"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec1a"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec1a"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec2"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec2"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(-1, 1e-14); - - ratio = me.math.divide( - me - .fromAst( - stateVariables["/Bevec2a"].stateValues.displacement[1], - ) - .evaluate_to_constant(), - me - .fromAst( - stateVariables["/Bevec2a"].stateValues.displacement[0], - ) - .evaluate_to_constant(), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(-1, 1e-14); - - ratio = me.math.divide( - reviveComplex(stateVariables["/Bevec1y"].stateValues.value), - reviveComplex(stateVariables["/Bevec1x"].stateValues.value), - ); - expect(ratio.re).closeTo(0, 1e-14); - expect(ratio.im).closeTo(1, 1e-14); - }); - }); -}); - -function reviveComplex(num) { - return me.math.complex({ re: num.re, im: num.im }); -}