Skip to content

Commit

Permalink
Overhaul polynomial type (#172)
Browse files Browse the repository at this point in the history
* Add polynomial type support to generics

Introduced a new polynomial_type subdirectory with Indeterminate and Monomial classes. Updated CMakeLists to include the new directory and source files, enhancing the generics module with polynomial capabilities.

* Update Monomial class with operator overloads and functions

Refactored Monomial class to include new operator overloads and additional member functions for improved functionality. Simplified the 'Indeterminate' constructor and modified stream operators to use the generics namespace.

* Fix typo in monomial.cpp header comment

Corrected the accidental removal of comment characters which unintentionally disrupted the header section of the file. This change ensures the header comment remains properly formatted.

* Remove extraneous characters from comment header

Deleted unnecessary characters "zr" from the comment header in monomial.cpp to clean up the file. This change helps maintain code readability and prevents potential confusion for future developers.

* Add mpq string representation and hash functions

Introduced `mpq_display_rep` for generating string representations of GMP rational numbers and `mpq_hash` for computing their hash values. Refactored `rational_type.cpp` to utilize these new functions, enhancing code modularity and clarity.

* Add Polynomial class with arithmetic operations

Introduced a new `Polynomial` class along with its header and source files. Implemented essential polynomial arithmetic operations including addition, subtraction, multiplication, and division. Updated the CMakeLists to include the new files, and annotated relevant methods with `RPY_NO_DISCARD` in `monomial.h`.

* Refactor index method and add monomial tests

Refactored the `index` method in `indeterminate.h` to use `integer_mask` directly for improved clarity and correctness. Added comprehensive unit tests for `Monomial` in the new file `test_monomial.cpp` and updated `CMakeLists.txt` to include these tests when building.

* Add unit tests for `Indeterminate` and `Polynomial` classes

Implemented GTest-based unit tests for the `Indeterminate` class, verifying constructors, operators, and hash functionality. Additionally, created a test file for the `Polynomial` class and updated the CMakeLists.txt to include these new tests.

* Add degree method and various enhancements to Polynomial

Introduced a `degree` method to compute the degree of a polynomial. Added additional constructors and utility functions, cleaned up headers,

* Add constructor and empty check to Monomial class

Introduce a new constructor to initialize Monomial with a prefix, index, and degree. Implement a method to check if the Monomial data is empty, enhancing class usability.

* Add unit tests for polynomial operations

Implement unit tests for default value, display, addition, subtraction, multiplication, and division of Polynomial class. These tests ensure proper functionality and correctness of polynomial operations.

* Add constructors and stream operator to Polynomial class

Implemented default copy and move constructors for the Polynomial class to ensure proper object management. Also added an overloaded stream operator for easy printing of Polynomial objects.

* Refactor polynomial multiplication test logic.

Changed the test case to multiply into a separate result polynomial instead of in-place. The expected result polynomial has been updated to reflect correct multiplication values. Adjusted assertions to compare the updated result correctly.

* Add tests for polynomial equality and hashing

This commit introduces new test cases for validating polynomial equality and hashing functionality. The tests ensure that polynomials are compared correctly and that their hash values are consistent as expected. This improves reliability and correctness in polynomial-related operations.

* Add polynomial type handling files

Introduced new header and source files for polynomial types, including arithmetic, comparison, and number traits. Modified the CMakeLists to include these files and added tests for the new polynomial type functionalities in a dedicated test suite.

* Refactor `poly_div_inplace` to use `mpq_srcptr`

Updated the `poly_div_inplace` function to accept `mpq_srcptr` directly instead of `dtl::RationalCoeff`. This change improves clarity and efficiency by eliminating unnecessary indirection. Additionally, provided an inline function for backward compatibility with existing `dtl::RationalCoeff` usage.

* Extend PolynomialArithmetic with ArithmeticTrait methods

Implemented the unsafe_add_inplace, unsafe_sub_inplace, unsafe_mul_inplace, and unsafe_div_inplace methods in PolynomialArithmetic, inheriting from ArithmeticTrait. Added necessary includes and assertions to ensure robustness of operations. This enhances polynomial arithmetic capabilities with runtime checks and debug assertions.

* Add polynomial_types.cpp to the build configuration

This commit includes polynomial_types.cpp in the list of source files in CMakeLists.txt. This change ensures that the polynomial types are compiled and linked properly in the build process.

* Refactor `polynomial_type.cpp` for improved readability.

Condensed single-line function bodies for better clarity. Updated `basic_properties` to reflect accurate properties. These changes enhance code maintainability without altering functionality.

* Update test assertions in `test_polynomial_type.cpp`.

Revised test expectations to match updated polynomial representation and improved formatting for properties assertions. These changes make tests more accurate and improve code maintainability without changing core functionality.

* Implement PolynomialType constructor and specialized traits

Added a constructor to PolynomialType to initialize arithmetic, comparison, and number traits. Updated `get_builtin_trait` method to return these specialized traits based on the given trait ID.

* Update tests for PolynomialType operations and functions

Modified unit tests to check that division and FromRational functions are supported by PolynomialType. Changed assertions from `EXPECT_FALSE` to `EXPECT_TRUE` to reflect current implementation capabilities.

* Add ctre and fmt dependencies

Included ctre and fmt packages in CMakeLists.txt for library linkage. Updated vcpkg.json to reflect new dependency versions for consistent package management.

* Change base_type to uint64_t and enhance parser functionality.

Updated the Indeterminate class to use uint64_t for base_type. Added clear and emplace methods to Monomial. Enhanced PolynomialType parsing with support for integers and rational coefficients, and restored parse_from_string.

* Change base_type to uint64_t and enhance parser functionality.

Updated the Indeterminate class to use uint64_t for base_type. Added clear and emplace methods to Monomial. Enhanced PolynomialType parsing with support for integers and rational coefficients, and restored parse_from_string.

* Add test for parsing mixed monomial with powers

Introduce a new unit test to ensure the PolynomialType can correctly parse and display mixed monomials with powers. This helps maintain the accuracy and robustness of polynomial representation.

* Add missing <numeric> include and remove unused <iostream>

The <numeric> header was added to monomial.cpp to utilize numeric algorithms. The unused <iostream> header was removed from polynomial_type.cpp to clean up the codebase and improve maintainability.
  • Loading branch information
inakleinbottle authored Nov 27, 2024
1 parent bf732fa commit ce1fce0
Show file tree
Hide file tree
Showing 27 changed files with 2,194 additions and 153 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ find_package(PCGRandom REQUIRED)
find_package(GMP REQUIRED)
find_package(MPFR REQUIRED)
find_package(range-v3 CONFIG REQUIRED)
find_package(ctre CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)

message(STATUS "Target architecture ${RPY_ARCH}")

Expand Down
82 changes: 38 additions & 44 deletions platform/include/roughpy/generics/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ namespace rpy::generics {
* includes methods and attributes which can be leveraged to manage and
* manipulate these properties efficiently and effectively.
*/
struct BasicProperties {
bool standard_layout : 1;
bool trivially_copyable : 1;
bool trivially_constructible : 1;
bool trivially_default_constructible : 1;
bool trivially_copy_constructible : 1;
bool trivially_copy_assignable : 1;
bool trivially_destructible : 1;
bool polymorphic : 1;
bool is_signed : 1;
bool is_floating_point : 1;
bool is_integral : 1;
struct BasicProperties
{
bool standard_layout: 1;
bool trivially_copyable: 1;
bool trivially_constructible: 1;
bool trivially_default_constructible: 1;
bool trivially_copy_constructible: 1;
bool trivially_copy_assignable: 1;
bool trivially_destructible: 1;
bool polymorphic: 1;
bool is_signed: 1;
bool is_floating_point: 1;
bool is_integral: 1;
};

template <typename T>
Expand All @@ -60,6 +61,7 @@ constexpr BasicProperties basic_properties_of() noexcept;

template <typename T>
TypePtr get_type() noexcept;

//{
// static_assert(false, "There is no Type associated with T");
// RPY_UNREACHABLE_RETURN(nullptr);
Expand All @@ -78,7 +80,6 @@ class ROUGHPY_PLATFORM_EXPORT Type : public mem::PolymorphicRefCounted
friend class Value;

public:

/**
* @brief Returns the type information of the current instance.
*
Expand Down Expand Up @@ -164,7 +165,6 @@ class ROUGHPY_PLATFORM_EXPORT Type : public mem::PolymorphicRefCounted
virtual void free_object(void* ptr) const = 0;

public:

virtual bool parse_from_string(void* data, string_view str) const noexcept;

/**
Expand All @@ -183,7 +183,7 @@ class ROUGHPY_PLATFORM_EXPORT Type : public mem::PolymorphicRefCounted
*/
virtual void
copy_or_move(void* dst, const void* src, size_t count, bool move) const
= 0;
= 0;

virtual void
destroy_range(void* data, size_t count) const = 0;
Expand Down Expand Up @@ -273,10 +273,7 @@ class ROUGHPY_PLATFORM_EXPORT Type : public mem::PolymorphicRefCounted
*
* @return A TypePtr representing the specific type.
*/
static TypePtr of() noexcept
{
return get_type<decay_t<T>>();
}
static TypePtr of() noexcept { return get_type<decay_t<T> >(); }

};

Expand Down Expand Up @@ -314,8 +311,8 @@ const BuiltinTypes& get_builtin_types() noexcept;
class ROUGHPY_PLATFORM_EXPORT MultiPrecisionTypes
{
MultiPrecisionTypes();
public:

public:
TypePtr integer_type;
TypePtr rational_type;

Expand All @@ -326,6 +323,9 @@ class ROUGHPY_PLATFORM_EXPORT MultiPrecisionTypes
static const MultiPrecisionTypes& get() noexcept;
};

RPY_NO_DISCARD
ROUGHPY_PLATFORM_EXPORT
TypePtr get_polynomial_type() noexcept;


template <typename T>
Expand All @@ -338,18 +338,18 @@ constexpr BasicProperties basic_properties_of() noexcept
{
using base_t = remove_cvref_t<T>;
return {
is_standard_layout_v<base_t>,
is_trivially_copyable_v<base_t>,
is_trivially_constructible_v<base_t>,
is_trivially_default_constructible_v<base_t>,
is_trivially_copy_constructible_v<base_t>,
is_trivially_copy_assignable_v<base_t>,
is_trivially_destructible_v<base_t>,
is_polymorphic_v<base_t>,
is_signed_v<base_t>,
is_floating_point_v<base_t>,
is_integral_v<base_t>,
};
is_standard_layout_v<base_t>,
is_trivially_copyable_v<base_t>,
is_trivially_constructible_v<base_t>,
is_trivially_default_constructible_v<base_t>,
is_trivially_copy_constructible_v<base_t>,
is_trivially_copy_assignable_v<base_t>,
is_trivially_destructible_v<base_t>,
is_polymorphic_v<base_t>,
is_signed_v<base_t>,
is_floating_point_v<base_t>,
is_integral_v<base_t>,
};
}

/**
Expand All @@ -366,7 +366,9 @@ constexpr BasicProperties basic_properties_of() noexcept
* @return The promoted type based on the provided `lhs` and `rhs` types.
* If neither type can be promoted to the other, `nullptr` is returned.
*/
RPY_NO_DISCARD TypePtr ROUGHPY_PLATFORM_EXPORT compute_promotion(const Type* lhs, const Type* rhs) noexcept;
RPY_NO_DISCARD TypePtr ROUGHPY_PLATFORM_EXPORT compute_promotion(
const Type* lhs,
const Type* rhs) noexcept;

/**
* @brief Computes the hash value of a given Type object.
Expand All @@ -386,16 +388,10 @@ inline hash_t hash_value(const Type& value) noexcept
}

RPY_NO_DISCARD constexpr bool
operator==(const Type& lhs, const Type& rhs) noexcept
{
return &lhs == &rhs;
}
operator==(const Type& lhs, const Type& rhs) noexcept { return &lhs == &rhs; }

RPY_NO_DISCARD constexpr bool
operator!=(const Type& lhs, const Type& rhs) noexcept
{
return !(lhs == rhs);
}
operator!=(const Type& lhs, const Type& rhs) noexcept { return !(lhs == rhs); }

/**
* @brief Retrieves the size of an object of the specified type.
Expand All @@ -411,7 +407,6 @@ inline size_t size_of(const Type& type) noexcept { return type.object_size(); }
namespace concepts {



/**
* @brief Check if the given type has standard layout
* @param type A reference to the Type object
Expand Down Expand Up @@ -550,7 +545,6 @@ inline bool is_arithmetic(Type const& type)
}// namespace concepts



template <>
inline TypePtr get_type<float>() noexcept
{
Expand Down Expand Up @@ -614,4 +608,4 @@ inline TypePtr get_type<uint64_t>() noexcept

}// namespace rpy::generics

#endif// ROUGHPY_GENERICS_TYPE_H
#endif// ROUGHPY_GENERICS_TYPE_H
2 changes: 2 additions & 0 deletions platform/src/generics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ target_sources(RoughPy_Platform PRIVATE
conversion_trait.cpp
multiprecision_types.cpp
number_trait.cpp
polynomial_types.cpp
type.cpp
type_builtin.cpp
type_promotion.cpp
Expand All @@ -29,6 +30,7 @@ target_sources(RoughPy_Platform PRIVATE

add_subdirectory(builtin_types)
add_subdirectory(multiprecision_types)
add_subdirectory(polynomial_type)



Expand Down
32 changes: 32 additions & 0 deletions platform/src/generics/multiprecision_types/mpq_string_rep.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Created by sam on 26/11/24.
//

#ifndef ROUGHPY_GENERICS_INTERNAL_MPQ_STRING_REP_H
#define ROUGHPY_GENERICS_INTERNAL_MPQ_STRING_REP_H


#include <gmp.h>

#include "roughpy/core/types.h"


namespace rpy::generics {

inline void mpq_display_rep(string& buffer, mpq_srcptr value) noexcept
{
// The GMP docs describe the size of a mpq string representation in the
// documentation https://gmplib.org/manual/Rational-Conversions
auto num_size = mpz_sizeinbase(mpq_numref(value), 10);
auto denom_size = mpz_sizeinbase(mpq_denref(value), 10);
buffer.resize(num_size + denom_size + 3);

mpq_get_str(buffer.data(), 10, value);

// The buffer has at least one null byte at the end, cut these off
while (buffer.back() == '\0') { buffer.pop_back(); }
}

}

#endif //ROUGHPY_GENERICS_INTERNAL_MPQ_STRING_REP_H
9 changes: 9 additions & 0 deletions platform/src/generics/multiprecision_types/mpz_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ inline hash_t mpz_hash(mpz_srcptr integer) noexcept
return result;
}

inline hash_t mpq_hash(mpq_srcptr integer) noexcept
{
auto num_hash = mpz_hash(mpq_numref(integer));
const auto denom_hash = mpz_hash(mpq_denref(integer));

hash_combine(num_hash, denom_hash);
return num_hash;
}


}

Expand Down
18 changes: 3 additions & 15 deletions platform/src/generics/multiprecision_types/rational_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <roughpy/platform/alloc.h>

#include "mpz_hash.h"
#include "mpq_string_rep.h"

using namespace rpy;
using namespace rpy::generics;
Expand Down Expand Up @@ -145,18 +146,9 @@ RationalType::display(std::ostream& os, const void* value) const

const auto* rat = static_cast<mpq_srcptr>(value);

// The GMP docs describe the size of a mpq string representation in the
// documentation https://gmplib.org/manual/Rational-Conversions
auto num_size = mpz_sizeinbase(mpq_numref(rat), 10);
auto denom_size = mpz_sizeinbase(mpq_denref(rat), 10);

string buffer;
buffer.resize(num_size + denom_size + 3);

mpq_get_str(buffer.data(), 10, rat);
mpq_display_rep(buffer, rat);

// The buffer has at least one null byte at the end, cut these off
while (buffer.back() == '\0') { buffer.pop_back(); }
return os << buffer;
}

Expand All @@ -165,11 +157,7 @@ hash_t RationalType::hash_of(const void* value) const noexcept
if (value == nullptr) { return 0; }

auto* rat = static_cast<mpq_srcptr>(value);
auto num_hash = mpz_hash(mpq_numref(rat));
const auto denom_hash = mpz_hash(mpq_denref(rat));

hash_combine(num_hash, denom_hash);
return num_hash;
return mpq_hash(rat);
}

TypePtr RationalType::get() noexcept
Expand Down
60 changes: 60 additions & 0 deletions platform/src/generics/polynomial_type/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@




target_sources(RoughPy_Platform PRIVATE
indeterminate.h
indeterminate.cpp
monomial.cpp
monomial.h
polynomial.cpp
polynomial.h
polynomial_arithmetic.cpp
polynomial_arithmetic.h
polynomial_comparison.cpp
polynomial_comparison.h
polynomial_number.cpp
polynomial_number.h
polynomial_type.cpp
polynomial_type.h
)

target_link_libraries(RoughPy_Platform PRIVATE
ctre::ctre)

if (ROUGHPY_BUILD_TESTS)

add_executable(test_polynomial
test_indeterminate.cpp
test_monomial.cpp
test_polynomial.cpp
indeterminate.cpp
indeterminate.h
monomial.cpp
monomial.h
polynomial.cpp
polynomial.h
)

target_include_directories(test_polynomial PRIVATE
${ROUGHPY_PLATFORM_SOURCE}
)

target_link_libraries(test_polynomial PRIVATE
RoughPy::Core
Boost::headers
GMP::GMP
GTest::gtest
)

setup_roughpy_cpp_tests(test_polynomial)

add_executable(test_polynomial_type
test_polynomial_type.cpp
)

target_link_libraries(test_polynomial_type PRIVATE RoughPy::Platform GTest::gtest)

setup_roughpy_cpp_tests(test_polynomial_type)

endif ()
15 changes: 15 additions & 0 deletions platform/src/generics/polynomial_type/indeterminate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Created by sam on 26/11/24.
//

#include "indeterminate.h"

#include <ostream>

using namespace rpy;
using namespace rpy::generics;


std::ostream& generics::operator<<(std::ostream& os, const Indeterminate& value) {
return os << value.prefix() << value.index();
}
Loading

0 comments on commit ce1fce0

Please sign in to comment.