figbertmath

[RADIOACTIVE] miscellaneous math programs in website form
git clone git://git.figbert.com/figbertmath.git
Log | Files | Refs | README

commit baab68b5a12bcd8ee673d97587141ec825b63185
parent 74c125455aba0f112360afc1fbf9c3a4fce5b805
Author: therealFIGBERT <figbertwelner@gmail.com>
Date:   Wed,  4 Dec 2019 09:24:32 -0800

Add simultaneous equation solver graphics, add immutability-helper package

Adding dynamic generation of equations buttons using matrix iteration in the largebutton/index.js and simultaneousEquation.js files. The solver does not yet execute the defined calculate function.

The immutability-helper package is used to update the matrix in the SimultaneousEquation class' state property.

Diffstat:
Mpackage.json | 1+
Msrc/components/highLevel/simultaneousEquation.js | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/components/lowLevel/largeButton/index.js | 63++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/components/lowLevel/largeButton/styles.module.css | 4++++
Msrc/components/lowLevel/pad/index.js | 11++++-------
Myarn.lock | 7+++++++
6 files changed, 208 insertions(+), 13 deletions(-)

diff --git a/package.json b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "immutability-helper": "^3.0.1", "prop-types": "^15.7.2", "react": "^16.12.0", "react-dom": "^16.12.0", diff --git a/src/components/highLevel/simultaneousEquation.js b/src/components/highLevel/simultaneousEquation.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import update from 'immutability-helper'; import { CalcOut } from "../lowLevel/calcOut"; import { Pad } from "../lowLevel/pad"; @@ -7,16 +8,144 @@ export class SimultaneousEquation extends React.Component { constructor(props) { super(props); this.state = { - output: '', - type: 'Two Variables', - amount: '2' + output: [], + dimension: 2, + coefficients: [['', ''], ['', '']], + sums: ['', ''] }; + this.modifyMatrix = this.modifyMatrix.bind(this); + this.solveMatrix = this.solveMatrix.bind(this); + this.onChange = this.onChange.bind(this); + } + + onChange(object) { + let name = object.target.name, + i, k; + const value = object.target.value; + if (name.indexOf('c') > -1) { + name = name.substr(1); + i = Number(name.split('_')[0]); + k = Number(name.split('_')[1]); + this.setState({ + coefficients: update(this.state.coefficients, {[i]: {[k]: {$set: value}}}) + }); + } else if (name.indexOf('s') > -1) { + i = Number(name.substr(1)); + this.setState({ + sums: update(this.state.sums, {[i]: {$set: value}}) + }); + } else { + this.setState({ + output: 'ERROR' + }); + } + } + + + modifyMatrix(object) { + const value = object.target.value; + let numOfVars = [], + rows = [], + sums = [], + newDimension; + if (value === 'raise') { + newDimension = this.state.dimension + 1; + } else if (value === 'lower') { + newDimension = this.state.dimension - 1; + if (newDimension < 2) { + newDimension = 2; + } + } + for (let i = 0; i < newDimension; i++) { + numOfVars.push(''); + sums.push(''); + } + for (let i = 0; i < newDimension; i++) { + rows.push(numOfVars); + } + this.setState({ + dimension: newDimension, + coefficients: rows, + sums: sums + }); + } + + solveMatrix(equations, sums) { + let abs = Math.abs; + function array_fill(i, n, v) { + let a = []; + while (i < n) { + a.push(v); + i++; + } + return a; + } + + // Adds the sums to the equations array + for (let i = 0; i < equations.length; i++) { + equations[i].push(sums[i]); + } + const numberOfEquations = equations.length; + + for (let i = 0; i < numberOfEquations; i++) { + // Iterates over the first column of every row below the current one (i) and determines which row is the largest + let maxEl = abs(equations[i][i]), + maxRow = i; + for (let k = i + 1; k < numberOfEquations; k++) { + if (abs(equations[k][i]) > maxEl) { + maxEl = abs(equations[k][i]); + maxRow = k; + } + } + // Swaps the larger row and the current row, if a swap should be made + if (maxRow !== i) { + for (let k = i; k < numberOfEquations + 1; k++) { + const tmp = equations[maxRow][k]; + equations[maxRow][k] = equations[i][k]; + equations[i][k] = tmp; + } + } + // Makes all lower numbers in the column zero + for (let k = i + 1; k < numberOfEquations; k++) { + const c = -equations[k][i] / equations[i][i]; + for (let j = i; j < numberOfEquations + 1; j++) { + if (i === j) { + equations[k][j] = 0; + } else { + equations[k][j] += c * equations[i][j]; + } + } + } + } + + //Solve the simplified matrix + sums = array_fill(0, numberOfEquations, 0); + for (let i = numberOfEquations - 1; i > -1; i--) { + sums[i] = equations[i][numberOfEquations] / equations[i][i]; + for (let k = i - 1; k > -1; k--) { + equations[k][numberOfEquations] -= equations[k][i] * sums[i]; + } + } + + //Set the output to the array of values + this.setState({ + output: sums + }); } render() { return ( <div> <CalcOut mode={this.props.mode} output={this.state.output} /> + <Pad + type={'large'} + mode={this.props.mode} + buttonValues={['range', [this.state.coefficients, this.state.sums], 'select']} + displayValues={[this.state.dimension, undefined, '…']} + onClick={this.modifyMatrix} + onChange={this.onChange} + onModeClick={this.props.onModeChange} + /> </div> ); } diff --git a/src/components/lowLevel/largeButton/index.js b/src/components/lowLevel/largeButton/index.js @@ -5,7 +5,8 @@ import styles from './styles.module.css'; export class LargeButton extends React.Component { render() { const canBeDisabled = this.props.mode === 'angSize', - acceptsInput = this.props.mode !== 'select'; + acceptsInput = this.props.mode !== 'select', + equationFormat = this.props.mode === 'simultaneousEQ'; if (this.props.value === 'select') { return ( <button @@ -78,6 +79,56 @@ export class LargeButton extends React.Component { </button> ); } + } else if (equationFormat) { + const alphabet = (function(charA, charZ) { + let a = [], i = charA.charCodeAt(0), j = charZ.charCodeAt(0); + for (; i <= j; ++i) { + a.push(String.fromCharCode(i)); + } + return a; + }('a', 'z')); + let coefficients = this.props.value[0], + sums = this.props.value[1], + buttons = []; + for (let i = 0; i < coefficients.length; i++) { + let eq = []; + for (let k = 0; k < coefficients[i].length; k++) { + const name = 'c' + i + '_' + k; + eq.push( + <div> + <input + type='number' + className={styles.smallInput} + name={name} + value={coefficients[i][k]} + onChange={this.props.onChange} + /> + {alphabet[k]} + </div> + ); + if (k + 1 !== coefficients[i].length) { eq.push('+') } + } + eq.push( + '=', + <input + type='number' + className={styles.smallInput} + name={'s' + i} + value={sums[i]} + onChange={this.props.onChange} + /> + ); + buttons.push( + <div className={styles.rowButton}> + {eq} + </div> + ) + } + return ( + <div> + {buttons} + </div> + ); } else if (acceptsInput) { return ( <div className={styles.columnButton}> @@ -111,7 +162,13 @@ LargeButton.propTypes = { onChange: PropTypes.func, onModeClick: PropTypes.func, disabledTruth: PropTypes.bool, - value: PropTypes.string, - displayValue: PropTypes.string, + value: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.array + ]), + displayValue: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]), textValue: PropTypes.string }; \ No newline at end of file diff --git a/src/components/lowLevel/largeButton/styles.module.css b/src/components/lowLevel/largeButton/styles.module.css @@ -9,6 +9,10 @@ input { font-family: Tomorrow, -apple-system, sans-serif; } +.smallInput { + width: 2vmax; +} + .columnButton { background: #ac1a2d; color: rgba(255, 255, 255, .7); diff --git a/src/components/lowLevel/pad/index.js b/src/components/lowLevel/pad/index.js @@ -31,9 +31,9 @@ export class Pad extends React.Component { onClick={onClick} onChange={onChange} onModeClick={onModeClick} - disabledTruth={disabledTruths == null ? false : disabledTruths[index]} value={value} - displayValue={displayValues[index]} + disabledTruth={disabledTruths == null ? false : disabledTruths[index]} + displayValue={displayValues == null ? '' : displayValues[index]} textValue={textValues == null ? '' : textValues[index]} /> ); @@ -48,15 +48,12 @@ export class Pad extends React.Component { } Pad.propTypes = { type: PropTypes.string.isRequired, - buttonValues: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), - PropTypes.arrayOf(PropTypes.string) - ]).isRequired, + buttonValues: PropTypes.array.isRequired, onClick: PropTypes.func, mode: PropTypes.string, onChange: PropTypes.func, onModeClick: PropTypes.func, disabledTruths: PropTypes.arrayOf(PropTypes.bool), - displayValues: PropTypes.arrayOf(PropTypes.string), + displayValues: PropTypes.array, textValues: PropTypes.arrayOf(PropTypes.string) }; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock @@ -4797,6 +4797,13 @@ immer@1.10.0: resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== +immutability-helper@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-3.0.1.tgz#4f609c5afbf8d78cb297970e8af2fba8b0eda1d6" + integrity sha512-U92ROQQt7XkIwrdqCByUI118TQM1hXdKnRQpvKeA0HRyGSnJipu9IWHe4UD8zCN00O8UnQjQzPCgZ1CC3yBzHA== + dependencies: + invariant "^2.2.4" + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"