from sage.matrix.constructor import matrix
from sage.matrix.matrix_space import MatrixSpace
from sage.groups.group import Group
from sage.categories.groups import Groups
from sage.structure.element import MultiplicativeGroupElement, parent
from sage.modules.free_module import VectorSpace
from sage.modules.free_module_element import vector
from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.integer import Integer
from sage.categories.fields import Fields
_Fields = Fields()
from geometry.translation import TranslationGroup
ZZ_0 = Integer(0)
ZZ_1 = Integer(1)
ZZ_2 = Integer(2)
ZZ_3 = Integer(3)
ZZ_4 = Integer(4)
[docs]class Similarity(MultiplicativeGroupElement):
r"""Class for a similarity of the plane."""
def __init__(self, parent, a, b, s, t):
r'''Construct the similarity (x,y) mapsto (ax-by+s,bx+ay+t).'''
if parent is None:
raise ValueError("The parent must be provided")
self._a=a
self._b=b
self._s=s
self._t=t
self._parent=parent
MultiplicativeGroupElement.__init__(self,parent)
def _mul_(self,s):
r'''Compose two similarities.'''
C = self.__class__
return C(self._parent,
self._a*s._a-self._b*s._b,
self._b*s._a+self._a*s._b,
self._a*s._s-self._b*s._t+self._s,
self._b*s._s+self._a*s._t+self._t)
def __invert__(self):
r'''Invert a similarity.'''
det=self._a*self._a+self._b*self._b
a=self._a/det
b=-self._b/det
C = self.__class__
return C(self._parent,
a,
b,
-a*self._s+b*self._t,
-b*self._s-a*self._t)
def _div_(self,s):
return self._mul_(s.__invert__())
def __hash__(self):
return 73*hash(self._a)-19*hash(self._b)+13*hash(self._s)+53*hash(self._t)
def __call__(self,w):
r'''Return m*w+v.'''
return vector([self._a*w[0]-self._b*w[1]+self._s, self._b*w[0]+self._a*w[1]+self._t])
def _repr_(self):
return "Similarity (x,y) mapsto ("+str(self._a)+"*x-"+\
str(self._b)+"*y+"+str(self._s)+", "+\
str(self._b)+"*x+"+str(self._a)+"*y+"+str(self._t)+")"
def _cmp_(self, other):
x=cmp(self._a,other._a)
if x!=0:
return x
x=cmp(self._b,other._b)
if x!=0:
return x
x=cmp(self._s,other._s)
if x!=0:
return x
return cmp(self._t,other._t)
__cmp__=_cmp_
# For pickling:
#def __reduce__(self):
# return self.__class__, (self._parent, self._a, self._b, self._s, self._t)
def matrix(self):
return matrix(self._parent._f,[
[self._a, -self._b, self._s],
[self._b, self._a, self._t],
[self._parent._f.zero(), self._parent._f.zero(), self._parent._f.one()]])
def a(self):
return self._a
def b(self):
return self._b
def s(self):
return self._s
def t(self):
return self._t
[docs] def derivative(self):
r"""Return the 2x2 matrix corresponding to the derivative of the similarity of the plane."""
return matrix(self._parent._f,[
[self._a, -self._b],
[self._b, self._a]])
[docs]class SimilarityGroup(UniqueRepresentation,Group):
r'''Group representing all similarities in the plane.
This is the group generated by rotations, translations and dilations.
'''
Element = Similarity
def _element_constructor_(self, *args, **kwds):
if len(args)!=1:
return self.element_class(self, *args, **kwds)
x = args[0]
p=parent(x)
if self._f.has_coerce_map_from(p):
return self.element_class( self,self._f(x), self._f.zero(), self._f.zero(), self._f.zero())
if isinstance(p, SimilarityGroup):
return self.element_class(self, x.a(), x.b(), x.s(), x.t())
if isinstance(p, TranslationGroup):
return self.element_class( self,self._f.one(), self._f.zero(), x.s(), x.t() )
return self.element_class(self, x, **kwds)
def _coerce_map_from_(self, S):
if self._f.has_coerce_map_from(S):
return True
if isinstance(S, SimilarityGroup):
return self._f.has_coerce_map_from(S._f)
if isinstance(S, TranslationGroup):
return self._f.has_coerce_map_from(S.base_field())
def __init__(self, base_field):
self._f=base_field
# The vector space of vectors
self._vs = VectorSpace(self._f,2)
Group.__init__(self, category=Groups().Infinite())
def _repr_(self):
return "SimilarityGroup over field "+str(self._f)
def one(self):
return self.element_class(self,self._f.one(),self._f.zero(),self._f.zero(),self._f.zero())
def an_element(self):
return self.element_class(self,self._f(ZZ_3),self._f(ZZ_4),self._f(ZZ_2),self._f(-ZZ_1))
def is_abelian(self):
return False
def gens(self):
pairs=[
(self._f.one(),self._f.zero()),
(self._f(ZZ_2),self._f.zero()),
(self._f.zero(),self._f(ZZ_2)),
(self._f(ZZ_3),self._f(ZZ_4))]
l=[]
for p in pairs:
for v in self._vs.gens():
l.append(self.element_class(self,p[0],p[1],v[0],v[1]))
return l
# For pickling:
#def __reduce__(self):
# return self.__class__, (self._f,)
#def _cmp_(self, other):
# return self._f == other._f
#__cmp__=_cmp_
def base_field(self):
return self._f