def gss_aei(self, input_vf, input_num_steps=None, input_pix_dims=None): """ generalised scaling and squaring approximated exponential integrators """ # (0) self.initialise_input(input_vf) self.initialise_number_of_steps(input_num_steps=input_num_steps, input_pix_dims=input_pix_dims) # (1) if self.num_steps == 0: self.phi = self.vf else: init = 1 << self.num_steps self.phi = self.vf / init # (1.5) phi = 1 + v + 0.5jac*v jv = np.squeeze(jac.compute_jacobian(self.phi)) v_sq = np.squeeze(self.phi) new_shape = list( self.omega) + [1] * (4 - self.dimension) + [self.dimension] jv_prod_v = matrices.matrix_vector_field_product( jv, v_sq).reshape(new_shape) self.phi += 0.5 * jv_prod_v # (2) for _ in range(0, self.num_steps): self.phi = cp.lagrangian_dot_lagrangian(self.phi, self.phi, s_i_o=self.s_i_o) return self.phi
def test_matrix_vector_field_product_2d(): def field_vector(t, x): t = float(t) x = [float(y) for y in x] return x[1], -1 * x[0] def field_matrix(t, x): t = float(t) x = [float(y) for y in x] return 0.5, 0.6, x[0], 0.8 def field_ground_product(t, x): t = float(t) x = [float(y) for y in x] return 0.5 * x[1] - 0.6 * x[0], x[0] * x[1] - 0.8 * x[0] v = np.zeros([20, 20, 2]) jac = np.zeros([20, 20, 4]) ground_jac_v = np.zeros([20, 20, 2]) for i in range(0, 20): for j in range(0, 20): v[i, j, :] = field_vector(1, [i, j]) jac[i, j, :] = field_matrix(1, [i, j]) ground_jac_v[i, j, :] = field_ground_product(1, [i, j]) jac_v = mat.matrix_vector_field_product(jac, v) assert_array_equal(jac_v.shape, np.array([20, 20, 2])) assert_array_equal(jac_v, ground_jac_v)
def iterative_jacobian_product(vf, n): """ :param vf: input SVF :param n: number of iterations :return: a new SVF defined by the jacobian product J_v^(n-1) v """ jv_field = compute_jacobian(vf)[...] v_field = vf[...] jv_n_prod_v = matrices.matrix_vector_field_product(matrices.matrix_fields_product_iterative(jv_field, n-1), v_field) return jv_n_prod_v
def jacobian_product(vf_left, vf_right): """ Compute the jacobian product between two 2d or 3d SVF self and right: J_{self}(right) the results is a second SVF. :param vf_left : svf :param vf_right: svf :return: J_{right}(left) : jacobian product between 2 svfs """ left = np.copy(vf_left) right = np.copy(vf_right) result_array = matrices.matrix_vector_field_product(compute_jacobian(right), left) return result_array
def scalar_dot_eulerian(sf_left, vf_right_eul, affine_left_right=None, s_i_o=3, mode='constant', cval=0.0, prefilter=False): omega_right = qr.get_omega(vf_right_eul) d = len(omega_right) if affine_left_right is not None: A_l, A_r = affine_left_right # multiply each point of the vector field by the transformation matrix vf_right_eul = matrices.matrix_vector_field_product( np.linalg.inv(A_l).dot(A_r), vf_right_eul) if d == 2: assert vf_right_eul.shape[: 2] == sf_left.shape[:: -1], 'Shape inconsistency.' coord = [ vf_right_eul[..., i].reshape(omega_right, order='F').T for i in range(d) ][::-1] result = np.zeros_like(sf_left) else: coord = [ vf_right_eul[..., i].reshape(omega_right, order='F') for i in range(d) ] result = np.zeros_like(sf_left) ndimage.map_coordinates(sf_left, coord, output=result, order=s_i_o, mode=mode, cval=cval, prefilter=prefilter) return result
def test_matrix_vector_field_product_toy_example_3d(): def field_vector(t, x): t = float(t) x = [float(y) for y in x] return 2 * x[1], 3 * x[0], x[0] - x[2] def field_matrix(t, x): t = float(t) x = [float(y) for y in x] return 0.5*x[0], 0.5*x[1], 0.5*x[2], \ 0.5, x[0], 0.3, \ 0.2*x[2], 3.0, 2.1*x[2] def field_ground_product(t, x): t = float(t) x = [float(y) for y in x] return 0.5*2*x[0]*x[1] + 0.5*3*x[0]*x[1] + 0.5*x[2]*(x[0] - x[2]), \ 0.5*2*x[1] + 3*x[0]*x[0] + 0.3*(x[0] - x[2]), \ 0.2*2*x[2]*x[1] + 3*3*x[0] + 2.1*x[2]*(x[0] - x[2]) v = np.zeros([20, 20, 20, 3]) jac = np.zeros([20, 20, 20, 9]) ground_jac_v = np.zeros([20, 20, 20, 3]) for i in range(0, 20): for j in range(0, 20): for k in range(0, 20): v[i, j, k, :] = field_vector(1, [i, j, k]) jac[i, j, k, :] = field_matrix(1, [i, j, k]) ground_jac_v[i, j, k, :] = field_ground_product(1, [i, j, k]) jac_v = mat.matrix_vector_field_product(jac, v) assert_array_equal(jac_v.shape, np.array([20, 20, 20, 3])) assert_array_almost_equal(jac_v, ground_jac_v)
def euler_aei(self, input_vf, input_num_steps=None, input_pix_dims=None): """ euler with approximated exponential integrators """ # (0) self.initialise_input(input_vf) self.initialise_number_of_steps(input_num_steps=input_num_steps, input_pix_dims=input_pix_dims) self.vf = self.vf / self.num_steps jv = np.squeeze(jac.compute_jacobian(self.vf)) v_sq = np.squeeze(self.vf) new_shape = list( self.omega) + [1] * (4 - self.dimension) + [self.dimension] jv_prod_v = matrices.matrix_vector_field_product( jv, v_sq).reshape(new_shape) self.vf += 0.5 * jv_prod_v for _ in range(self.num_steps): self.phi = cp.lagrangian_dot_lagrangian(self.vf, self.phi, s_i_o=self.s_i_o) return self.phi
def lagrangian_dot_eulerian(vf_left_lag, vf_right_eul, affine_left_right=None, s_i_o=2, mode='constant', cval=0.0, prefilter=True, add_right=True): omega_right = qr.get_omega(vf_right_eul) d = len(omega_right) if affine_left_right is not None: A_l, A_r = affine_left_right vf_right_eul = matrices.matrix_vector_field_product( np.linalg.inv(A_l).dot(A_r), vf_right_eul) coord = [ vf_right_eul[..., i].reshape(omega_right, order='F') for i in range(d) ] result = np.squeeze(np.zeros_like(vf_left_lag)) for i in range(d): # see if the for can be avoided with tests. ndimage.map_coordinates(np.squeeze(vf_left_lag[..., i]), coord, output=result[..., i], order=s_i_o, mode=mode, cval=cval, prefilter=prefilter) if add_right: # option for the scaling and squaring. return result.reshape( vf_left_lag.shape) + cs.eulerian_to_lagrangian(vf_right_eul) else: return result.reshape(vf_left_lag.shape)