Skip to content

Commit fedf214

Browse files
Release Managervbraun
Release Manager
authored andcommitted
Trac #15897: UniqueFactory for QuaternionAlgebras
Quaternion algebras use a generic dictionary to cache objects (instead of `UniqueRepresentation` or `UniqueFactory`). This ticket replaces this generic cache with a `UniqueFactory` implementation. URL: http://trac.sagemath.org/15897 Reported by: saraedum Ticket author(s): Julian Rueth Reviewer(s): David Roe, Peter Bruin
2 parents 1aaaaff + bdaaaff commit fedf214

File tree

2 files changed

+70
-71
lines changed

2 files changed

+70
-71
lines changed

src/sage/algebras/quatalg/quaternion_algebra.py

+69-69
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
44
AUTHORS:
55
6-
- Jon Bobber -- 2009 rewrite
6+
- Jon Bobber (2009): rewrite
77
8-
- William Stein -- 2009 rewrite
8+
- William Stein (2009): rewrite
9+
10+
- Julian Rueth (2014-03-02): use UniqueFactory for caching
911
1012
This code is partly based on Sage code by David Kohel from 2005.
1113
@@ -21,6 +23,7 @@
2123
########################################################################
2224
# Copyright (C) 2009 William Stein <[email protected]>
2325
# Copyright (C) 2009 Jonathon Bober <[email protected]>
26+
# Copyright (C) 2014 Julian Rueth <[email protected]>
2427
#
2528
# Distributed under the terms of the GNU General Public License (GPL)
2629
#
@@ -53,6 +56,7 @@
5356
from sage.matrix.constructor import diagonal_matrix, matrix
5457
from sage.structure.sequence import Sequence
5558
from sage.structure.element import is_RingElement
59+
from sage.structure.factory import UniqueFactory
5660
from sage.modules.free_module import VectorSpace, FreeModule
5761
from sage.modules.free_module_element import vector
5862

@@ -72,9 +76,7 @@
7276
# Constructor
7377
########################################################
7478

75-
_cache = {}
76-
77-
def QuaternionAlgebra(arg0, arg1=None, arg2=None, names='i,j,k'):
79+
class QuaternionAlgebraFactory(UniqueFactory):
7880
"""
7981
There are three input formats:
8082
@@ -192,60 +194,76 @@ def QuaternionAlgebra(arg0, arg1=None, arg2=None, names='i,j,k'):
192194
sage: parent(Q._b)
193195
Rational Field
194196
"""
197+
def create_key(self, arg0, arg1=None, arg2=None, names='i,j,k'):
198+
"""
199+
Create a key that uniquely determines a quaternion algebra.
195200
196-
# QuaternionAlgebra(D)
197-
if arg1 is None and arg2 is None:
198-
K = QQ
199-
D = Integer(arg0)
200-
a, b = hilbert_conductor_inverse(D)
201-
a = Rational(a); b = Rational(b)
201+
TESTS::
202202
203-
elif arg2 is None:
204-
# If arg0 or arg1 are Python data types, coerce them
205-
# to the relevant Sage types. This is a bit inelegant.
206-
L = []
207-
for a in [arg0,arg1]:
208-
if is_RingElement(a):
209-
L.append(a)
210-
elif isinstance(a, int) or isinstance(a, long):
211-
L.append(Integer(a))
212-
elif isinstance(a, float):
213-
L.append(RR(a))
214-
else:
215-
raise ValueError("a and b must be elements of a ring with characteristic not 2")
203+
sage: QuaternionAlgebra.create_key(-1,-1)
204+
(Rational Field, -1, -1, ('i', 'j', 'k'))
205+
206+
"""
207+
# QuaternionAlgebra(D)
208+
if arg1 is None and arg2 is None:
209+
K = QQ
210+
D = Integer(arg0)
211+
a, b = hilbert_conductor_inverse(D)
212+
a = Rational(a); b = Rational(b)
213+
214+
elif arg2 is None:
215+
# If arg0 or arg1 are Python data types, coerce them
216+
# to the relevant Sage types. This is a bit inelegant.
217+
L = []
218+
for a in [arg0,arg1]:
219+
if is_RingElement(a):
220+
L.append(a)
221+
elif isinstance(a, int) or isinstance(a, long):
222+
L.append(Integer(a))
223+
elif isinstance(a, float):
224+
L.append(RR(a))
225+
else:
226+
raise ValueError("a and b must be elements of a ring with characteristic not 2")
216227

217-
# QuaternionAlgebra(a, b)
218-
v = Sequence(L)
219-
K = v.universe().fraction_field()
220-
a = K(v[0])
221-
b = K(v[1])
228+
# QuaternionAlgebra(a, b)
229+
v = Sequence(L)
230+
K = v.universe().fraction_field()
231+
a = K(v[0])
232+
b = K(v[1])
222233

223-
# QuaternionAlgebra(K, a, b)
224-
else:
225-
K = arg0
226-
if K not in _Fields:
227-
raise TypeError("base ring of quaternion algebra must be a field")
228-
a = K(arg1)
229-
b = K(arg2)
234+
# QuaternionAlgebra(K, a, b)
235+
else:
236+
K = arg0
237+
if K not in _Fields:
238+
raise TypeError("base ring of quaternion algebra must be a field")
239+
a = K(arg1)
240+
b = K(arg2)
230241

231-
if K.characteristic() == 2:
232-
# Lameness!
233-
raise ValueError("a and b must be elements of a ring with characteristic not 2")
234-
if a == 0 or b == 0:
235-
raise ValueError("a and b must be nonzero")
242+
if K.characteristic() == 2:
243+
# Lameness!
244+
raise ValueError("a and b must be elements of a ring with characteristic not 2")
245+
if a == 0 or b == 0:
246+
raise ValueError("a and b must be nonzero")
236247

237-
global _cache
238-
names = normalize_names(3, names)
239-
key = (K, a, b, names)
240-
if key in _cache:
241-
return _cache[key]
242-
A = QuaternionAlgebra_ab(K, a, b, names=names)
243-
A._key = key
244-
_cache[key] = A
245-
return A
248+
names = normalize_names(3, names)
249+
return (K, a, b, names)
246250

247251

252+
def create_object(self, version, key, **extra_args):
253+
"""
254+
Create the object from the key (extra arguments are ignored). This is
255+
only called if the object was not found in the cache.
248256
257+
TESTS::
258+
259+
sage: QuaternionAlgebra.create_object("6.0", (QQ, -1, -1, ('i', 'j', 'k')))
260+
Quaternion Algebra (-1, -1) with base ring Rational Field
261+
262+
"""
263+
K, a, b, names = key
264+
return QuaternionAlgebra_ab(K, a, b, names=names)
265+
266+
QuaternionAlgebra = QuaternionAlgebraFactory("QuaternionAlgebra")
249267

250268
########################################################
251269
# Classes
@@ -872,23 +890,6 @@ def __cmp__(self, other):
872890
if c: return c
873891
return cmp((self._a, self._b), (other._a, other._b))
874892

875-
def __reduce__(self):
876-
"""
877-
Internal method used for pickling.
878-
879-
TESTS::
880-
881-
sage: QuaternionAlgebra(QQ,-1,-2).__reduce__()
882-
(<function unpickle_QuaternionAlgebra_v0 at ...>, (Rational Field, -1, -2, ('i', 'j', 'k')))
883-
884-
Test uniqueness of parent::
885-
886-
sage: Q = QuaternionAlgebra(QQ,-1,-2)
887-
sage: loads(dumps(Q)) is Q
888-
True
889-
"""
890-
return unpickle_QuaternionAlgebra_v0, self._key
891-
892893
def gen(self, i=0):
893894
"""
894895
Return the `i^{th}` generator of ``self``.
@@ -1238,7 +1239,7 @@ def unpickle_QuaternionAlgebra_v0(*key):
12381239
EXAMPLES::
12391240
12401241
sage: Q = QuaternionAlgebra(-5,-19)
1241-
sage: f, t = Q.__reduce__()
1242+
sage: t = (QQ, -5, -19, ('i', 'j', 'k'))
12421243
sage: sage.algebras.quatalg.quaternion_algebra.unpickle_QuaternionAlgebra_v0(*t)
12431244
Quaternion Algebra (-5, -19) with base ring Rational Field
12441245
sage: loads(dumps(Q)) == Q
@@ -1248,7 +1249,6 @@ def unpickle_QuaternionAlgebra_v0(*key):
12481249
"""
12491250
return QuaternionAlgebra(*key)
12501251

1251-
12521252
class QuaternionOrder(Algebra):
12531253
"""
12541254
An order in a quaternion algebra.

src/sage/algebras/quaternion_algebra.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ def unpickle_QuaternionAlgebra_v0(*key):
88
99
EXAMPLES::
1010
11-
sage: Q = QuaternionAlgebra(-5,-19)
12-
sage: f, t = Q.__reduce__()
11+
sage: t = (QQ, -5, -19, ('i', 'j', 'k'))
1312
sage: import sage.algebras.quaternion_algebra
1413
sage: sage.algebras.quaternion_algebra.unpickle_QuaternionAlgebra_v0(*t)
1514
Quaternion Algebra (-5, -19) with base ring Rational Field

0 commit comments

Comments
 (0)