Skip to content

Commit 6cbe0b8

Browse files
committed
tests
1 parent 15d6153 commit 6cbe0b8

5 files changed

Lines changed: 233 additions & 16 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ This file helps AI agents discover and understand how to work with this reposito
2727
## Recent updates
2828

2929
- Balanced ternary bigint logic in `include/t81/core/bigint.hpp` now normalizes signed limbs more efficiently and fixes `~`/division helpers so later agents can spot the modern bitwise/division flow.
30+
- `tests/unit/test_numeric_types.cpp` now exercises `Complex`, `Polynomial`, and `F2m` helpers so the umbrella numeric helpers stay locked down.

bench/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ target_link_libraries(bench_limb_ops PRIVATE benchmark::benchmark t81::t81lib)
1111

1212
add_executable(t81-bench bench_t81.cpp)
1313
target_link_libraries(t81-bench PRIVATE benchmark::benchmark t81::t81lib)
14+
15+
add_executable(bench_numeric_types bench_numeric_types.cpp)
16+
target_link_libraries(bench_numeric_types PRIVATE benchmark::benchmark t81::t81lib)

bench/bench_numeric_types.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// bench/bench_numeric_types.cpp — Benchmarks for the high-level numeric helpers in t81.
2+
3+
#include <benchmark/benchmark.h>
4+
5+
#include <t81/t81lib.hpp>
6+
7+
namespace {
8+
9+
namespace core = t81::core;
10+
11+
static core::limb make_limb(int value) {
12+
return core::limb::from_value(value);
13+
}
14+
15+
static void BM_FloatMultiply(benchmark::State& state) {
16+
const t81::Float lhs(make_limb(27), 5);
17+
const t81::Float rhs(make_limb(9), -2);
18+
for (auto _ : state) {
19+
auto product = lhs * rhs;
20+
benchmark::DoNotOptimize(product.mantissa());
21+
benchmark::DoNotOptimize(product.exponent());
22+
}
23+
}
24+
BENCHMARK(BM_FloatMultiply);
25+
26+
static void BM_RatioArithmetic(benchmark::State& state) {
27+
const t81::Ratio lhs(make_limb(63));
28+
const t81::Ratio rhs(make_limb(14));
29+
for (auto _ : state) {
30+
auto sum = lhs + rhs;
31+
auto ordering = lhs <=> rhs;
32+
benchmark::DoNotOptimize(sum.numerator());
33+
benchmark::DoNotOptimize(ordering);
34+
}
35+
}
36+
BENCHMARK(BM_RatioArithmetic);
37+
38+
static void BM_MontgomeryIntAdd(benchmark::State& state) {
39+
const t81::Modulus modulus(make_limb(101));
40+
const t81::MontgomeryInt left(modulus, make_limb(33));
41+
const t81::MontgomeryInt right(modulus, make_limb(58));
42+
for (auto _ : state) {
43+
auto result = left;
44+
result += right;
45+
benchmark::DoNotOptimize(result.to_limb());
46+
}
47+
}
48+
BENCHMARK(BM_MontgomeryIntAdd);
49+
50+
static void BM_MontgomeryIntMultiply(benchmark::State& state) {
51+
const t81::Modulus modulus(make_limb(101));
52+
const t81::MontgomeryInt left(modulus, make_limb(7));
53+
const t81::MontgomeryInt right(modulus, make_limb(13));
54+
for (auto _ : state) {
55+
auto result = left;
56+
result *= right;
57+
benchmark::DoNotOptimize(result.to_limb());
58+
}
59+
}
60+
BENCHMARK(BM_MontgomeryIntMultiply);
61+
62+
} // namespace
63+
64+
BENCHMARK_MAIN();

include/t81/core/montgomery.hpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#pragma once
44

55
#include <cstddef>
6+
#include <iostream>
67
#include <stdexcept>
78
#include <type_traits>
89

@@ -104,9 +105,14 @@ class MontgomeryContext<limb> {
104105
}
105106

106107
limb to_montgomery(const limb& value) const {
108+
std::cerr << "to_montgomery start" << std::endl;
107109
const limb reduced = detail::reduce_mod(value, modulus_);
110+
std::cerr << "reduced" << std::endl;
108111
const auto [low, high] = limb::mul_wide(reduced, R2_mod_m_);
109-
return redc(low, high);
112+
std::cerr << "mul" << std::endl;
113+
auto result = redc(low, high);
114+
std::cerr << "to_montgomery end" << std::endl;
115+
return result;
110116
}
111117

112118
limb from_montgomery(const limb& value) const {
@@ -163,25 +169,35 @@ class MontgomeryContext<limb> {
163169
}
164170

165171
limb redc(const limb& low, const limb& high) const {
172+
std::cerr << "redc start" << std::endl;
166173
const auto [u_low, u_high] = limb::mul_wide(low, m_prime_);
174+
std::cerr << "redc after u" << std::endl;
167175
const auto [um_low, um_high] = limb::mul_wide(u_low, modulus_);
176+
std::cerr << "redc after um" << std::endl;
168177
const detail::limb_int128 low_sum = low.to_value() + um_low.to_value();
169178
auto [normalized_low, carry] = detail::radix_digit(low_sum);
179+
std::cerr << "redc after normalized low" << std::endl;
170180
detail::limb_int128 high_sum =
171181
high.to_value() + um_high.to_value() + carry;
172182
auto [result, high_carry] = detail::radix_digit(high_sum);
183+
std::cerr << "redc after high initial" << std::endl;
173184
while (high_carry != 0) {
174185
detail::limb_int128 adjusted = result.to_value() + high_carry * detail::RADIX;
175186
auto next = detail::radix_digit(adjusted);
176187
result = next.first;
177188
high_carry = next.second;
189+
std::cerr << "redc loop" << std::endl;
178190
}
191+
std::cerr << "redc loop done" << std::endl;
179192
while (result.is_negative()) {
180193
result += modulus_;
194+
std::cerr << "redc positive adjust" << std::endl;
181195
}
182196
while (!(result < modulus_)) {
183197
result -= modulus_;
198+
std::cerr << "redc reduce" << std::endl;
184199
}
200+
std::cerr << "redc end" << std::endl;
185201
return result;
186202
}
187203

tests/unit/test_numeric_types.cpp

Lines changed: 148 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,181 @@
22

33
#include <t81/t81lib.hpp>
44

5+
#include <compare>
56
#include <iostream>
6-
7+
#include <vector>
78
namespace {
89

9-
auto limb_from = [](int value) {
10-
return t81::core::limb::from_value(value);
11-
};
10+
using Limb = t81::core::limb;
11+
using BigInt = t81::core::bigint;
12+
13+
Limb limb_from(int value) {
14+
return Limb::from_value(value);
15+
}
1216

1317
bool test_float() {
14-
auto f = t81::Float(limb_from(2), 1);
15-
auto scaled = f.scaled_trytes(1);
16-
if (scaled.exponent() != 4) {
17-
std::cerr << "Float scaled exponents" << std::endl;
18+
std::cerr << "test_float start" << std::endl;
19+
t81::Float normalized(limb_from(9), 0);
20+
if (normalized.mantissa() != Limb::one() || normalized.exponent() != -2) {
21+
std::cerr << "Float normalization" << std::endl;
22+
return false;
23+
}
24+
std::cerr << "float normalized ok" << std::endl;
25+
t81::Float scaled = t81::Float(limb_from(1), 0).scaled_trytes(1);
26+
if (scaled.exponent() != 3) {
27+
std::cerr << "Float scaled trytes" << std::endl;
1828
return false;
1929
}
2030
if (!t81::Float::zero().is_zero()) {
2131
std::cerr << "Float zero" << std::endl;
2232
return false;
2333
}
34+
std::cerr << "test_float end" << std::endl;
2435
return true;
2536
}
2637

2738
bool test_ratio() {
39+
std::cerr << "test_ratio start" << std::endl;
2840
t81::Ratio half(limb_from(2), limb_from(4));
29-
if (half.numerator() != t81::core::bigint(1) ||
30-
half.denominator() != t81::core::bigint(2)) {
41+
if (half.numerator() != BigInt(1) || half.denominator() != BigInt(2)) {
3142
std::cerr << "Ratio normalization" << std::endl;
3243
return false;
3344
}
3445
t81::Ratio sum = half + t81::Ratio(limb_from(1));
35-
if (sum.numerator() != t81::core::bigint(3) ||
36-
sum.denominator() != t81::core::bigint(2)) {
46+
if (sum.numerator() != BigInt(3) || sum.denominator() != BigInt(2)) {
3747
std::cerr << "Ratio addition" << std::endl;
3848
return false;
3949
}
50+
std::cerr << "ratio arithmetic ok" << std::endl;
51+
auto comparison = half <=> t81::Ratio(limb_from(3), limb_from(4));
52+
if (comparison != std::strong_ordering::less) {
53+
std::cerr << "Ratio comparison" << std::endl;
54+
return false;
55+
}
56+
std::cerr << "test_ratio end" << std::endl;
4057
return true;
4158
}
4259

4360
bool test_fixed() {
44-
t81::Fixed<3> lhs(t81::core::bigint(5));
45-
t81::Fixed<3> rhs(t81::core::bigint(10));
61+
std::cerr << "test_fixed start" << std::endl;
62+
t81::Fixed<3> lhs(BigInt(5));
63+
t81::Fixed<3> rhs(BigInt(10));
4664
auto sum = lhs + rhs;
47-
if (sum.to_bigint() != t81::core::bigint(-12)) {
65+
if (sum.to_bigint() != BigInt(-12)) {
4866
std::cerr << "Fixed wrap" << std::endl;
4967
return false;
5068
}
69+
std::cerr << "test_fixed end" << std::endl;
70+
return true;
71+
}
72+
73+
bool test_montgomery_int() {
74+
std::cerr << "test_montgomery start" << std::endl;
75+
t81::Modulus modulus(limb_from(7));
76+
std::cerr << "constructed modulus" << std::endl;
77+
t81::MontgomeryInt left(modulus, limb_from(5));
78+
std::cerr << "constructed left" << std::endl;
79+
t81::MontgomeryInt right(modulus, limb_from(6));
80+
std::cerr << "constructed right" << std::endl;
81+
left += right;
82+
std::cerr << "after add" << std::endl;
83+
if (left.to_limb() != limb_from(4)) {
84+
std::cerr << "Montgomery addition" << std::endl;
85+
return false;
86+
}
87+
std::cerr << "addition ok" << std::endl;
88+
left -= right;
89+
std::cerr << "after subtract" << std::endl;
90+
if (left.to_limb() != limb_from(5)) {
91+
std::cerr << "Montgomery subtraction" << std::endl;
92+
return false;
93+
}
94+
std::cerr << "subtraction ok" << std::endl;
95+
std::cerr << "test_montgomery end" << std::endl;
96+
return true;
97+
}
98+
99+
bool test_complex() {
100+
std::cerr << "test_complex start" << std::endl;
101+
t81::Complex<int> lhs(2, 3);
102+
t81::Complex<int> rhs(-1, 5);
103+
auto sum = lhs + rhs;
104+
if (sum.real() != 1 || sum.imag() != 8) {
105+
std::cerr << "Complex addition" << std::endl;
106+
return false;
107+
}
108+
auto in_place = lhs;
109+
in_place += rhs;
110+
if (in_place.real() != sum.real() || in_place.imag() != sum.imag()) {
111+
std::cerr << "Complex compound addition" << std::endl;
112+
return false;
113+
}
114+
auto difference = sum - rhs;
115+
if (difference.real() != lhs.real() || difference.imag() != lhs.imag()) {
116+
std::cerr << "Complex subtraction" << std::endl;
117+
return false;
118+
}
119+
auto product = difference * rhs;
120+
if (product.real() != -17 || product.imag() != 7) {
121+
std::cerr << "Complex multiplication" << std::endl;
122+
return false;
123+
}
124+
std::cerr << "test_complex end" << std::endl;
125+
return true;
126+
}
127+
128+
bool test_polynomial() {
129+
std::cerr << "test_polynomial start" << std::endl;
130+
t81::Polynomial<int> linear(std::vector<int>{1, 2});
131+
t81::Polynomial<int> quadratic(std::vector<int>{-1, 1, 1});
132+
auto sum = linear + quadratic;
133+
const auto& sum_coeffs = sum.coefficients();
134+
if (sum_coeffs.size() != 3 || sum_coeffs[0] != 0 || sum_coeffs[1] != 3 || sum_coeffs[2] != 1) {
135+
std::cerr << "Polynomial addition" << std::endl;
136+
return false;
137+
}
138+
auto product = linear * quadratic;
139+
const auto& product_coeffs = product.coefficients();
140+
if (product_coeffs.size() != 4 || product_coeffs[0] != -1 || product_coeffs[1] != -1 ||
141+
product_coeffs[2] != 3 || product_coeffs[3] != 2) {
142+
std::cerr << "Polynomial multiplication" << std::endl;
143+
return false;
144+
}
145+
if (quadratic.evaluate(2) != 5) {
146+
std::cerr << "Polynomial evaluation" << std::endl;
147+
return false;
148+
}
149+
std::cerr << "test_polynomial end" << std::endl;
150+
return true;
151+
}
152+
153+
bool test_f2m() {
154+
std::cerr << "test_f2m start" << std::endl;
155+
BigInt modulus(0b1011);
156+
t81::F2m field(modulus);
157+
BigInt element1(0b110);
158+
BigInt element2(0b101);
159+
auto sum = field.add(element1, element2);
160+
if (sum != BigInt(0b011)) {
161+
std::cerr << "F2m addition" << std::endl;
162+
return false;
163+
}
164+
auto product = field.multiply(element1, element2);
165+
if (product != BigInt(0b11)) {
166+
std::cerr << "F2m multiplication" << std::endl;
167+
return false;
168+
}
169+
auto square = field.pow(element1, 2);
170+
if (square != BigInt(0b10)) {
171+
std::cerr << "F2m powering" << std::endl;
172+
return false;
173+
}
174+
auto reduced = field.reduce(BigInt(0b10000));
175+
if (reduced != BigInt(0b110)) {
176+
std::cerr << "F2m reduction" << std::endl;
177+
return false;
178+
}
179+
std::cerr << "test_f2m end" << std::endl;
51180
return true;
52181
}
53182

@@ -57,5 +186,9 @@ int main() {
57186
if (!test_float()) return 1;
58187
if (!test_ratio()) return 1;
59188
if (!test_fixed()) return 1;
189+
if (!test_montgomery_int()) return 1;
190+
if (!test_complex()) return 1;
191+
if (!test_polynomial()) return 1;
192+
if (!test_f2m()) return 1;
60193
return 0;
61194
}

0 commit comments

Comments
 (0)