Skip to content

Instantly share code, notes, and snippets.

@chaidhat
Last active October 4, 2020 13:26
Show Gist options
  • Save chaidhat/0f080e0bb1fefcf73c39ccd7f02bf0fd to your computer and use it in GitHub Desktop.
Save chaidhat/0f080e0bb1fefcf73c39ccd7f02bf0fd to your computer and use it in GitHub Desktop.
Approximates simultaneous equations by brute force. Works with multiple solutions.
# 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]))
"""
@chaidhat
Copy link
Author

chaidhat commented Oct 2, 2020

I have developed a powerful brute-forcer for simultaneous equations with multiple variables and can work with equations with more than one solution. You can specify multiple formulae which uses multiple variables and the program will return the solutions (can be more than one) with the lowest error.
Below is an example of how to use it.

Task

An exponential graph increases from a horizontal asymptote of y = 10. Passes through (0,20) and (10,40).
The graph would use this format of equation:
y = a^(x+b) + 10
To find out constants a and b we can make two simultaneous equations.
a^b + 10 = 20
a^(b+10) + 10 =40

To input into the program, we must rearrange so that the equations are both equal to 0.
a^b - 10 = 0
a^(b+10) - 30 = 0

In the code below, we change 'a' to 'x' and 'b' to 'y'
To save computational time, we can estimate x to be between 0 and 2 and y to be between 0 and 25. We ask it to find to 0.01 precision (step size).

Input

image

Result

My approximate:
x ≈ 1.12, y ≈ 20.01 in about 10 seconds
Theoretical solution:
x = 1.1161..., y = 20.9590...
image

Graph

image

@chaidhat
Copy link
Author

chaidhat commented Oct 3, 2020

Difficult equation

image
image
one solution exists.
w = -1,
x = 8,
y = -6,
z = -7,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment