Skip to content

Commit

Permalink
feat: migrate to ES6 classes and strict types (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
manzt authored Aug 6, 2022
1 parent d7d6785 commit afe55c0
Show file tree
Hide file tree
Showing 8 changed files with 930 additions and 1,187 deletions.
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
</head>

<body>
<nav></nav>
<d-figure class="teaser">
<canvas id="teaser"></canvas>
</d-figure>
Expand Down
44 changes: 23 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
{
"name": "eigen-tour",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"author": "Trevor Manz",
"license": "MIT",
"dependencies": {
"@types/d3": "^7.4.0",
"@types/numeric": "^1.2.2",
"apache-arrow": "^9.0.0",
"d3": "^7.6.1",
"mathjs": "^11.0.1",
"numeric": "^1.2.6"
},
"devDependencies": {
"typescript": "^4.7.4",
"vite": "^3.0.4"
}
"name": "eigen-tour",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "tsc --noEmit",
"fmt": "deno fmt --ignore=dist,node_modules --options-use-tabs"
},
"author": "Trevor Manz",
"license": "MIT",
"dependencies": {
"@types/d3": "^7.4.0",
"@types/numeric": "^1.2.2",
"apache-arrow": "^9.0.0",
"d3": "^7.6.1",
"mathjs": "^11.0.1",
"numeric": "^1.2.6"
},
"devDependencies": {
"typescript": "^4.7.4",
"vite": "^3.0.4"
}
}
272 changes: 142 additions & 130 deletions src/GrandTour.ts
Original file line number Diff line number Diff line change
@@ -1,137 +1,149 @@
// @ts-check
import * as math from "mathjs";
import numeric from "numeric";

import * as utils from "./utils";

export function GrandTour(ndim, init_matrix) {
this.ndim = ndim;
this.N = ndim*ndim;

this.STEPSIZE = 0.02;


this.angles;

this.initThetas = function(N) {
this.thetas = new Array(N);
for (let i=0; i<N; i++) {
this.thetas[i] = (Math.random()+0.5) * Math.PI;
}
};
this.initThetas(this.N);


this.setNdim = function(newNdim) {
if(newNdim > this.ndim){
for(let i=this.N; i<newNdim*newNdim; i++){
this.thetas[i] = (Math.random()-0.5) * 2 * Math.PI;
}
this.matrix = utils.embed(this.matrix, math.identity(newNdim)._data);
}else if(newNdim < this.ndim){
this.matrix = this.matrix.slice(0,newNdim).map(row=>row.slice(0,newNdim));
this.matrix = utils.orthogonalize(this.matrix);
}
this.ndim = newNdim;
this.N = this.ndim * this.ndim;
return this.matrix;
};

this.getMatrix = function(dt) {
if (dt !== undefined) {
if (this.angles === undefined) {
// torus method
// this.angles = this.thetas.map(theta=>0);
//
// another implementation similar to torus method
this.angles = this.thetas;
this.matrix = math.identity(this.ndim)._data;
} else {
// torus method
// this.angles = this.angles.map(
// (a,i) => a+dt*this.STEPSIZE*this.thetas[i]);
//
// another implementation similar to torus method
this.angles = this.thetas.map( (theta) =>
theta * dt * this.STEPSIZE );
}
// torus method
// this.matrix = math.identity(this.ndim)._data;
let k = -1;
for (let i=0; i<this.ndim; i++) {
for (let j=0; j<this.ndim; j++) {
if (i!==j && (true || i<=3 || j<=3) ) {
k++;
this.matrix = this.multiplyRotationMatrix(
this.matrix, i, j, this.angles[k]);
}
}
}
}
return this.matrix;
};


this.setMatrix = function(m) {
this.matrix = numeric.clone(m);
};


this.getRotationMatrix = function(dim0, dim1, theta) {
let res = math.identity(this.ndim)._data;
res[dim0][dim0] = Math.cos(theta);
res[dim0][dim1] = Math.sin(theta);
res[dim1][dim0] = -Math.sin(theta);
res[dim1][dim1] = Math.cos(theta);
return res;
};


this.multiplyRotationMatrix = function(matrix, i, j, theta) {
if(theta == 0){
return matrix;
}
let sin = Math.sin(theta);
let cos = Math.cos(theta);
// var res = matrix.map(d=>d.slice());
let columnI = matrix.map((d)=>d[i]);
let columnJ = matrix.map((d)=>d[j]);
for (let rowIndex=0; rowIndex<matrix.length; rowIndex++) {
matrix[rowIndex][i] = columnI[rowIndex]*cos + columnJ[rowIndex]*(-sin);
matrix[rowIndex][j] = columnI[rowIndex]*sin + columnJ[rowIndex]*cos;
}
return matrix;
};


this.get3dRotaionMatrix = function(t) {
let theta = 0.0 * t;
let cos = Math.cos(theta);
let sin = Math.sin(theta);

return [
[cos, 0, sin],
[0, 1, 0],
[-sin, 0, cos]];
};

this.project = function(data, dt, view) {
let matrix = this.getMatrix(dt);

matrix = math.transpose(matrix);
matrix = matrix.slice(0, 3);
matrix = math.transpose(matrix);
if(view!==undefined){
matrix = math.multiply(view, matrix);
}
let res = math.multiply(data, matrix.slice(0,data[0].length));

return res;
};
function initThetas(N: number) {
return Array.from({ length: N }, () => (Math.random() + 0.5) * Math.PI);
}

this.setNdim(this.ndim);
this.matrix = this.getMatrix(0);
if(init_matrix !== undefined){
this.setMatrix(init_matrix);
}
export class GrandTour {
STEPSIZE = 0.02;
matrix: number[][];

STEPSIZE_PREV?: number;
angles?: number[];
thetas: number[];
#ndim: number;

constructor(ndim: number, init_matrix?: number[][]) {
this.#ndim = ndim;
this.thetas = initThetas(this.N);
this.matrix = this.getMatrix(0);
if (init_matrix) {
this.setMatrix(init_matrix);
}
}

get N() {
return this.ndim * this.ndim;
}

get ndim() {
return this.#ndim;
}

set ndim(newNdim: number) {
if (newNdim > this.#ndim) {
for (let i = this.N; i < newNdim * newNdim; i++) {
this.thetas[i] = (Math.random() - 0.5) * 2 * Math.PI;
}
this.matrix = utils.embed(
this.matrix,
(math.identity(newNdim) as math.Matrix).toArray() as number[][],
);
} else if (newNdim < this.ndim) {
this.matrix = this.matrix.slice(0, newNdim).map((row) =>
row.slice(0, newNdim)
);
this.matrix = utils.orthogonalize(this.matrix);
}
this.#ndim = newNdim;
}

getMatrix(dt?: number) {
if (dt !== undefined) {
if (this.angles === undefined) {
// torus method
// this.angles = this.thetas.map(theta=>0);
//
// another implementation similar to torus method
this.angles = this.thetas;
let mat = math.identity(this.ndim) as math.Matrix;
this.matrix = mat.toArray() as number[][];
} else {
// torus method
// this.angles = this.angles.map(
// (a,i) => a+dt*this.STEPSIZE*this.thetas[i]);
//
// another implementation similar to torus method
this.angles = this.thetas.map((theta) => theta * dt * this.STEPSIZE);
}
// torus method
// this.matrix = math.identity(this.ndim)._data;
let k = -1;
for (let i = 0; i < this.ndim; i++) {
for (let j = 0; j < this.ndim; j++) {
if (i !== j && (true || i <= 3 || j <= 3)) {
k++;
this.matrix = this.multiplyRotationMatrix(
this.matrix,
i,
j,
this.angles[k],
);
}
}
}
}
return this.matrix;
}

setMatrix(m: number[][]) {
this.matrix = numeric.clone(m);
}

getRotationMatrix(dim0: number, dim1: number, theta: number) {
let m = math.identity(this.ndim) as math.Matrix;
let res = m.toArray() as number[][];
res[dim0][dim0] = Math.cos(theta);
res[dim0][dim1] = Math.sin(theta);
res[dim1][dim0] = -Math.sin(theta);
res[dim1][dim1] = Math.cos(theta);
return res;
}

multiplyRotationMatrix(
matrix: number[][],
i: number,
j: number,
theta: number,
) {
if (theta == 0) {
return matrix;
}
let sin = Math.sin(theta);
let cos = Math.cos(theta);
// var res = matrix.map(d=>d.slice());
let columnI = matrix.map((d) => d[i]);
let columnJ = matrix.map((d) => d[j]);
for (let rowIndex = 0; rowIndex < matrix.length; rowIndex++) {
matrix[rowIndex][i] = columnI[rowIndex] * cos +
columnJ[rowIndex] * (-sin);
matrix[rowIndex][j] = columnI[rowIndex] * sin + columnJ[rowIndex] * cos;
}
return matrix;
}

get3dRotationMatrix(t: number) {
let theta = 0.0 * t;
let cos = Math.cos(theta);
let sin = Math.sin(theta);
return [
[cos, 0, sin] as const,
[0, 1, 0] as const,
[-sin, 0, cos] as const,
] as const;
}

project(data: number[][], dt?: number, view?: number[][]) {
let matrix = this.getMatrix(dt);
matrix = math.transpose(matrix);
matrix = matrix.slice(0, 3);
matrix = math.transpose(matrix);
if (view !== undefined) {
matrix = math.multiply(view, matrix) as number[][];
}
return math.multiply(data, matrix.slice(0, data[0].length)) as number[][];
}
}
Loading

0 comments on commit afe55c0

Please sign in to comment.