# b45ch1/algopy

calling CGraph.jacobian and CGraph.gradient is now more consistent:

Use
cg.jacobian([3.,5,7])
1 parent 6b68a09 commit a7628a33b125960ccedaf34ad4f89cf18e0edb15 Sebastian Walter committed Aug 28, 2012
Showing with 91 additions and 8 deletions.
1. +2 −1 algopy/tracer/tests/test_tracer.py
2. +85 −2 algopy/tracer/tracer.py
3. +4 −4 documentation/sphinx/getting_started.py
4. +0 −1 run_tests.py
 @@ -966,7 +966,8 @@ def test_broadcasting(self): cg = CGraph() x = Function(x) A = Function(A) - z = A - dot(x,x.T)/A + A*x /dot(A[:,:1], A[1:,:]) + #z = A - dot(x,x.T)/A + A*x /dot(A[:,:1], A[1:,:]) + z = A - x cg.trace_off() cg.independentFunctionList = [x,A] cg.dependentFunctionList = [z]
 @@ -202,7 +202,10 @@ def f(x1, x2): raise Exception('you are trying to compute the gradient of a non-scalar valued function') if isinstance(x, list): - x_list = x + if isinstance(x[0], numpy.ndarray) or isinstance(x[0], list): + x_list = x + else: + x_list = [numpy.asarray(x)] else: x_list = [x] @@ -253,6 +256,12 @@ def f(x): print cg.jacobian(numpy.array([1.,2.])) """ + + x = numpy.asarray(x) + + if x.ndim != 1: + raise ValueError("x.ndim must be 1 but provided %d"%x.ndim) + M = self.dependentFunctionList[0].size tmp = numpy.zeros((1,M) + numpy.shape(x)) @@ -286,6 +295,20 @@ def jac_vec(self, x, v): Jv: array_like the Jacobian-vector product """ + + x = numpy.asarray(x) + v = numpy.asarray(v) + + if x.ndim != 1: + raise ValueError("x.ndim must be 1 but provided %d"%x.ndim) + + if v.ndim != 1: + raise ValueError("v.ndim must be 1 but provided %d"%v.ndim) + + if x.shape != v.shape: + raise ValueError("x.shape must be the same as v.shape but provided x.shape=%s, v.shape=%s "%(x.shape, v.shape)) + + N = self.independentFunctionList[0].size tmp = numpy.zeros((2,1) + numpy.shape(x)) @@ -315,6 +338,19 @@ def vec_jac(self, w, x): wJ: array_like the vector-Jacobian product """ + + x = numpy.asarray(x) + w = numpy.asarray(w) + + if x.ndim != 1: + raise ValueError("x.ndim must be 1 but provided %d"%x.ndim) + + if w.ndim != 1: + raise ValueError("w.ndim must be 1 but provided %d"%w.ndim) + + if x.shape != w.shape: + raise ValueError("x.shape must be the same w.shape, but provided x.shape=%s and w.shape=%s"%(x.shape, w.shape)) + M = self.dependentFunctionList[0].size tmp = numpy.zeros((1,1) + numpy.shape(x)) @@ -344,6 +380,11 @@ def hessian(self, x): two-dimensional array containing the Hessian """ + + x = numpy.asarray(x) + + if x.ndim != 1: + raise ValueError("x.ndim must be 1 but provided %d"%x.ndim) utpm_x_list = [algopy.UTPM.init_jacobian(x)] self.pushforward(utpm_x_list) @@ -374,7 +415,19 @@ def hess_vec(self, x, v): """ - xtmp = numpy.zeros((2,1) + x.shape) + x = numpy.asarray(x) + v = numpy.asarray(v) + + if x.ndim != 1: + raise ValueError("x.ndim must be 1 but provided %d"%x.ndim) + + if v.ndim != 1: + raise ValueError("v.ndim must be 1 but provided %d"%v.ndim) + + if x.shape != v.shape: + raise ValueError("x.shape must be the same as v.shape, but provided x.shape=%s and v.shape=%s"%(x.shape, v.shape)) + + xtmp = numpy.zeros((2,1) + numpy.shape(x)) xtmp[0,0] = x; xtmp[1,0] = v xtmp = algopy.UTPM(xtmp) @@ -406,6 +459,19 @@ def vec_hess(self, w, x): one-dimensional array containing the Hessian vector product """ + + x = numpy.asarray(x) + w = numpy.asarray(w) + + if x.ndim != 1: + raise ValueError("x.ndim must be 1 but provided %d"%x.ndim) + + if w.ndim != 1: + raise ValueError("w.ndim must be 1 but provided %d"%w.ndim) + + if x.shape != w.shape: + raise ValueError("x.shape must be the same as w.shape, but provided x.shape=%s and w.shape=%s"%(x.shape, w.shape)) + self.pushforward([algopy.UTPM.init_jacobian(x)]) ybar = self.dependentFunctionList[0].x.zeros_like() ybar.data[0,:] = w @@ -435,6 +501,23 @@ def vec_hess_vec(self, w, x, v): two-dimensional array containing the result """ + + + x = numpy.asarray(x) + v = numpy.asarray(v) + w = numpy.asarray(w) + + if x.ndim != 1: + raise ValueError("x.ndim must be 1 but provided %d"%x.ndim) + + if v.ndim != 1: + raise ValueError("v.ndim must be 1 but provided %d"%v.ndim) + + if w.ndim != 1: + raise ValueError("w.ndim must be 1 but provided %d"%w.ndim) + + if x.shape != v.shape or x.shape != w.shape: + raise ValueError("x.shape must be the same as v.shape or v.shape, but provided x.shape=%s, v.shape=%s and w.shape=%s"%(x.shape, v.shape, w.shape)) # raise NotImplementedError('this function does not work correctly yet')
 @@ -24,10 +24,10 @@ def eval_f(x): cg.dependentFunctionList = [y] # STEP 2: use the computational graph to evaluate derivatives -print 'gradient =', cg.gradient([[3.,5,7]]) -print 'Jacobian =', cg.jacobian([[3.,5,7]]) -print 'Hessian =', cg.hessian([[3.,5.,7.]]) -print 'Hessian vector product =', cg.hess_vec([[3.,5.,7.]],[[4,5,6]]) +print 'gradient =', cg.gradient([3.,5,7]) +print 'Jacobian =', cg.jacobian([3.,5,7]) +print 'Hessian =', cg.hessian([3.,5.,7.]) +print 'Hessian vector product =', cg.hess_vec([3.,5.,7.],[4,5,6])
 @@ -1,5 +1,4 @@ from algopy.tracer.tests.test_tracer import * -from algopy.utps.tests.test_utps import * from algopy.utpm.tests.test_utpm import * from algopy.utpm.tests.test_algorithms import * from algopy.tests.test_globalfuncs import *