Last active
October 4, 2020 13:26
-
-
Save chaidhat/0f080e0bb1fefcf73c39ccd7f02bf0fd to your computer and use it in GitHub Desktop.
Approximates simultaneous equations by brute force. Works with multiple solutions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Chaidhat Chaimongkol | |
# 02-10-20 for 5 hours | |
# I have developed a brute-forcer for simultaneous equations with two variables and can work with equations with more than one solution. Below is an example of how to use it. | |
import parser | |
import math | |
import copy | |
from math import sin | |
# const 10^PRECISION_THRESHOLD is the allowable difference in floating point values to be considered equal | |
PRECISION_THRESHOLD = 10 | |
# const is the starting point for lowest error. Should be much higher than expected error for the program. | |
HIGHEST_ERROR = 10**10 | |
class Variable: | |
def __init__(self, name, test_min, test_max, test_step): | |
self.name = name | |
self.test_min = test_min | |
self.test_max = test_max | |
self.test_step = test_step | |
self.val = self.test_min | |
self.lowest_error = HIGHEST_ERROR | |
self.child = None | |
def Simulate(self, f_codes, variables, lowest_error): | |
# append our variables to parent's variables | |
outputs = [] | |
while self.val < self.test_max: | |
# update our variable with current value | |
variables[-1] = round(self.val, PRECISION_THRESHOLD) | |
# is this the bottomost child? | |
if self.child == None: | |
# YES: evaluate the final results | |
error = 0 | |
# evaluate all formulae | |
for f_code in f_codes: | |
output = eval(f_code) | |
error += abs(output) | |
if error < lowest_error[0] + 10**-PRECISION_THRESHOLD: | |
lowest_error[0] = error | |
outputs.append((error, copy.copy(variables))) | |
else: | |
# NO: recurse/branch deeper | |
# append a variable for child use (lists are mutable) | |
variables.append(0) | |
child = copy.copy(self.child) | |
# recursive simulate | |
outputs.extend(child.Simulate(f_codes, variables, lowest_error)) | |
# pop the child's variable out | |
variables.pop() | |
# iterate | |
self.val += self.test_step | |
return outputs | |
def findSimul(formulae, variables): | |
# interface user formulae variable names to actual python identifiers | |
for i, formula in enumerate(formulae): | |
for j, variable in enumerate(variables): | |
formula = formula.replace(variable.name, "[" + str(j) + "]") | |
# final replace, to not have overlapping replaces | |
formulae[i] = formula.replace("[", "variables[") | |
# compile the formulae | |
f_codes = [] | |
for formula in formulae: | |
f_codes.append(parser.expr(formula).compile()) | |
# assign child for recursive evaluation | |
for index, variable in enumerate(variables[:-1]): | |
variable.child = variables[index + 1] | |
# lowest_error is a list to force mutability | |
lowest_error = [HIGHEST_ERROR] | |
# recursively evaluate | |
outputs = variables[0].Simulate(f_codes, [0], lowest_error) | |
# prune errors | |
solutions = [] | |
for output in outputs: | |
error = output[0] | |
# if error == closest error | |
if error <= lowest_error[0] + 10**-PRECISION_THRESHOLD: | |
solution = output[1] | |
for i, solution_n in enumerate(solution): | |
# round floating point errors | |
solution[i] = variables[i].name + " = " + str(round(solution_n, PRECISION_THRESHOLD)) | |
# append only x and y | |
solutions.append(solution) | |
if lowest_error[0] > 1: | |
print("ERROR HIGH", lowest_error[0]) | |
return solutions | |
print("Input amounnt of variables to simulate") | |
answer = int(input("> ")) | |
variables = [] | |
for i in range(answer): | |
print("\tVar", i+1, ": Input name of variable (e.g. x)") | |
variable_name = input("\t> ") | |
print("\tVar", i+1, ": Input minimum test value") | |
variable_min = float(input("\t> ")) | |
print("\tVar", i+1, ": Input maximum test value") | |
variable_max = float(input("\t> ")) | |
print("\tVar", i+1, ": Input step size") | |
variable_step = float(input("\t> ")) | |
variables.append(Variable(variable_name, variable_min, variable_max, variable_step)) | |
print("\n") | |
print("Input amount of formulae to compare") | |
answer = int(input("> ")) | |
formulae = [] | |
for i in range(answer): | |
print("\tFormula", i+1, ": Input formula") | |
formulae.append(input("\t> 0 = ")) | |
print(findSimul(formulae, variables)) | |
""" | |
# you can also use code to figure out variables | |
# we define our variables | |
# minimum test, maximum test | |
# we can also specify a step size | |
# example one: equation with more than one solution | |
x = Variable("x", -20, 20, 0.5) | |
y = Variable("y", -20, 20, 0.5) | |
print(findSimul(["x**2 - x - 6 - y", "6 - 2*x - y"], [x, y])) | |
# example two: find equations with one variable | |
x = Variable("x", -20, 20, 0.0001) | |
print(findSimul(["x**2 - 2"], [x])) | |
# example three: 4 equation with 4 variables | |
w = Variable("w", -10, 10, 1) | |
x = Variable("x", -10, 10, 1) | |
y = Variable("y", -10, 10, 1) | |
z = Variable("z", -10, 10, 1) | |
print(findSimul(["(x + 2*y - 3*z + 4*w) - 12", "(2*x + 2*y - 2*z + 3*w) - 10", "y + z - 1", "x - y + z - 2*w + 4"], [w, x, y, z])) | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Difficult equation
one solution exists.
w = -1,
x = 8,
y = -6,
z = -7,