Skip to content

Commit

Permalink
Preparing data in progress...
Browse files Browse the repository at this point in the history
  • Loading branch information
Smoren committed May 14, 2024
1 parent c26192f commit ec2a7ba
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 97 deletions.
5 changes: 3 additions & 2 deletions src/lib/analysis/compounds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ export class CompoundsAnalyzer implements CompoundsAnalyzerSummary {
private readonly compoundsTypesMap: Array<Compound[]>;
private readonly atoms: Array<AtomInterface>;
private readonly atomsTypesMap: Array<AtomInterface[]>;
private readonly typesCount: number;

constructor(compounds: Array<Compound>, atoms: Array<AtomInterface>) {
this.compounds = compounds;
this.atoms = atoms;
this.typesCount = Math.max(...atoms.map((atom) => atom.type)) + 1;
this.compoundsTypesMap = this.groupCompoundsByTypes();
this.atomsTypesMap = this.groupAtomsByTypes();
}
Expand Down Expand Up @@ -155,8 +157,7 @@ export class CompoundsAnalyzer implements CompoundsAnalyzerSummary {

private convertMapToArray<T>(map: Record<number, T[]>): Array<T[]> {
const types = Object.keys(map).map((key) => Number(key));
const maxType = Math.max(...types);
const result: Array<T[]> = Array.from({ length: maxType+1 }, () => []);
const result: Array<T[]> = Array.from({ length: this.typesCount }, () => []);

for (const type of types) {
result[type] = map[type];
Expand Down
77 changes: 50 additions & 27 deletions src/lib/analysis/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,62 @@
import type { TotalSummary } from '../types/analysis';
import { arrayUnaryOperation } from '../math';
import type { TotalSummary, TotalSummaryWeights } from '../types/analysis';
import { sortedNumbers, weighArray, weighMatrix } from '../math';

function prepareArray<T extends number>(input: T[], sort: boolean): T[] {
if (!sort) {
return [...input];
}
return [...input].sort((lhs, rhs) => lhs - rhs);
function createTransparentWeights(): TotalSummaryWeights {
return {
ATOMS_MEAN_SPEED: 1,
ATOMS_TYPE_MEAN_SPEED: 1,
ATOMS_TYPE_LINKS_MEAN_COUNT: 1,
LINKS_CREATED_MEAN: 1,
LINKS_DELETED_MEAN: 1,
LINKS_TYPE_CREATED_MEAN: 1,
LINKS_TYPE_DELETED_MEAN: 1,
COMPOUNDS_PER_ATOM: 1,
COMPOUNDS_PER_ATOM_BY_TYPES: 1,
COMPOUND_LENGTH_SUMMARY: {
size: 1,
frequency: 1,
min: 1,
max: 1,
mean: 1,
median: 1,
},
COMPOUND_LENGTH_BY_TYPES_SUMMARY: {
size: 1,
frequency: 1,
min: 1,
max: 1,
mean: 1,
median: 1,
},
};
}

export function prepareTotalSummary(summary: TotalSummary, sort: boolean = true): number[] {
export function weighTotalSummary(
summary: TotalSummary,
weights?: TotalSummaryWeights,
rowModifier?: (row: number[]) => number[],
): number[] {
weights = weights ?? createTransparentWeights();
rowModifier = rowModifier ?? ((row) => row);

const compoundsPerAtom = summary.COMPOUNDS.size / summary.WORLD.ATOMS_COUNT[0];
const compoundsPerAtomByTypes = arrayUnaryOperation(
summary.COMPOUNDS.sizeByTypes,
(x) => x / summary.WORLD.ATOMS_COUNT[0],
);
const compoundsPerAtomByTypes = summary.COMPOUNDS.sizeByTypes.map((x) => x / summary.WORLD.ATOMS_COUNT[0]);
const compoundLengthSummary = Object.values(summary.COMPOUNDS.itemLengthSummary);
const compoundLengthByTypesSummary = summary.COMPOUNDS.itemLengthByTypesSummary.map(
(item) => Object.values(item),
);

return [
prepareArray(summary.WORLD.ATOMS_MEAN_SPEED, sort),
prepareArray(summary.WORLD.ATOMS_TYPE_MEAN_SPEED, sort),
prepareArray(summary.WORLD.ATOMS_TYPE_LINKS_MEAN_COUNT, sort),
prepareArray(summary.WORLD.LINKS_CREATED_MEAN, sort),
prepareArray(summary.WORLD.LINKS_DELETED_MEAN, sort),
prepareArray(summary.WORLD.LINKS_TYPE_CREATED_MEAN, sort),
prepareArray(summary.WORLD.LINKS_TYPE_DELETED_MEAN, sort),
compoundsPerAtom,
compoundsPerAtomByTypes,
compoundLengthSummary,
compoundLengthByTypesSummary,
weighArray(rowModifier(summary.WORLD.ATOMS_MEAN_SPEED), weights.ATOMS_MEAN_SPEED),
weighArray(rowModifier(summary.WORLD.ATOMS_TYPE_MEAN_SPEED), weights.ATOMS_TYPE_MEAN_SPEED),
weighArray(rowModifier(summary.WORLD.ATOMS_TYPE_LINKS_MEAN_COUNT), weights.ATOMS_TYPE_LINKS_MEAN_COUNT),
weighArray(rowModifier(summary.WORLD.LINKS_CREATED_MEAN), weights.LINKS_CREATED_MEAN),
weighArray(rowModifier(summary.WORLD.LINKS_DELETED_MEAN), weights.LINKS_DELETED_MEAN),
weighArray(rowModifier(summary.WORLD.LINKS_TYPE_CREATED_MEAN), weights.LINKS_TYPE_CREATED_MEAN),
weighArray(rowModifier(summary.WORLD.LINKS_TYPE_DELETED_MEAN), weights.LINKS_TYPE_DELETED_MEAN),
weighArray(rowModifier([compoundsPerAtom]), weights.COMPOUNDS_PER_ATOM),
weighArray(rowModifier(compoundsPerAtomByTypes), weights.COMPOUNDS_PER_ATOM_BY_TYPES),
weighArray(rowModifier(compoundLengthSummary), Object.values(weights.COMPOUND_LENGTH_SUMMARY)),
weighMatrix(compoundLengthByTypesSummary, Object.values(weights.COMPOUND_LENGTH_BY_TYPES_SUMMARY), rowModifier),
].flat(Infinity) as number[];
}

export function prepareTotalSummaryList(summaryList: TotalSummary[]): number[] {
return summaryList.map((summary) => prepareTotalSummary(summary)).flat(1);
}
14 changes: 14 additions & 0 deletions src/lib/math/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ import {
concatTensors,
setMatrixMainDiagonal,
setTensorMainDiagonal,
makeMatrixSymmetric,
makeTensorSymmetric,
sortedNumbers,
weighArray,
weighMatrix,
normalizeArray,
normalizeMatrixColumns,
} from './operations';
import {
createVector,
Expand Down Expand Up @@ -48,6 +55,13 @@ export {
concatTensors,
setMatrixMainDiagonal,
setTensorMainDiagonal,
makeMatrixSymmetric,
makeTensorSymmetric,
sortedNumbers,
weighArray,
weighMatrix,
normalizeArray,
normalizeMatrixColumns,
round,
roundWithStep,
};
177 changes: 116 additions & 61 deletions src/lib/math/operations.ts
Original file line number Diff line number Diff line change
@@ -1,110 +1,165 @@
import { createEmptyMatrix, createEmptyTensor } from './factories';
import { isEqual } from "@/lib/math/helpers";
import { fullCopyObject } from "@/lib/utils/functions";

export function arrayUnaryOperation<T>(
input: Array<T>,
operator: (item: T) => T,
): Array<T> {
const result: Array<T> = [];
const result: Array<T> = [];

for (const item of input) {
result.push(operator(item));
}
for (const item of input) {
result.push(operator(item));
}

return result;
return result;
}

export function arrayBinaryOperation<T>(
lhs: Array<T>,
rhs: Array<T>,
operator: (lhs: T, rhs: T) => T,
): Array<T> {
const result: Array<T> = [];
const len = Math.min(lhs.length, rhs.length);
const result: Array<T> = [];
const len = Math.min(lhs.length, rhs.length);

for (let i=0; i<len; ++i) {
result.push(operator(lhs[i], rhs[i]));
}
for (let i = 0; i < len; ++i) {
result.push(operator(lhs[i], rhs[i]));
}

return result;
return result;
}

export function concatArrays<T>(lhs: T[], rhs: T[]): T[] {
return [...lhs, ...rhs];
return [...lhs, ...rhs];
}

export function concatMatrices(lhs: number[][], rhs: number[][], defaultValue: number = 0): number[][] {
const n = lhs.length + rhs.length;
const m = lhs[0].length + rhs[0].length;
const result = createEmptyMatrix(n, m, defaultValue);

for (let i=0; i<lhs.length; ++i) {
const row = lhs[i];
for (let j=0; j<row.length; ++j) {
result[i][j] = row[j];
}
const n = lhs.length + rhs.length;
const m = lhs[0].length + rhs[0].length;
const result = createEmptyMatrix(n, m, defaultValue);

for (let i = 0; i < lhs.length; ++i) {
const row = lhs[i];
for (let j = 0; j < row.length; ++j) {
result[i][j] = row[j];
}
}

for (let i=0; i<rhs.length; ++i) {
const row = rhs[i];
for (let j=0; j<row.length; ++j) {
result[lhs.length + i][lhs[0].length + j] = row[j];
}
for (let i = 0; i < rhs.length; ++i) {
const row = rhs[i];
for (let j = 0; j < row.length; ++j) {
result[lhs.length + i][lhs[0].length + j] = row[j];
}
}

return result;
return result;
}

export function concatTensors(lhs: number[][][], rhs: number[][][], defaultValue: number = 0): number[][][] {
const n = lhs.length + rhs.length;
const m = lhs[0].length + rhs[0].length;
const k = lhs[0][0].length + rhs[0][0].length;
const result = createEmptyTensor(n, m, k, defaultValue);

for (let i=0; i<lhs.length; ++i) {
for (let j=0; j<lhs[i].length; ++j) {
for (let k=0; k<lhs[i][j].length; ++k) {
result[i][j][k] = lhs[i][j][k];
}
}
const n = lhs.length + rhs.length;
const m = lhs[0].length + rhs[0].length;
const k = lhs[0][0].length + rhs[0][0].length;
const result = createEmptyTensor(n, m, k, defaultValue);

for (let i = 0; i < lhs.length; ++i) {
for (let j = 0; j < lhs[i].length; ++j) {
for (let k = 0; k < lhs[i][j].length; ++k) {
result[i][j][k] = lhs[i][j][k];
}
}
}

for (let i=0; i<rhs.length; ++i) {
for (let j=0; j<rhs[i].length; ++j) {
for (let k=0; k<rhs[i][j].length; ++k) {
result[lhs.length + i][lhs[0].length + j][lhs[0][0].length + k] = rhs[i][j][k];
}
}
for (let i = 0; i < rhs.length; ++i) {
for (let j = 0; j < rhs[i].length; ++j) {
for (let k = 0; k < rhs[i][j].length; ++k) {
result[lhs.length + i][lhs[0].length + j][lhs[0][0].length + k] = rhs[i][j][k];
}
}
}

return result;
return result;
}

export function setMatrixMainDiagonal<T>(matrix: T[][], value: T): T[][] {
for (let i=0; i<matrix.length; ++i) {
matrix[i][i] = value;
}
return matrix;
for (let i = 0; i < matrix.length; ++i) {
matrix[i][i] = value;
}
return matrix;
}

export function setTensorMainDiagonal<T>(tensor: T[][][], value: T): T[][][] {
for (let i=0; i<tensor.length; ++i) {
tensor[i][i][i] = value;
}
return tensor;
for (let i = 0; i < tensor.length; ++i) {
tensor[i][i][i] = value;
}
return tensor;
}

export function makeMatrixSymmetric<T>(matrix: T[][]): T[][] {
for (let i=0; i<matrix.length; ++i) {
for (let j=0; j<i; ++j) {
matrix[i][j] = matrix[j][i];
}
for (let i = 0; i < matrix.length; ++i) {
for (let j = 0; j < i; ++j) {
matrix[i][j] = matrix[j][i];
}
return matrix;
}
return matrix;
}

export function makeTensorSymmetric<T>(tensor: T[][][]): T[][][] {
for (let i=0; i<tensor.length; ++i) {
makeMatrixSymmetric(tensor[i]);
for (let i = 0; i < tensor.length; ++i) {
makeMatrixSymmetric(tensor[i]);
}
return tensor;
}

export function sortedNumbers(input: number[]): number[] {
return [...input].sort((lhs, rhs) => lhs - rhs);
}

export function weighArray(input: number[], weight: number | number[]): number[] {
if (Array.isArray(weight)) {
return input.map((x, i) => x * weight[i]);
}
return input.map((x) => x * weight);
}

export function weighMatrix(
input: number[][],
weight: number | number[],
rowModifier?: (row: number[]) => number[],
): number[][] {
return input.map((item) => weighArray((rowModifier ?? ((row) => row))(item), weight));
}

export function normalizeArray(input: number[]): number[] {
const result = fullCopyObject(input);

if (result.length === 0) {
return result;
}

const min = Math.min(...result);
const max = Math.max(...result);

if (isEqual(min, max)) {
return isEqual(min, 0) ? result.map(() => 0) : result.map(() => 1);
}

return result.map((x) => (x - min) / (max - min));
}

export function normalizeMatrixColumns(input: number[][]): number[][] {
const result = fullCopyObject(input);

if (result.length === 0) {
return result;
}

for (let i = 0; i < result[0].length; i++) {
const columnNormalized = normalizeArray(result.map((row) => row[i]));
for (let j = 0; j < result.length; j++) {
result[j][i] = columnNormalized[j];
}
return tensor;
}

return result;
}
14 changes: 14 additions & 0 deletions src/lib/types/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,17 @@ export type TotalSummary = {
WORLD: WorldSummary<number[]>;
COMPOUNDS: CompoundsAnalyzerSummary;
}

export type TotalSummaryWeights = {
ATOMS_MEAN_SPEED: number;
ATOMS_TYPE_MEAN_SPEED: number;
ATOMS_TYPE_LINKS_MEAN_COUNT: number;
LINKS_CREATED_MEAN: number;
LINKS_DELETED_MEAN: number;
LINKS_TYPE_CREATED_MEAN: number;
LINKS_TYPE_DELETED_MEAN: number;
COMPOUNDS_PER_ATOM: number;
COMPOUNDS_PER_ATOM_BY_TYPES: number;
COMPOUND_LENGTH_SUMMARY: CompoundsSummary;
COMPOUND_LENGTH_BY_TYPES_SUMMARY: CompoundsSummary;
}
Loading

0 comments on commit ec2a7ba

Please sign in to comment.