This commit is contained in:
Lucas Tadeu Marculino 2025-11-17 19:52:44 -03:00
commit fb20596fba
36 changed files with 8679 additions and 0 deletions

50
www/tests/demo.mjs Normal file
View file

@ -0,0 +1,50 @@
import assert from 'assert';
import { Objective } from '../src/Objective.js';
import { PSO } from '../src/PSO.js';
import { monod, pirt } from '../src/conhecidos.js';
function monodPirt(_, y, params) {
const K_S = params[0];
const mu_max = params[1];
const m_S = params[2];
const Y_XS = params[3];
const X = y[0];
const S = y[1];
const dmu = monod(S, mu_max, K_S);
const dX = X * dmu;
const qS = pirt(dmu, Y_XS, m_S);
const dS = -qS * X;
return [dX, dS];
}
const demoData = [
['tempo', 'substrato', 'celulas'],
[0, 3.0, 0.05],
[1, 2.9835, 0.0595],
[2, 2.964, 0.0708],
[3, 2.9406, 0.0843],
[4, 2.9129, 0.1003],
[5, 2.8799, 0.1194],
[6, 2.8407, 0.1421],
[7, 2.794, 0.1691],
[8, 2.7385, 0.2011],
[9, 2.6725, 0.2393],
[10, 2.5942, 0.2846],
[11, 2.501, 0.3384],
[12, 2.3905, 0.4023],
[13, 2.2594, 0.478],
[14, 2.104, 0.5678],
[15, 1.9202, 0.674],
];
const obj = new Objective(demoData, monodPirt, 100, 2);
const optim = new PSO(obj, 30, [
[0.005, 2],
[0.05, 0.9],
[0.0015, 0.05],
[0.3, 0.7],
]);
optim.run(1.49618, 1.49618, 0.7298, 30);
assert(Number.isFinite(optim.err_best_g));
console.log('Final error', optim.err_best_g);

View file

@ -0,0 +1,107 @@
import assert from 'assert';
import { Objective } from '../src/Objective.js';
import { PSO } from '../src/PSO.js';
import { monod, pirt } from '../src/conhecidos.js';
import { RK4, RK4getvalue } from '../src/runge-kutta.js';
function monodPirt(_, y, params) {
const K_S = params[0];
const mu_max = params[1];
const m_S = params[2];
const Y_XS = params[3];
const X = y[0];
const S = y[1];
const dmu = monod(S, mu_max, K_S);
const dX = X * dmu;
const qS = pirt(dmu, Y_XS, m_S);
const dS = -qS * X;
return [dX, dS];
}
function generateDataset(params, options) {
const {
initialCells,
initialSubstrate,
timeFinal,
sampleCount,
resolution,
} = options;
const y0 = [initialCells, initialSubstrate];
const timeArray = Array.from({ length: resolution + 1 }, (_, i) => (i * timeFinal) / resolution);
const solution = RK4(monodPirt, timeArray, y0, params);
const rows = [['tempo', 'substrato', 'celulas']];
for (let i = 0; i <= sampleCount; i++) {
const timePoint = (i * timeFinal) / sampleCount;
const [cells, substrate] = RK4getvalue(solution, timeArray, timePoint, monodPirt, params);
rows.push([timePoint, substrate, cells]);
}
return rows;
}
function createDeterministicRandom(seed) {
let state = seed >>> 0;
return function random() {
state = (state * 1664525 + 1013904223) >>> 0;
return state / 0x100000000;
};
}
const trueParams = [160, 0.45, 1.5, 0.5];
const dataset = generateDataset(trueParams, {
initialCells: 1.2,
initialSubstrate: 120,
timeFinal: 12,
sampleCount: 12,
resolution: 240,
});
const bounds = [
[140, 200],
[0.3, 0.6],
[1.0, 2.5],
[0.3, 0.7],
];
const objective = new Objective(dataset, monodPirt, 240, 2);
const originalRandom = Math.random;
Math.random = createDeterministicRandom(12345);
let optim;
try {
optim = new PSO(objective, 50, bounds);
optim.run(1.49618, 1.49618, 0.7298, 150);
} finally {
Math.random = originalRandom;
}
const defaultGuess = bounds.map(([min, max]) => (min + max) / 2);
const defaultError = objective.objective(defaultGuess);
assert(
optim.err_best_g < defaultError,
'Swarm should reduce the error compared to the midpoint default parameters',
);
const bestError = optim.err_best_g;
assert(
bestError < 1e-3,
`Best error ${bestError} should approach the synthetic optimum with the default hyperparameters`,
);
const boundaryMargin = optim.pos_best_g.map((value, index) => {
const [min, max] = bounds[index];
const distanceToEdge = Math.min(value - min, max - value);
return distanceToEdge;
});
boundaryMargin.forEach((margin, index) => {
assert(
margin > 1e-3,
`Parameter ${index} is clamped to the boundary, default configuration should explore the interior`,
);
});
console.log('Synthetic dataset best parameters', optim.pos_best_g);