This commit is contained in:
math 2025-03-31 17:03:07 +09:00
parent 3c39a7e58f
commit ca7e3db1b1
4 changed files with 267 additions and 77 deletions

View file

@ -10,4 +10,4 @@ add_compile_options(-Wall -Wextra -Wpedantic -O2 -funroll-loops)
add_executable(karatsuba src/karatsuba.cpp)
add_executable(pseudorandom src/pseudorandom.cpp)
add_executable(types src/types.cpp)
add_executable(multivar src/multivar.cpp)

147
src/multivar.cpp Normal file
View file

@ -0,0 +1,147 @@
#include <list>
#include <vector>
#include <version>
#include "types.hpp"
/**
* Constraint: degrees should have the same size across the board
*/
template<typename R>
struct monomial {
R coefficient;
vector<size_t> degrees;
};
template <typename R>
std::ostream& operator<<(std::ostream& os, const monomial<R>& r) {
os << r.coefficient;
for (size_t i = 0; i < r.degrees.size(); i++) {
os << " " << "X_" << i << "^" << r.degrees[i];
}
return os;
}
template<typename R>
int lexi_compare(const monomial<R> &lhs, const monomial<R> &rhs) {
for (int i = 0; i < lhs.degrees.size(); i++) {
if (lhs.degrees[i] > rhs.degrees[i]) {
return 1;
}
if (lhs.degrees[i] < rhs.degrees[i]) {
return -1;
}
}
// All degree terms are the same
return 0;
}
/**
* Ordered according to lexicographic order
* @tparam R ring
*/
template<typename R>
struct multipoly {
list<monomial<R>> monomials;
};
template <typename R>
std::ostream& operator<<(std::ostream& os, const multipoly<R>& poly) {
if (poly.monomials.empty()) {
os << "0";
} else {
auto ite = poly.monomials.begin();
os << *ite;
++ite;
for (; ite != poly.monomials.end(); ++ite) {
os << " + " << *ite;
}
}
return os;
}
template <typename R>
multipoly<R> &add_monomial(multipoly<R> &poly, const monomial<R> &monomial) {
auto ite = poly.monomials.begin();
for (; ite != poly.monomials.end(); ++ite) {
int cmp = lexi_compare(monomial, *ite);
if (cmp < 0) {
poly.monomials.insert(ite, monomial);
return poly;
}
if (cmp == 0) {
ite->coefficient = ite->coefficient + monomial.coefficient;
if (ite->coefficient == 0) {
poly.monomials.erase(ite);
}
return poly;
}
}
// Fail to insert before the very back
poly.monomials.insert(ite, monomial);
return poly;
}
template <typename R>
multipoly<R> operator+(const multipoly<R> &lhs, const multipoly<R> &rhs) {
auto result = lhs;
for (auto &rhs_mono : rhs.monomials) {
add_monomial(result, rhs_mono);
}
return result;
}
template <typename R>
multipoly<R> operator-(const multipoly<R> &lhs, const multipoly<R> &rhs) {
auto result = lhs;
for (auto &rhs_mono : rhs.monomials) {
auto negate_rhs = rhs_mono;
negate_rhs.coefficient = -negate_rhs.coefficient;
add_monomial(result, negate_rhs);
}
return result;
}
template <typename R>
multipoly<R> operator*(const multipoly<R> &lhs, const multipoly<R> &rhs) {
auto result = lhs;
// TODO Implement multiplication
return result;
}
template <typename R>
bool is_zero(multipoly<R> &poly) {
return poly.monomials.empty();
}
int main() {
auto m1 = monomial{2, vector<size_t>{3, 4}};
auto m2 = monomial{2, vector<size_t>{4, 2}};
auto m3 = monomial{3, vector<size_t>{3, 2}};
cout << "m1, m2, m3: " << m1 << ", " << m2 << ", " << m3 << endl;
cout << "compare m1, m2: " << lexi_compare(m1, m2) << endl;
cout << "compare m1, m3: " << lexi_compare(m1, m3) << endl;
cout << "compare m1, m1: " << lexi_compare(m1, m1) << endl;
cout << endl;
auto poly = multipoly<int>();
cout << "poly - step 0: " << poly << endl;
add_monomial(poly, m1);
cout << "poly - step 1: " << poly << endl;
add_monomial(poly, m2);
cout << "poly - step 2: " << poly << endl;
add_monomial(poly, m3);
cout << "poly - step 3: " << poly << endl;
add_monomial(poly, m1);
cout << "poly - step 4: " << poly << endl;
cout << "poly + poly: " << poly + poly << endl;
auto sub = poly - poly;
cout << "poly - poly: " << sub << endl;
cout << "poly - poly is zero: " << is_zero(sub) << endl;
return 0;
}

View file

@ -1,76 +0,0 @@
/*
* Until next time, let's boilerplate later
*/
#include <cmath>
#include <iostream>
using namespace std;
template<typename R>
struct rational {
R num;
R denom;
};
template<typename R>
rational<R> operator+(rational<R> &l, rational<R> &r) {
return rational(l.num * r.denom + r.num * l.denom, l.denom * r.denom);
}
template<typename R>
rational<R> operator-(rational<R> &l, rational<R> &r) {
return rational(l.num * r.denom - r.num * l.denom, l.denom * r.denom);
}
template<typename R>
rational<R> operator*(rational<R> &l, rational<R> &r) {
return rational(l.num * r.num, l.denom * r.denom);
}
template<typename R>
rational<R> operator/(rational<R> &l, rational<R> &r) {
return rational(l.num * r.denom, r.denom * l.num);
}
// TODO Take care of normalization
template<typename R>
bool operator==(rational<R> &l, rational<R> &r) {
return l.num == r.num && l.denom == r.denom;
}
template<typename R>
bool operator!=(rational<R> &l, rational<R> &r) {
return l.num != r.num || l.denom != r.denom;
}
/*
template<typename R>
ostream operator<< (ostream &os, rational<R> &r) {
}
*/
template<unsigned int>
struct prime_field {
size_t number;
};
template<unsigned int p>
prime_field<p> operator+(const prime_field<p> &l, const prime_field<p> &r) {
return prime_field(l.number + r.number % p);
}
template<unsigned int p>
prime_field<p> operator-(const prime_field<p> &l, const prime_field<p> &r) {
return prime_field(l.number - r.number % p);
}
template<unsigned int p>
prime_field<p> operator*(const prime_field<p> &l, const prime_field<p> &r) {
return prime_field(l.number * r.number % p);
}
// TODO /, ==, !=
int main() {
cout << "Hello World!" << endl;
}

119
src/types.hpp Normal file
View file

@ -0,0 +1,119 @@
#include <cmath>
#include <iostream>
using namespace std;
/**
* A generic function for computing the GCD
* @tparam R : this template variable should be a type for which all the necessary
* operations for Euclidean domains have been implemented
* @param a
* @param b
* @return
*/
template <typename R>
R gcd(R a, R b) {
if (b == 0)
return a;
R r = a % b;
while (r != 0) {
a = b;
b = r;
r = a % b;
}
return b;
}
/**
* Rational on R which is always normalized.
* @tparam R : a type for Euclidean domain
*/
template<typename R>
struct ratio {
R num;
R denom;
};
template<typename R>
ratio<R> &rational_of(R n) {
return ratio<R>(n, 1);
}
template<typename R>
ratio<R> &normalize(ratio<R> &n) {
const R gcd = gcd(n.num, n.denom);
n.num = n.num / gcd;
n.denom = n.denom / gcd;
return n;
}
template<typename R>
ratio<R> &operator+(const ratio<R> &l, const ratio<R> &r) {
return normalize(rational(l.num * r.denom + r.num * l.denom, l.denom * r.denom));
}
template<typename R>
ratio<R> &operator-(const ratio<R> &l, const ratio<R> &r) {
return normalize(rational(l.num * r.denom - r.num * l.denom, l.denom * r.denom));
}
template<typename R>
ratio<R> &operator*(const ratio<R> &l, const ratio<R> &r) {
return normalize(rational(l.num * r.num, l.denom * r.denom));
}
template<typename R>
ratio<R> &operator/(const ratio<R> &l, const ratio<R> &r) {
return normalize(rational(l.num * r.denom, r.denom * l.num));
}
template<typename R>
bool operator==(const ratio<R> &l, const ratio<R> &r) {
return l.num == r.num && l.denom == r.denom;
}
template<typename R>
bool operator!=(const ratio<R> &l, const ratio<R> &r) {
return l.num != r.num || l.denom != r.denom;
}
template <typename R>
std::ostream& operator<<(std::ostream& os, const ratio<R>& r) {
os << r.a << "/" << r.b;
return os;
}
/**
* Prime field where number is kept to be in range [0, p).
*/
template<unsigned int>
struct prime_field {
size_t number;
};
template<unsigned int p>
prime_field<p> &operator+(const prime_field<p> &l, const prime_field<p> &r) {
return prime_field((l.number + r.number) % p);
}
template<unsigned int p>
prime_field<p> &operator-(const prime_field<p> &l, const prime_field<p> &r) {
return prime_field((l.number - r.number) % p);
}
template<unsigned int p>
prime_field<p> &operator*(const prime_field<p> &l, const prime_field<p> &r) {
return prime_field((l.number * r.number) % p);
}
// TODO prime_field /
template<unsigned int p>
bool operator==(const prime_field<p> &l, const prime_field<p> &r) {
return l.number == r.number;
}
template<unsigned int p>
bool operator!=(const prime_field<p> &l, const prime_field<p> &r) {
return l.number != r.number;
}