def eval_covariance_matrix_qr(J1, J2): M,N = J1.shape K,N = J2.shape Q,R = qr_full(J2.T) Q2 = Q[:,K:].T J1_tilde = dot(J1,Q2.T) Q,R = qr(J1_tilde) V = solve(R.T, Q2) return dot(V.T,V)
def eval_covariance_matrix_qr(J1, J2): M, N = J1.shape K, N = J2.shape Q, R = qr_full(J2.T) Q2 = Q[:, K:].T J1_tilde = dot(J1, Q2.T) Q, R = qr(J1_tilde) V = solve(R.T, Q2) return dot(V.T, V)
def algopy_expm(A, n): """ Compute the matrix exponential using Pade approximation. Reference -- N. J. Higham, "The Scaling and Squaring Method for the Matrix Exponential Revisited", SIAM. J. Matrix Anal. & Appl. 26, 1179 (2005). """ # XXX can I get rid of the n argument to this function? # XXX also my algopy_eye function does not work anyway. ident = algopy_eye(n, dtype=A) U, V = _algopy_pade7(A, ident) return algopy.solve(-U + V, U + V)
def test_pullback_solve_inv_comparison(self): """simple check that the reverse mode of solve(A,Id) computes the same solution as inv(A) """ (D,P,N) = 3,7,10 A_data = numpy.random.rand(D,P,N,N) # make A_data sufficiently regular for p in range(P): for n in range(N): A_data[0,p,n,n] += (N + 1) A = UTPM(A_data) # method 1: computation of the inverse matrix by solving an extended linear system # tracing cg1 = CGraph() A = Function(A) Id = numpy.eye(N) Ainv1 = solve(A,Id) cg1.trace_off() cg1.independentFunctionList = [A] cg1.dependentFunctionList = [Ainv1] # reverse Ainvbar = UTPM(numpy.random.rand(*(D,P,N,N))) cg1.pullback([Ainvbar]) # method 2: direct inversion # tracing cg2 = CGraph() A = Function(A.x) Ainv2 = inv(A) cg2.trace_off() cg2.independentFunctionList = [A] cg2.dependentFunctionList = [Ainv2] # reverse cg2.pullback([Ainvbar]) Abar1 = cg1.independentFunctionList[0].xbar Abar2 = cg2.independentFunctionList[0].xbar assert_array_almost_equal(Abar1.data, Abar2.data)
A = A[:,:2] # Method 1: Naive approach Apinv = dot(inv(dot(A.T,A)),A.T) print('naive approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv),A) - A) print('naive approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A),Apinv) - Apinv) print('naive approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('naive approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv)) # Method 2: Using the differentiated QR decomposition Q,R = qr(A) tmp1 = solve(R.T, A.T) tmp2 = solve(R, tmp1) Apinv = tmp2 print('QR approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv),A) - A) print('QR approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A),Apinv) - Apinv) print('QR approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('QR approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv)) # Method 3: Stable evaluation of the analytical derivative formula A0 = A.data[0,0] A1 = A.data[1,0] Q0, R0 = numpy.linalg.qr(A0)
A = A[:, :2] # Method 1: Naive approach Apinv = dot(inv(dot(A.T, A)), A.T) print('naive approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv), A) - A) print('naive approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A), Apinv) - Apinv) print('naive approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('naive approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv)) # Method 2: Using the differentiated QR decomposition Q, R = qr(A) tmp1 = solve(R.T, A.T) tmp2 = solve(R, tmp1) Apinv = tmp2 print('QR approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv), A) - A) print('QR approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A), Apinv) - Apinv) print('QR approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('QR approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv)) # Method 3: Stable evaluation of the analytical derivative formula A0 = A.data[0, 0] A1 = A.data[1, 0]
y.data[1, 0, :, 0] = [1, 2, 1, 2, 1] alpha = 10**-5 A = dot(x, x.T) + alpha * dot(y, y.T) A = A[:, :2] # Method 1: Naive approach Apinv = dot(inv(dot(A.T, A)), A.T) print('naive approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv), A) - A) print('naive approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A), Apinv) - Apinv) print('naive approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('naive approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv)) # Method 2: Using the differentiated QR decomposition Q, R = qr(A) tmp1 = solve(R.T, A.T) tmp2 = solve(R, tmp1) Apinv = tmp2 print('QR approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv), A) - A) print('QR approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A), Apinv) - Apinv) print('QR approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('QR approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv))
def _truss(A): P = 1e5 # applied loads Ls = 360 # length of sides Ld = np.sqrt(360**2 * 2) # length of diagonals # start = algopy.zeors(10, dtype=) start = np.array([5, 3, 6, 4, 4, 2, 5, 6, 3, 4]) - 1 finish = np.array([3, 1, 4, 2, 3, 1, 4, 3, 2, 1]) - 1 phi = np.deg2rad(np.array([0, 0, 0, 0, 90, 90, -45, 45, -45, 45])) L = np.concatenate(([Ls] * 6, [Ld] * 4), axis=0) nbar = np.size(A) E = 1e7 * np.ones( nbar) # modulus of elasticity rho = 0.1 * np.ones(nbar) # material density Fx = algopy.zeros(6, dtype=float) Fy = np.array([0.0, -P, 0.0, -P, 0.0, 0.0]) rigidx = np.array([0, 0, 0, 0, 1, 1]) rigidy = np.array([0, 0, 0, 0, 1, 1]) n = np.size(Fx) #number of nodes DOF = 2 # compute mass mass = sum(rho * A * L) # assemble global matrices K = algopy.zeros((DOF * n, DOF * n), dtype=A) S = algopy.zeros((nbar, DOF * n), dtype=A) for i in range(nbar): #loop through each bar Ksub, Ssub = bar(E[i], A[i], L[i], phi[i]) idx = node2idx([start[i], finish[i]], DOF) idxx, idxy = np.meshgrid(idx,idx) for j in range(4): S[i, int(idx[j])] = Ssub[j] for k in range(4): K[int(idxy[j,k]), (idxx[j,k])] += Ksub[j,k] # set_trace() #setup applied loads # F = algopy.zeros(n * DOF, dtype=A) F = np.zeros(n * DOF) for i in range(n): idx = node2idx([i], DOF) # F[int(idx[0])] = Fx[i] # F[int(idx[1])] = Fy[i] F[idx[0]] = Fx[i] F[idx[1]] = Fy[i] #setup boundary condition idxx = np.argwhere(rigidx).squeeze() idxy = np.argwhere(rigidy).squeeze() removex = node2idx(idxx.tolist(), DOF) tempx = np.reshape(removex, (2,-1), order='F') removey = node2idx(idxy.tolist() , DOF) tempy = np.reshape(removey, (2,-1), order='F') removex = tempx[0,:] removey = tempy[1,:] remove = np.concatenate((removex, removey), axis=0) # K = np.delete(K, remove, axis=0) # K = np.delete(K, remove, axis=1) # F = np.delete(F, remove) # S = np.delete(S, remove, axis=1) K = K[:8, :8] F = F[:8] S = S[:, :8] d = algopy.solve(K, F.reshape((8,1))) # d = F.solve(K) # d = K.solve(F) stress = algopy.dot(S, d) return mass, stress
x.data[0,0,:,0] = [1,1,1,1,1] x.data[1,0,:,0] = [1,1,1,1,1] y.data[0,0,:,0] = [1,2,1,2,1] y.data[1,0,:,0] = [1,2,1,2,1] alpha = 10**-5 A = dot(x,x.T) + alpha*dot(y,y.T) A = A[:,:2] # Method 1: Naive approach Apinv = dot(inv(dot(A.T,A)),A.T) print('naive approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv),A) - A) print('naive approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A),Apinv) - Apinv) print('naive approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('naive approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv)) # Method 2: Using the differentiated QR decomposition Q,R = qr(A) tmp1 = solve(R.T, A.T) tmp2 = solve(R, tmp1) Apinv = tmp2 print('QR approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv),A) - A) print('QR approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A),Apinv) - Apinv) print('QR approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T - dot(Apinv, A)) print('QR approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T - dot(A, Apinv))
# N number of cols of J1 # K number of rows of J2 (must be smaller than N) D, P, M, N, K, Nx = 2, 1, 100, 3, 1, 1 # METHOD 1: nullspace method cg1 = CGraph() J1 = Function(UTPM(numpy.random.rand(*(D, P, M, N)))) J2 = Function(UTPM(numpy.random.rand(*(D, P, K, N)))) Q, R = Function.qr_full(J2.T) Q2 = Q[:, K:].T J1_tilde = dot(J1, Q2.T) Q, R = qr(J1_tilde) V = solve(R.T, Q2) C = dot(V.T, V) cg1.trace_off() cg1.independentFunctionList = [J1, J2] cg1.dependentFunctionList = [C] print('covariance matrix: C =\n', C) print('check that Q2.T spans the nullspace of J2:\n', dot(J2, Q2.T)) # METHOD 2: image space method (potentially numerically unstable) cg2 = CGraph() J1 = Function(J1.x) J2 = Function(J2.x)
D,P,M,N,K,Nx = 2,1,100,3,1,1 # METHOD 1: nullspace method cg1 = CGraph() J1 = Function(UTPM(numpy.random.rand(*(D,P,M,N)))) J2 = Function(UTPM(numpy.random.rand(*(D,P,K,N)))) Q,R = Function.qr_full(J2.T) Q2 = Q[:,K:].T J1_tilde = dot(J1,Q2.T) Q,R = qr(J1_tilde) V = solve(R.T, Q2) C = dot(V.T,V) cg1.trace_off() cg1.independentFunctionList = [J1, J2] cg1.dependentFunctionList = [C] print('covariance matrix: C =\n',C) print('check that Q2.T spans the nullspace of J2:\n', dot(J2,Q2.T)) # METHOD 2: image space method (potentially numerically unstable) cg2 = CGraph() J1 = Function(J1.x) J2 = Function(J2.x)
def truss_AD(A): """Computes mass and stress for the 10-bar truss problem Parameters ---------- A : ndarray of length nbar cross-sectional areas of each bar see image in book for number order if needed Outputs ------- mass : float mass of the entire structure stress : ndarray of length nbar stress in each bar """ # --- specific truss setup ----- P = 1e5 # applied loads Ls = 360.0 # length of sides Ld = sqrt(360**2 * 2) # length of diagonals start = [5, 3, 6, 4, 4, 2, 5, 6, 3, 4] finish = [3, 1, 4, 2, 3, 1, 4, 3, 2, 1] phi = np.array([0, 0, 0, 0, 90, 90, -45, 45, -45, 45]) * pi / 180 L = np.array([Ls, Ls, Ls, Ls, Ls, Ls, Ld, Ld, Ld, Ld]) nbar = len(A) # number of bars E = 1e7 * np.ones(nbar) # modulus of elasticity rho = 0.1 * np.ones(nbar) # material density Fx = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) Fy = np.array([0.0, -P, 0.0, -P, 0.0, 0.0]) rigid = [False, False, False, False, True, True] # ------------------ n = len(Fx) # number of nodes DOF = 2 # number of degrees of freedom # mass mass = np.sum(rho * A * L) # stiffness and stress matrices K = algopy.zeros((DOF * n, DOF * n), dtype=A) S = np.zeros((nbar, DOF * n)) for i in range(nbar): # loop through each bar # compute submatrix for each element Ksub, Ssub = bar(E[i], A[i], L[i], phi[i]) # insert submatrix into global matrix idx = node2idx([ start[i], finish[i] ], DOF) # pass in the starting and ending node number for this element # K[np.ix_(idx, idx)] += Ksub for j in range(4): for k in range(4): K[idx[j], idx[k]] += Ksub[j, k] S[i, idx] = Ssub # applied loads F = np.zeros((n * DOF, 1)) for i in range(n): idx = node2idx([i + 1], DOF) # add 1 b.c. made indexing 1-based for convenience F[idx[0]] = Fx[i] F[idx[1]] = Fy[i] # boundary condition idx = np.squeeze(np.where(rigid)) remove = node2idx(idx + 1, DOF) # add 1 b.c. made indexing 1-based for convenience # K = np.delete(K, remove, axis=0) # K = np.delete(K, remove, axis=1) K = K[:8, :8] F = np.delete(F, remove, axis=0) S = np.delete(S, remove, axis=1) # solve for deflections d = algopy.solve(K, F) # compute stress stress = algopy.dot(S, d).reshape(nbar) return mass, stress