Skip to content

Commit

Permalink
Added activation function editing
Browse files Browse the repository at this point in the history
  • Loading branch information
Niyaz-Mohamed committed Aug 30, 2024
1 parent b0f81b5 commit 8ebc7d9
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 23 deletions.
3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ <h2>Rules</h2>
<option value="waves">Waves</option>
<option value="mitosis">Mitosis</option>
<option value="pathways">Pathways</option>
<option value="game-of-life">Game of Life</option>
</select>
</div>
<div class="rule-div">
Expand Down Expand Up @@ -499,7 +500,7 @@ <h2>Rules</h2>
<option value="absolute">Absolute</option>
<option value="tanh">tanh</option>
<option value="inverse-gaussian">Inverse Gaussian</option>
<option selected>Custom</option>
<option selected disabled>Custom</option>
</select>
<div id="neural-code-editor"></div>
</div>
Expand Down
83 changes: 62 additions & 21 deletions js/inputs/settings.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { automata, NeuralCA, setAutomata } from "../automata.js";
import {
genShieldedFunction,
getConsoleText,
mooreNeighborhood,
reshape2DArray,
Expand Down Expand Up @@ -377,47 +378,69 @@ presetSelector.onchange = (event) => {
[-0.9, -0.66, -0.9],
[0.68, -0.9, 0.68],
],
activation: (x) => -(1 / Math.pow(2, 0.6 * Math.pow(x, 2))) + 1,
activation: eval(
`(${"function activation(x) {\n\treturn -(1 / Math.pow(2, 0.6 * Math.pow(x, 2))) + 1\n}"})`
),
},
stars: {
weights: [
[0.565, -0.716, 0.565],
[-0.759, 0.627, -0.759],
[0.565, -0.716, 0.565],
],
activation: (x) => Math.abs(x),
activation: eval(
`(${"function activation(x) {\n\treturn Math.abs(x)\n}"})`
),
},
"slime-mold": {
weights: [
[0.8, -0.85, 0.8],
[-0.85, -0.2, -0.85],
[0.8, -0.85, 0.8],
],
activation: (x) => -1 / (0.89 * Math.pow(x, 2) + 1) + 1,
activation: eval(
`(${"function activation(x) {\n\treturn -1 / (0.89 * Math.pow(x, 2) + 1) + 1\n}"})`
),
},
waves: {
weights: [
[0.565, -0.716, 0.565],
[-0.716, 0.627, -0.716],
[0.565, -0.716, 0.565],
],
activation: (x) => Math.abs(1.2 * x),
activation: eval(
`(${"function activation(x) {\n\treturn Math.abs(1.2 * x)\n}"})`
),
},
mitosis: {
weights: [
[-0.939, 0.88, -0.939],
[0.88, 0.4, 0.88],
[-0.939, 0.88, -0.939],
],
activation: (x) => -1 / (0.91 * Math.pow(x, 2) + 1) + 1,
activation: eval(
`(${"function activation(x) {\n\treturn -1 / (0.91 * Math.pow(x, 2) + 1) + 1\n}"})`
),
},
pathways: {
weights: [
[0.0, 1.0, 0.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 0.0],
],
activation: (x) => 1 / Math.pow(2, Math.pow(x - 3.5, 2)),
activation: eval(
`(${"function activation(x) {\n\treturn 1 / Math.pow(2, Math.pow(x - 3.5, 2))\n}"})`
),
},
"game-of-life": {
weights: [
[1.0, 1.0, 1.0],
[1.0, 9.0, 1.0],
[1.0, 1.0, 1.0],
],
activation: eval(
`(${"function activation(x) {\n\tif (x == 3 || x == 11 || x == 12) {\n\treturn 1;\n}\nreturn 0}"})`
),
},
};

Expand All @@ -430,11 +453,10 @@ presetSelector.onchange = (event) => {
createGrid("neural-settings");

// Update activation
const activationSelector = document.getElementById(
"neural-activation-select"
);
console.log(event.target.value);
activationSelector.selectedIndex = activationSelector.options.length - 1; // Set to custom activation
automata.activation = argMap[event.target.value].activation;
editor.setValue(automata.activation.toString());
automata.randomize();
};

Expand All @@ -445,15 +467,27 @@ activationSelector.onchange = (event) => {
setActivation(event.target.value);
};

function setActivation(type, args = []) {
function setActivation(type) {
// String representations of preset strings
const funcMap = {
identity: (x) => x,
power: (x) => Math.pow(x, 2),
absolute: (x) => Math.abs(x),
tanh: (x) => (Math.exp(2 * x) - 1) / (Math.exp(2 * x) + 1),
"inverse-gaussian": (x) => -(1 / Math.pow(2, Math.pow(x, 2))) + 1,
identity: "function activation(x) {\n\treturn x;\n}",
power: "function activation(x) {\n\treturn Math.pow(x, 2);\n}",
absolute: "function activation(x) {\n\treturn Math.abs(x);\n}",
tanh: "function activation(x) {\n\treturn (Math.exp(2 * x) - 1) / (Math.exp(2 * x) + 1);\n}",
"inverse-gaussian":
"function activation(x) {\n\treturn -(1 / Math.pow(2, Math.pow(x, 2))) + 1;\n}",
};
automata.activation = funcMap[type];

// Convert string representations to actual functions using eval
const evaluatedFuncMap = Object.fromEntries(
Object.entries(funcMap).map(([key, funcString]) => {
return [key, eval(`(${funcString})`)];
})
);
automata.activation = evaluatedFuncMap[type];

// Update code editor
editor.setValue(automata.activation.toString());
}

// Intialize activation func code editor
Expand All @@ -470,14 +504,21 @@ editor.session.setUseSoftTabs(true);
editor.setValue(
"function activation(x) {\n\treturn -(1 / Math.pow(2, 0.6 * Math.pow(x, 2))) + 1;\n}"
);
editor.session.on("change", function (delta) {
editor.session.on("change", function (_) {
// Set to custom activation
activationSelector.selectedIndex = activationSelector.options.length - 1;
// Parse the code
const code = editor.getValue();
try {
// Evaluate the code and assign the function to a variable
const activation = eval(`(${code})`);
console.log(eval(`(${code})`));
// Evaluate the code and test it on a value
const activation = genShieldedFunction(eval(`(${code})`));
const testValues = [Math.random(), Math.random(), Math.random(), 0, 1];
testValues.forEach((value) => activation(value));
automata.activation = activation;
setConsoleText("Updated Activation Function!");
} catch (error) {
console.error("Error in the code:", error);
console.log(`Error: ${error}`);
setConsoleText("Invalid Activation Function!");
}
});

Expand Down
13 changes: 12 additions & 1 deletion js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,17 @@ export function reshape2DArray(
return newArray;
}

// Parses a function string and shields against misuse
export function genShieldedFunction(func) {
return (x) => {
// Create a new scope for `f`
return (function () {
const document = null;
const window = null;
return func(x);
})();
};
}
// Generates random number using a normal distribution
export function gaussianRandom(mean, variance) {
let u1 = Math.random();
Expand Down Expand Up @@ -237,7 +248,7 @@ export function shiftHue(rgbColor, hueShift = 0) {
const newR = r * matrix[0][0] + g * matrix[0][1] + b * matrix[0][2];
const newG = r * matrix[1][0] + g * matrix[1][1] + b * matrix[1][2];
const newB = r * matrix[2][0] + g * matrix[2][1] + b * matrix[2][2];
// Clamp values within range od RGB
// Clamp values within range of RGB
return [
Math.round(Math.max(Math.min(newR, 255), 0)),
Math.round(Math.max(Math.min(newG, 255), 0)),
Expand Down

0 comments on commit 8ebc7d9

Please sign in to comment.