Skip to content

Commit 5fe080d

Browse files
working on tests
1 parent 382ee68 commit 5fe080d

File tree

3 files changed

+35
-85
lines changed

3 files changed

+35
-85
lines changed

Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,12 @@ num-rational = "0.2"
2727
rand = "0.5"
2828
rand_pcg = "0.1.1"
2929
lazy_static = "1.4"
30-
pyo3 = { version = "0.8.0", optional = true }
30+
31+
[dependencies.pyo3]
32+
# switch back to PyO3/pyo3 when
33+
# https://github.com/PyO3/pyo3/pull/630 lands;
34+
# switch to crates.io version once new version is published
35+
git = "https://github.com/programmerjake/pyo3.git"
36+
rev = "f55037c3779521520971cd528b05680b283e440c"
37+
optional = true
38+
features = ["num-bigint"]

src/python.rs

Lines changed: 14 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,80 +6,19 @@
66
use crate::algebraic_numbers::RealAlgebraicNumber;
77
use crate::traits::ExactDivAssign;
88
use num_bigint::BigInt;
9-
use num_bigint::Sign;
109
use num_traits::Signed;
11-
use num_traits::ToPrimitive;
1210
use num_traits::Zero;
1311
use pyo3::basic::CompareOp;
1412
use pyo3::exceptions::TypeError;
1513
use pyo3::exceptions::ValueError;
1614
use pyo3::exceptions::ZeroDivisionError;
1715
use pyo3::prelude::*;
18-
use pyo3::types::IntoPyDict;
1916
use pyo3::types::PyAny;
20-
use pyo3::types::PyBytes;
21-
use pyo3::types::PyInt;
22-
use pyo3::types::PyType;
23-
use pyo3::FromPy;
2417
use pyo3::PyNativeType;
2518
use pyo3::PyNumberProtocol;
2619
use pyo3::PyObjectProtocol;
2720
use std::sync::Arc;
2821

29-
// TODO: Switch to using BigInt's python conversions once they are implemented
30-
// see https://github.com/PyO3/pyo3/issues/543
31-
#[derive(Clone, Debug)]
32-
pub struct PyBigInt(pub BigInt);
33-
34-
impl ToPyObject for PyBigInt {
35-
fn to_object(&self, py: Python) -> PyObject {
36-
if let Some(value) = self.0.to_i64() {
37-
value.to_object(py)
38-
} else {
39-
let (sign, bytes) = self.0.to_bytes_le();
40-
let int_type: &PyType = py.get_type::<PyInt>();
41-
let retval = int_type
42-
.call_method1("from_bytes", (bytes, "little"))
43-
.unwrap()
44-
.downcast_ref::<PyInt>()
45-
.unwrap();
46-
if sign == Sign::Minus {
47-
retval.call_method0("__neg__").unwrap().to_object(py)
48-
} else {
49-
retval.to_object(py)
50-
}
51-
}
52-
}
53-
}
54-
55-
impl FromPy<PyBigInt> for PyObject {
56-
fn from_py(value: PyBigInt, py: Python) -> Self {
57-
value.to_object(py)
58-
}
59-
}
60-
61-
impl FromPyObject<'_> for PyBigInt {
62-
fn extract(ob: &PyAny) -> PyResult<Self> {
63-
let value = ob.downcast_ref::<PyInt>()?;
64-
if let Ok(value) = value.extract::<i64>() {
65-
Ok(PyBigInt(value.into()))
66-
} else {
67-
let mut len = 32;
68-
let bytes = loop {
69-
match value.call_method(
70-
"to_bytes",
71-
(len, "little"),
72-
Some([("signed", true)].into_py_dict(ob.py())),
73-
) {
74-
Ok(bytes) => break bytes.downcast_ref::<PyBytes>()?,
75-
Err(_) => len *= 2,
76-
}
77-
};
78-
Ok(PyBigInt(BigInt::from_signed_bytes_le(bytes.as_bytes())))
79-
}
80-
}
81-
}
82-
8322
#[pyclass(name=RealAlgebraicNumber, module="algebraics")]
8423
#[derive(Clone)]
8524
struct RealAlgebraicNumberPy {
@@ -91,10 +30,10 @@ impl FromPyObject<'_> for RealAlgebraicNumberPy {
9130
if let Ok(value) = value.downcast_ref::<RealAlgebraicNumberPy>() {
9231
return Ok(value.clone());
9332
}
94-
let value = value.extract::<Option<&PyInt>>()?;
33+
let value = value.extract::<Option<BigInt>>()?;
9534
let value = match value {
9635
None => RealAlgebraicNumber::zero(),
97-
Some(value) => RealAlgebraicNumber::from(value.extract::<PyBigInt>()?.0),
36+
Some(value) => RealAlgebraicNumber::from(value),
9837
}
9938
.into();
10039
Ok(RealAlgebraicNumberPy { value })
@@ -109,37 +48,30 @@ impl RealAlgebraicNumberPy {
10948
value: RealAlgebraicNumber::zero().into(),
11049
}));
11150
}
112-
fn __trunc__(&self) -> PyBigInt {
51+
fn __trunc__(&self) -> BigInt {
11352
let gil = Python::acquire_gil();
11453
let py = gil.python();
115-
py.allow_threads(|| PyBigInt(self.value.to_integer_trunc()))
54+
py.allow_threads(|| self.value.to_integer_trunc())
11655
}
117-
fn __floor__(&self) -> PyBigInt {
56+
fn __floor__(&self) -> BigInt {
11857
let gil = Python::acquire_gil();
11958
let py = gil.python();
120-
py.allow_threads(|| PyBigInt(self.value.to_integer_floor()))
59+
py.allow_threads(|| self.value.to_integer_floor())
12160
}
122-
fn __ceil__(&self) -> PyBigInt {
61+
fn __ceil__(&self) -> BigInt {
12362
let gil = Python::acquire_gil();
12463
let py = gil.python();
125-
py.allow_threads(|| PyBigInt(self.value.to_integer_ceil()))
64+
py.allow_threads(|| self.value.to_integer_ceil())
12665
}
127-
fn to_integer(&self) -> Option<PyBigInt> {
128-
self.value.to_integer().map(PyBigInt)
66+
fn to_integer(&self) -> Option<BigInt> {
67+
self.value.to_integer()
12968
}
130-
fn to_rational(&self) -> Option<(PyBigInt, PyBigInt)> {
131-
self.value.to_rational().map(|value| {
132-
let (numer, denom) = value.into();
133-
(PyBigInt(numer), PyBigInt(denom))
134-
})
69+
fn to_rational(&self) -> Option<(BigInt, BigInt)> {
70+
self.value.to_rational().map(Into::into)
13571
}
13672
#[getter]
137-
fn minimal_polynomial(&self) -> Vec<PyBigInt> {
138-
self.value
139-
.minimal_polynomial()
140-
.iter()
141-
.map(PyBigInt)
142-
.collect()
73+
fn minimal_polynomial(&self) -> Vec<BigInt> {
74+
self.value.minimal_polynomial().iter().collect()
14375
}
14476
#[getter]
14577
fn degree(&self) -> usize {
@@ -270,5 +202,3 @@ fn algebraics(_py: Python, m: &PyModule) -> PyResult<()> {
270202
m.add_class::<RealAlgebraicNumberPy>()?;
271203
Ok(())
272204
}
273-
274-
// FIXME: add tests

tests/test_real_algebraic_number.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from algebraics import RealAlgebraicNumber
55
import unittest
6+
import math
67

78

89
class TestRealAlgebraicNumber(unittest.TestCase):
@@ -31,6 +32,17 @@ def test_construct(self):
3132
"lower_bound_numer: -5, upper_bound_numer: -5, "
3233
"log2_denom: 0 } }>")
3334

35+
def test_trunc(self):
36+
self.assertEqual(math.trunc(RealAlgebraicNumber(123)), 123)
37+
self.assertEqual(math.trunc(RealAlgebraicNumber(123) / 10), 12)
38+
self.assertEqual(math.trunc(RealAlgebraicNumber(128) / 10), 12)
39+
self.assertEqual(math.trunc(RealAlgebraicNumber(123)
40+
** (RealAlgebraicNumber(1) / 2)), 11)
41+
self.assertEqual(math.trunc(RealAlgebraicNumber(-123)), -123)
42+
self.assertEqual(math.trunc(RealAlgebraicNumber(-123) / 10), -12)
43+
self.assertEqual(math.trunc(RealAlgebraicNumber(-128) / 10), -12)
44+
self.assertEqual(math.trunc(-(RealAlgebraicNumber(123)
45+
** (RealAlgebraicNumber(1) / 2))), -11)
3446
# FIXME: add more tests
3547

3648

0 commit comments

Comments
 (0)