PrettyPFA
PFA was designed for data processing.
PrettyPFA provides a C-like syntax for PFA, with slight difference in syntax from mainstream progrmming languages.
A PrettyPFA document is split into sections, each of which has different rules. The syntax of these sections resembles PFA in YAML.
Not everything is built algorithmically in PFA; some parts of a PFA document, such as pre- and post-processing, are usually written by hand. For these parts, there are compilers that turn human-readable code into PFA.
Below are some examples of building models using PrettyPFA.
Link to complete PrettyPFA reference - https://github.com/opendatagroup/hadrian/wiki/PrettyPFA-Reference
In [1]:
from titus.genpy import PFAEngine
from titus import prettypfa
Finding Square Root¶
In [2]:
pfaDocument = prettypfa.jsonNode("""
name: SquareRoot
input: double
output: union(double, null)
action:
if (input >= 0.0)
m.sqrt(input)
else
null
""")
engine, = PFAEngine.fromJson(pfaDocument)
In [3]:
engine.action(5)
Out[3]:
Rule Based Classification¶
JSON¶
In [4]:
pfaDocument = """
{
"input": {
"type": "record",
"name": "Iris",
"fields": [
{"name": "sepal_length_cm", "type": "double"},
{"name": "sepal_width_cm", "type": "double"},
{"name": "petal_length_cm", "type": "double"},
{"name": "petal_width_cm", "type": "double"},
{"name": "class", "type": "string"}
]
},
"output": "string",
"action": [{
"if": {"<": ["input.petal_length_cm", 2.5]},
"then": {"string": "Iris-setosa"},
"else":{
"if": {"<": ["input.petal_length_cm", 4.8]},
"then": {"string": "Iris-versicolor"},
"else":{
"if": {"<": ["input.petal_width_cm", 1.7]},
"then": {"string": "Iris-versicolor"},
"else": {"string": "Iris-virginica"}
}
}
}]
}
"""
engine, = PFAEngine.fromJson(pfaDocument)
In [5]:
engine.action({"sepal_length_cm": 5.1, "sepal_width_cm": 3.5,
"petal_length_cm": 1.4, "petal_width_cm": 0.2,
"class": "Iris-setosa"})
Out[5]:
In [6]:
import csv
dataset = csv.reader(open("../../assets/iris.csv"))
fields = next(dataset)
numCorrect = 0.0
numTotal = 0.0
for datum in dataset:
asRecord = dict(zip(fields, datum))
if engine.action(asRecord) == asRecord["class"]:
numCorrect += 1.0
numTotal += 1.0
print("accuracy", numCorrect/numTotal)
PrettyPFA (Conditional Statements)¶
In [7]:
pfaDocument = prettypfa.jsonNode('''
input: record(sepal_length_cm: double,
sepal_width_cm: double,
petal_length_cm: double,
petal_width_cm: double)
output: string
action:
if (input.petal_length_cm < 2.5)
"Iris-setosa"
else if (input.petal_length_cm < 4.8)
"Iris-versicolor"
else if (input.petal_width_cm < 1.7)
"Iris-versicolor"
else
"Iris-virginica"
''')
engine, = PFAEngine.fromJson(pfaDocument)
In [8]:
engine.action({"sepal_length_cm": 5.1, "sepal_width_cm": 3.5,
"petal_length_cm": 1.4, "petal_width_cm": 0.2,
"class": "Iris-setosa"})
Out[8]:
PrettyPFA (Rule Based)¶
In [9]:
pfaDocument = prettypfa.jsonNode('''
input: record(sepal_length_cm: double,
sepal_width_cm: double,
petal_length_cm: double,
petal_width_cm: double)
output: string
types:
Rules = array(record(field: string,
cut: double,
result: string))
cells:
rules(Rules) = [
{field: "petal_length_cm", cut: 2.5, result: "Iris-setosa"},
{field: "petal_length_cm", cut: 4.8, result: "Iris-versicolor"},
{field: "petal_width_cm", cut: 1.7, result: "Iris-versicolor"},
{field: "none", cut: -1, result: "Iris-virginica"}
]
action:
var result = "";
for (index = 0; result == ""; index = index + 1) {
var rule = rules[index];
var fieldValue =
if (rule.field == "sepal_length_cm") input.sepal_length_cm
else if (rule.field == "sepal_width_cm") input.sepal_width_cm
else if (rule.field == "petal_length_cm") input.petal_length_cm
else if (rule.field == "petal_width_cm") input.petal_width_cm
else -1.0;
if (rule.field == "none" || fieldValue < rule.cut)
result = rule.result;
};
result
''')
engine, = PFAEngine.fromJson(pfaDocument)
In [10]:
engine.action({"sepal_length_cm": 5.1, "sepal_width_cm": 3.5,
"petal_length_cm": 1.4, "petal_width_cm": 0.2,
"class": "Iris-setosa"})
Out[10]:
Quadratic Formula¶
In [11]:
pfaDocument = prettypfa.json('''
input: record(a: double, b: double, c: double)
output: union(null,
record(Output,
solution1: double,
solution2: double))
action:
var a = input.a, b = input.b, c = input.c;
var discriminant = b**2 - 4*a*c;
if (discriminant >= 0.0) {
// if there are any real solutions, return them
var x1 = -b + m.sqrt(discriminant)/(2*a);
var x2 = -b - m.sqrt(discriminant)/(2*a);
new(Output, solution1: x1, solution2: x2)
}
else
// otherwise, return null (N/A)
null
''')
engine, = PFAEngine.fromJson(pfaDocument)
In [12]:
print(engine.action({"a": 1, "b": 8, "c": 4}))
In [13]:
print(engine.action({"a": 1, "b": 2, "c": 3}))
Applying Function¶
In [14]:
pfa = prettypfa.json("""
input: enum([linear, square, cube])
output: int
action:
apply(input, 2)
fcns:
linear = fcn(x: int -> int) x;
square = fcn(x: int -> int) x**2;
cube = fcn(x: int -> int) x**3;
""")
engine, = PFAEngine.fromJson(pfa)
In [15]:
engine.action("cube")
Out[15]: