UNPKG

@qbead/bloch-sphere

Version:

A 3D Bloch Sphere visualisation built with Three.js and TypeScript.

309 lines (265 loc) 9.08 kB
import { describe, expect, test } from 'bun:test' import { Complex } from './complex' describe('Complex', () => { describe('Static constructors', () => { test('ZERO returns 0 + 0i', () => { const zero = Complex.ZERO expect(zero.real).toBe(0) expect(zero.imag).toBe(0) }) test('ONE returns 1 + 0i', () => { const one = Complex.ONE expect(one.real).toBe(1) expect(one.imag).toBe(0) }) test('I returns 0 + 1i', () => { const i = Complex.I expect(i.real).toBe(0) expect(i.imag).toBe(1) }) test('from(number) creates complex number', () => { const c = Complex.from(5) expect(c.real).toBe(5) expect(c.imag).toBe(0) }) test('from(number, number) creates complex number', () => { const c = Complex.from(3, 4) expect(c.real).toBe(3) expect(c.imag).toBe(4) }) test('from([number, number]) creates complex number', () => { const c = Complex.from([3, 4]) expect(c.real).toBe(3) expect(c.imag).toBe(4) }) test('from(Complex) clones complex number', () => { const original = new Complex(3, 4) const clone = Complex.from(original) expect(clone.real).toBe(3) expect(clone.imag).toBe(4) expect(clone).not.toBe(original) // Different instances }) test('random() returns complex number with values in [0, 1)', () => { const c = Complex.random() expect(c.real).toBeGreaterThanOrEqual(0) expect(c.real).toBeLessThan(1) expect(c.imag).toBeGreaterThanOrEqual(0) expect(c.imag).toBeLessThan(1) }) test('unitRandom() returns complex number with magnitude 1', () => { const c = Complex.unitRandom() expect(c.magnitude).toBeCloseTo(1, 10) }) test('fromPolar() creates complex number from polar coordinates', () => { const c = Complex.fromPolar(5, Math.PI / 2) expect(c.real).toBeCloseTo(0, 10) expect(c.imag).toBeCloseTo(5, 10) }) test('fromPolar() with zero angle gives real number', () => { const c = Complex.fromPolar(3, 0) expect(c.real).toBeCloseTo(3, 10) expect(c.imag).toBeCloseTo(0, 10) }) }) describe('Arithmetic operations', () => { test('plus() adds two complex numbers', () => { const a = new Complex(3, 4) const b = new Complex(1, 2) const result = a.plus(b) expect(result.real).toBe(4) expect(result.imag).toBe(6) }) test('plus() works with real numbers', () => { const a = new Complex(3, 4) const result = a.plus(5) expect(result.real).toBe(8) expect(result.imag).toBe(4) }) test('plus() works with array notation', () => { const a = new Complex(3, 4) const result = a.plus([1, 2]) expect(result.real).toBe(4) expect(result.imag).toBe(6) }) test('minus() subtracts two complex numbers', () => { const a = new Complex(5, 6) const b = new Complex(2, 3) const result = a.minus(b) expect(result.real).toBe(3) expect(result.imag).toBe(3) }) test('minus() works with real numbers', () => { const a = new Complex(5, 4) const result = a.minus(2) expect(result.real).toBe(3) expect(result.imag).toBe(4) }) test('times() multiplies two complex numbers', () => { // (3 + 4i) * (1 + 2i) = 3 + 6i + 4i + 8i² = 3 + 10i - 8 = -5 + 10i const a = new Complex(3, 4) const b = new Complex(1, 2) const result = a.times(b) expect(result.real).toBe(-5) expect(result.imag).toBe(10) }) test('times() multiplies by real number', () => { const a = new Complex(3, 4) const result = a.times(2) expect(result.real).toBe(6) expect(result.imag).toBe(8) }) test('times() by i rotates by 90 degrees', () => { const a = new Complex(3, 4) const result = a.times(Complex.I) expect(result.real).toBe(-4) expect(result.imag).toBe(3) }) test('dividedBy() divides two complex numbers', () => { // (3 + 4i) / (1 + 2i) = (3 + 4i)(1 - 2i) / (1 + 4) = (3 - 6i + 4i - 8i²) / 5 = (11 - 2i) / 5 const a = new Complex(3, 4) const b = new Complex(1, 2) const result = a.dividedBy(b) expect(result.real).toBeCloseTo(11 / 5, 10) expect(result.imag).toBeCloseTo(-2 / 5, 10) }) test('dividedBy() real number scales', () => { const a = new Complex(6, 8) const result = a.dividedBy(2) expect(result.real).toBe(3) expect(result.imag).toBe(4) }) test('dividedBy() ONE returns same number', () => { const a = new Complex(3, 4) const result = a.dividedBy(Complex.ONE) expect(result.real).toBeCloseTo(3, 10) expect(result.imag).toBeCloseTo(4, 10) }) }) describe('Properties', () => { test('magnitude of 3 + 4i is 5', () => { const c = new Complex(3, 4) expect(c.magnitude).toBe(5) }) test('magnitude of real number is absolute value', () => { const c = new Complex(-5, 0) expect(c.magnitude).toBe(5) }) test('magnitude of i is 1', () => { const c = Complex.I expect(c.magnitude).toBe(1) }) test('phase of 1 + 0i is 0', () => { const c = new Complex(1, 0) expect(c.phase).toBe(0) }) test('phase of 0 + 1i is π/2', () => { const c = new Complex(0, 1) expect(c.phase).toBeCloseTo(Math.PI / 2, 10) }) test('phase of -1 + 0i is π', () => { const c = new Complex(-1, 0) expect(Math.abs(c.phase)).toBeCloseTo(Math.PI, 10) }) test('phase of 0 - 1i is -π/2', () => { const c = new Complex(0, -1) expect(c.phase).toBeCloseTo(-Math.PI / 2, 10) }) }) describe('conjugate()', () => { test('conjugate of 3 + 4i is 3 - 4i', () => { const c = new Complex(3, 4) const conj = c.conjugate() expect(conj.real).toBe(3) expect(conj.imag).toBe(-4) }) test('conjugate of real number is itself', () => { const c = new Complex(5, 0) const conj = c.conjugate() expect(conj.real).toBe(5) expect(Math.abs(conj.imag)).toBe(0) // Handle -0 vs 0 }) test('conjugate of i is -i', () => { const c = Complex.I const conj = c.conjugate() expect(conj.real).toBe(0) expect(conj.imag).toBe(-1) }) test('double conjugate returns original', () => { const c = new Complex(3, 4) const double = c.conjugate().conjugate() expect(double.real).toBe(c.real) expect(double.imag).toBe(c.imag) }) }) describe('Identity and algebraic properties', () => { test('z * conjugate(z) is real and equals |z|²', () => { const z = new Complex(3, 4) const product = z.times(z.conjugate()) expect(product.imag).toBeCloseTo(0, 10) expect(product.real).toBeCloseTo(z.magnitude ** 2, 10) }) test('addition is commutative', () => { const a = new Complex(3, 4) const b = new Complex(1, 2) const ab = a.plus(b) const ba = b.plus(a) expect(ab.real).toBe(ba.real) expect(ab.imag).toBe(ba.imag) }) test('multiplication is commutative', () => { const a = new Complex(3, 4) const b = new Complex(1, 2) const ab = a.times(b) const ba = b.times(a) expect(ab.real).toBeCloseTo(ba.real, 10) expect(ab.imag).toBeCloseTo(ba.imag, 10) }) test('addition is associative', () => { const a = new Complex(1, 2) const b = new Complex(3, 4) const c = new Complex(5, 6) const ab_c = a.plus(b).plus(c) const a_bc = a.plus(b.plus(c)) expect(ab_c.real).toBeCloseTo(a_bc.real, 10) expect(ab_c.imag).toBeCloseTo(a_bc.imag, 10) }) test('multiplication is associative', () => { const a = new Complex(1, 2) const b = new Complex(3, 4) const c = new Complex(5, 6) const ab_c = a.times(b).times(c) const a_bc = a.times(b.times(c)) expect(ab_c.real).toBeCloseTo(a_bc.real, 10) expect(ab_c.imag).toBeCloseTo(a_bc.imag, 10) }) test('distributive property', () => { const a = new Complex(1, 2) const b = new Complex(3, 4) const c = new Complex(5, 6) const left = a.times(b.plus(c)) const right = a.times(b).plus(a.times(c)) expect(left.real).toBeCloseTo(right.real, 10) expect(left.imag).toBeCloseTo(right.imag, 10) }) test('i² = -1', () => { const i = Complex.I const result = i.times(i) expect(result.real).toBeCloseTo(-1, 10) expect(result.imag).toBeCloseTo(0, 10) }) }) describe('toString()', () => { test('formats complex number correctly', () => { const c = new Complex(3, 4) expect(c.toString()).toBe('3 + 4i') }) test('formats real number correctly', () => { const c = new Complex(5, 0) expect(c.toString()).toBe('5 + 0i') }) test('formats negative imaginary part', () => { const c = new Complex(3, -4) expect(c.toString()).toBe('3 + -4i') }) }) })