LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
bigint_combinatorics.cpp
浏览该文件的文档.
1#include "bigint.hpp"
4
5namespace LMCAS {
6namespace {
7
8Result<unsigned int> kernel_argument(const BigInt& value, const char* operation) {
9 if (value.is_negative()) {
11 CasErrc::DomainError, "combinatorial arguments must be nonnegative", operation);
12 }
13 const auto converted = value.try_to_uint64();
14 if (!converted || *converted > std::numeric_limits<unsigned int>::max()) {
16 CasErrc::ResourceLimit, "argument exceeds the LMMP unsigned kernel range", operation);
17 }
18 return static_cast<unsigned int>(*converted);
19}
20
21Result<void> reserve_product(const BigInt& largest_factor, unsigned int factors,
22 ComputationContext& context, const char* operation) {
23 auto steps = context.consume_steps(factors, operation);
24 if (!steps) {
25 return steps;
26 }
27 const auto factor_bits = largest_factor.bit_length();
28 if (factors != 0 && factor_bits > std::numeric_limits<std::size_t>::max() / factors) {
30 "combinatorial bit bound overflows", operation);
31 }
32 return context.require_integer_bits(factor_bits * factors, operation);
33}
34
36 const char* operation) {
37 auto access = context.consume_steps(0, operation);
38 if (!access) {
39 return Result<BigInt>::failure(access.error());
40 }
41 auto bits = context.require_integer_bits(value.bit_length(), operation);
42 if (!bits) {
43 return Result<BigInt>::failure(bits.error());
44 }
45 return Result<BigInt>::success(std::move(value));
46}
47
49 if (result) {
50 return std::move(result.value());
51 }
52 if (result.error().code == CasErrc::DomainError) {
53 throw std::domain_error(result.error().message);
54 }
55 if (result.error().code == CasErrc::ResourceLimit) {
56 throw std::length_error(result.error().message);
57 }
58 throw std::runtime_error(result.error().message);
59}
60
61}
62
63Result<BigInt> BigInt::factorial_checked(const BigInt& n,
64 ComputationContext& context) try {
65 constexpr auto operation = "BigInt::factorial_checked";
66 auto access = context.consume_steps(1, operation);
67 if (!access) {
68 return Result<BigInt>::failure(access.error());
69 }
70 auto argument = kernel_argument(n, operation);
71 if (!argument) {
72 return Result<BigInt>::failure(argument.error());
73 }
74 if (argument.value() <= 1) {
75 return finish_combinatorial(BigInt(1), context, operation);
76 }
77 auto budget = reserve_product(n, argument.value(), context, operation);
78 if (!budget) {
79 return Result<BigInt>::failure(budget.error());
80 }
82 mp_bitcnt_t binary_shift = 0;
83 const auto limbs = lmmp_factorial_size_(argument.value(), &binary_shift);
84 BigInt result;
85 result.realloc_to(limbs);
86 result.size_ = lmmp_factorial_(result.data_, binary_shift, limbs, argument.value());
87 result.sign_ = POSITIVE;
88 result.normalize();
89 return finish_combinatorial(std::move(result), context, operation);
90} catch (const std::bad_alloc&) {
92 "factorial allocation failed", "BigInt::factorial_checked");
93} catch (const std::length_error& error) {
94 return Result<BigInt>::failure(CasErrc::ResourceLimit, error.what(), "BigInt::factorial_checked");
95}
96
97Result<BigInt> BigInt::npr_checked(const BigInt& n, const BigInt& r,
99 constexpr auto operation = "BigInt::npr_checked";
100 auto access = context.consume_steps(1, operation);
101 if (!access) {
102 return Result<BigInt>::failure(access.error());
103 }
104 auto total = kernel_argument(n, operation);
105 auto rank = kernel_argument(r, operation);
106 if (!total) {
107 return Result<BigInt>::failure(total.error());
108 }
109 if (!rank) {
110 return Result<BigInt>::failure(rank.error());
111 }
112 if (rank.value() > total.value()) {
113 return finish_combinatorial(BigInt(0), context, operation);
114 }
115 if (rank.value() == 0) {
116 return finish_combinatorial(BigInt(1), context, operation);
117 }
118 auto budget = reserve_product(n, rank.value(), context, operation);
119 if (!budget) {
120 return Result<BigInt>::failure(budget.error());
121 }
123 mp_bitcnt_t binary_shift = 0;
124 const auto limbs = lmmp_nPr_size_(total.value(), rank.value(), &binary_shift);
125 BigInt result;
126 result.realloc_to(limbs);
127 result.size_ = lmmp_nPr_(result.data_, binary_shift, limbs, total.value(), rank.value());
128 result.sign_ = POSITIVE;
129 result.normalize();
130 return finish_combinatorial(std::move(result), context, operation);
131} catch (const std::bad_alloc&) {
133 "permutation allocation failed", "BigInt::npr_checked");
134} catch (const std::length_error& error) {
135 return Result<BigInt>::failure(CasErrc::ResourceLimit, error.what(), "BigInt::npr_checked");
136}
137
138Result<BigInt> BigInt::ncr_checked(const BigInt& n, const BigInt& r,
140 constexpr auto operation = "BigInt::ncr_checked";
141 auto access = context.consume_steps(1, operation);
142 if (!access) {
143 return Result<BigInt>::failure(access.error());
144 }
145 auto total = kernel_argument(n, operation);
146 auto rank = kernel_argument(r, operation);
147 if (!total) {
148 return Result<BigInt>::failure(total.error());
149 }
150 if (!rank) {
151 return Result<BigInt>::failure(rank.error());
152 }
153 if (rank.value() > total.value()) {
154 return finish_combinatorial(BigInt(0), context, operation);
155 }
156 const unsigned int reduced_rank = std::min(rank.value(), total.value() - rank.value());
157 if (reduced_rank == 0) {
158 return finish_combinatorial(BigInt(1), context, operation);
159 }
160 auto budget = reserve_product(n, reduced_rank, context, operation);
161 if (!budget) {
162 return Result<BigInt>::failure(budget.error());
163 }
165 mp_bitcnt_t binary_shift = 0;
166 const auto limbs = lmmp_nCr_size_(total.value(), reduced_rank, &binary_shift);
167 BigInt result;
168 result.realloc_to(limbs);
169 result.size_ = lmmp_nCr_(result.data_, binary_shift, limbs, total.value(), reduced_rank);
170 result.sign_ = POSITIVE;
171 result.normalize();
172 return finish_combinatorial(std::move(result), context, operation);
173} catch (const std::bad_alloc&) {
175 "combination allocation failed", "BigInt::ncr_checked");
176} catch (const std::length_error& error) {
177 return Result<BigInt>::failure(CasErrc::ResourceLimit, error.what(), "BigInt::ncr_checked");
178}
179
180Result<BigInt> BigInt::factorial_checked(const BigInt& n) {
182 return factorial_checked(n, context);
183}
184
185Result<BigInt> BigInt::npr_checked(const BigInt& n, const BigInt& r) {
187 return npr_checked(n, r, context);
188}
189
190Result<BigInt> BigInt::ncr_checked(const BigInt& n, const BigInt& r) {
192 return ncr_checked(n, r, context);
193}
194
195BigInt BigInt::factorial(const BigInt& n) {
196 return require_combinatorial(factorial_checked(n));
197}
198
199BigInt BigInt::npr(const BigInt& n, const BigInt& r) {
200 return require_combinatorial(npr_checked(n, r));
201}
202
203BigInt BigInt::ncr(const BigInt& n, const BigInt& r) {
204 return require_combinatorial(ncr_checked(n, r));
205}
206
207}
任意精度整数 BigInt,底层调用 LMMP 实现高性能大数运算。
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< BigInt > finish_combinatorial(BigInt value, ComputationContext &context, const char *operation)
Result< unsigned int > kernel_argument(const BigInt &value, const char *operation)
Result< void > reserve_product(const BigInt &largest_factor, unsigned int factors, ComputationContext &context, const char *operation)
void ensure_lmmc_lifecycle() noexcept
ComputationContext const std::string & operation
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
std::string message
const std::string const ExprPtr & value