├── rls.toml
├── .gitignore
├── tests
├── __init__.py
└── test_real_algebraic_number.py
├── pyproject.toml
├── src
├── prelude.rs
├── lib.rs
├── generate_gcd_test_cases.mac
├── polynomial
│ ├── distinct_degree_factorization.rs
│ ├── same_degree_factorization.rs
│ ├── mul.rs
│ ├── add_sub.rs
│ └── factorization_over_integers.rs
├── python.rs
├── lattice.rs
├── traits.rs
└── array2d.rs
├── Notices.txt
├── Cargo.toml
├── CHANGELOG.md
├── README.md
├── Cargo.lock
└── LICENSE.md
/rls.toml:
--------------------------------------------------------------------------------
1 | features = ["python-extension"]
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | __pycache__
4 | *.pyc
5 | /.vscode
6 | .venv
7 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: LGPL-2.1-or-later
2 | # See Notices.txt for copyright information
3 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: LGPL-2.1-or-later
2 | # See Notices.txt for copyright information
3 | [build-system]
4 | requires = ["maturin>=1.0,<2.0"]
5 | build-backend = "maturin"
6 |
7 | [tool.maturin]
8 | features = ["python-extension"]
9 |
--------------------------------------------------------------------------------
/src/prelude.rs:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: LGPL-2.1-or-later
2 | // See Notices.txt for copyright information
3 | pub use crate::{
4 | algebraic_numbers::RealAlgebraicNumber,
5 | traits::{
6 | ExactDiv as _, ExactDivAssign as _, ExtendedGCD as _, IntervalUnion as _,
7 | IntervalUnionAssign as _, GCD as _,
8 | },
9 | };
10 | pub use num_traits::{
11 | CheckedAdd as _, CheckedDiv as _, CheckedMul as _, CheckedRem as _, CheckedSub as _, One as _,
12 | Pow as _, Signed as _, Zero as _,
13 | };
14 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: LGPL-2.1-or-later
2 | // See Notices.txt for copyright information
3 |
4 | #[macro_use]
5 | extern crate lazy_static;
6 |
7 | pub mod algebraic_numbers;
8 | pub(crate) mod array2d;
9 | pub mod interval_arithmetic;
10 | pub(crate) mod lattice;
11 | pub mod mod_int;
12 | pub mod polynomial;
13 | pub mod prelude;
14 | pub mod python;
15 | pub(crate) mod quadratic_numbers;
16 | pub mod traits;
17 | pub mod util;
18 |
19 | pub use algebraic_numbers::RealAlgebraicNumber;
20 |
21 | macro_rules! doctest {
22 | ($x:expr) => {
23 | #[allow(unused_doc_comments)]
24 | #[doc = $x]
25 | extern "C" {}
26 | };
27 | }
28 |
29 | doctest!(include_str!("../README.md"));
30 |
--------------------------------------------------------------------------------
/Notices.txt:
--------------------------------------------------------------------------------
1 | Copyright 2018-2019 Jacob Lifshay
2 |
3 | This file is part of Algebraics.
4 |
5 | Algebraics is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU Lesser General Public License as published by
7 | the Free Software Foundation, either version 2.1 of the License, or
8 | (at your option) any later version.
9 |
10 | Algebraics is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU Lesser General Public License for more details.
14 |
15 | You should have received a copy of the GNU Lesser General Public License
16 | along with Algebraics. If not, see .
17 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: LGPL-2.1-or-later
2 | # See Notices.txt for copyright information
3 | [package]
4 | name = "algebraics"
5 | version = "0.3.0"
6 | authors = ["Jacob Lifshay "]
7 | edition = "2018"
8 | license = "LGPL-2.1-or-later"
9 | description = "algebraic numbers library"
10 | keywords = ["algebraic-numbers", "arbitrary-precision", "polynomials", "real-numbers", "exact-arithmetic"]
11 | repository = "https://salsa.debian.org/Kazan-team/algebraics"
12 | readme = "README.md"
13 | categories = ["algorithms", "data-structures", "science"]
14 |
15 | [features]
16 | default = []
17 | python = ["pyo3"]
18 | python-extension = ["python", "pyo3/extension-module"]
19 |
20 | [lib]
21 | name = "algebraics"
22 | crate-type = ["rlib", "cdylib"]
23 |
24 | [dependencies]
25 | num-traits = "0.2.14"
26 | num-bigint = "0.4.3"
27 | num-integer = "0.1.44"
28 | num-rational = "0.4.0"
29 | rand = "0.8.5"
30 | rand_pcg = "0.3.1"
31 | lazy_static = "1.4"
32 |
33 | [dependencies.pyo3]
34 | version = "0.25.1"
35 | optional = true
36 | features = ["num-bigint"]
37 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7 |
8 | ## [Unreleased]
9 |
10 | ### Changed
11 |
12 | * add changes here
13 |
14 | ## [0.3.0]
15 |
16 | ### Changed
17 |
18 | * Updated dependency versions
19 |
20 | ## [0.2.0]
21 |
22 | ### Changed
23 |
24 | * Update PyO3 from v0.8.2 to v0.9.0
25 |
26 | ## [0.1.2]
27 |
28 | ### Added
29 |
30 | * Add Python bindings using PyO3 v0.8.2
31 |
32 | ## [0.1.1]
33 |
34 | ### Changed
35 |
36 | * Split common functionality out into internal function `remove_zero_from_interval`
37 |
38 | ### Added
39 |
40 | * Added functions for calculating the integer part of the base-2 log of a `RealAlgebraicNumber`
41 |
42 | ## 0.1.0
43 |
44 | ### Added
45 |
46 | * Initial release
47 |
48 | [Unreleased]: https://salsa.debian.org/Kazan-team/algebraics/-/compare/v0.2.0...master
49 | [0.2.0]: https://salsa.debian.org/Kazan-team/algebraics/-/compare/v0.1.2...v0.2.0
50 | [0.1.2]: https://salsa.debian.org/Kazan-team/algebraics/-/compare/v0.1.1...v0.1.2
51 | [0.1.1]: https://salsa.debian.org/Kazan-team/algebraics/-/compare/v0.1.0...v0.1.1
52 |
--------------------------------------------------------------------------------
/src/generate_gcd_test_cases.mac:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later
2 | * See Notices.txt for copyright information
3 | *
4 | * Maxima program to generate the test cases for Polynomial::>::gcd_lcm
5 | *
6 | * run by using:
7 | * maxima -b generate_gcd_test_cases.mac
8 | */
9 |
10 | number_to_text(v):=block(
11 | [n, d],
12 | n:num(v),
13 | d:denom(v),
14 | if d=1 then return(concat("ri(", n, ")")),
15 | concat("r(", n, ", ", d, ")")
16 | )$
17 |
18 | poly_to_text(p):=block(
19 | [p:ratexpand(p),l],
20 | if p=0 then return("Zero::zero()"),
21 | if hipow(p, x)=0 then (
22 | return(concat(number_to_text(p), ".into()"))
23 | ),
24 | l:makelist(
25 | [number_to_text(ratcoef(p, x, i)), ", "],
26 | i,
27 | 0,
28 | hipow(p, x)),
29 | l:reverse(rest(reverse(flatten(l)))),
30 | apply(concat, append(["vec!["], l, ["].into()"]))
31 | )$
32 |
33 | print_test_case(a, b, g, l):=(
34 | printf(
35 | true,
36 | "test_case(~% ~a,~% ~a,~% ~a,~% ~a,~%);~%",
37 | poly_to_text(a),
38 | poly_to_text(b),
39 | poly_to_text(g),
40 | poly_to_text(l)
41 | )
42 | )$
43 |
44 | n:200$
45 | (
46 | thru n do block(
47 | [a, b, g, l],
48 | a:sum(random(3)*x^i, i, 0, 3)/(random(3)+1),
49 | b:sum(random(3)*x^i, i, 0, 3)/(random(3)+1),
50 | g:ratsimp(content(gcd(a, b), x)[2]),
51 | l:a*b,
52 | if g#0 then l:l/g,
53 | l:ratsimp(l),
54 | if g#1 or random(n) < 10 then print_test_case(a, b, g, l)
55 | ),
56 | print_test_case(0, 0, 0, 0)
57 | )$
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## [Algebraic Numbers](https://en.wikipedia.org/wiki/Algebraic_number) Library
2 |
3 | Use when you need exact arithmetic, speed is not critical, and rational numbers aren't good enough.
4 |
5 | ## Example:
6 |
7 | ```rust
8 | use algebraics::prelude::*;
9 | use algebraics::RealAlgebraicNumber as Number;
10 |
11 | let two = Number::from(2);
12 |
13 | // 2 is a rational number
14 | assert!(two.is_rational());
15 |
16 | // 1/2 is the reciprocal of 2
17 | let one_half = two.recip();
18 |
19 | // 1/2 is also a rational number
20 | assert!(one_half.is_rational());
21 |
22 | // 2^(1/4)
23 | let root = (&two).pow((1, 4));
24 |
25 | // we can use all the standard comparison operators
26 | assert!(root != Number::from(3));
27 | assert!(root < Number::from(2));
28 | assert!(root > Number::from(1));
29 |
30 | // we can use all of add, subtract, multiply, divide, and remainder
31 | let sum = &root + &root;
32 | let difference = &root - Number::from(47);
33 | let product = &root * &one_half;
34 | let quotient = &one_half / &root;
35 | let remainder = &root % &one_half;
36 |
37 | // root is not a rational number
38 | assert!(!root.is_rational());
39 |
40 | // the calculations are always exact
41 | assert_eq!((&root).pow(4), two);
42 |
43 | // lets compute 30 decimal places of root
44 | let scale = Number::from(10).pow(30);
45 | let scaled = &root * scale;
46 | let digits = scaled.into_integer_trunc();
47 | assert_eq!(
48 | digits.to_string(),
49 | 1_18920_71150_02721_06671_74999_70560u128.to_string()
50 | );
51 |
52 | // get the minimal polynomial
53 | let other_number = root + two.pow((1, 2));
54 | assert_eq!(
55 | &other_number.minimal_polynomial().to_string(),
56 | "2 + -8*X + -4*X^2 + 0*X^3 + 1*X^4"
57 | );
58 |
59 | // works with really big numbers
60 | let really_big = Number::from(1_00000_00000i64).pow(20) + Number::from(23);
61 | assert_eq!(
62 | &really_big.to_integer_floor().to_string(),
63 | "100000000000000000000000000000000000000000000\
64 | 000000000000000000000000000000000000000000000\
65 | 000000000000000000000000000000000000000000000\
66 | 000000000000000000000000000000000000000000000\
67 | 000000000000000000023"
68 | )
69 | ```
70 |
71 | ## Python support
72 |
73 | Using algebraics from Python:
74 |
75 | ```bash
76 | python3 -m pip install algebraics
77 | ```
78 |
79 | ```python
80 | from algebraics import RealAlgebraicNumber
81 | sqrt_2 = 2 ** (RealAlgebraicNumber(1) / 2)
82 | assert sqrt_2 * sqrt_2 == 2
83 | ```
84 |
85 | Using algebraics in your own Rust project:
86 |
87 | ```toml
88 | [dependencies.algebraics]
89 | version = "0.3"
90 | ```
91 |
92 | Developing algebraics:
93 |
94 | ```bash
95 | cargo install maturin
96 | maturin develop --cargo-extra-args="--features python-extension"
97 | ```
98 |
--------------------------------------------------------------------------------
/src/polynomial/distinct_degree_factorization.rs:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: LGPL-2.1-or-later
2 | // See Notices.txt for copyright information
3 |
4 | use crate::{
5 | mod_int::{ModularInteger, ModularReducePow, Modulus, PrimeModulus},
6 | polynomial::Polynomial,
7 | traits::{ExtendedGCD, GCD},
8 | };
9 | use num_integer::Integer;
10 | use num_traits::Zero;
11 | use std::{fmt, hash::Hash};
12 |
13 | impl Polynomial>
14 | where
15 | V: ModularReducePow + Integer + GCD