Date post: | 10-Feb-2017 |
Category: |
Software |
Upload: | christoph-matthies |
View: | 280 times |
Download: | 2 times |
Conrad Calmez Christoph Matthies
Robert Lehmann
Pybelsberg
© 2006 by Jeremy Quinn, https://www.flickr.com/photos/sharkbait/3148200301
a = pt(100, 100)b = pt(200, 200)
always {a.dist(b) == 200
}
a.setX(50)a.dist(b) # => 200
babelsberg-js
© 2006 by Jeremy Quinn, https://www.flickr.com/photos/sharkbait/314820030
https://github.com/timfel/babelsberg-js2
a = pt(100, 100)b = pt(200, 200)
always {a.dist(b) == 200
}
a.setX(50)a.dist(b) # => 200
© 2006 by Jeremy Quinn, https://www.flickr.com/photos/sharkbait/314820030
babelsberg-js
3
a = Point(100, 100)b = Point(200, 200)
@alwaysdef constraint(): return a.dist(b) == 200
a.x = 50a.dist(b) # => 200
pybelsberg
© 2006 by Jeremy Quinn, https://www.flickr.com/photos/sharkbait/3148200304
p = Problem()
p.a_x = p.a_y = 100; p.b_x = p.b_y = 200
constraint = …
p.always(constraint)
print(dist((p.a_x, p.a_y), (p.b_x, p.b_y)))# => 200
Boilerplate
6
p = Problem()
p.a_x = p.a_y = 100; p.b_x = p.b_y = 200
constraint = …
p.always(constraint)
print(dist((p.a_x, p.a_y), (p.b_x, p.b_y)))# => 200
Boilerplate
?
7
def constraint(a_x, a_y, b_x, b_y):
return dist((a_x, a_y), (b_x, b_y)) — 200
1Defining the constraint
actually: f(a.x, a.y, b.x, b.y) = √(a.x−b.x)² + (a.y−b.y)²
13
Satisfying constraints
● Finding values to satisfy constraints is solving equations.
● Solving equations means finding theroot of polynomials.
dist((a_x, a_y), (b_x, b_y)) — 200)
14
def constraint(a_x, a_y, b_x, b_y):return dist((a_x, a_y), (b_x, b_y)) — 200
def constraint(a_x, a_y, b_x, b_y):return dist((a_x, a_y), (b_x, b_y)) == 200
2Define constraints naturally
15
class Expr(object):
def __add__(self, other):
return Expr('+', self, other)
def __eq__(self, other):
return Expr('=', self, other)
…
def to_eval(self): return self.left.to_eval() + self.operator \ + self.right.to_eval()
Remember performed operations
16
def constraint(a_x, a_y, b_x, b_y):return dist((a_x, a_y), (b_x, b_y)) == 200
3No explicit declaration of parameters
17
class Namespace(dict): def __getattr__(self, key): print("getattr", key)
def foo(): a + b
ns = Namespace()proxy = types.FunctionType(foo.__code__, ns)proxy()# => ???
Execute function in different global scope
19
Execute function in different global scope
class Namespace(dict): def __getattr__(self, key): print("getattr", key)
def foo(): a + b
ns = Namespace()proxy = types.FunctionType(foo.__code__, ns)proxy()# => getattr a# => getattr b
20
2.7.6case LOAD_GLOBAL:
w = GETITEM(names, oparg); x = PyDict_GetItem(f->f_globals, w); PUSH(x);
3.3.5TARGET(LOAD_GLOBAL)
w = GETITEM(names, oparg); if (PyDict_CheckExact(f->f_globals)) {
… } else {
/* Slow-path if globals or builtins is not a dict */ x = PyObject_GetItem(f->f_globals, w);
… }
PUSH(x);
CPython: Python/ceval.c
21
def constraint():return dist((a_x, a_y), (b_x, b_y)) == 200
a_x = 50print(a_x, a_y, b_x, b_y)# => 50 100 200 -32.14print(dist(a_x, a_y), (b_x, b_y)))# => 200
4Work with global variables
22
TARGET(STORE_FAST) v = POP(); // SETLOCAL(oparg, v);PyObject *tmp = fastlocals[i];fastlocals[i] = value;Py_XDECREF(tmp);FAST_DISPATCH();
CPython: Python/ceval.c
no Python protocol is used -- GAME OVER23
class Namespace(dict): def __setattr__(self, key): print("setattr", key)
def foo(): global a a = 2
ns = Namespace()proxy = types.FunctionType(foo.__code__, ns)proxy()# => no output ☹
Function globals can be overridden?
24
TARGET(STORE_GLOBAL) { PyObject *name = GETITEM(names, oparg); PyObject *v = POP(); int err; err = PyDict_SetItem(f->f_globals, name, v); Py_DECREF(v); if (err != 0) goto error; DISPATCH(); }
GAME OVER -- bug, see ticket #1402289
CPython: Python/ceval.c
25
class Namespace(dict):def __setitem__(self, key, val):
print("setitem", key, val)
class Meta(type):def __prepare__(self, obj):
return Namespace()
class Object(metaclass=Meta):x = 2
# => setitem __module__ __main__# => setitem __qualname__ Object# => setitem x 2
Use class as scope
27
class Namespace(dict):def __setitem__(self, key, val):
print("setitem", key, val)
class Meta(type):def __prepare__(self, obj):
return Namespace()
class Object(metaclass=Meta):x = 2
# => setitem __module__ __main__# => setitem __qualname__ Object# => setitem x 2
Use class as scope
Stamp © 2012 Stuart Miles, FreeDigitalPhotos.net, http://www.freedigitalphotos.net/images/Other_Metaphors_and__g307-Reject_Stamp_p86053.html28
a = Point(100, 100)b = Point(200, 200)
@alwaysdef point_distance_constraint(): return a.dist(b) == 200
a.x = 50# a.__setattr__('x', 50) ~› solve()a.dist(b) # => 200
5Catch instance variables
29
class A(object): pass
def setattr(self, name, value): print("setattr", name, value)
a = A()
a.__setattr__ = setattr
a.x = 10# no output ☹
Notice instance variable assignment
30
3.3.5int PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value){
PyTypeObject *tp = Py_TYPE(v);int err;Py_INCREF(name);
if (tp->tp_setattr != NULL) {err = (*tp->tp_setattr)(v, name_str, value);Py_DECREF(name);return err;
}…return -1;
}
CPython: Objects/object.c
31
class A(object): pass
def setattr(self, name, value): print("setattr", name, value)
a = A()
type(a).__setattr__ = setattr
a.x = 10# => setattr x 10
Use type
32
import codecsdef decode(text): return u'x=5\n' + text.decode('utf8')codecs.register('babelsberg', decode)
# encoding: babelsbergprint(x) # => 5
Custom encoding
*
* not the actual codecs API 34
## main.py ☹import custom_codecimport demo
## demo.py# encoding: babelsbergprint(x) # => 5
Custom encoding, caveat
depends on
35
## main.py ☹import custom_codecimport demo
## demo.py# encoding: babelsbergprint(x) # => 5
Custom encoding, caveat
36
<demo>a = Point(100.0, 100.0)b = Point(200.0, 200.0)
@alwaysdef constant_distance(): yield a.distance(b) == 200
assert_almost_equals(a.distance(b), 200)
a.x = 50assert_almost_equals(a.distance(b), 200)
37
0 LOAD_GLOBAL 0 (a) 3 LOAD_ATTR 1 (dist) 6 LOAD_GLOBAL 2 (b) 9 CALL_FUNCTION 112 LOAD_CONST 1 (200)15 COMPARE_OP 2 (==)18 POP_TOP 19 LOAD_CONST 0 (None)22 RETURN_VALUE
a = Point(100, 100)b = Point(200, 200)
@alwaysdef constant_distance(): a.dist(b) == 200
patch(obj):for each instance variable of obj:
remember original valuereplace with wrapped valuea.x, a.y, b.x, b.y
38
constraint = constant_distance()
for all remembered instance variables:solver.add(instance_variable == value)
solver.add(constraint)solver.solve()
(= 200 (sqrt(+
(**(- a.x b.x)2)
(**(- a.y b.y)2)
)))
39
scipy.optimize.fsolve(
func, #A function that takes at least one argument.
x0, #The starting estimate for the roots of func(x) = 0.
args=(), #Any extra arguments to func.
fprime=None, #A function to compute the Jacobian of func with derivatives across the rows.
By default, the Jacobian will be estimated.
full_output=0, #If True, return optional outputs.
col_deriv=0, #Specify whether the Jacobian function computes derivatives down the columns
(faster, because there is no transpose operation).
xtol=1.49012e-08, #The calculation will terminate if the relative error between two
consecutive iterates is at most xtol
maxfev=0, #The maximum number of calls to the function. If zero, then 100*(N+1) is the maximum where N is the number of elements in x0.
band=None, #If set to a two-sequence containing the number of sub- and super-diagonals within
the band of the Jacobi matrix, the Jacobi matrix is considered banded (only for fprime=None).
epsfcn=None, #A suitable step length for the forward-difference approximation of the
Jacobian (for fprime=None). If epsfcn is less than the machine precision, it is assumed that the relative
errors in the functions are of the order of the machine precision.
factor=100,
diag=None)
42
scipy.optimize.fsolve
constraint = lambda args: [ math.sqrt( (args[0]-args[1])**2 + (args[2]-args[3])**2 ) - 200 ]*4
fsolve(constraint, [1, 1, 1, 1])# => (array([ 201., 1., 1., 1.])
starting values
43
scipy.optimize.fsolve
● Requires transformation○ “Return the roots of the (non-linear) equations defined by
func(x) = 0”○ Cannot access instance variables○ Function value must be closer to 0 if the parameters are
closer to the solution○ x = y → x - y = 0 x > y → x - y if x - y > 0 else 0
● Requires starting estimate○ Hard to determine best value for user-defined equations
44
Z3 theorem prover
● Developed by Microsoft Research http://z3.codeplex.com/
● General-purpose solver (not only for finding roots)● Many built-in theories
○ linear arithmetic, nonlinear arithmetic, bitvectors, arrays, datatypes, quantifiers
● Python bindings○ already does ASTs
46
from z3 import *
a_x, a_y = Real('a.x'), Real('a.y')b_x, b_y = Real('b.x'), Real('b.y')
s = Solver()s.add(a_x == 100, …)s.add(sqrt((a_x-b_x)**2 + (a_y-b_y)**2) == 200)
print(s.check()) # => satprint(s.model()) # => [a.x = 26.79, a.y = 100, …]
Z3 theorem prover
47
Z3 theorem prover
● Quality of life improvement○ Try to minimize the amount of variables that are
changed by the solver due to a constraint
48
Add all constraints● Put a rollback point (“push” in Z3 lingo)● Add all current variables (eg. from Point constructor, example
a = Point(50, 100)) as “soft constraints”○ ie., boolnew → a.x = 50
● Solver tells us which implications are wrong (wereinvalidated to satisfy constraints)
● We remove these from future runs, so that these variables are preferably modified
Z3 theorem prover
49
s.add(sqrt((a.x - b.x)**2 … == 200)s.push()
s.add(a.x == 100, a.y == 100, b.x == 50, b.y == 50)s.check() # => unsat, a.x
s.pop()s.add(a.x == 100, a.y == 100, …)
s.check() # => sat
trans
actio
n
50