From 9968d8697dceb319988204f7520829508ae20f49 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 9 Nov 2019 15:49:27 +0000 Subject: [PATCH] Move random functions to their own file This makes tools/g3c a slightly more manageable length. It also makes it easier to switch to the new numpy random API in future, which would solve our non-deterministic CI woes. --- clifford/tools/g3/__init__.py | 37 ++------ clifford/tools/g3/random.py | 34 +++++++ clifford/tools/g3c/__init__.py | 166 ++++----------------------------- clifford/tools/g3c/random.py | 165 ++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 177 deletions(-) create mode 100644 clifford/tools/g3/random.py create mode 100644 clifford/tools/g3c/random.py diff --git a/clifford/tools/g3/__init__.py b/clifford/tools/g3/__init__.py index 43b6747c..9893c993 100644 --- a/clifford/tools/g3/__init__.py +++ b/clifford/tools/g3/__init__.py @@ -22,10 +22,10 @@ .. autosummary:: :toctree: generated/ - random_unit_vector - random_euc_mv generate_rotation_rotor - random_rotation_rotor + random.random_unit_vector + random.random_euc_mv + random.random_rotation_rotor Misc @@ -50,7 +50,6 @@ import clifford as cf import math import numpy as np -import numba I3 = e123 @@ -139,27 +138,6 @@ def rotation_matrix_to_rotor(M): return quaternion_to_rotor(Q) -def random_unit_vector(): - """ Creates a random unit vector """ - return (np_to_euc_mv(np.random.randn(3))).normal() - - -@numba.njit -def val_random_euc_mv(l_max=10): - """ Creates a random vector normally distributed with length l_max """ - output = np.zeros(32) - np_in = l_max*np.random.randn(3) - output[1] = np_in[0] - output[2] = np_in[1] - output[3] = np_in[2] - return output - - -def random_euc_mv(l_max=10): - """ Creates a random vector normally distributed with length l_max """ - return np_to_euc_mv(l_max*np.random.randn(3)) - - def generate_rotation_rotor(theta, euc_vector_m, euc_vector_n): """ Generates a rotation of angle theta in the m, n plane @@ -172,11 +150,6 @@ def generate_rotation_rotor(theta, euc_vector_m, euc_vector_n): return rotor -def random_rotation_rotor(max_angle=np.pi): - """ Creates a random rotation rotor """ - return generate_rotation_rotor(max_angle * np.random.rand(), random_unit_vector(), random_unit_vector()) - - def angle_between_vectors(v1, v2): """ Returns the angle between two conformal vectors @@ -244,3 +217,7 @@ def rotor_align_vecs(u_list, v_list): """ Returns the rotation rotor that aligns the set of vectors u and v """ M = rotation_matrix_align_vecs(u_list, v_list) return rotation_matrix_to_rotor(M) + + +# for compatibility with old code expecting these functions to be here +from .random import * # noqa: E402 diff --git a/clifford/tools/g3/random.py b/clifford/tools/g3/random.py new file mode 100644 index 00000000..30d47788 --- /dev/null +++ b/clifford/tools/g3/random.py @@ -0,0 +1,34 @@ +""" +Tools to generate G3 objects randomly +""" + +import numpy as np +import numba + +from . import generate_rotation_rotor, np_to_euc_mv + + +def random_unit_vector(): + """ Creates a random unit vector """ + return (np_to_euc_mv(np.random.randn(3))).normal() + + +@numba.njit +def val_random_euc_mv(l_max=10): + """ Creates a random vector normally distributed with length l_max """ + output = np.zeros(32) + np_in = l_max*np.random.randn(3) + output[1] = np_in[0] + output[2] = np_in[1] + output[3] = np_in[2] + return output + + +def random_euc_mv(l_max=10): + """ Creates a random vector normally distributed with length l_max """ + return np_to_euc_mv(l_max*np.random.randn(3)) + + +def random_rotation_rotor(max_angle=np.pi): + """ Creates a random rotation rotor """ + return generate_rotation_rotor(max_angle * np.random.rand(), random_unit_vector(), random_unit_vector()) diff --git a/clifford/tools/g3c/__init__.py b/clifford/tools/g3c/__init__.py index 2d5e451d..7c2830ff 100644 --- a/clifford/tools/g3c/__init__.py +++ b/clifford/tools/g3c/__init__.py @@ -10,25 +10,25 @@ .. autosummary:: :toctree: generated/ - random_bivector + random.random_bivector + random.random_point_pair_at_origin + random.random_point_pair + random.random_line_at_origin + random.random_line + random.random_circle_at_origin + random.random_circle + random.random_sphere_at_origin + random.random_sphere + random.random_plane_at_origin + random.random_plane + random.random_translation_rotor + random.random_rotation_translation_rotor + random.random_conformal_point + standard_point_pair_at_origin - random_point_pair_at_origin - random_point_pair standard_line_at_origin - random_line_at_origin - random_line - random_circle_at_origin - random_circle - random_sphere_at_origin - random_sphere - random_plane_at_origin - random_plane - generate_n_clusters generate_random_object_cluster - random_translation_rotor - random_rotation_translation_rotor - random_conformal_point generate_dilation_rotor generate_translation_rotor @@ -155,8 +155,7 @@ import math import numba import numpy as np -from clifford.tools.g3 import quaternion_to_rotor, random_euc_mv, \ - random_rotation_rotor, generate_rotation_rotor, val_random_euc_mv +from clifford.tools.g3 import quaternion_to_rotor from clifford.g3c import * import clifford as cf from clifford import grades_present, NUMBA_PARALLEL, MVArray @@ -762,16 +761,6 @@ def generate_random_object_cluster(n_objects, object_generator, max_cluster_tran return cluster_objects -def random_translation_rotor(maximum_translation=10.0): - """ generate a random translation rotor """ - return generate_translation_rotor(random_euc_mv(maximum_translation)) - - -def random_rotation_translation_rotor(maximum_translation=10.0, maximum_angle=np.pi): - """ generate a random combined rotation and translation rotor """ - return (random_translation_rotor(maximum_translation)*random_rotation_rotor(maximum_angle)).normal() - - @numba.njit def project_val(val, grade): """ fast grade projection """ @@ -791,13 +780,6 @@ def project_val(val, grade): return output -def random_conformal_point(l_max=10): - """ - Creates a random conformal point - """ - return up(random_euc_mv(l_max=l_max)) - - def generate_dilation_rotor(scale): """ Generates a rotor that performs dilation about the origin @@ -1529,129 +1511,16 @@ def val_rotor_rotor_between_planes(P1_val, P2_val): return val_normalised(P21_val) -def random_bivector(): - r""" - Creates a random bivector on the form described by R. Wareham in - Mesh Vertex Pose and Position Interpolation using Geometric Algebra. - $$ B = ab + c*n_{\inf}$$ where $a, b, c \in \mathcal(R)^3$ - """ - a = random_euc_mv() - c = random_euc_mv() - return a * I3 + c * ninf - - def standard_point_pair_at_origin(): """ Creates a standard point pair at the origin """ return (up(-0.5*e1)^up(0.5*e1)).normal() -def random_point_pair_at_origin(): - """ - Creates a random point pair bivector object at the origin - """ - mv_a = random_euc_mv() - plane_a = (mv_a*I3).normal() - - mv_b = plane_a*mv_a*plane_a - pp = (up(mv_a) ^ up(mv_b)).normal() - return pp - - -def random_point_pair(): - """ - Creates a random point pair bivector object - """ - mv_a = random_euc_mv() - mv_b = random_euc_mv() - pp = (up(mv_a) ^ up(mv_b)).normal() - return pp - - def standard_line_at_origin(): """ Creates a standard line at the origin """ return (standard_point_pair_at_origin()^einf).normal() -def random_line_at_origin(): - """ - Creates a random line at the origin - """ - pp = (random_point_pair_at_origin()^einf).normal() - return pp - - -def random_line(): - """ - Creates a random line - """ - mv_a = random_euc_mv() - mv_b = random_euc_mv() - line_a = ((up(mv_a) ^ up(mv_b) ^ ninf)).normal() - return line_a - - -def random_circle_at_origin(): - """ - Creates a random circle at the origin - """ - mv_a = random_euc_mv() - mv_r = random_euc_mv() - r = generate_rotation_rotor(np.pi/2, mv_a, mv_r) - mv_b = r*mv_a*~r - mv_c = r * mv_b * ~r - pp = (up(mv_a) ^ up(mv_b) ^ up(mv_c)).normal() - return pp - - -def random_circle(): - """ - Creates a random circle - """ - mv_a = val_random_euc_mv() - mv_b = val_random_euc_mv() - mv_c = val_random_euc_mv() - return layout.MultiVector(value=val_normalised(omt_func(omt_func(val_up(mv_a), val_up(mv_b)), val_up(mv_c)))) - - -def random_sphere_at_origin(): - """ - Creates a random sphere at the origin - """ - C = random_circle_at_origin() - sphere = circle_to_sphere(C) - return sphere - - -def random_sphere(): - """ - Creates a random sphere - """ - mv_a = random_euc_mv() - mv_b = random_euc_mv() - mv_c = random_euc_mv() - mv_d = random_euc_mv() - sphere = ((up(mv_a) ^ up(mv_b) ^ up(mv_c) ^ up(mv_d))).normal() - return sphere - - -def random_plane_at_origin(): - """ - Creates a random plane at the origin - """ - c = random_circle_at_origin() - plane = (c ^ einf).normal() - return plane - - -def random_plane(): - """ - Creates a random plane - """ - c = random_circle() - plane = (c ^ ninf).normal() - return plane - - @numba.njit def val_apply_rotor(mv_val, rotor_val): """ Applies rotor to multivector in a fast way - JITTED """ @@ -1855,3 +1724,6 @@ def from_value_array(value_array): v_down = np.vectorize(fast_down, otypes=[ConformalMVArray]) v_apply_rotor_inv = np.vectorize(apply_rotor_inv, otypes=[ConformalMVArray]) v_meet = np.vectorize(meet, otypes=[ConformalMVArray], signature='(),()->()') + +# for compatibility with old code expecting these functions to be here +from .random import * # noqa: E402 diff --git a/clifford/tools/g3c/random.py b/clifford/tools/g3c/random.py new file mode 100644 index 00000000..f1a53340 --- /dev/null +++ b/clifford/tools/g3c/random.py @@ -0,0 +1,165 @@ +""" +Tools to generate G3C objects randomly +""" + +import numpy as np + +from clifford.tools.g3 import generate_rotation_rotor +from clifford.tools.g3.random import ( + random_euc_mv, random_rotation_rotor, val_random_euc_mv, +) +from clifford.g3c import * + +# TODO: resolve circular dependencies +from . import ( + ninf, val_normalised, omt_func, val_up, circle_to_sphere, + generate_translation_rotor, I3 +) + + +__all__ = [ + "random_point_pair_at_origin", + "random_point_pair", + "random_line_at_origin", + "random_line", + "random_circle_at_origin", + "random_circle", + "random_sphere_at_origin", + "random_sphere", + "random_plane_at_origin", + "random_plane", + "random_translation_rotor", + "random_rotation_translation_rotor", + "random_conformal_point", + "random_bivector", +] + + +def random_point_pair_at_origin(): + """ + Creates a random point pair bivector object at the origin + """ + mv_a = random_euc_mv() + plane_a = (mv_a*I3).normal() + + mv_b = plane_a*mv_a*plane_a + pp = (up(mv_a) ^ up(mv_b)).normal() + return pp + + +def random_point_pair(): + """ + Creates a random point pair bivector object + """ + mv_a = random_euc_mv() + mv_b = random_euc_mv() + pp = (up(mv_a) ^ up(mv_b)).normal() + return pp + + +def random_line_at_origin(): + """ + Creates a random line at the origin + """ + pp = (random_point_pair_at_origin()^einf).normal() + return pp + + +def random_line(): + """ + Creates a random line + """ + mv_a = random_euc_mv() + mv_b = random_euc_mv() + line_a = ((up(mv_a) ^ up(mv_b) ^ ninf)).normal() + return line_a + + +def random_circle_at_origin(): + """ + Creates a random circle at the origin + """ + mv_a = random_euc_mv() + mv_r = random_euc_mv() + r = generate_rotation_rotor(np.pi/2, mv_a, mv_r) + mv_b = r*mv_a*~r + mv_c = r * mv_b * ~r + pp = (up(mv_a) ^ up(mv_b) ^ up(mv_c)).normal() + return pp + + +def random_circle(): + """ + Creates a random circle + """ + mv_a = val_random_euc_mv() + mv_b = val_random_euc_mv() + mv_c = val_random_euc_mv() + return layout.MultiVector(value=val_normalised(omt_func(omt_func(val_up(mv_a), val_up(mv_b)), val_up(mv_c)))) + + +def random_sphere_at_origin(): + """ + Creates a random sphere at the origin + """ + C = random_circle_at_origin() + sphere = circle_to_sphere(C) + return sphere + + +def random_sphere(): + """ + Creates a random sphere + """ + mv_a = random_euc_mv() + mv_b = random_euc_mv() + mv_c = random_euc_mv() + mv_d = random_euc_mv() + sphere = ((up(mv_a) ^ up(mv_b) ^ up(mv_c) ^ up(mv_d))).normal() + return sphere + + +def random_plane_at_origin(): + """ + Creates a random plane at the origin + """ + c = random_circle_at_origin() + plane = (c ^ einf).normal() + return plane + + +def random_plane(): + """ + Creates a random plane + """ + c = random_circle() + plane = (c ^ ninf).normal() + return plane + + +def random_translation_rotor(maximum_translation=10.0): + """ generate a random translation rotor """ + return generate_translation_rotor(random_euc_mv(maximum_translation)) + + +def random_rotation_translation_rotor(maximum_translation=10.0, maximum_angle=np.pi): + """ generate a random combined rotation and translation rotor """ + return (random_translation_rotor(maximum_translation)*random_rotation_rotor(maximum_angle)).normal() + + +def random_conformal_point(l_max=10): + """ + Creates a random conformal point + """ + return up(random_euc_mv(l_max=l_max)) + + +def random_bivector(): + r""" + Creates a random bivector on the form described by R. Wareham in + Mesh Vertex Pose and Position Interpolation using Geometric Algebra. + $$ B = ab + c*n_{\inf}$$ where $a, b, c \in \mathcal(R)^3$ + """ + a = random_euc_mv() + c = random_euc_mv() + return a * I3 + c * ninf