tritlib 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ **/__pycache__/
2
+ *.py[codz]
3
+ dist/
4
+ wheels/
5
+ .coverage
tritlib-0.1.0/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright © 2026, Eric Tellier
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders X be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
tritlib-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: tritlib
3
+ Version: 0.1.0
4
+ Summary: Balanced ternary arithmetic and multi-valued logic library
5
+ Author-email: Eric Tellier <eric.tellier@newick.fr>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: balanced-ternary,base3,kleene-logic,ternary,trit
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.10
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest; extra == 'dev'
17
+ Requires-Dist: pytest-cov; extra == 'dev'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # tritlib
21
+
22
+ Balanced ternary arithmetic and multi-valued logic library for Python.
23
+
24
+ ## What is balanced ternary?
25
+
26
+ Balanced ternary is a numeral system in base 3 where each digit (called a *trit*) takes values from {−1, 0, +1} instead of the conventional {0, 1, 2}. It allows representing negative numbers without a sign bit, and negation is as simple as inverting every trit. Donald Knuth called it *"perhaps the prettiest number system of all."*
27
+
28
+ ## Features
29
+
30
+ - `Trit` — immutable single‑trit type with arithmetic and logic operators
31
+ - `Trits` — arbitrary‑length balanced ternary integers
32
+ - `Tryte` — fixed‑width ternary words
33
+ - Multiple ternary logic systems: Kleene (K3), Łukasiewicz (L3), Heyting (HT) and more
34
+ - Step‑by‑step arithmetic (carry propagation, partial products) for educational use
35
+ - Pure Python, no dependencies, type‑hinted
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install tritlib
41
+ ```
42
+
43
+ ## Quick start
44
+
45
+ ```python
46
+ from tritlib.trit import Trit, P, Z, N
47
+
48
+ # Create trits
49
+ t = Trit(1) # +1
50
+ print(t) # "+"
51
+ print(-t) # "-"
52
+
53
+ # Predefined constants
54
+ assert P == Trit(1)
55
+ assert Z == Trit(0)
56
+ assert N == Trit(-1)
57
+ ```
58
+
59
+ ## Roadmap
60
+
61
+ - [x] `Trit` type with immutability, arithmetic, hashing
62
+ - [x] Trit‑level logic (Kleene K3)
63
+ - [x] `Trits` arbitrary‑precision integers
64
+ - [x] `Tryte` fixed‑width words
65
+ - [x] Additional logic systems (L3, HT, BI3, Post)
66
+ - [ ] Conversion utilities (int, str, float, binary‑coded ternary)
67
+ - [ ] Educational step‑by‑step computation output
68
+
69
+ ## Development
70
+
71
+ ```bash
72
+ git clone https://codeberg.org/newick_2/tritlib.git
73
+ cd tritlib
74
+ python -m venv .venv
75
+ source .venv/bin/activate
76
+ pip install -e ".[dev]"
77
+ python -m pytest
78
+ ```
79
+
80
+ ## License
81
+
82
+ MIT License — see LICENSE file for details.
@@ -0,0 +1,63 @@
1
+ # tritlib
2
+
3
+ Balanced ternary arithmetic and multi-valued logic library for Python.
4
+
5
+ ## What is balanced ternary?
6
+
7
+ Balanced ternary is a numeral system in base 3 where each digit (called a *trit*) takes values from {−1, 0, +1} instead of the conventional {0, 1, 2}. It allows representing negative numbers without a sign bit, and negation is as simple as inverting every trit. Donald Knuth called it *"perhaps the prettiest number system of all."*
8
+
9
+ ## Features
10
+
11
+ - `Trit` — immutable single‑trit type with arithmetic and logic operators
12
+ - `Trits` — arbitrary‑length balanced ternary integers
13
+ - `Tryte` — fixed‑width ternary words
14
+ - Multiple ternary logic systems: Kleene (K3), Łukasiewicz (L3), Heyting (HT) and more
15
+ - Step‑by‑step arithmetic (carry propagation, partial products) for educational use
16
+ - Pure Python, no dependencies, type‑hinted
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install tritlib
22
+ ```
23
+
24
+ ## Quick start
25
+
26
+ ```python
27
+ from tritlib.trit import Trit, P, Z, N
28
+
29
+ # Create trits
30
+ t = Trit(1) # +1
31
+ print(t) # "+"
32
+ print(-t) # "-"
33
+
34
+ # Predefined constants
35
+ assert P == Trit(1)
36
+ assert Z == Trit(0)
37
+ assert N == Trit(-1)
38
+ ```
39
+
40
+ ## Roadmap
41
+
42
+ - [x] `Trit` type with immutability, arithmetic, hashing
43
+ - [x] Trit‑level logic (Kleene K3)
44
+ - [x] `Trits` arbitrary‑precision integers
45
+ - [x] `Tryte` fixed‑width words
46
+ - [x] Additional logic systems (L3, HT, BI3, Post)
47
+ - [ ] Conversion utilities (int, str, float, binary‑coded ternary)
48
+ - [ ] Educational step‑by‑step computation output
49
+
50
+ ## Development
51
+
52
+ ```bash
53
+ git clone https://codeberg.org/newick_2/tritlib.git
54
+ cd tritlib
55
+ python -m venv .venv
56
+ source .venv/bin/activate
57
+ pip install -e ".[dev]"
58
+ python -m pytest
59
+ ```
60
+
61
+ ## License
62
+
63
+ MIT License — see LICENSE file for details.
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "tritlib"
7
+ version = "0.1.0"
8
+ description = "Balanced ternary arithmetic and multi-valued logic library"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">= 3.10"
12
+ authors = [
13
+ { name = "Eric Tellier", email = "eric.tellier@newick.fr"}
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering :: Mathematics",
20
+ "Typing :: Typed",
21
+ ]
22
+ keywords = ["ternary", "balanced-ternary", "trit", "base3", "kleene-logic"]
23
+
24
+ [project.optional-dependencies]
25
+ dev = ["pytest", "pytest-cov"]
@@ -0,0 +1,13 @@
1
+ """
2
+ tritlib: A Python library for trinary arithmetic and logic operations.
3
+
4
+ This package provides classes for working with trits (ternary digits), trits numbers, and fixed-width trytes.
5
+ It supports arithmetic operations, comparisons, and conversions between strings, integers, and trits.
6
+ """
7
+
8
+ from .trit import Trit, N, Z, P
9
+ from .trits import Trits
10
+ from .tryte import Tryte
11
+ from .logic import Lukasiewicz, RM3, BI3, HT, Kleene
12
+
13
+ __all__ = ["Trit", "Trits", "Tryte", "N", "Z", "P", "Lukasiewicz", "RM3", "BI3", "HT", "Kleene"]
@@ -0,0 +1,14 @@
1
+ """
2
+ tritlib.logic: Ternary logic operations.
3
+
4
+ This subpackage provides implementations of various ternary logic systems:
5
+ Lukasiewicz, RM3, BI3, Heyting, and Kleene.
6
+ """
7
+
8
+ from .lukasiewicz import Lukasiewicz
9
+ from .rm3 import RM3
10
+ from .bi3 import BI3
11
+ from .heyting import HT
12
+ from .kleene import Kleene
13
+
14
+ __all__ = ["Lukasiewicz", "RM3", "BI3", "HT", "Kleene"]
@@ -0,0 +1,28 @@
1
+ from abc import ABC, abstractmethod
2
+ from tritlib import Trit
3
+ class TernaryLogic(ABC):
4
+ """
5
+ Abstract base class for ternary logic operations.
6
+ Defines methods for logical NOT, AND, OR, and IMPLY operations on trits.
7
+ Subclasses must implement the `imply_op` method.
8
+
9
+ Methods:
10
+ not_op(a): Returns the logical NOT of a trit.
11
+ and_op(a, b): Returns the logical AND of two trits.
12
+ or_op(a, b): Returns the logical OR of two trits.
13
+ imply_op(a, b): Abstract method for logical implication (to be implemented by subclasses).
14
+ """
15
+
16
+ def not_op(self, a: Trit) -> Trit:
17
+ return -a
18
+
19
+ def and_op(self, a: Trit, b: Trit) -> Trit:
20
+ return a & b
21
+
22
+ def or_op(self, a: Trit, b: Trit) -> Trit:
23
+ return a | b
24
+
25
+ @abstractmethod
26
+ def imply_op(self, a: Trit, b: Trit) -> Trit: ...
27
+
28
+
@@ -0,0 +1,35 @@
1
+ from tritlib.logic.base import TernaryLogic
2
+ from tritlib import N, P,Z, Trit
3
+
4
+ class BI3(TernaryLogic):
5
+ """
6
+ Implements BI3 ternary logic operations.
7
+ Provides specific implementations for logical AND, OR, and IMPLY operations.
8
+
9
+ Methods:
10
+ and_op(a, b): Returns the BI3 logical AND of two trits.
11
+ or_op(a, b): Returns the BI3 logical OR of two trits.
12
+ imply_op(a, b): Returns the BI3 logical implication of two trits.
13
+ """
14
+ def and_op(self, a: Trit, b: Trit) -> Trit:
15
+ if a == N or b == N or (a == b == Z):
16
+ return N
17
+ elif a == b == P:
18
+ return P
19
+ return Z
20
+
21
+ def imply_op(self, a: Trit, b: Trit) -> Trit:
22
+ print(f"BI3.imply_op called: a={a} ({a.value}), b={b} ({b.value}), b==Z: {b==Z}")
23
+ if a == Z or b == Z:
24
+ return Z
25
+ elif b == P:
26
+ return P
27
+ else:
28
+ return -a
29
+
30
+ def or_op(self, a: Trit, b: Trit) -> Trit:
31
+ if a == b == N :
32
+ return N
33
+ if a == P or b == P or (a == b == Z):
34
+ return P
35
+ return Z
@@ -0,0 +1,25 @@
1
+ from tritlib.logic.base import TernaryLogic
2
+ from tritlib.trit import N, P,Z, Trit
3
+
4
+
5
+ class HT(TernaryLogic):
6
+ """
7
+ Implements Heyting ternary logic operations.
8
+ Provides specific implementations for logical NOT and IMPLY operations.
9
+
10
+ Methods:
11
+ not_op(a): Returns the Heyting logical NOT of a trit.
12
+ imply_op(a, b): Returns the Heyting logical implication of two trits.
13
+ """
14
+ def not_op(self, a:Trit) -> Trit:
15
+ return P if a == N else N
16
+
17
+ def imply_op(self, a: Trit, b: Trit) -> Trit:
18
+ print("HT")
19
+ if b == P:
20
+ return P
21
+ elif b == Z:
22
+ return Z if a == P else P
23
+ else :
24
+ return self.not_op(a)
25
+
@@ -0,0 +1,14 @@
1
+ from tritlib.logic.base import TernaryLogic
2
+ from tritlib.trit import Trit
3
+
4
+
5
+ class Kleene(TernaryLogic):
6
+ """
7
+ Implements Kleene ternary logic operations.
8
+ Provides a specific implementation for the logical IMPLY operation.
9
+
10
+ Methods:
11
+ imply_op(a, b): Returns the Kleene logical implication of two trits.
12
+ """
13
+ def imply_op(self, a: Trit, b: Trit) -> Trit:
14
+ return -a | b
@@ -0,0 +1,22 @@
1
+ from tritlib.logic.base import TernaryLogic
2
+ from tritlib.trit import Trit, P, Z
3
+
4
+
5
+ class Lukasiewicz(TernaryLogic):
6
+ """
7
+ Implements Lukasiewicz ternary logic operations.
8
+ Provides specific implementations for logical NOT and IMPLY operations.
9
+
10
+ Methods:
11
+ not_op(a): Returns the Lukasiewicz logical NOT of a trit.
12
+ imply_op(a, b): Returns the Lukasiewicz logical implication of two trits.
13
+ """
14
+ def not_op(self, a: Trit) -> Trit:
15
+ return -a
16
+
17
+ def imply_op(self, a: Trit, b: Trit) -> Trit:
18
+ if a == b == Z:
19
+ return P
20
+ else:
21
+ return -a | b
22
+
@@ -0,0 +1,23 @@
1
+ from tritlib.logic.base import TernaryLogic
2
+ from tritlib.trit import Trit, P, Z, N
3
+
4
+ class RM3(TernaryLogic):
5
+ """
6
+ Implements RM3 ternary logic operations.
7
+ Provides specific implementations for logical NOT and IMPLY operations.
8
+
9
+ Methods:
10
+ not_op(a): Returns the RM3 logical NOT of a trit.
11
+ imply_op(a, b): Returns the RM3 logical implication of two trits.
12
+ """
13
+ def imply_op(self, a: Trit, b: Trit) -> Trit:
14
+ if b == P :
15
+ return P
16
+ elif b == Z:
17
+ return -a
18
+ else :
19
+ return P if a == N else N
20
+
21
+
22
+ def not_op(self, a: Trit) -> Trit:
23
+ return -a
@@ -0,0 +1,113 @@
1
+ from functools import total_ordering
2
+
3
+ @total_ordering
4
+ class Trit:
5
+ """
6
+ Represents an immutable trinary digit (trit) with possible values: N (-1), Z (0), or P (1).
7
+ Provides arithmetic and logical operations for trits, including addition, multiplication,
8
+ negation, and bitwise operations.
9
+
10
+ Attributes:
11
+ _value (int): Internal value of the trit (-1, 0, or 1).
12
+
13
+ Properties:
14
+ value (int): Returns the integer value of the trit.
15
+
16
+ Methods:
17
+ __repr__(): Returns the official string representation of the trit.
18
+ __str__(): Returns the user-friendly string representation ('-', '0', or '+').
19
+ __eq__(other): Checks equality with another trit.
20
+ __hash__(): Returns the hash of the trit.
21
+ __neg__(): Returns the negation of the trit.
22
+ __mul__(other): Multiplies two trits.
23
+ half_add(other): Performs a half-addition with another trit, returning sum and carry.
24
+ full_add(other, carry): Performs a full-addition with another trit and a carry, returning sum and carry.
25
+ __invert__(): Returns the negation of the trit (alias for __neg__).
26
+ __and__(other): Returns the logical AND of two trits (minimum value).
27
+ __or__(other): Returns the logical OR of two trits (maximum value).
28
+ __lt__(other): Compares two trits for ordering.
29
+
30
+ Constants:
31
+ N (Trit): Represents the trit value -1.
32
+ Z (Trit): Represents the trit value 0.
33
+ P (Trit): Represents the trit value 1.
34
+ """
35
+ __slots__ = ("_value",)
36
+
37
+ def __init__(self, value: int):
38
+ if not -2 < value < 2:
39
+ raise ValueError
40
+
41
+ object.__setattr__(self,"_value", value)
42
+
43
+ def __repr__(self) -> str:
44
+ return f"Trit({self._value})"
45
+
46
+ def __str__(self) -> str:
47
+ if self._value > 0:
48
+ return "+"
49
+ elif self._value == 0:
50
+ return "0"
51
+ else :
52
+ return "-"
53
+
54
+ def __eq__(self, other) -> bool:
55
+ if not isinstance(other, Trit):
56
+ return NotImplemented
57
+ return self.value == other.value
58
+
59
+ def __hash__(self) -> int:
60
+ return hash(self._value)
61
+
62
+ def __setattr__(self, name, value):
63
+ raise AttributeError("Trit is immutable")
64
+
65
+ @property
66
+ def value(self) -> int:
67
+ return self._value
68
+
69
+ def __neg__(self) :
70
+ return Trit(-self._value)
71
+
72
+ def __mul__(self, other) :
73
+ if not isinstance(other, Trit):
74
+ return NotImplemented
75
+ return Trit(self.value * other.value)
76
+
77
+ def half_add(self, other):
78
+ if not isinstance(other, Trit):
79
+ return NotImplemented
80
+ if self.value == other.value :
81
+ s = -self
82
+ c = self
83
+ else:
84
+ s = Trit(self.value + other.value)
85
+ c = Z
86
+ return (s,c)
87
+
88
+ def full_add(self, other, carry):
89
+ if not (isinstance(other, Trit) and isinstance(carry, Trit)):
90
+ return NotImplemented
91
+ s1, c1 = self.half_add(other)
92
+ s2, c2 = s1.half_add(carry)
93
+ return s2, Trit(c1.value+c2.value)
94
+
95
+ def __invert__(self):
96
+ return self.__neg__()
97
+
98
+ def __and__(self, other):
99
+ if not isinstance(other, Trit):
100
+ return NotImplemented
101
+ return Trit(min(self._value, other._value))
102
+
103
+ def __or__(self, other):
104
+ if not isinstance(other, Trit):
105
+ return NotImplemented
106
+ return Trit(max(self._value, other._value))
107
+
108
+ def __lt__(self, other):
109
+ return self.value < other.value
110
+
111
+ N = Trit(-1)
112
+ Z = Trit(0)
113
+ P = Trit(1)
@@ -0,0 +1,215 @@
1
+ from functools import total_ordering
2
+ from typing import Tuple
3
+ from tritlib.trit import Trit, N, Z, P
4
+ from itertools import zip_longest
5
+
6
+ def _str_to_trits(s: str):
7
+ trit_dict = {"+": P, "-": N, "0": Z}
8
+ trits = []
9
+ for char in reversed(s):
10
+ if char not in trit_dict:
11
+ raise ValueError
12
+ else:
13
+ trits.append(trit_dict.get(char))
14
+ return trits
15
+
16
+ @total_ordering
17
+ class Trits:
18
+ """
19
+ Represents an immutable number in a balanced ternary system using trits (ternary digits: P, Z, N).
20
+ Supports arithmetic operations, comparisons, and conversions between strings and integers.
21
+
22
+ Attributes:
23
+ _trits (tuple[Trit]): Internal tuple of Trit objects representing the number.
24
+
25
+ Class Methods:
26
+ _from_trits(trits): Creates a Trits object from a list of Trit objects.
27
+ _from_le_trits(trits): Creates a Trits object from a list of Trit objects in little-endian order.
28
+ from_str(str_value): Creates a Trits object from a string representation (e.g., "+-0").
29
+
30
+ Properties:
31
+ _le_trits (list[Trit]): Returns the trits in little-endian order.
32
+
33
+ Methods:
34
+ __hash__(): Returns the hash of the Trits object.
35
+ __str__(): Returns the string representation of the Trits number.
36
+ __init__(n): Initializes a Trits object from a string or integer.
37
+ __eq__(other): Checks equality with another Trits object.
38
+ __lt__(other): Compares two Trits objects for ordering.
39
+ __add__(other): Adds two Trits numbers.
40
+ __sub__(other): Subtracts two Trits numbers.
41
+ __mul__(other): Multiplies two Trits numbers.
42
+ __floordiv__(other): Performs floor division between two Trits numbers.
43
+ to_int(): Converts the Trits number to an integer.
44
+
45
+ Usage:
46
+ >>> trits = Trits.from_str("+-0")
47
+ >>> print(trits)
48
+ +-0
49
+ """
50
+ __slots__ = ("_trits",)
51
+
52
+ def __hash__(self) -> int:
53
+ return hash(self._trits)
54
+
55
+ def __setattr__(self, name, value):
56
+ raise AttributeError("Trits is immutable")
57
+
58
+ @classmethod
59
+ def _from_trits(cls, trits: list[Trit]):
60
+ while len(trits)>1 and trits[-1] == Z:
61
+ trits.pop()
62
+ obj = cls.__new__(cls)
63
+ if len(trits) == 0:
64
+ trits = [Z]
65
+ object.__setattr__(obj,"_trits",tuple(trits))
66
+ return obj
67
+
68
+ @classmethod
69
+ def _from_le_trits(cls, trits: list[Trit]):
70
+ trits.reverse()
71
+ return cls._from_trits(trits)
72
+
73
+ @property
74
+ def _le_trits(self):
75
+ a = list(self.trits)
76
+ a.reverse()
77
+ return a
78
+
79
+ @classmethod
80
+ def from_str(cls, str_value: str):
81
+ return cls._from_trits(_str_to_trits(str_value))
82
+
83
+ def __str__(self):
84
+ trit_dict = {P: "+", N: "-", Z: "0"}
85
+ return "".join(trit_dict[t] for t in reversed(self._trits))
86
+
87
+ def __init__(self, n):
88
+ if isinstance(n, str):
89
+ object.__setattr__(self, "_trits", tuple(_str_to_trits(n)))
90
+ elif isinstance(n, int):
91
+ if n == 0:
92
+ object.__setattr__(self, "_trits", (Z,))
93
+ return
94
+ _trits = []
95
+ while n != 0:
96
+ n, r = divmod(n, 3)
97
+ if r == 2 :
98
+ n += 1
99
+ _trits.append(N)
100
+ elif r == 1:
101
+ _trits.append(P)
102
+ else :
103
+ _trits.append(Z)
104
+ object.__setattr__(self, "_trits", tuple(_trits))
105
+ else:
106
+ return NotImplemented
107
+
108
+ def __repr__(self):
109
+ return f"Trits(\"{str(self)}\")"
110
+
111
+ def __int__(self) -> int:
112
+ acc = 0
113
+ # Horner's method
114
+ for trit in reversed(self._trits):
115
+ acc = acc * 3 + trit.value
116
+
117
+ return acc
118
+
119
+ def __list__(self) -> list:
120
+ return list(self._trits)
121
+
122
+ @property
123
+ def trits(self) -> Tuple[Trit]:
124
+ return self._trits
125
+
126
+ def __eq__(self, other):
127
+ if not isinstance(other, Trits):
128
+ return NotImplemented
129
+ return self.trits == other.trits
130
+
131
+
132
+ def __add__(self, other):
133
+ if not isinstance(other, Trits):
134
+ return NotImplemented
135
+ _trits = []
136
+ c = Z
137
+ for a,b in zip_longest(self.trits, other.trits, fillvalue=Z):
138
+ s, c = a.full_add(b, c)
139
+ _trits.append(s)
140
+ if c != Z:
141
+ _trits.append(c)
142
+ return Trits._from_trits(_trits)
143
+
144
+ def __neg__(self):
145
+ return Trits._from_trits([-t for t in self._trits])
146
+
147
+ def __sub__(self, other):
148
+ if not isinstance(other, Trits):
149
+ return NotImplemented
150
+ return self + -other
151
+
152
+ def __mul__(self, other):
153
+ if not isinstance(other, Trits):
154
+ return NotImplemented
155
+ result = Trits._from_trits([Z])
156
+ for i,t in enumerate(self._trits):
157
+ if t == Z:
158
+ continue
159
+ partial = [Z] * i + [t*a for a in other._trits]
160
+ p = Trits._from_trits(partial)
161
+ result = result + p
162
+ return result
163
+
164
+ def __len__(self):
165
+ return len(self._trits)
166
+
167
+ def __lt__(self, other):
168
+ if not isinstance(other, Trits):
169
+ return NotImplemented
170
+ if len(self) < len(other):
171
+ return other.trits[-1] == P
172
+ elif len(self) > len(other):
173
+ return self.trits[-1] == N
174
+ else:
175
+ for t1, t2 in zip(reversed(self.trits), reversed(other.trits)):
176
+ if t1 < t2:
177
+ return True
178
+ elif t1 > t2:
179
+ return False
180
+ return False
181
+
182
+ def __divmod__(self, other):
183
+ if not isinstance(other, Trits):
184
+ return NotImplemented
185
+ if other == Trits(0):
186
+ raise ZeroDivisionError
187
+ if self._trits == (Z,):
188
+ return Trits(0), Trits(0)
189
+ if len(self) < len(other):
190
+ return Trits(0), self
191
+
192
+ s = self._le_trits
193
+ d = other._le_trits
194
+ partial_rest = s[:len(d)-1]
195
+ rem = s[len(d)-1:]
196
+ q = []
197
+ while len(rem) > 0:
198
+ partial_rest += [rem.pop(0)]
199
+ if d[0]*partial_rest[0] == P:
200
+ q.append(P)
201
+ pr = Trits._from_le_trits(partial_rest) - other
202
+ partial_rest = pr._le_trits
203
+ elif d[0]*partial_rest[0] == N:
204
+ q.append(N)
205
+ pr = Trits._from_le_trits(partial_rest) + other
206
+ partial_rest = pr._le_trits
207
+ else:
208
+ q.append(Z)
209
+ return Trits._from_le_trits(q), Trits._from_le_trits(partial_rest)
210
+
211
+ def __floordiv__(self, other):
212
+ return divmod(self, other)[0]
213
+
214
+ def __mod__(self, other):
215
+ return divmod(self, other)[1]
@@ -0,0 +1,217 @@
1
+ from functools import total_ordering
2
+ from tritlib.trits import Trits
3
+ from tritlib.trit import Z, N, P, Trit
4
+
5
+ @total_ordering
6
+ class Tryte:
7
+ """
8
+ Represents a fixed-width trit-based number system (tryte).
9
+ Supports arithmetic operations, comparisons, and conversions between trits and integers.
10
+ The class is immutable and handles overflow by truncating to the specified width.
11
+
12
+ Attributes:
13
+ _trits (tuple[Trit]): Internal tuple of Trit objects representing the tryte.
14
+ _width (int): Fixed width of the tryte.
15
+
16
+ Properties:
17
+ width (int): Returns the width of the tryte.
18
+ trits (list[Trit]): Returns the list of Trit objects representing the tryte.
19
+ _le_trits (list[Trit]): Returns the trits in little-endian order.
20
+
21
+ Class Methods:
22
+ _from_trits(trits, width): Creates a Tryte object from a list of Trit objects and a width.
23
+ from_le_trits(trits, width): Creates a Tryte object from a list of Trit objects in little-endian order and a width.
24
+
25
+ Methods:
26
+ __hash__(): Returns the hash of the Tryte object.
27
+ __init__(value, width): Initializes a Tryte object from a value (int or Trits) and a width.
28
+ __int__(): Converts the Tryte number to an integer.
29
+ to_trits(): Converts the Tryte object to a Trits object.
30
+ resize(width): Returns a new Tryte object with the specified width.
31
+ __len__(): Returns the number of trits in the tryte.
32
+ __eq__(other): Checks equality with another Tryte object.
33
+ __lt__(other): Compares two Tryte objects for ordering.
34
+ __repr__(): Returns the official string representation of the Tryte object.
35
+ __str__(): Returns the string representation of the Tryte number.
36
+ __add__(other): Adds two Tryte numbers.
37
+ __neg__(): Returns the negation of the Tryte number.
38
+ __sub__(other): Subtracts two Tryte numbers.
39
+ __mul__(other): Multiplies two Tryte numbers.
40
+ add_with_carry(other): Adds two Tryte numbers and returns the result and carry flag.
41
+ __divmod__(other): Performs division and modulus operations between two Tryte numbers.
42
+ __floordiv__(other): Performs floor division between two Tryte numbers.
43
+ __mod__(other): Performs modulus operation between two Tryte numbers.
44
+
45
+ Usage:
46
+ >>> tryte = Tryte(10, 5)
47
+ >>> print(tryte)
48
+ +-000
49
+ """
50
+ __slots__ = ("_trits", "_width")
51
+
52
+ def __hash__(self) -> int:
53
+ return hash(self._trits)
54
+
55
+ def __setattr__(self, name, value):
56
+ raise AttributeError("Trits is immutable")
57
+
58
+ def __init__(self, value, width: int):
59
+ trits = Trits(value)
60
+ if len(trits) > width:
61
+ raise OverflowError
62
+ else:
63
+ trits = list(trits.trits) + [Z] * (width - len(trits.trits))
64
+ object.__setattr__(self, "_trits", tuple(trits))
65
+ object.__setattr__(self, "_width", width)
66
+
67
+ @classmethod
68
+ def _from_trits(cls, trits: list[Trit], width: int):
69
+ # Do not raise OverflowError to simulate hardware behaviour
70
+ trits = trits + [Z]*(width - len(trits))
71
+ obj = cls.__new__(cls)
72
+ object.__setattr__(obj,"_trits",tuple(trits[:width]))
73
+ object.__setattr__(obj,"_width",width)
74
+ return obj
75
+
76
+ @property
77
+ def width(self) -> int:
78
+ return self._width
79
+
80
+ def __int__(self) -> int:
81
+ acc = 0
82
+ # Horner's method
83
+ for trit in reversed(self._trits):
84
+ acc = acc * 3 + trit.value
85
+ return acc
86
+
87
+ @property
88
+ def trits(self) -> list[Trit]:
89
+ return list(self._trits)
90
+
91
+ def to_trits(self) -> Trits:
92
+ s = self.trits
93
+ while s[-1] == Z and len(s)>1:
94
+ s= s[:-1]
95
+ return Trits._from_trits(s)
96
+
97
+ @property
98
+ def _le_trits(self) -> list[Trit]:
99
+ s = list(self.trits)
100
+ r = []
101
+ while len(s)>0:
102
+ a = s.pop()
103
+ if len(r) == 0 and a == Z:
104
+ continue
105
+ r.append(a)
106
+ return [Z] if len(r) == 0 else r
107
+
108
+ @classmethod
109
+ def from_le_trits(cls, trits: list[Trit], width: int):
110
+ trits.reverse()
111
+ return cls._from_trits(trits, width)
112
+
113
+ def resize(self, width):
114
+ return Tryte._from_trits(self.trits, width)
115
+
116
+ def __len__(self) -> int:
117
+ return len(self._trits)
118
+
119
+ def __eq__(self, other) -> bool:
120
+ if len(self) != len(other):
121
+ raise ValueError
122
+ return self.trits == other.trits
123
+
124
+ def __lt__(self, other):
125
+ if len(self) != len(other):
126
+ raise ValueError
127
+ for t1, t2 in zip(reversed(self.trits), reversed(other.trits)):
128
+ if t1 < t2:
129
+ return True
130
+ elif t1 > t2:
131
+ return False
132
+ return False
133
+
134
+ def __repr__(self):
135
+ return f'Tryte({int(self)}, {self.width})'
136
+
137
+
138
+ def __str__(self):
139
+ trit_dict = {P: "+", N: "-", Z: "0"}
140
+ return "".join(trit_dict[t] for t in reversed(self._trits))
141
+
142
+ def __add__(self, other):
143
+ if not isinstance(other, Tryte):
144
+ return NotImplemented
145
+ if len(self) != len(other):
146
+ raise ValueError
147
+ _trits = []
148
+ c = Z
149
+ for a,b in zip(self.trits, other.trits):
150
+ s, c = a.full_add(b, c)
151
+ _trits.append(s)
152
+ return Tryte._from_trits(_trits, self.width)
153
+
154
+ def __neg__(self):
155
+ return Tryte._from_trits([-t for t in self.trits], self.width)
156
+
157
+ def __sub__(self, other):
158
+ return self + -other
159
+
160
+ def __mul__(self, other):
161
+ if not isinstance(other, Tryte):
162
+ return NotImplemented
163
+ result = Tryte._from_trits([Z], self.width)
164
+ for i,t in enumerate(self._trits):
165
+ if t == Z:
166
+ continue
167
+ partial = [Z] * i + [t*a for a in other._trits]
168
+ p = Tryte._from_trits(partial, self.width)
169
+ result = result + p
170
+ return Tryte._from_trits(list(result.trits), self.width)
171
+
172
+ def add_with_carry(self, other):
173
+ if not isinstance(other, Tryte):
174
+ return NotImplemented
175
+ if len(self) != len(other):
176
+ raise ValueError
177
+ _trits = []
178
+ c = Z
179
+ for a,b in zip(self.trits, other.trits):
180
+ s, c = a.full_add(b, c)
181
+ _trits.append(s)
182
+ return Tryte._from_trits(_trits, self.width), (c != Z)
183
+
184
+ def __divmod__(self, other):
185
+ if not isinstance(other, Tryte):
186
+ return NotImplemented
187
+ if other == Tryte(0, self.width):
188
+ raise ZeroDivisionError
189
+ if self == Tryte(0, self.width):
190
+ return Tryte(0, self.width), Tryte(0, self.width)
191
+ if len(self) < len(other):
192
+ return Tryte(0, self.width), self
193
+
194
+ s = self._le_trits
195
+ d = other._le_trits
196
+ partial_rest = s[:len(d)-1]
197
+ rem = s[len(d)-1:]
198
+ q = []
199
+ while len(rem) > 0:
200
+ partial_rest += [rem.pop(0)]
201
+ if d[0]*partial_rest[0] == P:
202
+ q.append(P)
203
+ pr = Tryte.from_le_trits(partial_rest, self.width) - other
204
+ partial_rest = pr._le_trits
205
+ elif d[0]*partial_rest[0] == N:
206
+ q.append(N)
207
+ pr = Tryte.from_le_trits(partial_rest, self.width) + other
208
+ partial_rest = pr._le_trits
209
+ else:
210
+ q.append(Z)
211
+ return Tryte.from_le_trits(q, self.width), Tryte.from_le_trits(partial_rest, self.width)
212
+
213
+ def __floordiv__(self, other):
214
+ return divmod(self, other)[0]
215
+
216
+ def __mod__(self, other):
217
+ return divmod(self, other)[1]
@@ -0,0 +1,92 @@
1
+ from tritlib import Z, N, P, RM3, BI3, Lukasiewicz, HT, Kleene
2
+
3
+ def test_logic_kleene():
4
+ logic = Kleene()
5
+ assert logic.and_op(N,P) == N
6
+
7
+ def test_kleene_imply():
8
+ logic = Kleene()
9
+ assert logic.imply_op(N,N) == P
10
+ assert logic.imply_op(Z,N) == Z
11
+ assert logic.imply_op(P,N) == N
12
+ assert logic.imply_op(N,Z) == P
13
+ assert logic.imply_op(Z,Z) == Z
14
+ assert logic.imply_op(P,Z) == Z
15
+ assert logic.imply_op(N,P) == P
16
+ assert logic.imply_op(Z,P) == P
17
+ assert logic.imply_op(P,P) == P
18
+
19
+ def test_lukasiewicz_imply():
20
+ logic = Lukasiewicz()
21
+ assert logic.imply_op(N,N) == P
22
+ assert logic.imply_op(Z,N) == Z
23
+ assert logic.imply_op(P,N) == N
24
+ assert logic.imply_op(N,Z) == P
25
+ assert logic.imply_op(Z,Z) == P
26
+ assert logic.imply_op(P,Z) == Z
27
+ assert logic.imply_op(N,P) == P
28
+ assert logic.imply_op(Z,P) == P
29
+ assert logic.imply_op(P,P) == P
30
+
31
+ def test_heyting():
32
+ logic = HT()
33
+ assert logic.not_op(N) == P
34
+ assert logic.not_op(Z) == N
35
+ assert logic.not_op(P) == N
36
+
37
+
38
+ assert logic.imply_op(N,N) == P
39
+ assert logic.imply_op(Z,N) == N
40
+ assert logic.imply_op(P,N) == N
41
+ assert logic.imply_op(N,Z) == P
42
+ assert logic.imply_op(Z,Z) == P
43
+ assert logic.imply_op(P,Z) == Z
44
+ assert logic.imply_op(N,P) == P
45
+ assert logic.imply_op(Z,P) == P
46
+ assert logic.imply_op(P,P) == P
47
+
48
+ def test_rmingle3():
49
+ logic = RM3()
50
+ assert logic.imply_op(N,N) == P
51
+ assert logic.imply_op(Z,N) == N
52
+ assert logic.imply_op(P,N) == N
53
+ assert logic.imply_op(N,Z) == P
54
+ assert logic.imply_op(Z,Z) == Z
55
+ assert logic.imply_op(P,Z) == N
56
+ assert logic.imply_op(N,P) == P
57
+ assert logic.imply_op(Z,P) == P
58
+ assert logic.imply_op(P,P) == P
59
+
60
+ def test_paraconsistance():
61
+ logic = BI3()
62
+ print(type(logic).__mro__)
63
+ print(type(logic).imply_op)
64
+ assert logic.and_op(N,N) == N
65
+ assert logic.and_op(N,Z) == N
66
+ assert logic.and_op(N,P) == N
67
+ assert logic.and_op(Z,N) == N
68
+ assert logic.and_op(Z,Z) == N
69
+ assert logic.and_op(Z,P) == Z
70
+ assert logic.and_op(P,N) == N
71
+ assert logic.and_op(P,Z) == Z
72
+ assert logic.and_op(P,P) == P
73
+
74
+ assert logic.or_op(N,N) == N
75
+ assert logic.or_op(N,Z) == Z
76
+ assert logic.or_op(N,P) == P
77
+ assert logic.or_op(Z,N) == Z
78
+ assert logic.or_op(Z,Z) == P
79
+ assert logic.or_op(Z,P) == P
80
+ assert logic.or_op(P,N) == P
81
+ assert logic.or_op(P,Z) == P
82
+ assert logic.or_op(P,P) == P
83
+
84
+ assert logic.imply_op(N,N) == P
85
+ assert logic.imply_op(Z,N) == Z
86
+ assert logic.imply_op(P,N) == N
87
+ assert logic.imply_op(N,Z) == Z
88
+ assert logic.imply_op(Z,Z) == Z
89
+ assert logic.imply_op(P,Z) == Z
90
+ assert logic.imply_op(N,P) == P
91
+ assert logic.imply_op(Z,P) == Z
92
+ assert logic.imply_op(P,P) == P
@@ -0,0 +1,21 @@
1
+ from tritlib.trit import Z, N, P
2
+
3
+ def test_and():
4
+ assert (P & P) == P
5
+ assert (P & Z) == Z
6
+ assert (P & N) == N
7
+ assert (Z & Z) == Z
8
+ assert (Z & N) == N
9
+
10
+ def test_or():
11
+ assert (N | N) == N
12
+ assert (N | Z) == Z
13
+ assert (N | P) == P
14
+ assert (Z | Z) == Z
15
+ assert (Z | P) == P
16
+
17
+ def test_not():
18
+ assert ~P == N
19
+ assert ~Z == Z
20
+ assert ~N == P
21
+
@@ -0,0 +1,73 @@
1
+ from tritlib.trit import Trit, N, P, Z
2
+ import pytest
3
+ def test_tritP():
4
+ t = Trit(1)
5
+ assert str(t) == "+"
6
+ assert t == P
7
+ assert repr(t) == "Trit(1)"
8
+
9
+ def test_tritN():
10
+ t = Trit(-1)
11
+ assert str(t) == "-"
12
+ assert t == N
13
+ assert repr(t) == "Trit(-1)"
14
+
15
+ def test_tritZ():
16
+ t = Trit(0)
17
+ assert str(t) == "0"
18
+ assert t == Z
19
+ assert repr(t) == "Trit(0)"
20
+
21
+ def test_trit_invalid():
22
+ with pytest.raises(ValueError):
23
+ Trit(2)
24
+ with pytest.raises(ValueError):
25
+ Trit(-3)
26
+
27
+
28
+ def test_hash():
29
+ assert hash(Trit(1)) == hash(P)
30
+ assert hash(Trit(0)) == hash(Z)
31
+ assert hash(Trit(-1)) == hash(N)
32
+
33
+ def test_immutable():
34
+ t = Trit(0)
35
+ with pytest.raises(AttributeError):
36
+ t._value = -1
37
+
38
+ def test_negation():
39
+ assert -P == N
40
+ assert -N == P
41
+ assert -Z == Z
42
+
43
+ def test_multiplication():
44
+ assert P * P == P
45
+ assert P * N == N
46
+ assert N * N == P
47
+ assert Z * P == Z
48
+ assert Z * Z == Z
49
+
50
+ def test_half_add():
51
+ # Pas de retenue
52
+ s, c = P.half_add(N)
53
+ assert s == Z
54
+ assert c == Z
55
+
56
+ # Retenue négative
57
+ s, c = N.half_add(N)
58
+ assert s == P
59
+ assert c == N
60
+
61
+ # Zéro neutre
62
+ s, c = P.half_add(Z)
63
+ assert s == P
64
+ assert c == Z
65
+
66
+ def full_add():
67
+ # sans retenue
68
+ s, c = P.full_add(N, Z)
69
+ assert s == Z and c == Z
70
+
71
+ # avec retenue qui propage
72
+ s, c = P.full_add(P, P)
73
+ assert s == Z and c == P
@@ -0,0 +1,100 @@
1
+ from tritlib.trits import Trits
2
+ import pytest
3
+
4
+ def test_trits_init():
5
+ assert Trits(0) == Trits.from_str("0")
6
+ assert int(Trits(5)) == 5
7
+ assert int(Trits(-5)) == -5
8
+ assert int(Trits(42)) == 42
9
+
10
+ def test_trits_init_from_str():
11
+ assert Trits(-1) == Trits.from_str("-")
12
+ assert Trits(1) == Trits.from_str("+")
13
+ assert Trits(0) == Trits.from_str("0")
14
+
15
+ assert Trits(2) == Trits.from_str("+-")
16
+ assert Trits(3) == Trits.from_str("+0")
17
+ assert Trits(5) == Trits.from_str("+--")
18
+ assert Trits(-2) == Trits.from_str("-+")
19
+ assert Trits(-3) == Trits.from_str("-0")
20
+ assert Trits(-5) == Trits.from_str("-++")
21
+
22
+ assert Trits(5) == Trits("+--")
23
+
24
+ def test_trits_to_str():
25
+ assert str(Trits(-1)) == "-"
26
+ assert str(Trits(1)) == "+"
27
+ assert str(Trits(0)) == "0"
28
+
29
+ assert str(Trits(2)) == "+-"
30
+ assert str(Trits(3)) == "+0"
31
+ assert str(Trits(5)) == "+--"
32
+ assert str(Trits(-2)) == "-+"
33
+ assert str(Trits(-3)) == "-0"
34
+ assert str(Trits(-5)) == "-++"
35
+
36
+ def tests_trits_len():
37
+ assert len(Trits(-1)) == 1
38
+ assert len(Trits(0)) == 1
39
+ assert len(Trits(1)) == 1
40
+ assert len(Trits(-2)) == 2
41
+ assert len(Trits(-5)) == 3
42
+ assert len(Trits(5)) == 3
43
+
44
+
45
+ def test_trits_add():
46
+ for i in range(-10,10):
47
+ for j in range(-10, 10):
48
+ assert int(Trits(i) + Trits(j)) == i+j
49
+
50
+ def test_trits_sub():
51
+ for i in range(-10,10):
52
+ for j in range(-10, 10):
53
+ assert int(Trits(i) - Trits(j)) == i-j
54
+
55
+ def test_trits_mul():
56
+ for i in range(-100,10):
57
+ for j in range(-10, 100):
58
+ assert int(Trits(i) * Trits(j)) == i*j
59
+
60
+ def test_trits_lt():
61
+ assert Trits(-1) < Trits(0) < Trits(1)
62
+ for i in range(-10,10):
63
+ for j in range(i+1, i+11):
64
+ assert Trits(i) < Trits(j)
65
+
66
+ def test_trits_le():
67
+ assert Trits(42) <= Trits(42)
68
+ assert Trits(0) <= Trits(20)
69
+ assert Trits(-19) <= Trits(14)
70
+
71
+ def test_trits_gt():
72
+ assert Trits(1) > Trits(0) > Trits(-1)
73
+ for i in range(-10,10):
74
+ for j in range(i-1, i-11):
75
+ assert Trits(i) > Trits(j)
76
+
77
+ def test_trits_ge():
78
+ assert Trits(42) >= Trits(42)
79
+ assert Trits(20) >= Trits(0)
80
+ assert Trits(-13) >= Trits(-20)
81
+
82
+
83
+ def test_divmod():
84
+ q, r = divmod(Trits(13), Trits(4))
85
+ assert int(q) * 4 + int(r) == 13
86
+ q, r = divmod(Trits(7), Trits(4))
87
+ assert int(q) == 2 and int(r) == -1
88
+ q, r = divmod(Trits(-7), Trits(4))
89
+ assert int(q) * 4 + int(r) == -7
90
+
91
+ q, r = divmod(Trits(0), Trits(5))
92
+ assert int(q) == 0 and int(r) == 0
93
+
94
+ with pytest.raises(ZeroDivisionError):
95
+ divmod(Trits(4),Trits(0))
96
+
97
+ q, r = divmod(Trits(5), Trits(15))
98
+ assert int(q) == 0 and int(r) == 5
99
+ q, r = divmod(Trits(14), Trits(15))
100
+ assert int(q) == 1 and int(r) == -1
@@ -0,0 +1,119 @@
1
+ from tritlib.trits import Trits
2
+ from tritlib.tryte import Tryte
3
+ from tritlib.trit import Z,N,P
4
+ import pytest
5
+
6
+ def test_tryte():
7
+ a = Tryte(0, width = 6)
8
+ assert a.trits == [Z]*6
9
+ b = Tryte(2, width = 6)
10
+ assert b.trits == [N, P] + [Z] * 4
11
+
12
+ with pytest.raises(OverflowError):
13
+ Tryte(-400, width=6)
14
+ with pytest.raises(OverflowError):
15
+ Tryte(400, width=6)
16
+
17
+ assert Tryte(42, width=6) == Tryte("+---0",6)
18
+
19
+ def test_tryte_lt():
20
+ assert Tryte(42, width=6) < Tryte(45, width=6)
21
+ assert Tryte(-19, width=6) < Tryte(45, width=6)
22
+ assert Tryte(-42, width=6) < Tryte(-14, width=6)
23
+ assert Tryte(45, width=6) > Tryte(-42, width=6)
24
+ assert Tryte(45, width=6) > Tryte(42, width=6)
25
+ assert Tryte(-15, width=6) > Tryte(-42, width=6)
26
+ assert Tryte(-42, width=6) <= Tryte(-42, width=6)
27
+ assert Tryte(42, width=6) >= Tryte(42, width=6)
28
+
29
+ def test_tryte_width():
30
+ assert len(Tryte(42,6)) == 6
31
+ with pytest.raises(ValueError):
32
+ _ = Tryte(42,6) > Tryte(42,9)
33
+ with pytest.raises(ValueError):
34
+ _ = Tryte(42,6) == Tryte(42,9)
35
+
36
+ def test_tryte_add():
37
+ assert Tryte(42,6) == Tryte(31,6) + Tryte(11,6)
38
+ assert Tryte(300,6) + Tryte(300,6)
39
+ assert (Tryte(332,6),False) == Tryte(300,6).add_with_carry(Tryte(32,6))
40
+ assert (Tryte(-364,6),True) == Tryte(300,6).add_with_carry(Tryte(65,6))
41
+ for i in range(-10,10):
42
+ for j in range(-10,10):
43
+ assert Tryte(j,6) + Tryte(i,6) == Tryte(i+j, 6)
44
+
45
+ def test_tryte_neg():
46
+ assert Tryte(4,6) == -Tryte(-4,6)
47
+ assert Tryte(0,6) == -Tryte(0,6)
48
+ assert Tryte(-10,6) == -Tryte(10,6)
49
+
50
+ def test_tryte_sub():
51
+ assert Tryte(6,6) - Tryte(7,6) == Tryte(-1,6)
52
+ assert Tryte(20,6) - Tryte(4,6) == Tryte(16,6)
53
+ assert Tryte(10,6) - Tryte(24,6) == Tryte(-14,6)
54
+ for i in range(-10,10):
55
+ for j in range(-10,10):
56
+ assert Tryte(j,6) - Tryte(i,6) == Tryte(j-i, 6)
57
+
58
+ def test_tryte_mul():
59
+ for i in range(-10,10):
60
+ for j in range(-10,10):
61
+ assert Tryte(j,6) * Tryte(i,6) == Tryte(i*j, 6)
62
+
63
+ def test_tryte_to_str():
64
+ assert str(Tryte(-1,6)) == "00000-"
65
+ assert str(Tryte(1,6)) == "00000+"
66
+ assert str(Tryte(0,6)) == "000000"
67
+ assert str(Tryte(2,6)) == "0000+-"
68
+ assert str(Tryte(3,6)) == "0000+0"
69
+ assert str(Tryte(5,6)) == "000+--"
70
+ assert str(Tryte(-2,6)) == "0000-+"
71
+ assert str(Tryte(-3,6)) == "0000-0"
72
+ assert str(Tryte(-5,6)) == "000-++"
73
+
74
+ def test_tryte_to_trits():
75
+ for i in range(-15,15):
76
+ assert Tryte(i,6).to_trits() == Trits(i)
77
+
78
+
79
+ def test_le_trits():
80
+ assert Tryte(-1,6)._le_trits == [N]
81
+ assert Tryte(2,6)._le_trits == [P,N]
82
+ assert Tryte(5,6)._le_trits == [P,N,N]
83
+ assert Tryte(5,9)._le_trits == [P,N,N]
84
+ assert Tryte(-5,6)._le_trits == [N,P,P]
85
+ assert Tryte(-5,9)._le_trits == [N,P,P]
86
+
87
+ assert Tryte.from_le_trits([N,P,P],6) == Tryte(-5,6)
88
+ assert Tryte.from_le_trits([P,N],6) == Tryte(2,6)
89
+ assert Tryte.from_le_trits([P,N,N],6) == Tryte(5,6)
90
+ assert Tryte.from_le_trits([N,P,P],9) == Tryte(-5,9)
91
+
92
+ def test_resize():
93
+ for j in range(-10,10):
94
+ for i in range(7,10):
95
+ a = Tryte(j, 6)
96
+ assert a.resize(i) == Tryte(j,i)
97
+
98
+ le_trits = [N,P,P,Z,P]
99
+ assert Tryte.from_le_trits(le_trits,6).resize(3) == Tryte.from_le_trits(le_trits[:3],3)
100
+
101
+
102
+ def test_divmod():
103
+ q, r = divmod(Tryte(13,6), Tryte(4,6))
104
+ assert int(q) * 4 + int(r) == 13
105
+ q, r = divmod(Tryte(7,6), Tryte(4,6))
106
+ assert int(q) == 2 and int(r) == -1
107
+ q, r = divmod(Tryte(-7,6), Tryte(4,6))
108
+ assert int(q) * 4 + int(r) == -7
109
+
110
+ q, r = divmod(Tryte(0,6), Tryte(5,6))
111
+ assert int(q) == 0 and int(r) == 0
112
+
113
+ with pytest.raises(ZeroDivisionError):
114
+ divmod(Tryte(4,6),Tryte(0,6))
115
+
116
+ q, r = divmod(Tryte(5,6), Tryte(15,6))
117
+ assert int(q) == 0 and int(r) == 5
118
+ q, r = divmod(Tryte(14,6), Tryte(15,6))
119
+ assert int(q) == 1 and int(r) == -1