simultaneousEquation.js (6847B)
1 import React from 'react'; 2 import PropTypes from 'prop-types'; 3 import update from 'immutability-helper'; 4 import { CalcOut } from "../lowLevel/calcOut"; 5 import { Pad } from "../lowLevel/pad"; 6 7 export class SimultaneousEquation extends React.Component { 8 constructor(props) { 9 super(props); 10 this.state = { 11 output: [], 12 dimension: 2, 13 coefficients: [['', ''], ['', '']], 14 sums: ['', ''] 15 }; 16 this.checkSolve = this.checkSolve.bind(this); 17 this.modifyMatrix = this.modifyMatrix.bind(this); 18 this.onChange = this.onChange.bind(this); 19 this.solveMatrix = this.solveMatrix.bind(this); 20 } 21 22 checkSolve() { 23 const coefficients = JSON.parse(JSON.stringify(this.state.coefficients)), 24 sums = JSON.parse(JSON.stringify(this.state.sums)); 25 let truth = true; 26 for (let i = 0; i < coefficients.length; i++) { 27 for (let k = 0; k < coefficients[i].length; k ++) { 28 if (coefficients[i][k] === '') { 29 truth = false; 30 } else { 31 coefficients[i][k] = Number(coefficients[i][k]); 32 } 33 } 34 } 35 if (truth) { 36 for (let i = 0; i < sums.length; i++) { 37 if (sums[i] === '') { 38 truth = false; 39 } else { 40 sums[i] = Number(sums[i]); 41 } 42 } 43 } 44 if (truth) { 45 this.solveMatrix(coefficients, sums) 46 } 47 } 48 49 modifyMatrix(object) { 50 const value = object.target.value; 51 let numOfVars = [], 52 rows = [], 53 sums = [], 54 newDimension; 55 if (value === 'raise') { 56 newDimension = this.state.dimension + 1; 57 if (newDimension > 5) { 58 newDimension = 5; 59 } 60 } else if (value === 'lower') { 61 newDimension = this.state.dimension - 1; 62 if (newDimension < 2) { 63 newDimension = 2; 64 } 65 } 66 for (let i = 0; i < newDimension; i++) { 67 numOfVars.push(''); 68 sums.push(''); 69 } 70 for (let i = 0; i < newDimension; i++) { 71 rows.push(numOfVars); 72 } 73 this.setState({ 74 output: [], 75 dimension: newDimension, 76 coefficients: rows, 77 sums: sums 78 }); 79 } 80 81 onChange(object) { 82 let name = object.target.name, 83 i, k; 84 const value = object.target.value; 85 if (name.indexOf('c') > -1) { 86 name = name.substr(1); 87 i = Number(name.split('_')[0]); 88 k = Number(name.split('_')[1]); 89 this.setState({ 90 coefficients: update(this.state.coefficients, {[i]: {[k]: {$set: value}}}) 91 }, () => { 92 this.checkSolve() 93 }); 94 } else if (name.indexOf('s') > -1) { 95 i = Number(name.substr(1)); 96 this.setState({ 97 sums: update(this.state.sums, {[i]: {$set: value}}) 98 }, () => { 99 this.checkSolve() 100 }); 101 } else { 102 this.setState({ 103 output: 'ERROR' 104 }); 105 } 106 } 107 108 solveMatrix(equations, sums) { 109 let abs = Math.abs; 110 function array_fill(i, n, v) { 111 let a = []; 112 while (i < n) { 113 a.push(v); 114 i++; 115 } 116 return a; 117 } 118 119 // Adds the sums to the equations array 120 for (let i = 0; i < equations.length; i++) { 121 equations[i].push(sums[i]); 122 } 123 const numberOfEquations = equations.length; 124 125 for (let i = 0; i < numberOfEquations; i++) { 126 // Iterates over the first column of every row below the current one (i) and determines which row is the largest 127 let maxEl = abs(equations[i][i]), 128 maxRow = i; 129 for (let k = i + 1; k < numberOfEquations; k++) { 130 if (abs(equations[k][i]) > maxEl) { 131 maxEl = abs(equations[k][i]); 132 maxRow = k; 133 } 134 } 135 // Swaps the larger row and the current row, if a swap should be made 136 if (maxRow !== i) { 137 for (let k = i; k < numberOfEquations + 1; k++) { 138 const tmp = equations[maxRow][k]; 139 equations[maxRow][k] = equations[i][k]; 140 equations[i][k] = tmp; 141 } 142 } 143 // Makes all lower numbers in the column zero 144 for (let k = i + 1; k < numberOfEquations; k++) { 145 const c = -equations[k][i] / equations[i][i]; 146 for (let j = i; j < numberOfEquations + 1; j++) { 147 if (i === j) { 148 equations[k][j] = 0; 149 } else { 150 equations[k][j] += c * equations[i][j]; 151 } 152 } 153 } 154 } 155 156 //Solve the simplified matrix 157 sums = array_fill(0, numberOfEquations, 0); 158 for (let i = numberOfEquations - 1; i > -1; i--) { 159 sums[i] = equations[i][numberOfEquations] / equations[i][i]; 160 for (let k = i - 1; k > -1; k--) { 161 equations[k][numberOfEquations] -= equations[k][i] * sums[i]; 162 } 163 } 164 165 //Round each number to four decimal places 166 const alphabet = (function(charA, charZ) { 167 let a = [], i = charA.charCodeAt(0), j = charZ.charCodeAt(0); 168 for (; i <= j; ++i) { 169 a.push(String.fromCharCode(i)); 170 } 171 return a; 172 }('a', 'z')); 173 for (let i = 0; i < sums.length; i++) { 174 if (sums[i] % 1 !== 0) { 175 sums[i] = Math.round((sums[i] + 0.00001) * 100) / 100; 176 } 177 sums[i] = alphabet[i] + ' = ' + sums[i]; 178 } 179 180 //Set the output to the array of values 181 this.setState({ 182 output: sums 183 }); 184 } 185 186 render() { 187 return ( 188 <div> 189 <CalcOut mode={this.props.mode} output={this.state.output} /> 190 <Pad 191 buttonValues={['range', [this.state.coefficients, this.state.sums], 'select']} 192 displayValues={[this.state.dimension, undefined, '…']} 193 mode={this.props.mode} 194 onChange={this.onChange} 195 onClick={this.modifyMatrix} 196 onModeClick={this.props.onModeChange} 197 type={'large'} 198 /> 199 </div> 200 ); 201 } 202 } 203 SimultaneousEquation.propTypes = { 204 mode: PropTypes.string.isRequired, 205 onModeChange: PropTypes.func.isRequired 206 };