Skip to content

Commit

Permalink
Merge pull request #3995 from pleroy/Prerequisites
Browse files Browse the repository at this point in the history
Prerequisites for the implementation of the Stehlé-Zimmermann algorithm
  • Loading branch information
pleroy authored May 5, 2024
2 parents e3e538c + f0fe98e commit a0aecac
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 52 deletions.
1 change: 1 addition & 0 deletions boost_multiprecision.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)..\Boost\multiprecision\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>BOOST_MP_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />
Expand Down
5 changes: 0 additions & 5 deletions functions/functions.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@
<ProjectGuid>{7cca653c-2e8f-4ffd-9e9f-bee590f3efab}</ProjectGuid>
<RootNamespace>functions</RootNamespace>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>BOOST_MP_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="accurate_table_generator.hpp" />
<ClInclude Include="accurate_table_generator_body.hpp" />
Expand Down
7 changes: 4 additions & 3 deletions numerics/polynomial_in_monomial_basis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class PolynomialInMonomialBasis : public Polynomial<Value_, Argument_> {
constexpr int degree() const override;
bool is_zero() const override;

Coefficients const& coefficients() const;
Argument const& origin() const;

// Returns a copy of this polynomial adjusted to the given origin.
Expand Down Expand Up @@ -355,10 +356,10 @@ operator-(Value const& left,
// Application monoid.

template<typename LValue, typename RValue,
typename Argument, int ldegree_, int rdegree_>
constexpr PolynomialInMonomialBasis<LValue, Argument, ldegree_ * rdegree_>
typename RArgument, int ldegree_, int rdegree_>
constexpr PolynomialInMonomialBasis<LValue, RArgument, ldegree_ * rdegree_>
Compose(PolynomialInMonomialBasis<LValue, RValue, ldegree_> const& left,
PolynomialInMonomialBasis<RValue, Argument, rdegree_> const& right);
PolynomialInMonomialBasis<RValue, RArgument, rdegree_> const& right);

// Returns a scalar polynomial obtained by pointwise inner product of two
// vector-valued polynomials.
Expand Down
49 changes: 31 additions & 18 deletions numerics/polynomial_in_monomial_basis_body.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "base/not_constructible.hpp"
#include "boost/multiprecision/number.hpp"
#include "geometry/cartesian_product.hpp"
#include "geometry/serialization.hpp"
#include "numerics/combinatorics.hpp"
Expand All @@ -24,6 +25,7 @@ namespace numerics {
namespace _polynomial_in_monomial_basis {
namespace internal {

using namespace boost::multiprecision;
using namespace principia::base::_not_constructible;
using namespace principia::geometry::_cartesian_product;
using namespace principia::geometry::_serialization;
Expand Down Expand Up @@ -444,6 +446,13 @@ is_zero() const {
return coefficients_ == Coefficients{};
}

template<typename Value_, typename Argument_, int degree_>
typename PolynomialInMonomialBasis<Value_, Argument_, degree_>::
Coefficients const&
PolynomialInMonomialBasis<Value_, Argument_, degree_>::coefficients() const {
return coefficients_;
}

template<typename Value_, typename Argument_, int degree_>
Argument_ const& PolynomialInMonomialBasis<Value_, Argument_, degree_>::
origin() const {
Expand Down Expand Up @@ -508,17 +517,19 @@ PolynomialInMonomialBasis<Value_, Argument_, degree_>::WithEvaluator() && {
template<typename Value_, typename Argument_, int degree_>
void PolynomialInMonomialBasis<Value_, Argument_, degree_>::
WriteToMessage(not_null<serialization::Polynomial*> message) const {
message->set_degree(degree_);
auto* const extension =
message->MutableExtension(
serialization::PolynomialInMonomialBasis::extension);
TupleSerializer<Coefficients, 0>::WriteToMessage(coefficients_, extension);
DoubleOrQuantityOrPointOrMultivectorSerializer<
Argument,
serialization::PolynomialInMonomialBasis>::WriteToMessage(origin_,
extension);
Evaluator<Value, Difference<Argument>, degree_>::WriteToMessage(
extension->mutable_evaluator(), evaluator_);
// No serialization for Boost types.
if constexpr (!is_number<Value>::value) {
message->set_degree(degree_);
auto* const extension = message->MutableExtension(
serialization::PolynomialInMonomialBasis::extension);
TupleSerializer<Coefficients, 0>::WriteToMessage(coefficients_, extension);
DoubleOrQuantityOrPointOrMultivectorSerializer<
Argument,
serialization::PolynomialInMonomialBasis>::WriteToMessage(origin_,
extension);
Evaluator<Value, Difference<Argument>, degree_>::WriteToMessage(
extension->mutable_evaluator(), evaluator_);
}
}

template<typename Value_, typename Argument_, int degree_>
Expand Down Expand Up @@ -750,19 +761,21 @@ operator-(Value const& left,
}

template<typename LValue, typename RValue,
typename Argument, int ldegree_, int rdegree_>
constexpr PolynomialInMonomialBasis<LValue, Argument, ldegree_ * rdegree_>
typename RArgument, int ldegree_, int rdegree_>
constexpr PolynomialInMonomialBasis<LValue, RArgument, ldegree_ * rdegree_>
Compose(PolynomialInMonomialBasis<LValue, RValue, ldegree_> const& left,
PolynomialInMonomialBasis<RValue, Argument, rdegree_> const& right) {
PolynomialInMonomialBasis<RValue, RArgument, rdegree_> const& right) {
using LArgument = RValue;
using LCoefficients =
typename PolynomialInMonomialBasis<LValue, RValue, ldegree_>::
typename PolynomialInMonomialBasis<LValue, LArgument, ldegree_>::
Coefficients;
using RCoefficients =
typename PolynomialInMonomialBasis<RValue, Argument, rdegree_>::
typename PolynomialInMonomialBasis<RValue, RArgument, rdegree_>::
Coefficients;
return PolynomialInMonomialBasis<LValue, Argument, ldegree_ * rdegree_>(
auto const left_at_origin = left.AtOrigin(LArgument{});
return PolynomialInMonomialBasis<LValue, RArgument, ldegree_ * rdegree_>(
TupleComposition<LCoefficients, RCoefficients>::Compose(
left.coefficients_, right.coefficients_),
left_at_origin.coefficients_, right.coefficients_),
right.origin_);
}

Expand Down
33 changes: 23 additions & 10 deletions numerics/polynomial_in_monomial_basis_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <tuple>

#include "boost/multiprecision/cpp_bin_float.hpp"
#include "boost/multiprecision/cpp_int.hpp"
#include "geometry/frame.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/instant.hpp"
Expand All @@ -28,6 +30,7 @@ namespace principia {
namespace numerics {

using ::testing::Eq;
using namespace boost::multiprecision;
using namespace principia::geometry::_frame;
using namespace principia::geometry::_grassmann;
using namespace principia::geometry::_instant;
Expand Down Expand Up @@ -277,18 +280,14 @@ TEST_F(PolynomialInMonomialBasisTest, Affine) {
}
}

// Compose contains a fold expression which fails to compile in Clang because of
// https://bugs.llvm.org/show_bug.cgi?id=30590. That bug will be fixed post-
// 11.0.0. Since we don't use Compose as of this writing, and working around
// the bug would be hard, we ifdef out the test.
#if PRINCIPIA_COMPILER_MSVC
TEST_F(PolynomialInMonomialBasisTest, Monoid) {
using P0 = PolynomialInMonomialBasis<Current, Temperature, 0>;
using P1A = PolynomialInMonomialBasis<Current, Temperature, 1>;
using P2A = PolynomialInMonomialBasis<Temperature, Instant, 2>;
using P2V = PolynomialInMonomialBasis<Temperature, Time, 2>;
using P3 = PolynomialInMonomialBasis<Current, Temperature, 3>;
Instant const t0;
P0 const p0(std::tuple{9 * Ampere});
P1A const p1a({2 * Ampere,
-4 * Ampere / Kelvin}, 3 * Kelvin);
P2A const p2a({1 * Kelvin,
3 * Kelvin / Second,
-8 * Kelvin / Second / Second}, t0);
Expand Down Expand Up @@ -332,11 +331,10 @@ TEST_F(PolynomialInMonomialBasisTest, Monoid) {
EXPECT_THAT(actual_v, AlmostEquals(-46396 * Ampere, 0));
}
{
auto const actual = Compose(p0, p2a)(t0);
EXPECT_THAT(actual, AlmostEquals(9 * Ampere, 0));
auto const actual = Compose(p1a, p2a)(t0 + 1 * Second);
EXPECT_THAT(actual, AlmostEquals(30 * Ampere, 0));
}
}
#endif

TEST_F(PolynomialInMonomialBasisTest, PointwiseInnerProduct) {
P2V::Coefficients const coefficients({
Expand Down Expand Up @@ -450,6 +448,21 @@ TEST_F(PolynomialInMonomialBasisTest, EvaluateLinear) {
EXPECT_THAT(estrin_light.EvaluateDerivative(1729 * Second), Eq(SpeedOfLight));
}

// Check that polynomials may be used with Boost multiprecision types.
TEST_F(PolynomialInMonomialBasisTest, Boost) {
using P2i = PolynomialInMonomialBasis<cpp_int, cpp_int, 2>;
P2i const p2i({1, 3, -8});
EXPECT_EQ(p2i(3), -62);

using P2r = PolynomialInMonomialBasis<cpp_rational, cpp_rational, 2>;
P2r const p2r({1, 3, -8});
EXPECT_EQ(p2r(cpp_rational(1, 3)), cpp_rational(10, 9));

using P2f = PolynomialInMonomialBasis<cpp_bin_float_50, cpp_bin_float_50, 2>;
P2f const p2f({1, 3, -8});
EXPECT_EQ(p2f(cpp_bin_float_50("1.25")), cpp_bin_float_50("-7.75"));
}

// Check that polynomials may be serialized.
TEST_F(PolynomialInMonomialBasisTest, Serialization) {
{
Expand Down
20 changes: 11 additions & 9 deletions quantities/concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,21 @@ using namespace base::_traits;
using namespace quantities::_quantities;

// TODO(egg): additive_group should subsume affine, but we use it there.
// We use |convertible_to| here because we want this concept to work with
// Boost multiprecision types which heavily use implicit conversions.
template<typename G>
concept additive_group = requires(G x, G y, int n) {
G{};
{ +x } -> std::same_as<G>;
{ -x } -> std::same_as<G>;
{ x + y } -> std::same_as<G>;
{ x - y } -> std::same_as<G>;
{ x += y } -> std::same_as<G&>;
{ x -= y } -> std::same_as<G&>;
{ +x } -> std::convertible_to<G>;
{ -x } -> std::convertible_to<G>;
{ x + y } -> std::convertible_to<G>;
{ x - y } -> std::convertible_to<G>;
{ x += y } -> std::convertible_to<G&>;
{ x -= y } -> std::convertible_to<G&>;
// An abelian group is a ℤ-module; we require the corresponding operations.
{ n * x } -> std::same_as<G>;
{ x * n } -> std::same_as<G>;
{ x *= n } -> std::same_as<G&>;
{ n * x } -> std::convertible_to<G>;
{ x * n } -> std::convertible_to<G>;
{ x *= n } -> std::convertible_to<G&>;
};

// A set acted upon simply transitively by an additive group.
Expand Down
8 changes: 8 additions & 0 deletions quantities/elementary_functions.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "boost/multiprecision/number.hpp"
#include "quantities/named_quantities.hpp"
#include "quantities/quantities.hpp"

Expand All @@ -8,6 +9,7 @@ namespace quantities {
namespace _elementary_functions {
namespace internal {

using namespace boost::multiprecision;
using namespace principia::quantities::_named_quantities;
using namespace principia::quantities::_quantities;

Expand Down Expand Up @@ -84,6 +86,11 @@ Angle ArcTanh(double x);
// |previous_angle|.
Angle UnwindFrom(Angle const& previous_angle, Angle const& α);

// Only dimensionless quantities can be rounded.
template<typename Q>
requires is_number<Q>::value || std::floating_point<Q>
Q Round(Q const& x);

} // namespace internal

using internal::Abs;
Expand All @@ -104,6 +111,7 @@ using internal::Mod;
using internal::NextDown;
using internal::NextUp;
using internal::Pow;
using internal::Round;
using internal::Sin;
using internal::Sinh;
using internal::Sqrt;
Expand Down
54 changes: 47 additions & 7 deletions quantities/elementary_functions_body.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,45 @@
#include <pmmintrin.h>

#include <cmath>
#include <type_traits>

#include "boost/multiprecision/cpp_int.hpp"
#include "numerics/cbrt.hpp"
#include "numerics/fma.hpp"
#include "numerics/next.hpp"
#include "quantities/concepts.hpp"
#include "quantities/si.hpp"

namespace principia {
namespace quantities {
namespace _elementary_functions {
namespace internal {

using namespace boost::multiprecision;
using namespace principia::numerics::_cbrt;
using namespace principia::numerics::_fma;
using namespace principia::numerics::_next;
using namespace principia::quantities::_concepts;
using namespace principia::quantities::_si;

template<typename Q1, typename Q2>
Product<Q1, Q2> FusedMultiplyAdd(Q1 const& x,
Q2 const& y,
Product<Q1, Q2> const& z) {
return si::Unit<Product<Q1, Q2>> *
numerics::_fma::FusedMultiplyAdd(
x / si::Unit<Q1>, y / si::Unit<Q2>, z / si::Unit<Product<Q1, Q2>>);
if constexpr (is_number<Q1>::value || is_number<Q2>::value) {
if constexpr ((number_category<Q1>::value == number_kind_integer ||
number_category<Q1>::value == number_kind_rational) &&
(number_category<Q2>::value == number_kind_integer ||
number_category<Q2>::value == number_kind_rational)) {
return x * y + z;
} else {
return fma(x, y, z);
}
} else {
return si::Unit<Product<Q1, Q2>> *
numerics::_fma::FusedMultiplyAdd(x / si::Unit<Q1>,
y / si::Unit<Q2>,
z / si::Unit<Product<Q1, Q2>>);
}
}

template<typename Q1, typename Q2>
Expand Down Expand Up @@ -59,8 +74,13 @@ Product<Q1, Q2> FusedNegatedMultiplySubtract(Q1 const& x,
}

template<typename Q>
FORCE_INLINE(inline) Q Abs(Q const& quantity) {
return si::Unit<Q> * std::abs(quantity / si::Unit<Q>);
FORCE_INLINE(inline)
Q Abs(Q const& x) {
if constexpr (is_number<Q>::value) {
return abs(x);
} else {
return si::Unit<Q> * std::abs(x / si::Unit<Q>);
}
}

template<typename Q>
Expand Down Expand Up @@ -143,7 +163,16 @@ inline constexpr double Pow<3>(double x) {

template<int exponent, typename Q>
constexpr Exponentiation<Q, exponent> Pow(Q const& x) {
return si::Unit<Exponentiation<Q, exponent>> * Pow<exponent>(x / si::Unit<Q>);
if constexpr (number_category<Q>::value == number_kind_rational) {
// It seems that Boost does not define |pow| for |cpp_rational|.
return cpp_rational(pow(numerator(x), exponent),
pow(denominator(x), exponent));
} else if constexpr (is_number<Q>::value) {
return pow(x, exponent);
} else {
return si::Unit<Exponentiation<Q, exponent>> *
Pow<exponent>(x / si::Unit<Q>);
}
}

inline double Sin(Angle const& α) {
Expand Down Expand Up @@ -175,6 +204,17 @@ Angle ArcTan(Quantity<D> const& y, Quantity<D> const& x) {
return ArcTan(y / si::Unit<Quantity<D>>, x / si::Unit<Quantity<D>>);
}

template<typename Q>
requires is_number<Q>::value || std::floating_point<Q>
Q Round(Q const& x) {
if constexpr (is_number<Q>::value) {
// TODO(phl): This is clunky. Use |divide_qr| or something.
return static_cast<Q>(round(static_cast<cpp_bin_float_50>(x)));
} else {
return std::round(x);
}
}

inline double Sinh(Angle const& α) {
return std::sinh((α / Radian));
}
Expand Down
Loading

0 comments on commit a0aecac

Please sign in to comment.