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 a NumberFieldOrderIdeal_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 is True, 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 to True (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 to O.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