Data driven programming; input data and output nice functional code ;)
This is a python 3.6+ project that uses algorithms to transform a set of conditions into functional python code. See some examples.
Install:
$ pip install shatter
pyeda==0.28.0
pandas==0.19.1
sympy==1.1
Keras==2.0.6
numpy==1.13.1
pip==9.0.1
scikit_learn==0.19.0
Copy paste this snippet:
from shatter.solver import Rules
def my_func(a, b):
pass
r = Rules(a=True, b=True, output=True)
r.solve(my_func)
Run it and see how my_func
code changes from pass
to return a and b
. We just
specified that when a
and b
are true then the output should be True
, that is equivalent to the
logical and
operator.
We can add further conditions and shatter
will compute the optimal function to get there.
Now we add 2 additional conditions with r.add()
:
from shatter.solver import Rules
def my_func(a, b):
pass
r = Rules(a=True, b=True, output=True)
r.add(a=False, b=True, output=True)
r.add(a=True, b=False, output=True)
r.solve(my_func)
In this case the solution is a or b
.
What if the output for a given logical condition is not a boolean? In that case a programmer would use an if. In the next example this package solves this case:
Change output to 1
:
from shatter.solver import Rules
def my_func(a, b):
pass
r = Rules(a=True, b=True, output=1)
r.solve(my_func)
The solution will be:
def my_func(a, b):
if a and b:
return 1
return False
Returns 1
or False
otherwise.
Say you want to add a arbitrary piece of code that evaluates to boolean, then:
from shatter.solver import Rules, Code
def any_code(a):
pass
r = Rules(condition=Code(code_str='isinstance(a, str)'), output=2)
r.solve(any_code)
The result should be:
def internal_code(a):
if isinstance(a, str):
return 2
return False
Here the piece of code isinstance(a, str)
was added as the if condition to output 2
Run this code:
from shatter.solver import Rules, Code, Output
def recursive(a):
pass
a = Code()
args = {'a': a + 1}
out = Output(function=recursive, arguments=args)
r = Rules(stopping_condition= a > 2, output=a, default=out)
solution = r.solve(recursive)
The result this time will be a recursive counting function :)
def recursive(a):
if a > 2:
return a
return recursive(a + 1)
With a = Code()
variable a
is initialized as a code piece. Then with
args = {'a': a + 1}
A dictionary for the inputs of the recursive
function is declared. Those inputs are fed into a Output
object:
out = Output(function=recursive, arguments=args)
After out
is passed via default
keyword when initializing the Rules
object. This default
keyword
is used to override the last return statement of the recursive
function.
Copy paste this snippet:
import pandas as pd
from sklearn import datasets
from shatter.solver import Rules, solve
@solve()
def solve_iris(x1, x2, x3, x4):
pass
iris = datasets.load_iris()
x = iris.data
y = iris.target
data_frame = pd.DataFrame(x, columns=['x1', 'x2', 'x3', 'x4'])
# Make binary and add to df
data_frame['output'] = [int(bool(e)) for e in y]
print(data_frame)
r = Rules(data_frame)
solution = r.solve(solve_iris)
Outputs:
def solve_iris():
return x3 >= 2.45
Clone repository:
`git clone [email protected]:jisazaTappsi/shatter.git`
See examples.
Takes a function and a truth table which is processed using the Quine-McCluskey Algorithm. Then finds an optimal boolean expression. This expression is inserted in the method definition.
Is initialized with one rule. Other rules can be added with Rules.add()
method. To generate
the solution call Rules.solve()
method.
The arguments of each rule are specified as optional arguments inside a Rules
constructor or inside a
Rules.add()
call. There are reserved keywords:
output
: Determines the value to be returned when the given condition is True.
output_args
: Dictionary with the values for the arguments when output is a function.
default
: Value returned when non of the rules are True.
Rules.solve()
function
: passed as a callable. This function is going to be filled with the solution to the present task.
unittest=None
: Test Case to be able to run and test the code generated each time the test runs.
See example for a deeper understanding.
solver.Output
: Class that helps define a function with arguments as an output. Has fields:
function
: A callable object.arguments
Dictionary with the function inputs.solver.Code
: Class that helps represent pieces of code. The code is fed as a string (with optional argument str_code
)
or it can be declared as variables. eg:
from shatter.solver import Code
a = Code()
b = Code()
print(a > b)
This will literally print the code a > b
rather than the objects or any result.
solver.Solution
: Class that contains the solution of the problem it includes:
rules
: The information given by the user.implementation
: Plain code.ast
: Abstract syntax tree