Skip to content

Instantly share code, notes, and snippets.

@reedspool
Created September 29, 2023 05:39
Show Gist options
  • Save reedspool/72c7454263ef9783708a6c7d6d9ed6da to your computer and use it in GitHub Desktop.
Save reedspool/72c7454263ef9783708a6c7d6d9ed6da to your computer and use it in GitHub Desktop.
Symbolic Differentiator V1
// I wrote about this at https://reeds.website/project-symbolic-differentiator
function Unexpected(character) {
return new Error("Unexpected character '" + character + "'");
}
function parse(text) {
// Array of all the text without whitespace
const characters = Array.from(text.replaceAll(/\s/g, ""));
const terms = [];
const freshTerm = {
coefficient: "",
variable: null,
exponent: "",
};
function finishTerm() {
if (term.coefficient === "") term.coefficient = "1";
if (term.variable === null && term.exponent === "") term.exponent = "0";
if (term.variable !== null && term.exponent === "") term.exponent = "1";
terms.push(term);
term = { ...freshTerm };
state = "beginning";
}
let term = { ...freshTerm };
let state = "beginning";
let lastCoefficient = "";
for (c of characters) {
switch (state) {
case "beginning":
if (c.match(/[0-9]/)) {
term.coefficient += c;
state = "coefficient";
} else if (c.match(/[a-zA-Z]/)) {
term.variable = c;
state = "variable";
} else {
throw new Unexpected(c);
}
break;
case "coefficient":
if (c.match(/[0-9]/)) {
term.coefficient += c;
state = "coefficient";
} else if (c.match(/[a-zA-Z]/)) {
term.variable = c;
state = "variable";
} else if (c === "+") {
finishTerm();
} else {
throw new Unexpected(c);
}
break;
case "variable":
if (c === "^") {
state = "exponent";
} else if (c === "+") {
finishTerm();
} else {
throw new Unexpected(c);
}
break;
case "exponent":
if (c.match(/[0-9]/)) {
term.exponent += c;
} else if (c === "+") {
finishTerm();
} else {
throw new Unexpected(c);
}
break;
}
}
finishTerm();
return terms;
}
function differentiate(terms) {
return terms
.filter(({ exponent }) => Number(exponent) > 0)
.map(({ coefficient, variable, exponent }) => ({
coefficient: String(Number(coefficient) * Number(exponent)),
variable: Number(exponent) === 1 ? null : variable,
exponent: String(Number(exponent) - 1),
}));
}
const expectedParsed = [
{
coefficient: "30",
variable: "x",
exponent: "52",
},
{
coefficient: "29",
variable: "x",
exponent: "1",
},
{
coefficient: "1",
variable: "x",
exponent: "2",
},
{
coefficient: "5",
variable: null,
exponent: "0",
},
];
const expectedDifferentiated = [
{
coefficient: "1560",
variable: "x",
exponent: "51",
},
{
coefficient: "29",
variable: null,
exponent: "0",
},
{
coefficient: "2",
variable: "x",
exponent: "1",
},
];
const input = "30x^52+29x+x^2+5";
const resultParsed = parse(input);
console.log("\nInput:\n");
console.log(input);
console.log("\nParsed:");
console.log(resultParsed);
console.log(
JSON.stringify(expectedParsed) === JSON.stringify(resultParsed)
? "Does match expected!"
: "Does NOT match expected!"
);
const resultDifferentiated = differentiate(resultParsed);
console.log("\nDifferentiated:");
console.log(resultDifferentiated);
console.log(
JSON.stringify(expectedDifferentiated) ===
JSON.stringify(resultDifferentiated)
? "Does match expected!"
: "Does NOT match expected!"
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment