def general_root(sigma): """ The general case of the root of a grade 0,4 multivector """ output = general_root_val(sigma.value) return [ cf.MultiVector(layout, output[0, :].copy()), cf.MultiVector(layout, output[1, :].copy()) ]
def ga_exp(B): """ Fast implementation of the translation and rotation specific exp function """ if np.sum(np.abs(B.value)) < np.finfo(float).eps: return cf.MultiVector(layout, unit_scalar_mv.value) return cf.MultiVector(layout, val_exp(B.value))
def test_rotor_between_objects(self): # Make a big array of data n_mvs = 1000 generator_list = [random_point_pair, random_line, random_circle, \ random_sphere, random_plane] for generator in generator_list: mv_a_array = np.array([generator() for i in range(n_mvs)], dtype=np.double) mv_b_array = np.array([generator() for i in range(n_mvs)], dtype=np.double) mv_c_array = np.zeros(mv_b_array.shape, dtype=np.double) mv_d_array = np.zeros(mv_b_array.shape, dtype=np.double) print('Starting kernel') t = time.time() blockdim = 64 griddim = int(math.ceil(n_mvs / blockdim)) rotor_between_objects_kernel[griddim, blockdim](mv_a_array, mv_b_array, mv_c_array) end_time = time.time() - t print('Kernel finished') print(end_time) # Now do the non cuda kernel t = time.time() for i in range(mv_a_array.shape[0]): mv_a = cf.MultiVector(self.layout, mv_a_array[i, :]) mv_b = cf.MultiVector(self.layout, mv_b_array[i, :]) mv_d_array[i, :] = rotor_between_objects(mv_a, mv_b).value print(time.time() - t) np.testing.assert_almost_equal(mv_c_array, mv_d_array)
def neg_twiddle_root(C): """ Square Root and Logarithm of Rotors in 3D Conformal Geometric Algebra Using Polar Decomposition Leo Dorst and Robert Valkenburg """ output = neg_twiddle_root_val(C.value) return [ cf.MultiVector(layout, output[0, :]), cf.MultiVector(layout, output[1, :]) ]
def val_object_cost_function(obj_a_val, obj_b_val): """ Evaluates the rotor cost function between two objects """ grade_a = grade_obj_func(obj_a_val, gradeList, 0.0000001) grade_b = grade_obj_func(obj_b_val, gradeList, 0.0000001) if grade_a != grade_b: return np.finfo(float).max else: R = rotor_between_objects(cf.MultiVector(layout, obj_a_val), cf.MultiVector(layout, obj_b_val)) return np.abs(val_rotor_cost_sparse(R.value))
def rotor_between_objects(C1, C2): """ Hadfield and Lasenby AGACSE2018 For any two conformal objects C1 and C2 this returns a rotor that takes C1 to C2 Return a valid object from the addition result 1 + C2C1 """ if float(gmt_func(C1.value, C1.value)[0]) > 0: C = 1 + cf.MultiVector(layout, gmt_func(C2.value, C1.value)) R = pos_twiddle_root(C)[0] return R else: return (1 - cf.MultiVector(layout, gmt_func(C2.value, C1.value))).normal()
def test_normalise_mvs_kernel(self): n_mvs = 500 mv_a_array = np.pi * np.array( [random_line().value for i in range(n_mvs)]) mv_d_array = np.zeros(mv_a_array.shape) mv_b_array = mv_a_array.copy() print('Starting kernel') t = time.time() blockdim = 64 griddim = int(math.ceil(n_mvs / blockdim)) normalise_mvs_kernel[griddim, blockdim](mv_a_array) end_time = time.time() - t print('Kernel finished') print(end_time) # Now do the non cuda kernel t = time.time() for i in range(mv_a_array.shape[0]): mv_a = cf.MultiVector(self.layout, mv_b_array[i, :]) mv_d_array[i, :] = mv_a.normal().value print(time.time() - t) np.testing.assert_almost_equal(mv_a_array, mv_d_array)
def MultiVector(self, *args, **kw): ''' create a multivector in this layout convenience func to Multivector(layout) ''' return cf.MultiVector(layout=self, *args, **kw)
def parse_multivector(self, mv_string: str) -> 'cf.MultiVector': """ Parses a multivector string into a MultiVector object """ # Get the names of the canonical blades blade_name_index_map = {name: index for index, name in enumerate(self.names)} # Clean up the input string a bit cleaned_string = re.sub('[()]', '', mv_string) # Create a multivector mv_out = cf.MultiVector(self) # Apply the regex for m in _blade_pattern.finditer(cleaned_string): # Clean up the search result cleaned_match = m.group(0) # Split on the '^' stuff = cleaned_match.split('^') if len(stuff) == 2: # Extract the value of the blade and the index of the blade blade_val = float("".join(stuff[0].split())) blade_index = blade_name_index_map[stuff[1].strip()] mv_out[blade_index] = blade_val elif len(stuff) == 1: # Extract the value of the scalar blade_val = float("".join(stuff[0].split())) blade_index = 0 mv_out[blade_index] = blade_val return mv_out
def rotor_vector_to_vector(v1, v2): """ Creates a rotor that takes one vector into another """ if np.sum(np.abs(v1.value - v2.value)) > 0.000001: theta = angle_between_vectors(v1, v2) return generate_rotation_rotor(theta, v1, v2) else: mv = cf.MultiVector(layout) mv.value[0] = 1.0 return mv
def generate_dilation_rotor(scale): """ Generates a rotor that performs dilation about the origin """ if abs(scale - 1.0) < 0.00001: u = np.zeros(32) u[0] = 1.0 return cf.MultiVector(layout, u) gamma = math.log(scale) return math.cosh(gamma / 2) + math.sinh(gamma / 2) * (ninf ^ no)
def rotor_between_objects(X1, X2): """ Lasenby and Hadfield AGACSE2018 For any two conformal objects X1 and X2 this returns a rotor that takes X1 to X2 Return a valid object from the addition result 1 + gamma*X2X1 """ return cf.MultiVector( layout, val_rotor_between_objects_root(val_normalised(X1.value), val_normalised(X2.value)))
def val_convert_2D_polar_line_to_conformal_line(rho, theta): """ Converts a 2D polar line to a conformal line """ a = np.cos(theta) b = np.sin(theta) x0 = a * rho y0 = b * rho x1 = int(x0 + 10000 * (-b)) y1 = int(y0 + 10000 * (a)) x2 = int(x0 - 10000 * (-b)) y2 = int(y0 - 10000 * (a)) p1_val = val_convert_2D_point_to_conformal(x1, y1) p2_val = val_convert_2D_point_to_conformal(x2, y2) line_val = omt_func(omt_func(p1_val, p2_val), ninf_val) line_val = line_val / abs(cf.MultiVector(layout, line_val)) return line_val
def add(a, b): return cf.MultiVector(a.layout, a.value + b.value)
def negate(a): return cf.MultiVector(a.layout, -a.value)
def negative_root(sigma): """ Square Root of Rotors - Evaluates the negative root """ res_val = negative_root_val(sigma.value) return cf.MultiVector(layout, res_val)
def rotorconversion(x): """ Converts between the parameters of a TR bivector and the rotor that it is generating """ return cf.MultiVector(layout, val_rotorconversion(x))
def annhilate_k(K, C): """ Removes K from C = KX via (K[0] - K[4])*C """ return cf.MultiVector(layout, val_annhilate_k(K.value, C.value))
def fast_dual(a): """ Fast dual """ return cf.MultiVector(layout, dual_func(a.value))
def rotor_between_planes(P1, P2): """ return the rotor between two planes """ return cf.MultiVector(layout, val_rotor_rotor_between_planes(P1.value, P2.value))
def val_distance_point_to_line(point, line): """ Returns the euclidean distance between a point and a line """ return float(abs(cf.MultiVector(layout, omt_func(point, line))))
def fast_down(mv): """ A fast version of down() """ return cf.MultiVector(layout, val_down(mv.value))
def fast_up(mv): """ Fast up mapping """ return cf.MultiVector(layout, val_up(mv.value))
def convert_2D_polar_line_to_conformal_line(rho, theta): """ Converts a 2D polar line to a conformal line """ line_val = val_convert_2D_polar_line_to_conformal_line(rho, theta) return cf.MultiVector(layout, line_val)
def normalised(mv): """ fast version of the normal() function """ return cf.MultiVector(layout, val_normalised(mv.value))
def apply_rotor(mv_in, rotor): """ Applies rotor to multivector in a fast way """ return cf.MultiVector(layout, val_apply_rotor(mv_in.value, rotor.value))
def add_e1(a): return cf.MultiVector(a.layout, a.value + e1.value)
def convert_2D_point_to_conformal(x, y): """ Convert a 2D point to conformal """ return cf.MultiVector(layout, val_convert_2D_point_to_conformal(x, y))
def apply_rotor_inv(mv_in, rotor, rotor_inv): """ Applies rotor to multivector in a fast way takes pre computed adjoint""" return cf.MultiVector( layout, val_apply_rotor_inv(mv_in.value, rotor.value, rotor_inv.value))
def rotor_between_lines(L1, L2): """ return the rotor between two lines """ return cf.MultiVector(layout, val_rotor_between_lines(L1.value, L2.value))