Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Free Modules

This section explains how to work with free modules, submodules and cosets of submodules.

If \(R\) is a commutative ring then the set \(R^n\) of all length \(n\) tuples of elements from \(R\) is a free \(R\)-module with standard basis \(e_1, \dots, e_n \in R^n\). \[e_1 = (1, 0, \dots, 0)\] \[e_2 = (0, 1, \dots, 0)\] \[\vdots\] \[e_n = (0, 0, \dots, 1)\]

Algebraeon supports working with free modules over the following rings \(R\):

  • The integers \(\mathbb{Z}\)
  • The rationals \(\mathbb{Q}\)
  • Any field
  • Any Euclidean domain

The examples in this section primarily illustrate how to use Algebraeon in the case \(R = \mathbb{Z}\).

Free Modules

The free module \(R^n\) is represented by objects of type FinitelyFreeModuleStructure. A free module structure can be obtained from the ring of scalars by calling .free_module(n) (the module will take the scalar ring structure by reference) or .into_free_module(n) (the module will take ownership of the scalar ring structure).

For example, to obtain \(\mathbb{Z}^3\)

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::RingToFinitelyFreeModuleSignature;
use algebraeon::sets::structure::MetaType;

let module = Integer::structure().into_free_module(3);

Elements of \(\mathbb{Z}^3\) are represented by objects of type Vec<Integer> and basic operations with the elements are provided by the module structure.

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::rings::structure::*;
use algebraeon::sets::structure::*;

let module = Integer::structure().into_free_module(3);

let a = vec![1.into(), 2.into(), 3.into()];
let b = vec![(-1).into(), 2.into(), (-2).into()];

assert!(module.equal(
    &module.neg(&a),
    &vec![(-1).into(), (-2).into(), (-3).into()]
));

assert!(
    module.equal(&module.add(&a, &b), 
    &vec![0.into(), 4.into(), 1.into()]
));

assert!(
    module.equal(&module.sub(&a, &b),
    &vec![2.into(), 0.into(), 5.into()]
));

assert!(module.equal(
    &module.scalar_mul(&a, &5.into()),
    &vec![5.into(), 10.into(), 15.into()]
));

The scalar ring structure can be obtained from a module by calling .ring().

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let module = Integer::structure().into_free_module(3);

let ring = module.ring();
assert_eq!(ring, &Integer::structure());

Submodules

The set of submodules of the free module \(R^n\) is represented by objects of type FinitelyFreeSubmoduleStructure. This structure can be obtained from a module by calling .submodules() (the structure will take the module structure by reference) or .into_submodules() (the structure will take ownership of the module structure).

For example, to obtain the set of all submodules of \(\mathbb{Z}^3\)

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

Submodules of \(R^n\) are represented by objects of type FinitelyFreeSubmodule.

Constructing Submodules

The zero submodule \({0} \subseteq R^n\) can be constructed using .zero_submodule() and the full submodule \(R^n \subseteq R^n\) can be constructed using .full_submodule().

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

assert_eq!(submodules.zero_submodule().rank(), 0);
assert_eq!(submodules.full_submodule().rank(), 3);

The submodule given by the span of some elements of the module can be constructed using .span(..).

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

assert_eq!(
    submodules
        .span(vec![
            &vec![1.into(), 2.into(), 2.into()],
            &vec![2.into(), 1.into(), 1.into()],
            &vec![3.into(), 3.into(), 3.into()]
        ])
        .rank(),
    2
);

The submodule given by the kernel of some elements can be constructed using .kernel(..).

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

assert!(submodules.equal(
    &submodules.kernel(vec![
        &vec![1.into(), 2.into()],
        &vec![2.into(), 1.into()],
        &vec![3.into(), 3.into()],
    ]),
    &submodules.span(vec![&vec![1.into(), 1.into(), (-1).into()]])
));

Basic Operations

Test submodules for equality using .equal(..).

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

assert!(submodules.equal(
    &submodules.span(vec![
        &vec![2.into(), 2.into(), 0.into()],
        &vec![2.into(), (-2).into(), 0.into()],
    ]),
    &submodules.span(vec![
        &vec![4.into(), 0.into(), 0.into()],
        &vec![0.into(), 4.into(), 0.into()],
        &vec![2.into(), 2.into(), 0.into()],
    ])
));

assert!(!submodules.equal(
    &submodules.span(vec![
        &vec![1.into(), 1.into(), 0.into()],
        &vec![2.into(), 3.into(), 0.into()],
    ]),
    &submodules.span(vec![
        &vec![1.into(), 2.into(), 3.into()],
        &vec![1.into(), 1.into(), 0.into()],
    ])
));

Check whether a submodule contains an element using .contains_element(..).

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

let a = submodules.span(vec![
    &vec![2.into(), 2.into(), 0.into()],
    &vec![2.into(), (-2).into(), 0.into()],
]);

assert!(submodules.contains_element(&a, &vec![4.into(), 4.into(), 0.into()]));
assert!(!submodules.contains_element(&a, &vec![3.into(), 4.into(), 0.into()]));
assert!(!submodules.contains_element(&a, &vec![4.into(), 4.into(), 1.into()]));

Check whether a submodule is a subset of another submodule using .contains(..).

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

let a = submodules.span(vec![&vec![3.into(), 3.into(), 3.into()]]);
let b = submodules.span(vec![&vec![6.into(), 6.into(), 6.into()]]);

assert!(submodules.contains(&a, &b));
assert!(!submodules.contains(&b, &a));

Compute the sum of two submodules using .sum(..) and compute the intersection of two submodules using .intersection(..).

use algebraeon::nzq::Integer;
use algebraeon::rings::module::finitely_free_module::*;
use algebraeon::sets::structure::*;

let submodules = Integer::structure().into_free_module(3).into_submodules();

let a = submodules.span(vec![&vec![4.into(), 4.into(), 4.into()]]);
let b = submodules.span(vec![&vec![6.into(), 6.into(), 6.into()]]);

let sum_ab = submodules.span(vec![&vec![2.into(), 2.into(), 2.into()]]);
assert!(submodules.equal(&submodules.sum(&a, &b), &sum_ab));

let intersect_ab = submodules.span(vec![&vec![12.into(), 12.into(), 12.into()]]);
assert!(submodules.equal(&submodules.intersect(&a, &b), &intersect_ab));