Ideals of (Not Necessarily Maximal) Orders in Number Fields¶
This module implements (integral) ideals of orders in number fields.
Note
Currently, Sage only offers very limited functionality for ideals of non-maximal orders (compared to the maximal case). This should hopefully change in the future.
EXAMPLES:
sage: O = QuadraticField(-1).order(5*i)
sage: I = O.ideal([13, 5*i-1]); I
Ideal (60*a + 1, 65*a) of Order of conductor 5 generated by 5*a
in Number Field in a with defining polynomial x^2 + 1 with a = 1*I
>>> from sage.all import *
>>> O = QuadraticField(-Integer(1)).order(Integer(5)*i)
>>> I = O.ideal([Integer(13), Integer(5)*i-Integer(1)]); I
Ideal (60*a + 1, 65*a) of Order of conductor 5 generated by 5*a
in Number Field in a with defining polynomial x^2 + 1 with a = 1*I
An ideal of an order in a relative number field:
sage: K.<a,b> = NumberField([x^2 + 1, x^2 - 3])
sage: O = K.order([3*a,2*b])
sage: I = O.ideal((-6*b + 6)*a + 6*b + 18); I
Ideal ((-60*b + 180)*a + 72, (-54*b + 174)*a - 6*b + 54, (-72*b + 288)*a + 72, 1872*a)
of Relative Order generated by [3*a - 2*b, -6*b*a + 6, 3*a]
in Number Field in a with defining polynomial x^2 + 1 over its base field
>>> from sage.all import *
>>> K = NumberField([x**Integer(2) + Integer(1), x**Integer(2) - Integer(3)], names=('a', 'b',)); (a, b,) = K._first_ngens(2)
>>> O = K.order([Integer(3)*a,Integer(2)*b])
>>> I = O.ideal((-Integer(6)*b + Integer(6))*a + Integer(6)*b + Integer(18)); I
Ideal ((-60*b + 180)*a + 72, (-54*b + 174)*a - 6*b + 54, (-72*b + 288)*a + 72, 1872*a)
of Relative Order generated by [3*a - 2*b, -6*b*a + 6, 3*a]
in Number Field in a with defining polynomial x^2 + 1 over its base field
Perhaps the most useful functionality at this time is mapping ideals of quadratic orders to corresponding binary quadratic forms:
sage: K.<t> = QuadraticField(-21463)
sage: O = K.order(t)
sage: I = O.ideal([123457, t + 45259]); I
Ideal (23058*t + 1, 123457*t) of Order of conductor 26 generated by t
in Number Field in t with defining polynomial x^2 + 21463 with t = 146.5025597046004?*I
sage: I.quadratic_form()
123457*x^2 - 90518*x*y + 16592*y^2
>>> from sage.all import *
>>> K = QuadraticField(-Integer(21463), names=('t',)); (t,) = K._first_ngens(1)
>>> O = K.order(t)
>>> I = O.ideal([Integer(123457), t + Integer(45259)]); I
Ideal (23058*t + 1, 123457*t) of Order of conductor 26 generated by t
in Number Field in t with defining polynomial x^2 + 21463 with t = 146.5025597046004?*I
>>> I.quadratic_form()
123457*x^2 - 90518*x*y + 16592*y^2
Todo
Generalize more functionality (such as primality testing and
factoring) from
NumberFieldFractionalIdeal
to ideals of not necessarily maximal orders.
AUTHORS:
Lorenz Panny (2022)
- sage.rings.number_field.order_ideal.NumberFieldOrderIdeal(O, *args, **kwds)[source]¶
Construct either a
NumberFieldOrderIdeal_generic
or aNumberFieldOrderIdeal_quadratic
from the given arguments.EXAMPLES:
sage: from sage.rings.number_field.order_ideal import NumberFieldOrderIdeal sage: R.<x> = QQ[] sage: K.<t> = NumberField(x^3 - 40) sage: O = K.order(t) sage: I = NumberFieldOrderIdeal(O, [13, t-1]); I Ideal (12*t^2 + 1, 12*t^2 + t, 13*t^2) of Order generated by t in Number Field in t with defining polynomial x^3 - 40 sage: K.absolute_degree() 3 sage: type(I) <class 'sage.rings.number_field.order_ideal.NumberFieldOrderIdeal_generic'>
>>> from sage.all import * >>> from sage.rings.number_field.order_ideal import NumberFieldOrderIdeal >>> R = QQ['x']; (x,) = R._first_ngens(1) >>> K = NumberField(x**Integer(3) - Integer(40), names=('t',)); (t,) = K._first_ngens(1) >>> O = K.order(t) >>> I = NumberFieldOrderIdeal(O, [Integer(13), t-Integer(1)]); I Ideal (12*t^2 + 1, 12*t^2 + t, 13*t^2) of Order generated by t in Number Field in t with defining polynomial x^3 - 40 >>> K.absolute_degree() 3 >>> type(I) <class 'sage.rings.number_field.order_ideal.NumberFieldOrderIdeal_generic'>
sage: L.<u> = QuadraticField(-3) sage: J = NumberFieldOrderIdeal(L.maximal_order(), [(u+5)/2]) sage: L.absolute_degree() 2 sage: type(J) <class 'sage.rings.number_field.order_ideal.NumberFieldOrderIdeal_quadratic'>
>>> from sage.all import * >>> L = QuadraticField(-Integer(3), names=('u',)); (u,) = L._first_ngens(1) >>> J = NumberFieldOrderIdeal(L.maximal_order(), [(u+Integer(5))/Integer(2)]) >>> L.absolute_degree() 2 >>> type(J) <class 'sage.rings.number_field.order_ideal.NumberFieldOrderIdeal_quadratic'>
- class sage.rings.number_field.order_ideal.NumberFieldOrderIdeal_generic(O, gens, *, coerce=True)[source]¶
Bases:
Ideal_generic
An ideal of a not necessarily maximal order in a number field.
- free_module()[source]¶
Return the free \(\ZZ\)-module corresponding to this ideal as a submodule of the vector space associated to the ambient number field.
EXAMPLES:
sage: K.<t> = QuadraticField(-123) sage: g, = K.ring_of_integers().ring_generators() sage: O = K.order(567*g) sage: I = O.ideal([191, 567*t-27]); I Ideal (56133/2*t + 1/2, 108297*t) of Order of conductor 567 generated by 567/2*t + 1/2 in Number Field in t with defining polynomial x^2 + 123 with t = 11.09053650640942?*I sage: I.free_module() Free module of degree 2 and rank 2 over Integer Ring Echelon basis matrix: [ 1/2 56133/2] [ 0 108297] sage: I.free_module().is_submodule(O.free_module()) True
>>> from sage.all import * >>> K = QuadraticField(-Integer(123), names=('t',)); (t,) = K._first_ngens(1) >>> g, = K.ring_of_integers().ring_generators() >>> O = K.order(Integer(567)*g) >>> I = O.ideal([Integer(191), Integer(567)*t-Integer(27)]); I Ideal (56133/2*t + 1/2, 108297*t) of Order of conductor 567 generated by 567/2*t + 1/2 in Number Field in t with defining polynomial x^2 + 123 with t = 11.09053650640942?*I >>> I.free_module() Free module of degree 2 and rank 2 over Integer Ring Echelon basis matrix: [ 1/2 56133/2] [ 0 108297] >>> I.free_module().is_submodule(O.free_module()) True
- norm()[source]¶
Return the norm of this ideal.
The norm is defined as the index (as an abelian group) of the ideal in its order.
EXAMPLES:
sage: K.<t> = QuadraticField(-123) sage: g, = K.ring_of_integers().ring_generators() sage: O = K.order(567*g) sage: I = O.ideal([191, 567*t-27]) sage: I.norm() 191 sage: (O.free_module() / I.free_module()).cardinality() 191
>>> from sage.all import * >>> K = QuadraticField(-Integer(123), names=('t',)); (t,) = K._first_ngens(1) >>> g, = K.ring_of_integers().ring_generators() >>> O = K.order(Integer(567)*g) >>> I = O.ideal([Integer(191), Integer(567)*t-Integer(27)]) >>> I.norm() 191 >>> (O.free_module() / I.free_module()).cardinality() 191
- class sage.rings.number_field.order_ideal.NumberFieldOrderIdeal_quadratic(O, gens, *, coerce=True)[source]¶
Bases:
NumberFieldOrderIdeal_generic
An ideal of a not necessarily maximal order in a quadratic number field.
- conjugate()[source]¶
Return the conjugate of this ideal, defined by conjugating the generators.
EXAMPLES:
sage: K.<t> = QuadraticField(-123) sage: g, = K.ring_of_integers().ring_generators() sage: O = K.order(567*g) sage: I = O.ideal([191, 567*t-27]) sage: I.norm() 191 sage: I.norm() in I.conjugate() * I True sage: I.conjugate() * I == I.norm() * O True
>>> from sage.all import * >>> K = QuadraticField(-Integer(123), names=('t',)); (t,) = K._first_ngens(1) >>> g, = K.ring_of_integers().ring_generators() >>> O = K.order(Integer(567)*g) >>> I = O.ideal([Integer(191), Integer(567)*t-Integer(27)]) >>> I.norm() 191 >>> I.norm() in I.conjugate() * I True >>> I.conjugate() * I == I.norm() * O True
- gens_reduced()[source]¶
Express this ideal in terms of at most two generators, and one if possible (i.e., if the ideal is principal).
EXAMPLES:
sage: x = polygen(QQ) sage: K.<a> = NumberField(x^2 + 11*x + 5) sage: O = K.order(7*a) sage: I = O.ideal([31915, -71145879*a - 32195694]) sage: I.gens_reduced() (-63*a + 17,)
>>> from sage.all import * >>> x = polygen(QQ) >>> K = NumberField(x**Integer(2) + Integer(11)*x + Integer(5), names=('a',)); (a,) = K._first_ngens(1) >>> O = K.order(Integer(7)*a) >>> I = O.ideal([Integer(31915), -Integer(71145879)*a - Integer(32195694)]) >>> I.gens_reduced() (-63*a + 17,)
ALGORITHM:
Compute a reduction of the
quadratic_form()
to see if it represents \(1\), then use the transformation matrix to find an element in the ideal whose norm equals the norm of the ideal.
- gens_two()[source]¶
Express this ideal using exactly two generators, the first of which is a generator for the intersection of the ideal with \(\ZZ\).
EXAMPLES:
sage: K.<t> = QuadraticField(-100) sage: O = K.order(t) sage: I = O.ideal([123, 131-t, 21+23*t]) sage: I.gens_two() (41, t - 8) sage: I == O.ideal(I.gens_two()) True
>>> from sage.all import * >>> K = QuadraticField(-Integer(100), names=('t',)); (t,) = K._first_ngens(1) >>> O = K.order(t) >>> I = O.ideal([Integer(123), Integer(131)-t, Integer(21)+Integer(23)*t]) >>> I.gens_two() (41, t - 8) >>> I == O.ideal(I.gens_two()) True
The second generator is zero if and only if the ideal is generated by an integer:
sage: J = O.ideal([-33*t, 11*t-6589]) sage: J.gens_two() (11, 0) sage: J == O.ideal(11) True
>>> from sage.all import * >>> J = O.ideal([-Integer(33)*t, Integer(11)*t-Integer(6589)]) >>> J.gens_two() (11, 0) >>> J == O.ideal(Integer(11)) True
Warning
The returned generators do not necessarily form a \(\ZZ\)-basis of the ideal.
- is_equivalent(other, narrow=False)[source]¶
Determine whether this ideal is equivalent to another ideal in the same order.
If
narrow
isTrue
, test narrow equivalence instead.(Two ideals are equivalent if they differ by multiplication by a nonzero element. They are narrowly equivalent if they differ by multiplication by an element of positive norm.)
EXAMPLES:
sage: K.<a> = QuadraticField(-163) sage: O = K.order(7*a) sage: I = O.ideal([47, 7*a-35]) sage: J = O.ideal([71, 7*a-65]) sage: I.is_equivalent(J) False sage: (I^10).is_equivalent(J) True
>>> from sage.all import * >>> K = QuadraticField(-Integer(163), names=('a',)); (a,) = K._first_ngens(1) >>> O = K.order(Integer(7)*a) >>> I = O.ideal([Integer(47), Integer(7)*a-Integer(35)]) >>> J = O.ideal([Integer(71), Integer(7)*a-Integer(65)]) >>> I.is_equivalent(J) False >>> (I**Integer(10)).is_equivalent(J) True
sage: K.<a> = QuadraticField(229) sage: O = K.order(7*a) sage: O.class_number() 3 sage: I = O.ideal([3, 7*a-2]) sage: J = O.ideal([5, 7*a-4]) sage: I.is_equivalent(J) True
>>> from sage.all import * >>> K = QuadraticField(Integer(229), names=('a',)); (a,) = K._first_ngens(1) >>> O = K.order(Integer(7)*a) >>> O.class_number() 3 >>> I = O.ideal([Integer(3), Integer(7)*a-Integer(2)]) >>> J = O.ideal([Integer(5), Integer(7)*a-Integer(4)]) >>> I.is_equivalent(J) True
sage: K.<a> = QuadraticField(273) sage: O = K.order(11*a) sage: O.class_number() 20 sage: I = O.ideal([17, 11*a-11]) sage: J = O.ideal([19, 11*a-12]) sage: I.is_equivalent(J) False sage: (I^3).is_equivalent(J) False sage: (I^6).is_equivalent(J^2) True sage: el = 177 + 11*a sage: el.norm() -1704 sage: (I^6).is_equivalent(J^2, narrow=True) True sage: (I^6).is_equivalent(J^2*el, narrow=True) False
>>> from sage.all import * >>> K = QuadraticField(Integer(273), names=('a',)); (a,) = K._first_ngens(1) >>> O = K.order(Integer(11)*a) >>> O.class_number() 20 >>> I = O.ideal([Integer(17), Integer(11)*a-Integer(11)]) >>> J = O.ideal([Integer(19), Integer(11)*a-Integer(12)]) >>> I.is_equivalent(J) False >>> (I**Integer(3)).is_equivalent(J) False >>> (I**Integer(6)).is_equivalent(J**Integer(2)) True >>> el = Integer(177) + Integer(11)*a >>> el.norm() -1704 >>> (I**Integer(6)).is_equivalent(J**Integer(2), narrow=True) True >>> (I**Integer(6)).is_equivalent(J**Integer(2)*el, narrow=True) False
- is_principal()[source]¶
Determine whether or not this ideal is principal.
See also
To find a generator, use
gens_reduced()
.EXAMPLES:
sage: K.<a> = QuadraticField(-163) sage: O = K.order(7*a) sage: O.class_number() 24 sage: order = lambda v: next(e for e in range(1,99) if (v^e).is_principal()) sage: I = O.ideal([47, 7*a-35]) sage: order(I) 24 sage: J = O.ideal([71, 7*a-65]) sage: order(J) 12 sage: next(e for e in range(99) if (I^e * J.conjugate()).is_principal()) 10 sage: (I^10 * J.conjugate()).is_principal() True
sage: K.<a> = QuadraticField(229) sage: O = K.order(7*a) sage: I = O.ideal([3, 7*a-2]) sage: J = O.ideal([5, 7*a-4]) sage: (I * J.conjugate()).is_principal() True sage: el = 104 + 7*a sage: el.norm() -405 sage: (I * (J * el).conjugate()).is_principal() True
>>> from sage.all import * >>> K = QuadraticField(Integer(229), names=('a',)); (a,) = K._first_ngens(1) >>> O = K.order(Integer(7)*a) >>> I = O.ideal([Integer(3), Integer(7)*a-Integer(2)]) >>> J = O.ideal([Integer(5), Integer(7)*a-Integer(4)]) >>> (I * J.conjugate()).is_principal() True >>> el = Integer(104) + Integer(7)*a >>> el.norm() -405 >>> (I * (J * el).conjugate()).is_principal() True
- quadratic_form(basis)[source]¶
Return the binary quadratic form associated to this ideal.
This map induces an injective homomorphism from the narrow class group on ideals to the class group on quadratic forms.
If
basis
is set toTrue
(default:False
), the method additionally returns a \(\ZZ\)-basis \((a,b)\) of this ideal \(I\) such that \(f(x,y)\) equals \(\mathrm{norm}(xa+yb) / \mathrm{norm}(I)\), where \(f\) is the returned quadratic form.Note
The narrow class group is the group of invertible ideals modulo the principal ideals generated by an element of positive norm.
For imaginary quadratic orders, the narrow class group is identical to the class group.
For real quadratic orders, identifying the classes of \(f(x,y)\) and \(-f(y,x)\) recovers a correspondence with the standard class group.
REFERENCES:
The correspondence itself is classical. Implemented after [Coh1993], §5.2.
See also
sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.quadratic_form()
EXAMPLES:
sage: K.<t> = QuadraticField(-419) sage: O = K.order(t) sage: O.discriminant().factor() -1 * 2^2 * 419 sage: I = O.ideal([t-1, 105]); I Ideal (104*t + 1, 105*t) of Order of conductor 2 generated by t in Number Field in t with defining polynomial x^2 + 419 with t = 20.46948949045873?*I sage: f = I.quadratic_form(); f 105*x^2 - 208*x*y + 107*y^2 sage: f.discriminant().factor() -1 * 2^2 * 419 sage: power(f,3).reduced_form() x^2 + 419*y^2
>>> from sage.all import * >>> K = QuadraticField(-Integer(419), names=('t',)); (t,) = K._first_ngens(1) >>> O = K.order(t) >>> O.discriminant().factor() -1 * 2^2 * 419 >>> I = O.ideal([t-Integer(1), Integer(105)]); I Ideal (104*t + 1, 105*t) of Order of conductor 2 generated by t in Number Field in t with defining polynomial x^2 + 419 with t = 20.46948949045873?*I >>> f = I.quadratic_form(); f 105*x^2 - 208*x*y + 107*y^2 >>> f.discriminant().factor() -1 * 2^2 * 419 >>> power(f,Integer(3)).reduced_form() x^2 + 419*y^2
sage: u = 23*t - 45 sage: J = I*u sage: g = J.quadratic_form(); g 23485980*x^2 - 22795498*x*y + 5531329*y^2 sage: f.is_equivalent(g) True
>>> from sage.all import * >>> u = Integer(23)*t - Integer(45) >>> J = I*u >>> g = J.quadratic_form(); g 23485980*x^2 - 22795498*x*y + 5531329*y^2 >>> f.is_equivalent(g) True
The inverse operation (modulo equivalence) can be computed by passing a
BinaryQF
toO.ideal()
:sage: II = O.ideal(f); II Ideal (104*t + 1, 105*t) of Order of conductor 2 generated by t in Number Field in t with defining polynomial x^2 + 419 with t = 20.46948949045873?*I sage: II.quadratic_form().is_equivalent(f) True
>>> from sage.all import * >>> II = O.ideal(f); II Ideal (104*t + 1, 105*t) of Order of conductor 2 generated by t in Number Field in t with defining polynomial x^2 + 419 with t = 20.46948949045873?*I >>> II.quadratic_form().is_equivalent(f) True