From dc5b1c708b902d19f04e21565143ee598c9ac01e Mon Sep 17 00:00:00 2001 From: kwikrick Date: Thu, 23 Aug 2012 20:01:49 +0000 Subject: [PATCH] re-organised test suite --- geosolver/geometric.py | 13 +- geosolver/randomproblem.py | 15 +- test/test.py | 985 ------------------------------------- test/test_2d.py | 485 ++++++++++++++++++ test/test_3d.py | 375 ++++++++++++++ test/test_generic.py | 40 ++ test/test_geometry.py | 25 + test/test_mate.py | 146 ++++++ test/test_performance.py | 91 ++++ 9 files changed, 1178 insertions(+), 997 deletions(-) delete mode 100644 test/test.py create mode 100644 test/test_2d.py create mode 100644 test/test_3d.py create mode 100644 test/test_generic.py create mode 100644 test/test_geometry.py create mode 100644 test/test_mate.py create mode 100644 test/test_performance.py diff --git a/geosolver/geometric.py b/geosolver/geometric.py index d7ef452..3291d95 100644 --- a/geosolver/geometric.py +++ b/geosolver/geometric.py @@ -190,10 +190,6 @@ class GeometricProblem (Notifier, Listener): else: return None - def get_rigid(self, vars): - print "GeometricProblem.get_rigid NOT IMPLEMENTED" - return None - def get_fix(self, p): """return the fix constraint on given point, or None""" on_p = self.cg.get_constraints_on(p) @@ -209,6 +205,15 @@ class GeometricProblem (Notifier, Listener): print "GeometricProblem.get_coincidence NOT IMPLEMENTED" return None + def get_rigid(self, vars): + print "GeometricProblem.get_rigid NOT IMPLEMENTED" + return None + + def get_mate(self, vars): + print "GeometricProblem.get_mate NOT IMPLEMENTED" + return None + + def verify(self, solution): """returns true iff all constraints satisfied by given solution. solution is a dictionary mapping variables (names) to values (points)""" diff --git a/geosolver/randomproblem.py b/geosolver/randomproblem.py index 31ca8f8..aa68fd1 100644 --- a/geosolver/randomproblem.py +++ b/geosolver/randomproblem.py @@ -1,4 +1,4 @@ -# ----------- random problem generation ---------------- +#----------- random problem generation ---------------- import random from diagnostic import diag_print @@ -328,12 +328,11 @@ def random_triangular_problem_3D(npoints, radius, roundoff, pangle): problem.add_constraint(AngleConstraint(pl,p,pr,angle)) return problem - def test(): - #problem = random_triangular_problem_3D(10, 10.0, 0.0, 0.5) - problem = random_problem_2D(10, 10.0, 0.0, 0.6) - problem = randomize_angles(problem) - print problem - -if __name__ == "__main__": test() + #problem = random_triangular_problem_3D(10, 10.0, 0.0, 0.5) + problem = random_problem_2D(10, 10.0, 0.0, 0.6) + problem = randomize_angles(problem) + print problem +if __name__ == "__main__": + test() diff --git a/test/test.py b/test/test.py deleted file mode 100644 index a60d244..0000000 --- a/test/test.py +++ /dev/null @@ -1,985 +0,0 @@ -#!/usr/bin/env python -"""This module provides some tests for the GeoSolver. -The tests are also simple examples of how to use of the GeomSolver API""" - -from geosolver.geometric import * -from geosolver.vector import vector -from geosolver.randomproblem import * -from geosolver.diagnostic import diag_select, diag_print -import geosolver.tolerance as tolerance -from time import time - -# ---------- 3D problems ----- - -def fix3_problem_3d(): - """A problem with a fix constraint""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.0, 0.0, 1.0])) - #problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - #problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - #problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(FixConstraint('v1', vector([0.0,0.0,0.0]))) - problem.add_constraint(FixConstraint('v2', vector([10.0,0.0,0.0]))) - problem.add_constraint(FixConstraint('v3', vector([5.0,5.0,0.0]))) - return problem - -def fix2_problem_3d(): - """A problem with a fix constraint""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.0, 0.0, 1.0])) - #problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(FixConstraint('v1', vector([0.0,0.0,0.0]))) - problem.add_constraint(FixConstraint('v2', vector([10.0,0.0,0.0]))) - return problem - -def fix1_problem_3d(): - """A problem with a fix constraint""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.0, 0.0, 1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(FixConstraint('v1', vector([0.0,0.0,0.0]))) - return problem - - - -def double_banana_problem(): - """The double banana problem""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_point('v5', vector([0.5, 0.5,-1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) - - problem.add_point('w1', vector([0.0, 0.0, 0.0])) - problem.add_point('w2', vector([1.0, 0.0, 0.0])) - problem.add_point('w3', vector([0.0, 1.0, 0.0])) - problem.add_constraint(DistanceConstraint('w1', 'w2', 10.0)) - problem.add_constraint(DistanceConstraint('w1', 'w3', 10.0)) - problem.add_constraint(DistanceConstraint('w2', 'w3', 10.0)) - problem.add_constraint(DistanceConstraint('w1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('w2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('w3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('w1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('w2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('w3', 'v5', 10.0)) - - return problem - -def double_banana_plus_one_problem(): - """The double banana problem, plus one constraint (well-constrained)""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_point('v5', vector([0.5, 0.5,-1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) - - problem.add_point('w1', vector([0.0, 0.0, 0.0])) - problem.add_point('w2', vector([1.0, 0.0, 0.0])) - problem.add_point('w3', vector([0.0, 1.0, 0.0])) - problem.add_constraint(DistanceConstraint('w1', 'w2', 10.0)) - problem.add_constraint(DistanceConstraint('w1', 'w3', 10.0)) - problem.add_constraint(DistanceConstraint('w2', 'w3', 10.0)) - problem.add_constraint(DistanceConstraint('w1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('w2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('w3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('w1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('w2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('w3', 'v5', 10.0)) - - problem.add_constraint(DistanceConstraint('v1', 'w1', 10.0)) - - return problem - - -def double_tetrahedron_problem(): - """The double tetrahedron problem""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_point('v5', vector([0.5, 0.5,-1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) - return problem - - -def dad_tetrahedron_problem(): - """The double tetrahedron problem with an angle""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_point('v5', vector([0.5, 0.5,-1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(AngleConstraint('v2', 'v1','v3', 60.0*math.pi/180.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) - return problem - -def ada_tetrahedron_problem(): - """The double tetrahedron problem with an angle""" - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_point('v5', vector([0.5, 0.5,-1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(AngleConstraint('v3', 'v1','v2', 60.0*math.pi/180.0)) - problem.add_constraint(AngleConstraint('v1', 'v2','v3', 60.0*math.pi/180.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) - return problem - -def ada_3d_problem(): - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([random.random() for i in [1,2]])) - problem.add_point('v2', vector([random.random() for i in [1,2]])) - problem.add_point('v3', vector([random.random() for i in [1,2]])) - problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) - problem.add_constraint(AngleConstraint('v3', 'v1', 'v2', - angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) - )) - problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', - angle_3p(problem.get_point('v1'), problem.get_point('v2'), problem.get_point('v3')) - )) - return problem - - - - -def overconstrained_tetra(): - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - # overconstrain me! - problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', math.pi/3)) - #problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', math.pi/4)) - return problem - -def diamond_3d(): - """creates a diamond shape with point 'v1'...'v4' in 3D with one solution""" - # Following should be well-constraint, gives underconstrained (need extra rule/pattern) - L=10.0 - problem = GeometricProblem(dimension=3) - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([-5.0, 5.0, 0.0])) - problem.add_point('v3', vector([5.0, 5.0, 0.0])) - problem.add_point('v4', vector([0.0, 10.0, 0.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', L)) - problem.add_constraint(DistanceConstraint('v1', 'v3', L)) - problem.add_constraint(DistanceConstraint('v2', 'v3', L)) - problem.add_constraint(DistanceConstraint('v2', 'v4', L)) - problem.add_constraint(DistanceConstraint('v3', 'v4', L)) - # this bit of code constrains the points v1...v4 in a plane with point p above it - problem.add_point('p', vector([0.0, 0.0, 1.0])) - problem.add_constraint(DistanceConstraint('v1', 'p', 1.0)) - problem.add_constraint(AngleConstraint('v2','v1','p', math.pi/2)) - problem.add_constraint(AngleConstraint('v3','v1','p', math.pi/2)) - problem.add_constraint(AngleConstraint('v4','v1','p', math.pi/2)) - return problem - -# -------- 2D problems - -def ddd_problem(): - problem = GeometricProblem(dimension=2) - problem.add_point('v1', vector([random.random() for i in [1,2]])) - problem.add_point('v2', vector([random.random() for i in [1,2]])) - problem.add_point('v3', vector([random.random() for i in [1,2]])) - problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) - problem.add_constraint(DistanceConstraint('v1','v3',distance_2p(problem.get_point('v1'), problem.get_point('v3')))) - problem.add_constraint(DistanceConstraint('v2','v3',distance_2p(problem.get_point('v2'), problem.get_point('v3')))) - return problem - -def dad_problem(): - problem = GeometricProblem(dimension=2) - problem.add_point('v1', vector([random.random() for i in [1,2]])) - problem.add_point('v2', vector([random.random() for i in [1,2]])) - problem.add_point('v3', vector([random.random() for i in [1,2]])) - problem.add_constraint(DistanceConstraint('v1','v2', - distance_2p(problem.get_point('v1'), problem.get_point('v2')) - )) - problem.add_constraint(DistanceConstraint('v2','v3', - distance_2p(problem.get_point('v2'), problem.get_point('v3')) - )) - problem.add_constraint(AngleConstraint('v1','v2','v3', - angle_3p(problem.get_point('v1'), problem.get_point('v2'), problem.get_point('v3')) - )) - return problem - -def add_problem(): - problem = GeometricProblem(dimension=2) - problem.add_point('v1', vector([random.random() for i in [1,2]])) - problem.add_point('v2', vector([random.random() for i in [1,2]])) - problem.add_point('v3', vector([random.random() for i in [1,2]])) - problem.add_constraint(DistanceConstraint('v1','v2', - distance_2p(problem.get_point('v1'), problem.get_point('v2')) - )) - problem.add_constraint(DistanceConstraint('v2','v3', - distance_2p(problem.get_point('v2'), problem.get_point('v3')) - )) - problem.add_constraint(AngleConstraint('v3','v1','v2', - angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) - )) - return problem - - -def aad_problem(): - problem = GeometricProblem(dimension=2) - problem.add_point('v1', vector([random.random() for i in [1,2]])) - problem.add_point('v2', vector([random.random() for i in [1,2]])) - problem.add_point('v3', vector([random.random() for i in [1,2]])) - problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) - problem.add_constraint(AngleConstraint('v2', 'v3', 'v1', - angle_3p(problem.get_point('v2'), problem.get_point('v3'), problem.get_point('v1')) - )) - problem.add_constraint(AngleConstraint('v3', 'v1', 'v2', - angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) - )) - return problem - -def ada_problem(): - problem = GeometricProblem(dimension=2) - problem.add_point('v1', vector([random.random() for i in [1,2]])) - problem.add_point('v2', vector([random.random() for i in [1,2]])) - problem.add_point('v3', vector([random.random() for i in [1,2]])) - problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) - problem.add_constraint(AngleConstraint('v3', 'v1', 'v2', - angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) - )) - problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', - angle_3p(problem.get_point('v1'), problem.get_point('v2'), problem.get_point('v3')) - )) - return problem - - - -def propagation_problem(): - problem = GeometricProblem(dimension=2) - problem.add_point('v1', vector([random.random() for i in [1,2]])) - problem.add_point('v2', vector([random.random() for i in [1,2]])) - problem.add_point('v3', vector([random.random() for i in [1,2]])) - problem.add_point('v4', vector([random.random() for i in [1,2]])) - problem.add_point('v5', vector([random.random() for i in [1,2]])) - - problem.add_constraint(DistanceConstraint('v1','v2', - distance_2p(problem.get_point('v1'), problem.get_point('v2')) - )) - - problem.add_constraint(DistanceConstraint('v1','v3', - distance_2p(problem.get_point('v1'), problem.get_point('v3')) - )) - - problem.add_constraint(DistanceConstraint('v2','v3', - distance_2p(problem.get_point('v2'), problem.get_point('v3')) - )) - - problem.add_constraint(DistanceConstraint('v2','v4', - distance_2p(problem.get_point('v2'), problem.get_point('v4')) - )) - - problem.add_constraint(DistanceConstraint('v1','v5', - distance_2p(problem.get_point('v1'), problem.get_point('v5')) - )) - - problem.add_constraint(AngleConstraint('v3', 'v1', 'v4', - angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v4')) - )) - - problem.add_constraint(AngleConstraint('v3', 'v2', 'v5', - angle_3p(problem.get_point('v3'), problem.get_point('v2'), problem.get_point('v5')) - )) - - return problem - - -def balloon_problem(): - """test angle propagation via balloon""" - problem = GeometricProblem(dimension=2) - problem.add_point('A', vector([0.0, 0.0])) - problem.add_point('B', vector([1.0, -1.0])) - problem.add_point('C', vector([1.0, +1.0])) - problem.add_point('D', vector([2.0, 0.0])) - problem.add_constraint(AngleConstraint('B','A','C', - angle_3p(problem.get_point('B'), problem.get_point('A'), problem.get_point('C')) - )) - problem.add_constraint(AngleConstraint('A','B','C', - angle_3p(problem.get_point('A'), problem.get_point('B'), problem.get_point('C')) - )) - problem.add_constraint(AngleConstraint('B','C','D', - angle_3p(problem.get_point('B'), problem.get_point('C'), problem.get_point('D')) - )) - problem.add_constraint(AngleConstraint('C','D','B', - angle_3p(problem.get_point('C'), problem.get_point('D'), problem.get_point('B')) - )) - problem.add_constraint(DistanceConstraint('A', 'D', 6.0)) - return problem - -def double_triangle(): - problem = GeometricProblem(dimension=2) - problem.add_point('v1', vector([0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0])) - problem.add_point('v4', vector([1.0, 1.0])) - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - return problem - -def triple_double_triangle(): - problem = GeometricProblem(dimension=2) - problem.add_point('QX', vector([0.0, 0.0])) - problem.add_point('QA2', vector([1.0, 0.0])) - problem.add_point('QA3', vector([0.0, 1.0])) - problem.add_point('QY', vector([1.0, 1.0])) - problem.add_constraint(DistanceConstraint('QX', 'QA2', 10.0)) - problem.add_constraint(DistanceConstraint('QX', 'QA3', 10.0)) - problem.add_constraint(DistanceConstraint('QA2', 'QA3', 10.0)) - problem.add_constraint(DistanceConstraint('QA2', 'QY', 10.0)) - problem.add_constraint(DistanceConstraint('QA3', 'QY', 10.0)) - - #problem.add_point('QX', vector([0.0, 0.0])) - problem.add_point('QB2', vector([1.0, 0.0])) - problem.add_point('QZ', vector([0.0, 1.0])) - problem.add_point('QB4', vector([1.0, 1.0])) - problem.add_constraint(DistanceConstraint('QX', 'QB2', 10.0)) - problem.add_constraint(DistanceConstraint('QX', 'QZ', 10.0)) - problem.add_constraint(DistanceConstraint('QB2', 'QZ', 10.0)) - problem.add_constraint(DistanceConstraint('QB2', 'QB4', 10.0)) - problem.add_constraint(DistanceConstraint('QZ', 'QB4', 10.0)) - - #problem.add_point('QY', vector([0.0, 0.0])) - problem.add_point('QC2', vector([1.0, 0.0])) - #problem.add_point('QZ', vector([0.0, 1.0])) - problem.add_point('QC4', vector([1.0, 1.0])) - problem.add_constraint(DistanceConstraint('QY', 'QC2', 10.0)) - problem.add_constraint(DistanceConstraint('QY', 'QZ', 10.0)) - problem.add_constraint(DistanceConstraint('QC2', 'QZ', 10.0)) - problem.add_constraint(DistanceConstraint('QC2', 'QC4', 10.0)) - problem.add_constraint(DistanceConstraint('QZ', 'QC4', 10.0)) - - return problem - - - - -def hog1(): - # double triangle with inter-angle (needs angle propagation) - problem = GeometricProblem(dimension=2) - problem.add_point('A', vector([0.0, 0.0])) - problem.add_point('B', vector([1.0, 0.0])) - problem.add_point('C', vector([1.0, 1.0])) - problem.add_point('D', vector([0.0, 1.0])) - problem.add_constraint(DistanceConstraint('A', 'B', 10.0)) - problem.add_constraint(DistanceConstraint('B', 'C', 10.0)) - problem.add_constraint(DistanceConstraint('C', 'D', 10.0)) - problem.add_constraint(AngleConstraint('B','A','C', math.pi / 8)) - problem.add_constraint(AngleConstraint('B','A','D', math.pi / 4)) - return problem - -def hog2(): - # several triangles with inter-angles (needs angle propagation) - problem = GeometricProblem(dimension=2) - problem.add_point('M', vector([0.0, 0.0])) - problem.add_point('A', vector([0.0, 1.0])) - problem.add_point('B', vector([1.0, 1.0])) - problem.add_point('C', vector([2.0, 1.0])) - problem.add_point('D', vector([3.0, 1.0])) - problem.add_point('E', vector([4.0, 1.0])) - problem.add_constraint(DistanceConstraint('A', 'M', 10.0)) - problem.add_constraint(DistanceConstraint('A', 'E', 10.0)) - problem.add_constraint(DistanceConstraint('B', 'E', 7.0)) - problem.add_constraint(DistanceConstraint('C', 'E', 6.0)) - problem.add_constraint(DistanceConstraint('D', 'E', 5.0)) - problem.add_constraint(AngleConstraint('A','M','B', math.pi / 20)) - problem.add_constraint(AngleConstraint('B','M','C', math.pi / 20)) - problem.add_constraint(AngleConstraint('D','M','C', math.pi / 20)) - problem.add_constraint(AngleConstraint('D','M','E', math.pi / 20)) - return problem - -def balloons(): - # for testing angle propagation via balloon - problem = GeometricProblem(dimension=2) - problem.add_point('A', vector([0.0, 0.0])) - problem.add_point('B', vector([0.0, 1.0])) - problem.add_point('C', vector([1.0, 1.0])) - problem.add_point('D', vector([2.0, 1.0])) - problem.add_constraint(AngleConstraint('B','A','C', math.pi / 8)) - problem.add_constraint(AngleConstraint('A','B','C', math.pi / 8)) - problem.add_constraint(AngleConstraint('B','C','D', math.pi / 8)) - problem.add_constraint(AngleConstraint('C','D','B', math.pi / 8)) - problem.add_constraint(DistanceConstraint('A', 'D', 6.0)) - return problem - -def twoscisors(): - problem = GeometricProblem(dimension=2) - problem.add_point('A', vector([0.0, 0.0])) - problem.add_point('B', vector([0.0, 1.0])) - problem.add_point('C', vector([1.0, 1.0])) - problem.add_point('D', vector([2.0, 1.0])) - problem.add_constraint(AngleConstraint('B','A','C', math.pi / 8)) - problem.add_constraint(AngleConstraint('B','D','C', math.pi / 8)) - problem.add_constraint(DistanceConstraint('A', 'B', 6.0)) - problem.add_constraint(DistanceConstraint('A', 'C', 6.0)) - problem.add_constraint(DistanceConstraint('D', 'B', 6.0)) - problem.add_constraint(DistanceConstraint('D', 'C', 6.0)) - return problem - -def selection_problem(): - """The double tetrahedron problem with selection constraints""" - - problem = GeometricProblem(dimension=3) - - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_point('v5', vector([0.5, 0.5,-1.0])) - - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) - - #problem.add_constraint(SelectionConstraint(is_right_handed, ['v1','v2','v4','v5'])) - problem.add_constraint(RightHandedConstraint('v1','v2','v4','v5')) - - return problem - - - -# ------ 2D tests ------- - -def test_fix(n): - """Test fix constraints""" - #diag_select("drplan._search_triangle") - - print "generate a random 2D problem" - problem = random_problem_2D(n) - - print "create dr planner" - drplanner = GeometericSolver(problem) - print "number of top clusters:", len(drplanner.dr.top_level()) - #print "top clusters:", map(str, drplanner.dr.top_level()) - - cons = problem.cg.constraints() - dists = filter(lambda d: isinstance(d, DistanceConstraint), cons) - con = random.choice(dists) - print "remove distance", con - problem.rem_constraint(con) - print "number of top clusters:", len(drplanner.dr.top_level()) - #print "top clusters:", map(str, drplanner.dr.top_level()) - - print "replace with two fixes" - v1 = con.variables()[0] - v2 = con.variables()[1] - f1 = FixConstraint(v1, problem.get_point(v1)) - f2 = FixConstraint(v2, problem.get_point(v2)) - problem.add_constraint(f1) - problem.add_constraint(f2) - print "number of top clusters:", len(drplanner.dr.top_level()) - #print "top clusters:", map(str, drplanner.dr.top_level()) - -def test_fix2(n): - """Test fix constraints""" - # diag_select("drplan.*") - print "generate a random 2D problem" - problem = random_problem_2D(n) - - cons = problem.cg.constraints() - dists = filter(lambda d: isinstance(d, DistanceConstraint), cons) - con = random.choice(dists) - print "remove distance", con - problem.rem_constraint(con) - - print "replace with two fixes" - v1 = con.variables()[0] - v2 = con.variables()[1] - f1 = FixConstraint(v1, problem.get_point(v1)) - f2 = FixConstraint(v2, problem.get_point(v2)) - problem.add_constraint(f1) - problem.add_constraint(f2) - - print "create dr planner" - drplanner = GeometricSolver(problem) - print "number of top clusters:", len(drplanner.dr.top_level()) - print "top clusters:", map(str, drplanner.dr.top_level()) - - -def find_error(count, size, over_ratio): - """Test solver by generating random problems""" - random.seed(1) - diag_select("xyzzy") - for i in range(0,count): - if random.random() > over_ratio: - if not test_random_wellconstrained(size): - print "failed wellconstrained problem #"+str(i) - return - else: - if not test_random_overconstrained(size): - print "failed overconstrained problem #"+str(i) - return - print "all tests passed" - - -def test_random_overconstrained(size): - # start with random well-constrained problem - problem = random_problem_2D(size, 0.0) - # add one random contraint - for i in range(100): - try: - add_random_constraint(problem, 0.5) - break - except: - pass - if i == 99: - raise StandardError, "could not add extra constraint" - # test - try: - drplanner = GeometricSolver(problem) - ntop = len(drplanner.dr.top_level()) - if ntop > 1: - message = "underconstrained" - check = False - elif ntop == 0: - message = "no top level" - check = False - else: # ntop == 1 - top = drplanner.dr.top_level()[0] - if not top.overconstrained: - message = "well-constrained" - check = False - else: - check = True - except Exception, e: - message = "error:",e - check = False - #end try - if check == False: - print "--- problem ---" - print problem - print "--- diasgnostic messages ---" - diag_select("drplan") - drplanner = GeometricSolver(problem) - print "--- plan ---" - top = drplanner.dr.top_level() - print drplanner.dr - print "--- top level ---" - print len(top),"clusters:" - for cluster in drplanner.dr.top_level(): - print cluster - print "--- conclusion ---" - print message - return False - else: - return True - - -def test_random_wellconstrained(size): - problem = random_problem_2D(size, 0.0) - try: - drplanner = GeometricSolver(problem) - ntop = len(drplanner.dr.top_level()) - if ntop > 1: - message = "underconstrained" - check = False - elif ntop == 0: - message = "no top level" - check = False - else: # ntop == 1 - top = drplanner.dr.top_level()[0] - if top.overconstrained: - message = "overconstrained" - check = False - else: - check = True - except Exception, e: - print "error in problem:",e - check = False - #end try - if check == False: - print "--- problem ---" - print problem - print "--- diasgnostic messages ---" - diag_select("drplan") - drplanner = GeometricSolver(problem) - top = drplanner.dr.top_level() - print "--- plan ---" - print drplanner.dr - print "--- top level ---" - print len(top),"clusters:" - for cluster in drplanner.dr.top_level(): - print cluster - print "--- conclusion ---" - print message - return False - else: - return True - -#fed - -def buggy1(): - problem = GeometricProblem(dimension=2) - p0 = "P0" - p1 = "P1" - p2 = "P2" - p3 = "P3" - problem.add_point(p2,vector([4.2516273494524803, -9.510959969336783])) - problem.add_point(p3,vector([0.96994030830283862, -3.6416260233938491])) - problem.add_point(p0,vector([6.6635607149389386, -8.5894325593219882])) - problem.add_point(p1,vector([-0.06750282559988996, 6.6760454282229134])) - problem.add_constraint(AngleConstraint(p1,p3,p0,2.38643631762)) - problem.add_constraint(DistanceConstraint(p2,p0,2.58198282856)) - problem.add_constraint(AngleConstraint(p1,p0,p2,-1.52046205861)) - problem.add_constraint(DistanceConstraint(p3,p1,10.3696977989)) - problem.add_constraint(AngleConstraint(p3,p0,p1,0.440080782652)) - return problem - -def test_mergehogs(): - diag_select(".") - problem = GeometricProblem(dimension=2) - problem.add_point('x',vector([0.0, 0.0])) - problem.add_point('a',vector([1.0, 0.0])) - problem.add_point('b',vector([0.0, 1.0])) - problem.add_point('c',vector([-1.0, 0.0])) - problem.add_point('d',vector([0.0, -1.0])) - problem.add_constraint(AngleConstraint('a','x','b', 30.0/180*math.pi)) - problem.add_constraint(AngleConstraint('b','x','c', 30.0/180*math.pi)) - problem.add_constraint(AngleConstraint('c','x','d', 30.0/180*math.pi)) - solver = GeometricSolver(problem) - print solver.dr - for hog in solver.dr.hedgehogs(): - conf = list(solver.mg.get(hog))[0] - print hog - print conf - print problem.verify(conf.map) - -def test_non_triangular(n): - problem = random_problem_2D(n) - print "before:" - print problem - randomize_angles(problem) - print "after:" - print problem - test(problem) - - -# ----------- 3d tests ---------- - -def test_ada_3d(): - problem = ada_3d_problem() - diag_select("nothing") - print "problem:" - print problem - solver = GeometricSolver(problem) - print "drplan:" - print solver.dr - print "number of top-level rigids:",len(solver.dr.top_level()) - result = solver.get_result() - print "result:" - print result - print "result is",result.flag, "with", len(result.solutions),"solutions" - check = True - if len(result.solutions) == 0: - check = False - diag_select(".*") - for sol in result.solutions: - print "solution:",sol - check = check and problem.verify(sol) - diag_select("nothing") - if check: - print "all solutions valid" - else: - print "INVALID" - - -# ------- generic test ------- - -def test(problem): - """Test solver on a given problem""" - #diag_select(".*") - print "problem:" - print problem - print "Solving..." - solver = GeometricSolver(problem) - print "...done" - print "drplan:" - print solver.dr - print "top-level rigids:",list(solver.dr.top_level()) - result = solver.get_result() - print "result:" - print result - print "result is",result.flag, "with", len(result.solutions),"solutions" - check = True - if len(result.solutions) == 0: - check = False - diag_select("(GeometricProblem.verify)|(satisfied)") - for sol in result.solutions: - print "solution:",sol - check = check and problem.verify(sol) - if check: - print "all solutions valid" - else: - print "INVALID" - -# ----- what to test today ------- - -#if __name__ == "__main__": -# find_error(1000, 4) - -#if __name__ == "__main__": -# test(random_problem_2D(4, 0.0)) - -#if __name__ == "__main__": -# diag_select("(.*Method)|(GeometricProblem.verify)") -# test(random_AAD()) - -#if __name__ == "__main__": -# #diag_select("(.*Method)|(GeometricProblem.verify)") -# diag_select("drplan") -# test(propagation_problem()) - -#if __name__ == "__main__": -# diag_select("(GeometricProblem.verify)") -# test(balloon_problem()) - -# create statistics for solving time -def stats_solving(): - print "size \t # \t time \t result" - for size in range(4,31): - for i in range(1,10): - problem = random_triangular_problem_3D(size,10.0,0.0,0.0) - t1 = time() - solver = GeometricSolver(problem) - result = solver.get_status() - t2 = time() - t = t2-t1 - print size,"\t",i,"\t",t,"\t",result - -# create statistics for incremental solving time -def stats_incremental(): - #diag_select("clsolver.remove") - print "size \t # \t time \t result" - for size in range(4,31): - for i in range(1,10): - problem = random_triangular_problem_3D(size,10.0,0.0,0.0) - solver = GeometricSolver(problem) - t1 = time() - constraint = random.choice(problem.cg.constraints()) - problem.rem_constraint(constraint) - problem.add_constraint(constraint) - result = solver.get_status() - t2 = time() - t = t2-t1 - print size,"\t",i,"\t",t,"\t",result - -# create statistics for parametric change -def stats_parametric_incremental(): - #diag_select("clsolver.remove") - print "size \t # \t time \t result" - for size in range(4,31): - for i in range(1,10): - problem = random_triangular_problem_3D(size,10.0,0.0,0.0) - solver = GeometricSolver(problem) - constraint = random.choice(problem.cg.constraints()) - #problem.rem_constraint(constraint) - #problem.add_constraint(constraint) - #problem.rem_constraint(constraint) - #problem.add_constraint(constraint) - t1 = time() - #problem.rem_constraint(constraint) - #problem.add_constraint(constraint) - #constraint.set_parameter(constraint.get_parameter()) - result = solver.get_status() - t2 = time() - t = t2-t1 - print size,"\t",i,"\t",t,"\t",result - -# create statistics for parametric change -def stats_parametric(): - #diag_select("clsolver.remove") - print "size \t # \t time \t result" - for size in range(4,31): - for i in range(1,10): - problem = random_triangular_problem_3D(size,10.0,0.0,0.0) - solver = GeometricSolver(problem) - constraint = random.choice(problem.cg.constraints()) - t1 = time() - constraint.set_parameter(constraint.get_parameter()) - result = solver.get_status() - t2 = time() - t = t2-t1 - print size,"\t",i,"\t",t,"\t",result - -def runstats(): - stats_solving() - stats_incremental() - stats_parametric_incremental() - stats_parametric() - -def selection_test(): - problem = GeometricProblem(dimension=3) - - problem.add_point('v1', vector([0.0, 0.0, 0.0])) - problem.add_point('v2', vector([1.0, 0.0, 0.0])) - problem.add_point('v3', vector([0.0, 1.0, 0.0])) - problem.add_point('v4', vector([0.5, 0.5, 1.0])) - problem.add_point('v5', vector([0.5, 0.5,-1.0])) - - problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) - problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) - - s1 = SelectionConstraint(is_right_handed, ['v1','v2','v4','v5']) - - # add selection con - problem.add_constraint(s1) - - # solve - solver = GeometricSolver(problem, False) - print len(solver.get_solutions()), "solutions" - - # remove and add constraint - print "removing selection-constraint" - problem.rem_constraint(s1) - - # solve again - print len(solver.get_solutions()), "solutions" - - # remove and add constraint - print "re-adding selection constraint" - problem.add_constraint(s1) - - # solve again - print len(solver.get_solutions()), "solutions" - - # remove distance - print "removing and re-adding distance v1-v5" - problem.rem_constraint(problem.get_distance("v1","v5")) - problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) - - # solve again - print len(solver.get_solutions()), "solutions" - - -def test3d(): - #diag_select("clsolver") - #test(double_tetrahedron_problem()) - #test(ada_tetrahedron_problem()) - #test(double_banana_problem()) - #test(double_banana_plus_one_problem()) - #test(random_triangular_problem_3D(10,10.0,0.0,0.5)) - #test(random_distance_problem_3D(10,1.0,0.0)) - #test(fix1_problem_3d()) - test(fix2_problem_3d()) - #test(fix3_problem_3d()) - #diag_select("SelectionMethod.*") - #test(selection_problem(),False) - #selection_test() - #test(overconstrained_tetra()) - #test(diamond_3d(),False) - -def test2d(): - #diag_select("clsolver") - #test(ddd_problem()) - #test(double_triangle()) - test(triple_double_triangle()) - #test(dad_problem()) - #test(add_problem()) - #test(ada_problem()) - #test(aad_problem()) - -def line_problem(): - """A problem with a fix constraint""" - problem = GeometricProblem(dimension=3) - problem.add_variable(Point('p1'),vector([0.0, 0.0, 0.0])) - problem.add_variable(Line('l1'),vector([0.0, 0.0, 0.0, 1.0, 1.0, 1.0])) - problem.add_constraint(CoincidenceConstraint(Point('p1'), Line('l1'))) - return problem - -def test_line(): - test(line_problem()) - -if __name__ == "__main__": - test_line() diff --git a/test/test_2d.py b/test/test_2d.py new file mode 100644 index 0000000..fe66303 --- /dev/null +++ b/test/test_2d.py @@ -0,0 +1,485 @@ +#!/usr/bin/env python +"""This module provides some tests for the GeoSolver. +These test are for 2D solving. +The tests are also simple examples of how to use of the GeomSolver API""" + +import random +from test_generic import test +from geosolver.geometric import GeometricProblem, GeometricSolver, DistanceConstraint, AngleConstraint, FixConstraint +from geosolver.vector import vector +from geosolver.randomproblem import random_problem_2D +from geosolver.diagnostic import diag_select, diag_print +from geosolver.intersections import distance_2p, angle_3p + +# -------- 2D problems + +def ddd_problem(): + problem = GeometricProblem(dimension=2) + problem.add_point('v1', vector([random.random() for i in [1,2]])) + problem.add_point('v2', vector([random.random() for i in [1,2]])) + problem.add_point('v3', vector([random.random() for i in [1,2]])) + problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) + problem.add_constraint(DistanceConstraint('v1','v3',distance_2p(problem.get_point('v1'), problem.get_point('v3')))) + problem.add_constraint(DistanceConstraint('v2','v3',distance_2p(problem.get_point('v2'), problem.get_point('v3')))) + return problem + +def dad_problem(): + problem = GeometricProblem(dimension=2) + problem.add_point('v1', vector([random.random() for i in [1,2]])) + problem.add_point('v2', vector([random.random() for i in [1,2]])) + problem.add_point('v3', vector([random.random() for i in [1,2]])) + problem.add_constraint(DistanceConstraint('v1','v2', + distance_2p(problem.get_point('v1'), problem.get_point('v2')) + )) + problem.add_constraint(DistanceConstraint('v2','v3', + distance_2p(problem.get_point('v2'), problem.get_point('v3')) + )) + problem.add_constraint(AngleConstraint('v1','v2','v3', + angle_3p(problem.get_point('v1'), problem.get_point('v2'), problem.get_point('v3')) + )) + return problem + +def add_problem(): + problem = GeometricProblem(dimension=2) + problem.add_point('v1', vector([random.random() for i in [1,2]])) + problem.add_point('v2', vector([random.random() for i in [1,2]])) + problem.add_point('v3', vector([random.random() for i in [1,2]])) + problem.add_constraint(DistanceConstraint('v1','v2', + distance_2p(problem.get_point('v1'), problem.get_point('v2')) + )) + problem.add_constraint(DistanceConstraint('v2','v3', + distance_2p(problem.get_point('v2'), problem.get_point('v3')) + )) + problem.add_constraint(AngleConstraint('v3','v1','v2', + angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) + )) + return problem + + +def aad_problem(): + problem = GeometricProblem(dimension=2) + problem.add_point('v1', vector([random.random() for i in [1,2]])) + problem.add_point('v2', vector([random.random() for i in [1,2]])) + problem.add_point('v3', vector([random.random() for i in [1,2]])) + problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) + problem.add_constraint(AngleConstraint('v2', 'v3', 'v1', + angle_3p(problem.get_point('v2'), problem.get_point('v3'), problem.get_point('v1')) + )) + problem.add_constraint(AngleConstraint('v3', 'v1', 'v2', + angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) + )) + return problem + +def ada_problem(): + problem = GeometricProblem(dimension=2) + problem.add_point('v1', vector([random.random() for i in [1,2]])) + problem.add_point('v2', vector([random.random() for i in [1,2]])) + problem.add_point('v3', vector([random.random() for i in [1,2]])) + problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) + problem.add_constraint(AngleConstraint('v3', 'v1', 'v2', + angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) + )) + problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', + angle_3p(problem.get_point('v1'), problem.get_point('v2'), problem.get_point('v3')) + )) + return problem + + + +def propagation_problem(): + problem = GeometricProblem(dimension=2) + problem.add_point('v1', vector([random.random() for i in [1,2]])) + problem.add_point('v2', vector([random.random() for i in [1,2]])) + problem.add_point('v3', vector([random.random() for i in [1,2]])) + problem.add_point('v4', vector([random.random() for i in [1,2]])) + problem.add_point('v5', vector([random.random() for i in [1,2]])) + + problem.add_constraint(DistanceConstraint('v1','v2', + distance_2p(problem.get_point('v1'), problem.get_point('v2')) + )) + + problem.add_constraint(DistanceConstraint('v1','v3', + distance_2p(problem.get_point('v1'), problem.get_point('v3')) + )) + + problem.add_constraint(DistanceConstraint('v2','v3', + distance_2p(problem.get_point('v2'), problem.get_point('v3')) + )) + + problem.add_constraint(DistanceConstraint('v2','v4', + distance_2p(problem.get_point('v2'), problem.get_point('v4')) + )) + + problem.add_constraint(DistanceConstraint('v1','v5', + distance_2p(problem.get_point('v1'), problem.get_point('v5')) + )) + + problem.add_constraint(AngleConstraint('v3', 'v1', 'v4', + angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v4')) + )) + + problem.add_constraint(AngleConstraint('v3', 'v2', 'v5', + angle_3p(problem.get_point('v3'), problem.get_point('v2'), problem.get_point('v5')) + )) + + return problem + + +def balloon_problem(): + """test angle propagation via balloon""" + problem = GeometricProblem(dimension=2) + problem.add_point('A', vector([0.0, 0.0])) + problem.add_point('B', vector([1.0, -1.0])) + problem.add_point('C', vector([1.0, +1.0])) + problem.add_point('D', vector([2.0, 0.0])) + problem.add_constraint(AngleConstraint('B','A','C', + angle_3p(problem.get_point('B'), problem.get_point('A'), problem.get_point('C')) + )) + problem.add_constraint(AngleConstraint('A','B','C', + angle_3p(problem.get_point('A'), problem.get_point('B'), problem.get_point('C')) + )) + problem.add_constraint(AngleConstraint('B','C','D', + angle_3p(problem.get_point('B'), problem.get_point('C'), problem.get_point('D')) + )) + problem.add_constraint(AngleConstraint('C','D','B', + angle_3p(problem.get_point('C'), problem.get_point('D'), problem.get_point('B')) + )) + problem.add_constraint(DistanceConstraint('A', 'D', 6.0)) + return problem + +def double_triangle(): + problem = GeometricProblem(dimension=2) + problem.add_point('v1', vector([0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0])) + problem.add_point('v4', vector([1.0, 1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + return problem + +def triple_double_triangle(): + problem = GeometricProblem(dimension=2) + problem.add_point('QX', vector([0.0, 0.0])) + problem.add_point('QA2', vector([1.0, 0.0])) + problem.add_point('QA3', vector([0.0, 1.0])) + problem.add_point('QY', vector([1.0, 1.0])) + problem.add_constraint(DistanceConstraint('QX', 'QA2', 10.0)) + problem.add_constraint(DistanceConstraint('QX', 'QA3', 10.0)) + problem.add_constraint(DistanceConstraint('QA2', 'QA3', 10.0)) + problem.add_constraint(DistanceConstraint('QA2', 'QY', 10.0)) + problem.add_constraint(DistanceConstraint('QA3', 'QY', 10.0)) + + #problem.add_point('QX', vector([0.0, 0.0])) + problem.add_point('QB2', vector([1.0, 0.0])) + problem.add_point('QZ', vector([0.0, 1.0])) + problem.add_point('QB4', vector([1.0, 1.0])) + problem.add_constraint(DistanceConstraint('QX', 'QB2', 10.0)) + problem.add_constraint(DistanceConstraint('QX', 'QZ', 10.0)) + problem.add_constraint(DistanceConstraint('QB2', 'QZ', 10.0)) + problem.add_constraint(DistanceConstraint('QB2', 'QB4', 10.0)) + problem.add_constraint(DistanceConstraint('QZ', 'QB4', 10.0)) + + #problem.add_point('QY', vector([0.0, 0.0])) + problem.add_point('QC2', vector([1.0, 0.0])) + #problem.add_point('QZ', vector([0.0, 1.0])) + problem.add_point('QC4', vector([1.0, 1.0])) + problem.add_constraint(DistanceConstraint('QY', 'QC2', 10.0)) + problem.add_constraint(DistanceConstraint('QY', 'QZ', 10.0)) + problem.add_constraint(DistanceConstraint('QC2', 'QZ', 10.0)) + problem.add_constraint(DistanceConstraint('QC2', 'QC4', 10.0)) + problem.add_constraint(DistanceConstraint('QZ', 'QC4', 10.0)) + + return problem + +def hog1(): + # double triangle with inter-angle (needs angle propagation) + problem = GeometricProblem(dimension=2) + problem.add_point('A', vector([0.0, 0.0])) + problem.add_point('B', vector([1.0, 0.0])) + problem.add_point('C', vector([1.0, 1.0])) + problem.add_point('D', vector([0.0, 1.0])) + problem.add_constraint(DistanceConstraint('A', 'B', 10.0)) + problem.add_constraint(DistanceConstraint('B', 'C', 10.0)) + problem.add_constraint(DistanceConstraint('C', 'D', 10.0)) + problem.add_constraint(AngleConstraint('B','A','C', math.pi / 8)) + problem.add_constraint(AngleConstraint('B','A','D', math.pi / 4)) + return problem + +def hog2(): + # several triangles with inter-angles (needs angle propagation) + problem = GeometricProblem(dimension=2) + problem.add_point('M', vector([0.0, 0.0])) + problem.add_point('A', vector([0.0, 1.0])) + problem.add_point('B', vector([1.0, 1.0])) + problem.add_point('C', vector([2.0, 1.0])) + problem.add_point('D', vector([3.0, 1.0])) + problem.add_point('E', vector([4.0, 1.0])) + problem.add_constraint(DistanceConstraint('A', 'M', 10.0)) + problem.add_constraint(DistanceConstraint('A', 'E', 10.0)) + problem.add_constraint(DistanceConstraint('B', 'E', 7.0)) + problem.add_constraint(DistanceConstraint('C', 'E', 6.0)) + problem.add_constraint(DistanceConstraint('D', 'E', 5.0)) + problem.add_constraint(AngleConstraint('A','M','B', math.pi / 20)) + problem.add_constraint(AngleConstraint('B','M','C', math.pi / 20)) + problem.add_constraint(AngleConstraint('D','M','C', math.pi / 20)) + problem.add_constraint(AngleConstraint('D','M','E', math.pi / 20)) + return problem + +def balloons(): + # for testing angle propagation via balloon + problem = GeometricProblem(dimension=2) + problem.add_point('A', vector([0.0, 0.0])) + problem.add_point('B', vector([0.0, 1.0])) + problem.add_point('C', vector([1.0, 1.0])) + problem.add_point('D', vector([2.0, 1.0])) + problem.add_constraint(AngleConstraint('B','A','C', math.pi / 8)) + problem.add_constraint(AngleConstraint('A','B','C', math.pi / 8)) + problem.add_constraint(AngleConstraint('B','C','D', math.pi / 8)) + problem.add_constraint(AngleConstraint('C','D','B', math.pi / 8)) + problem.add_constraint(DistanceConstraint('A', 'D', 6.0)) + return problem + +def twoscisors(): + problem = GeometricProblem(dimension=2) + problem.add_point('A', vector([0.0, 0.0])) + problem.add_point('B', vector([0.0, 1.0])) + problem.add_point('C', vector([1.0, 1.0])) + problem.add_point('D', vector([2.0, 1.0])) + problem.add_constraint(AngleConstraint('B','A','C', math.pi / 8)) + problem.add_constraint(AngleConstraint('B','D','C', math.pi / 8)) + problem.add_constraint(DistanceConstraint('A', 'B', 6.0)) + problem.add_constraint(DistanceConstraint('A', 'C', 6.0)) + problem.add_constraint(DistanceConstraint('D', 'B', 6.0)) + problem.add_constraint(DistanceConstraint('D', 'C', 6.0)) + return problem + +# ------ 2D tests ------- + +def test_fix(n): + """Test fix constraints""" + #diag_select("drplan._search_triangle") + + print "generate a random 2D problem" + problem = random_problem_2D(n) + + print "create dr planner" + drplanner = GeometericSolver(problem) + print "number of top clusters:", len(drplanner.dr.top_level()) + #print "top clusters:", map(str, drplanner.dr.top_level()) + + cons = problem.cg.constraints() + dists = filter(lambda d: isinstance(d, DistanceConstraint), cons) + con = random.choice(dists) + print "remove distance", con + problem.rem_constraint(con) + print "number of top clusters:", len(drplanner.dr.top_level()) + #print "top clusters:", map(str, drplanner.dr.top_level()) + + print "replace with two fixes" + v1 = con.variables()[0] + v2 = con.variables()[1] + f1 = FixConstraint(v1, problem.get_point(v1)) + f2 = FixConstraint(v2, problem.get_point(v2)) + problem.add_constraint(f1) + problem.add_constraint(f2) + print "number of top clusters:", len(drplanner.dr.top_level()) + #print "top clusters:", map(str, drplanner.dr.top_level()) + +def test_fix2(n): + """Test fix constraints""" + # diag_select("drplan.*") + print "generate a random 2D problem" + problem = random_problem_2D(n) + + cons = problem.cg.constraints() + dists = filter(lambda d: isinstance(d, DistanceConstraint), cons) + con = random.choice(dists) + print "remove distance", con + problem.rem_constraint(con) + + print "replace with two fixes" + v1 = con.variables()[0] + v2 = con.variables()[1] + f1 = FixConstraint(v1, problem.get_point(v1)) + f2 = FixConstraint(v2, problem.get_point(v2)) + problem.add_constraint(f1) + problem.add_constraint(f2) + + print "create dr planner" + drplanner = GeometricSolver(problem) + print "number of top clusters:", len(drplanner.dr.top_level()) + print "top clusters:", map(str, drplanner.dr.top_level()) + + +def find_error(count, size, over_ratio): + """Test solver by generating random problems""" + random.seed(1) + diag_select("xyzzy") + for i in range(0,count): + if random.random() > over_ratio: + if not test_random_wellconstrained(size): + print "failed wellconstrained problem #"+str(i) + return + else: + if not test_random_overconstrained(size): + print "failed overconstrained problem #"+str(i) + return + print "all tests passed" + + +def test_random_overconstrained(size): + # start with random well-constrained problem + problem = random_problem_2D(size, 0.0) + # add one random contraint + for i in range(100): + try: + add_random_constraint(problem, 0.5) + break + except: + pass + if i == 99: + raise StandardError, "could not add extra constraint" + # test + try: + drplanner = GeometricSolver(problem) + ntop = len(drplanner.dr.top_level()) + if ntop > 1: + message = "underconstrained" + check = False + elif ntop == 0: + message = "no top level" + check = False + else: # ntop == 1 + top = drplanner.dr.top_level()[0] + if not top.overconstrained: + message = "well-constrained" + check = False + else: + check = True + except Exception, e: + message = "error:",e + check = False + #end try + if check == False: + print "--- problem ---" + print problem + print "--- diasgnostic messages ---" + diag_select("drplan") + drplanner = GeometricSolver(problem) + print "--- plan ---" + top = drplanner.dr.top_level() + print drplanner.dr + print "--- top level ---" + print len(top),"clusters:" + for cluster in drplanner.dr.top_level(): + print cluster + print "--- conclusion ---" + print message + return False + else: + return True + + +def test_random_wellconstrained(size): + problem = random_problem_2D(size, 0.0) + try: + drplanner = GeometricSolver(problem) + ntop = len(drplanner.dr.top_level()) + if ntop > 1: + message = "underconstrained" + check = False + elif ntop == 0: + message = "no top level" + check = False + else: # ntop == 1 + top = drplanner.dr.top_level()[0] + if top.overconstrained: + message = "overconstrained" + check = False + else: + check = True + except Exception, e: + print "error in problem:",e + check = False + #end try + if check == False: + print "--- problem ---" + print problem + print "--- diasgnostic messages ---" + diag_select("drplan") + drplanner = GeometricSolver(problem) + top = drplanner.dr.top_level() + print "--- plan ---" + print drplanner.dr + print "--- top level ---" + print len(top),"clusters:" + for cluster in drplanner.dr.top_level(): + print cluster + print "--- conclusion ---" + print message + return False + else: + return True + +#fed + +def buggy1(): + problem = GeometricProblem(dimension=2) + p0 = "P0" + p1 = "P1" + p2 = "P2" + p3 = "P3" + problem.add_point(p2,vector([4.2516273494524803, -9.510959969336783])) + problem.add_point(p3,vector([0.96994030830283862, -3.6416260233938491])) + problem.add_point(p0,vector([6.6635607149389386, -8.5894325593219882])) + problem.add_point(p1,vector([-0.06750282559988996, 6.6760454282229134])) + problem.add_constraint(AngleConstraint(p1,p3,p0,2.38643631762)) + problem.add_constraint(DistanceConstraint(p2,p0,2.58198282856)) + problem.add_constraint(AngleConstraint(p1,p0,p2,-1.52046205861)) + problem.add_constraint(DistanceConstraint(p3,p1,10.3696977989)) + problem.add_constraint(AngleConstraint(p3,p0,p1,0.440080782652)) + return problem + +def test_mergehogs(): + diag_select(".") + problem = GeometricProblem(dimension=2) + problem.add_point('x',vector([0.0, 0.0])) + problem.add_point('a',vector([1.0, 0.0])) + problem.add_point('b',vector([0.0, 1.0])) + problem.add_point('c',vector([-1.0, 0.0])) + problem.add_point('d',vector([0.0, -1.0])) + problem.add_constraint(AngleConstraint('a','x','b', 30.0/180*math.pi)) + problem.add_constraint(AngleConstraint('b','x','c', 30.0/180*math.pi)) + problem.add_constraint(AngleConstraint('c','x','d', 30.0/180*math.pi)) + solver = GeometricSolver(problem) + print solver.dr + for hog in solver.dr.hedgehogs(): + conf = list(solver.mg.get(hog))[0] + print hog + print conf + print problem.verify(conf.map) + +def test_non_triangular(n): + problem = random_problem_2D(n) + print "before:" + print problem + randomize_angles(problem) + print "after:" + print problem + test(problem) + +def test2d(): + #diag_select("clsolver") + test(ddd_problem()) + test(double_triangle()) + test(triple_double_triangle()) + test(dad_problem()) + test(add_problem()) + test(ada_problem()) + test(aad_problem()) + +if __name__ == "__main__": + test2d() diff --git a/test/test_3d.py b/test/test_3d.py new file mode 100644 index 0000000..6474234 --- /dev/null +++ b/test/test_3d.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python +"""This module provides some tests for the GeoSolver. +These tests are concerned with 3D solving. +The tests are also simple examples of how to use of the GeomSolver API""" + +import random +import math +from test_generic import test +from geosolver.geometric import GeometricProblem, GeometricSolver, DistanceConstraint,AngleConstraint, FixConstraint,RightHandedConstraint +from geosolver.vector import vector +from geosolver.randomproblem import random_triangular_problem_3D, random_distance_problem_3D +from geosolver.diagnostic import diag_select, diag_print +from geosolver.intersections import distance_2p, angle_3p + +# ---------- 3D problems ----- + +def fix3_problem_3d(): + """A problem with a fix constraint""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.0, 0.0, 1.0])) + #problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + #problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + #problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(FixConstraint('v1', vector([0.0,0.0,0.0]))) + problem.add_constraint(FixConstraint('v2', vector([10.0,0.0,0.0]))) + problem.add_constraint(FixConstraint('v3', vector([5.0,5.0,0.0]))) + return problem + +def fix2_problem_3d(): + """A problem with a fix constraint""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.0, 0.0, 1.0])) + #problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(FixConstraint('v1', vector([0.0,0.0,0.0]))) + problem.add_constraint(FixConstraint('v2', vector([10.0,0.0,0.0]))) + return problem + +def fix1_problem_3d(): + """A problem with a fix constraint""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.0, 0.0, 1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(FixConstraint('v1', vector([0.0,0.0,0.0]))) + return problem + + + +def double_banana_problem(): + """The double banana problem""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_point('v5', vector([0.5, 0.5,-1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) + + problem.add_point('w1', vector([0.0, 0.0, 0.0])) + problem.add_point('w2', vector([1.0, 0.0, 0.0])) + problem.add_point('w3', vector([0.0, 1.0, 0.0])) + problem.add_constraint(DistanceConstraint('w1', 'w2', 10.0)) + problem.add_constraint(DistanceConstraint('w1', 'w3', 10.0)) + problem.add_constraint(DistanceConstraint('w2', 'w3', 10.0)) + problem.add_constraint(DistanceConstraint('w1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('w2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('w3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('w1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('w2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('w3', 'v5', 10.0)) + + return problem + +def double_banana_plus_one_problem(): + """The double banana problem, plus one constraint (well-constrained)""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_point('v5', vector([0.5, 0.5,-1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) + + problem.add_point('w1', vector([0.0, 0.0, 0.0])) + problem.add_point('w2', vector([1.0, 0.0, 0.0])) + problem.add_point('w3', vector([0.0, 1.0, 0.0])) + problem.add_constraint(DistanceConstraint('w1', 'w2', 10.0)) + problem.add_constraint(DistanceConstraint('w1', 'w3', 10.0)) + problem.add_constraint(DistanceConstraint('w2', 'w3', 10.0)) + problem.add_constraint(DistanceConstraint('w1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('w2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('w3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('w1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('w2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('w3', 'v5', 10.0)) + + problem.add_constraint(DistanceConstraint('v1', 'w1', 10.0)) + + return problem + + +def double_tetrahedron_problem(): + """The double tetrahedron problem""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_point('v5', vector([0.5, 0.5,-1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) + return problem + + +def dad_tetrahedron_problem(): + """The double tetrahedron problem with an angle""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_point('v5', vector([0.5, 0.5,-1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(AngleConstraint('v2', 'v1','v3', 60.0*math.pi/180.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) + return problem + +def ada_tetrahedron_problem(): + """The double tetrahedron problem with an angle""" + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_point('v5', vector([0.5, 0.5,-1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(AngleConstraint('v3', 'v1','v2', 60.0*math.pi/180.0)) + problem.add_constraint(AngleConstraint('v1', 'v2','v3', 60.0*math.pi/180.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) + return problem + +def ada_3d_problem(): + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([random.random() for i in [1,2]])) + problem.add_point('v2', vector([random.random() for i in [1,2]])) + problem.add_point('v3', vector([random.random() for i in [1,2]])) + problem.add_constraint(DistanceConstraint('v1','v2',distance_2p(problem.get_point('v1'), problem.get_point('v2')))) + problem.add_constraint(AngleConstraint('v3', 'v1', 'v2', + angle_3p(problem.get_point('v3'), problem.get_point('v1'), problem.get_point('v2')) + )) + problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', + angle_3p(problem.get_point('v1'), problem.get_point('v2'), problem.get_point('v3')) + )) + return problem + + + + +def overconstrained_tetra(): + problem = GeometricProblem(dimension=3) + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + # overconstrain me! + problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', math.pi/3)) + #problem.add_constraint(AngleConstraint('v1', 'v2', 'v3', math.pi/4)) + return problem + +def diamond_3d(): + """creates a diamond shape with point 'v1'...'v4' in 3D with one solution""" + # Following should be well-constraint, gives underconstrained (need extra rule/pattern) + L=10.0 + problem = GeometricProblem(dimension=3, use_prototype=False) # no prototype based selection + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([-5.0, 5.0, 0.0])) + problem.add_point('v3', vector([5.0, 5.0, 0.0])) + problem.add_point('v4', vector([0.0, 10.0, 0.0])) + problem.add_constraint(DistanceConstraint('v1', 'v2', L)) + problem.add_constraint(DistanceConstraint('v1', 'v3', L)) + problem.add_constraint(DistanceConstraint('v2', 'v3', L)) + problem.add_constraint(DistanceConstraint('v2', 'v4', L)) + problem.add_constraint(DistanceConstraint('v3', 'v4', L)) + # this bit of code constrains the points v1...v4 in a plane with point p above it + problem.add_point('p', vector([0.0, 0.0, 1.0])) + problem.add_constraint(DistanceConstraint('v1', 'p', 1.0)) + problem.add_constraint(AngleConstraint('v2','v1','p', math.pi/2)) + problem.add_constraint(AngleConstraint('v3','v1','p', math.pi/2)) + problem.add_constraint(AngleConstraint('v4','v1','p', math.pi/2)) + return problem + +# ----------- 3d tests ---------- + +def test_ada_3d(): + problem = ada_3d_problem() + diag_select("nothing") + print "problem:" + print problem + solver = GeometricSolver(problem) + print "drplan:" + print solver.dr + print "number of top-level rigids:",len(solver.dr.top_level()) + result = solver.get_result() + print "result:" + print result + print "result is",result.flag, "with", len(result.solutions),"solutions" + check = True + if len(result.solutions) == 0: + check = False + diag_select(".*") + for sol in result.solutions: + print "solution:",sol + check = check and problem.verify(sol) + diag_select("nothing") + if check: + print "all solutions valid" + else: + print "INVALID" + +def selection_test(): + problem = GeometricProblem(dimension=3,use_prototype=False) + + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_point('v5', vector([0.5, 0.5,-1.0])) + + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) + + s1 = RightHandedConstraint('v1','v2','v4','v5') + + # add selection con + problem.add_constraint(s1) + + # solve + solver = GeometricSolver(problem) + print len(solver.get_solutions()), "solutions" + + # remove and add constraint + print "removing selection-constraint" + problem.rem_constraint(s1) + + # solve again + print len(solver.get_solutions()), "solutions" + + # remove and add constraint + print "re-adding selection constraint" + problem.add_constraint(s1) + + # solve again + print len(solver.get_solutions()), "solutions" + + # remove distance + print "removing and re-adding distance v1-v5" + problem.rem_constraint(problem.get_distance("v1","v5")) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + + # solve again + print len(solver.get_solutions()), "solutions" + +def selection_problem(): + """The double tetrahedron problem with selection constraints""" + + problem = GeometricProblem(dimension=3, use_prototype=False) # no prototype based selection + + problem.add_point('v1', vector([0.0, 0.0, 0.0])) + problem.add_point('v2', vector([1.0, 0.0, 0.0])) + problem.add_point('v3', vector([0.0, 1.0, 0.0])) + problem.add_point('v4', vector([0.5, 0.5, 1.0])) + problem.add_point('v5', vector([0.5, 0.5,-1.0])) + + problem.add_constraint(DistanceConstraint('v1', 'v2', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v3', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v4', 10.0)) + problem.add_constraint(DistanceConstraint('v1', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v2', 'v5', 10.0)) + problem.add_constraint(DistanceConstraint('v3', 'v5', 10.0)) + + #problem.add_constraint(SelectionConstraint(is_right_handed, ['v1','v2','v4','v5'])) + problem.add_constraint(RightHandedConstraint('v1','v2','v4','v5')) + + return problem + + +def test3d(): + #diag_select("clsolver") + test(double_tetrahedron_problem()) + test(ada_tetrahedron_problem()) + test(double_banana_problem()) + test(double_banana_plus_one_problem()) + test(random_triangular_problem_3D(10,10.0,0.0,0.5)) + test(random_distance_problem_3D(10,1.0,0.0)) + test(fix1_problem_3d()) + test(fix2_problem_3d()) + test(fix3_problem_3d()) + test(selection_problem()) + selection_test() + test(overconstrained_tetra()) + test(diamond_3d()) + +if __name__ == "__main__": + test3d() diff --git a/test/test_generic.py b/test/test_generic.py new file mode 100644 index 0000000..2b2c774 --- /dev/null +++ b/test/test_generic.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +"""This module provides some generic tests routines for the GeoSolver. +These can be used by other specific test modules, i.e. 2d, 3d, etc. +The tests are also simple examples of how to use of the GeomSolver API""" + +from geosolver.geometric import GeometricProblem, GeometricSolver +from geosolver.vector import vector +from geosolver.diagnostic import diag_select, diag_print +import geosolver.tolerance as tolerance + +# ------- generic test ------- + +def test(problem): + """Test solver on a given problem""" + #diag_select(".*") + print "problem:" + print problem + print "Solving..." + solver = GeometricSolver(problem) + print "...done" + print "drplan:" + print solver.dr + print "top-level rigids:",list(solver.dr.top_level()) + result = solver.get_result() + print "result:" + print result + print "result is",result.flag, "with", len(result.solutions),"solutions" + check = True + if len(result.solutions) == 0: + check = False + diag_select("(GeometricProblem.verify)|(satisfied)") + for sol in result.solutions: + print "solution:",sol + check = check and problem.verify(sol) + if check: + print "all solutions valid" + else: + print "INVALID" + + diff --git a/test/test_geometry.py b/test/test_geometry.py new file mode 100644 index 0000000..792135c --- /dev/null +++ b/test/test_geometry.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +"""This module provides some tests for the GeoSolver. +These tests are concerned with geometric primitives. +The tests are also simple examples of how to use of the GeomSolver API""" + +import random +from test_generic import test +from geosolver.geometric import GeometricProblem, GeometricSolver, DistanceConstraint, AngleConstraint, FixConstraint +from geosolver.geometric import Point, Line, CoincidenceConstraint +from geosolver.vector import vector +from geosolver.diagnostic import diag_select, diag_print + +def line_problem(): + """A problem with a Point, a Line and a CoincicentConstraint""" + problem = GeometricProblem(dimension=3) + problem.add_variable(Point('p1'),vector([0.0, 0.0, 0.0])) + problem.add_variable(Line('l1'),vector([0.0, 0.0, 0.0, 1.0, 1.0, 1.0])) + problem.add_constraint(CoincidenceConstraint(Point('p1'), Line('l1'))) + return problem + +def test_line(): + test(line_problem()) + +if __name__ == "__main__": + test_line() diff --git a/test/test_mate.py b/test/test_mate.py new file mode 100644 index 0000000..f0c5e40 --- /dev/null +++ b/test/test_mate.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +"""This module provides an example of how to use GeoSolver to define 3D blocks +and how to mate them using the Mate constraint.""" + +import random +import math +from geosolver.graph import Graph +from test_generic import test +from geosolver.intersections import translate_3D, rotate_3D_x, rotate_3D_y, rotate_3D_z,scale_3D, id_transform_3D +from geosolver.geometric import MateConstraint, RigidConstraint +from geosolver.geometric import GeometricProblem, GeometricSolver +from geosolver.geometric import DistanceConstraint,AngleConstraint, FixConstraint,RightHandedConstraint +from geosolver.vector import vector +from geosolver.randomproblem import random_triangular_problem_3D, random_distance_problem_3D +from geosolver.diagnostic import diag_select, diag_print +from geosolver.intersections import distance_2p, angle_3p +from geosolver.configuration import Configuration +from time import time + + +# ------------- creating and manupulating blocks --------- + +def block_var(block, index): + return str(block)+"#"+str(index) + +def add_block(problem,name,x,y,z): + """A block with variables name+#1...8 and dimensions x,y,z""" + problem.add_point(block_var(name,'left-bot-front'), vector([-1.0, -1.0, -1.0])) + problem.add_point(block_var(name,'left-bot-back'), vector([-1.0, -1.0, 1.0])) + problem.add_point(block_var(name,'left-top-front'), vector([-1.0, 1.0, -1.0])) + problem.add_point(block_var(name,'left-top-back'), vector([-1.0, 1.0, 1.0])) + problem.add_point(block_var(name,'right-bot-front'), vector([1.0, -1.0, -1.0])) + problem.add_point(block_var(name,'right-bot-back'), vector([1.0, -1.0, 0.0])) + problem.add_point(block_var(name,'right-top-front'), vector([1.0, 1.0, -1.0])) + problem.add_point(block_var(name,'right-top-back'), vector([1.0, 1.0, 1.0])) + conf = Configuration({ + block_var(name,'left-bot-front'):vector([-x/2, -y/2, -z/2]), + block_var(name,'left-bot-back'):vector([-x/2, -y/2, +z/2]), + block_var(name,'left-top-front'):vector([-x/2, +y/2, -z/2]), + block_var(name,'left-top-back'):vector([-x/2, +y/2, +z/2]), + block_var(name,'right-bot-front'):vector([+x/2, -y/2, -z/2]), + block_var(name,'right-bot-back'):vector([+x/2, -y/2, +z/2]), + block_var(name,'right-top-front'):vector([+x/2, +y/2, -z/2]), + block_var(name,'right-top-back'):vector([+x/2, +y/2, +z/2]) + }) + problem.add_constraint(RigidConstraint(conf)) + return problem + +def mate_blocks(problem, block1, o1, x1, y1, block2, o2, x2, y2, dx, dy): + """Mate two blocks. + block1 and block2 are the names of the blocks. + o1, x1 and x2 are vertices of the blocks. + o1-x1 identifies the so-called x-edge in block1. + o1-y1 identifies the y-edge in block1. + --- no longer needed -- The x-edge and y-edge must be actual egdes in block1, or an error will be generated. + The same for block2. + dx is the relative position of the x-edges of the two blocks. + dy is the relative position of the y-edges of the two blocks. + Note that if the blocks are not actually block-shaped, the axis will not be properly + aligned and the faces will not be properly mated. + """ + # determine variable names of the points + vo1 = block_var(block1,o1) + vx1 = block_var(block1,x1) + vy1 = block_var(block1,y1) + vo2 = block_var(block2,o2) + vx2 = block_var(block2,x2) + vy2 = block_var(block2,y2) + # ---- no longer needed --- determine points opposite to given origin and plane + # vz1 = block_var(block1,get_block_opposite(o1, x1, y1)) + # vz2 = block_var(block2,get_block_opposite(o2, x2, y2)) + # determine transformation + trans = translate_3D(dx, dy,0.0) + # add constraint + problem.add_constraint(MateConstraint(vo1,vx1,vy1,vo2,vx2,vy2,trans)) + + +# ----- no longer used, but maybe in the future? -- ---- + +# create a graph of the edges in a block +blockgraph = Graph() +edges = [('left-bot-front','left-bot-back'), + ('left-bot-front','left-top-front'), + ('left-bot-front','right-bot-front'), + ('left-bot-back','left-top-back'), + ('left-bot-back','right-bot-back'), + ('left-top-front','left-top-back'), + ('left-top-front','right-top-front'), + ('left-top-back','right-top-back'), + ('right-bot-front','right-bot-back'), + ('right-bot-front','right-top-front'), + ('right-bot-back','right-top-back'), + ('right-top-font','right-top-back')] + +for edge in edges: + # add bi-directional edge to graoh + blockgraph.add_bi(edge[0], edge[1]) + +def get_block_opposite(o, x, y): + """return the index of the vertex connected to o but not connected to x and y""" + if not blockgraph.has_vertex(o): + raise Exception, "vertex %s is not a block vertex"%(str(o)) + # determine vertices connected to + connected = list(blockgraph.outgoing_vertices(o)) + if x not in connected: + raise Exception, "edge (%s,%s) is not a block edge"%(str(o),str(x)) + if y not in connected: + raise Exception, "edge (%s,%s) is not a block edge"%(str(o),str(y)) + connected.remove(x) + connected.remove(y) + if len(connected) != 1: + raise Exception, "could not find opposite edge, because I am an idiot." + return connected[0] + +# ----------- test mate constraint + +def test_mate(): + problem = GeometricProblem(dimension=3) + + # create and mate two blocks + add_block(problem, "A", 4.0, 2.0, 6.0) + add_block(problem, "B", 4.0, 2.0, 6.0) + mate_blocks(problem, "A", 'right-bot-front','right-bot-back','right-top-front', + "B", 'left-bot-front','left-bot-back','left-top-front', + 0.5, 0.0) + # add global coordinate system + problem.add_point("origin",vector([0.0,0.0,0.0])) + problem.add_point("x-axis",vector([1.0,0.0,0.0])) + problem.add_point("y-axis",vector([0.0,1.0,0.0])) + problem.add_constraint(FixConstraint("origin",vector([0.0,0.0,0.0]))) + problem.add_constraint(FixConstraint("x-axis",vector([1.0,0.0,0.0]))) + problem.add_constraint(FixConstraint("y-axis",vector([0.0,1.0,0.0]))) + + # fix block1 to cs + problem.add_constraint(MateConstraint("origin","x-axis","y-axis", + block_var("A", "left-bot-front"),block_var("A", "right-bot-front"),block_var("A", "left-top-front"), + id_transform_3D())) + + test(problem) + + +if __name__ == "__main__": + #test_twoblocks() + #test_z_index() + test_mate() + diff --git a/test/test_performance.py b/test/test_performance.py new file mode 100644 index 0000000..7a85acf --- /dev/null +++ b/test/test_performance.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +"""This module provides some tests for the GeoSolver. +These test are concerned with the performance of the solver +The tests are also simple examples of how to use of the GeomSolver API""" + +import random +import math +from test_generic import test +from geosolver.geometric import GeometricProblem, GeometricSolver, DistanceConstraint,AngleConstraint, FixConstraint,RightHandedConstraint +from geosolver.vector import vector +from geosolver.randomproblem import random_triangular_problem_3D, random_distance_problem_3D +from geosolver.diagnostic import diag_select, diag_print +from geosolver.intersections import distance_2p, angle_3p +from time import time + +# create statistics for solving time +def stats_solving(): + print "size \t # \t time \t result" + for size in range(4,31): + for i in range(1,10): + problem = random_triangular_problem_3D(size,10.0,0.0,0.0) + t1 = time() + solver = GeometricSolver(problem) + result = solver.get_status() + t2 = time() + t = t2-t1 + print size,"\t",i,"\t",t,"\t",result + +# create statistics for incremental solving time +def stats_incremental(): + #diag_select("clsolver.remove") + print "size \t # \t time \t result" + for size in range(4,31): + for i in range(1,10): + problem = random_triangular_problem_3D(size,10.0,0.0,0.0) + solver = GeometricSolver(problem) + t1 = time() + constraint = random.choice(problem.cg.constraints()) + problem.rem_constraint(constraint) + problem.add_constraint(constraint) + result = solver.get_status() + t2 = time() + t = t2-t1 + print size,"\t",i,"\t",t,"\t",result + +# create statistics for parametric change +def stats_parametric_incremental(): + #diag_select("clsolver.remove") + print "size \t # \t time \t result" + for size in range(4,31): + for i in range(1,10): + problem = random_triangular_problem_3D(size,10.0,0.0,0.0) + solver = GeometricSolver(problem) + constraint = random.choice(problem.cg.constraints()) + #problem.rem_constraint(constraint) + #problem.add_constraint(constraint) + #problem.rem_constraint(constraint) + #problem.add_constraint(constraint) + t1 = time() + #problem.rem_constraint(constraint) + #problem.add_constraint(constraint) + #constraint.set_parameter(constraint.get_parameter()) + result = solver.get_status() + t2 = time() + t = t2-t1 + print size,"\t",i,"\t",t,"\t",result + +# create statistics for parametric change +def stats_parametric(): + #diag_select("clsolver.remove") + print "size \t # \t time \t result" + for size in range(4,31): + for i in range(1,10): + problem = random_triangular_problem_3D(size,10.0,0.0,0.0) + solver = GeometricSolver(problem) + constraint = random.choice(problem.cg.constraints()) + t1 = time() + constraint.set_parameter(constraint.get_parameter()) + result = solver.get_status() + t2 = time() + t = t2-t1 + print size,"\t",i,"\t",t,"\t",result + +def runstats(): + stats_solving() + stats_incremental() + stats_parametric_incremental() + stats_parametric() + +if __name__ == "__main__": + runstats()