Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e19a4b8f4074
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5db19fbf9efe
Choose a head ref
  • 5 commits
  • 5 files changed
  • 1 contributor

Commits on Sep 20, 2020

  1. Copy the full SHA
    b0dce12 View commit details
  2. formatting opinions

    eggrobin committed Sep 20, 2020
    Copy the full SHA
    9042a88 View commit details
  3. after pleroy’s review

    eggrobin committed Sep 20, 2020
    Copy the full SHA
    5b0b8c6 View commit details
  4. UTF-8

    eggrobin committed Sep 20, 2020
    Copy the full SHA
    72b7cbc View commit details
  5. Merge pull request #2725 from eggrobin/complexification

    Complexification
    eggrobin authored Sep 20, 2020
    Copy the full SHA
    5db19fb View commit details
Showing with 420 additions and 0 deletions.
  1. +114 −0 geometry/complexification.hpp
  2. +180 −0 geometry/complexification_body.hpp
  3. +114 −0 geometry/complexification_test.cpp
  4. +3 −0 geometry/geometry.vcxproj
  5. +9 −0 geometry/geometry.vcxproj.filters
114 changes: 114 additions & 0 deletions geometry/complexification.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@

#pragma once

#include <type_traits>
#include <ostream>

#include "geometry/hilbert.hpp"
#include "quantities/named_quantities.hpp"

namespace principia {
namespace geometry {
namespace internal_complexification {

using quantities::Difference;
using quantities::Product;
using quantities::Quotient;
using quantities::Sum;

template<typename Vector>
class Complexification {
public:
explicit Complexification(Vector const& real_part);
explicit Complexification(Vector const& real_part,
Vector const& imaginary_part);

Vector const& real_part() const;
Vector const& imaginary_part() const;

Complexification Conjugate() const;

typename Hilbert<Vector>::InnerProductType Norm²() const;

private:
Vector real_part_;
Vector imaginary_part_;
};

template<typename Vector>
bool operator==(Complexification<Vector> const& left,
Complexification<Vector> const& right);
template<typename Vector>
bool operator!=(Complexification<Vector> const& left,
Complexification<Vector> const& right);

template<typename Vector>
Complexification<Vector> operator+(Complexification<Vector> const& right);
template<typename Vector>
Complexification<Vector> operator-(Complexification<Vector> const& right);

template<typename L, typename Vector>
Complexification<Sum<L, Vector>> operator+(
L const& left,
Complexification<Vector> const& right);
template<typename Vector, typename R>
Complexification<Sum<Vector, R>> operator+(
Complexification<Vector> const& left,
R const& right);
template<typename Vector>
Complexification<Vector> operator+(
Complexification<Vector> const& left,
Complexification<Vector> const& right);
template<typename L, typename Vector>
Complexification<Difference<L, Vector>> operator-(
L const& left,
Complexification<Vector> const& right);
template<typename Vector, typename R>
Complexification<Difference<Vector, R>> operator-(
Complexification<Vector> const& left,
R const& right);
template<typename Vector>
Complexification<Vector> operator-(
Complexification<Vector> const& left,
Complexification<Vector> const& right);

template<typename L, typename RVector>
Complexification<Product<L, RVector>> operator*(
L const& left,
Complexification<RVector> const& right);
template<typename LVector, typename R>
Complexification<Product<LVector, R>> operator*(
Complexification<LVector> const& left,
R const& right);
// TODO(egg): Numerical analysis.
template<typename LVector, typename RVector>
Complexification<Product<LVector, RVector>> operator*(
Complexification<LVector> const& left,
Complexification<RVector> const& right);

// TODO(egg): Numerical analysis.
template<typename L, typename RVector>
Complexification<Quotient<L, RVector>> operator/(
L const& left,
Complexification<RVector> const& right);
template<typename LVector, typename R>
Complexification<Quotient<LVector, R>> operator/(
Complexification<LVector> const& left,
R const& right);
// TODO(egg): Numerical analysis.
template<typename LVector, typename RVector>
Complexification<Quotient<LVector, RVector>> operator/(
Complexification<LVector> const& left,
Complexification<RVector> const& right);

template<typename Vector>
std::ostream& operator<<(std::ostream& out, Complexification<Vector> const& z);

} // namespace internal_complexification

using internal_complexification::Complexification;

} // namespace geometry
} // namespace principia

#include "geometry/complexification_body.hpp"
180 changes: 180 additions & 0 deletions geometry/complexification_body.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@

#pragma once

#include "geometry/complexification.hpp"

namespace principia {
namespace geometry {
namespace internal_complexification {

template<typename Vector>
Complexification<Vector>::Complexification(Vector const& real_part)
: real_part_(real_part) {}

template<typename Vector>
Complexification<Vector>::Complexification(Vector const& real_part,
Vector const& imaginary_part)
: real_part_(real_part), imaginary_part_(imaginary_part) {}

template<typename Vector>
Vector const& Complexification<Vector>::real_part() const {
return real_part_;
}

template<typename Vector>
Vector const& Complexification<Vector>::imaginary_part() const {
return imaginary_part_;
}

template<typename Vector>
Complexification<Vector> Complexification<Vector>::Conjugate() const {
return Complexification{real_part(), -imaginary_part()};
}

template<typename Vector>
typename Hilbert<Vector>::InnerProductType Complexification<Vector>::Norm²()
const {
// TODO(egg): Hilbert::Norm².
return Hilbert<Vector>::InnerProduct(real_part_, real_part_) +
Hilbert<Vector>::InnerProduct(imaginary_part_, imaginary_part_);
}

template<typename Vector>
bool operator==(Complexification<Vector> const& left,
Complexification<Vector> const& right) {
return left.real_part() == right.real_part() &&
left.imaginary_part() == right.imaginary_part();
}

template<typename Vector>
bool operator!=(Complexification<Vector> const& left,
Complexification<Vector> const& right) {
return left.real_part() != right.real_part() ||
left.imaginary_part() != right.imaginary_part();
}

template<typename Vector>
Complexification<Vector> operator+(Complexification<Vector> const& right) {
return right;
}

template<typename Vector>
Complexification<Vector> operator-(Complexification<Vector> const& right) {
return Complexification<Vector>{-right.real_part(), -right.imaginary_part()};
}

template<typename L, typename Vector>
Complexification<Sum<L, Vector>> operator+(
L const& left,
Complexification<Vector> const& right) {
return Complexification<Sum<L, Vector>>{left + right.real_part(),
right.imaginary_part()};
}

template<typename Vector, typename R>
Complexification<Sum<Vector, R>> operator+(Complexification<Vector> const& left,
R const& right) {
return Complexification<Sum<Vector, R>>{left.real_part() + right,
left.imaginary_part()};
}

template<typename Vector>
Complexification<Vector> operator+(Complexification<Vector> const& left,
Complexification<Vector> const& right) {
return Complexification<Vector>{
left.real_part() + right.real_part(),
left.imaginary_part() + right.imaginary_part()};
}

template<typename L, typename Vector>
Complexification<Difference<L, Vector>> operator-(
L const& left,
Complexification<Vector> const& right) {
return Complexification<Difference<L, Vector>>{left - right.real_part(),
right.imaginary_part()};
}

template<typename Vector, typename R>
Complexification<Difference<Vector, R>> operator-(
Complexification<Vector> const& left,
R const& right) {
return Complexification<Difference<Vector, R>>{left.real_part() - right,
left.imaginary_part()};
}

template<typename Vector>
Complexification<Vector> operator-(Complexification<Vector> const& left,
Complexification<Vector> const& right) {
return Complexification<Vector>{
left.real_part() - right.real_part(),
left.imaginary_part() - right.imaginary_part()};
}

template<typename L, typename RVector>
Complexification<Product<L, RVector>> operator*(
L const& left,
Complexification<RVector> const& right) {
return Complexification<Product<L, RVector>>(left * right.real_part(),
left * right.imaginary_part());
}

template<typename LVector, typename R>
Complexification<Product<LVector, R>> operator*(
Complexification<LVector> const& left,
R const& right) {
return Complexification<Product<LVector, R>>(left.real_part() * right,
left.imaginary_part() * right);
}

template<typename LVector, typename RVector>
Complexification<Product<LVector, RVector>> operator*(
Complexification<LVector> const& left,
Complexification<RVector> const& right) {
auto const& lr = left.real_part();
auto const& li = left.imaginary_part();
auto const& rr = right.real_part();
auto const& ri = right.imaginary_part();
return Complexification<Product<LVector, RVector>>(lr * rr - li * ri,
lr * ri + li * rr);
}

template<typename L, typename RVector>
Complexification<Quotient<L, RVector>> operator/(
L const& left,
Complexification<RVector> const& right) {
auto const& rr = right.real_part();
auto const& ri = right.imaginary_part();
auto const& denominator = rr * rr + ri * ri;
return Complexification<Quotient<L, RVector>>(left * rr / denominator,
-left * ri / denominator);
}

template<typename LVector, typename R>
Complexification<Quotient<LVector, R>> operator/(
Complexification<LVector> const& left,
R const& right) {
return Complexification<Quotient<LVector, R>>{left.real_part() / right,
left.imaginary_part() / right};
}

template<typename LVector, typename RVector>
Complexification<Quotient<LVector, RVector>> operator/(
Complexification<LVector> const& left,
Complexification<RVector> const& right) {
auto const& lr = left.real_part();
auto const& li = left.imaginary_part();
auto const& rr = right.real_part();
auto const& ri = right.imaginary_part();
auto const& denominator = rr * rr + ri * ri;
return Complexification<Quotient<LVector, RVector>>(
(lr * rr + li * ri) / denominator, (-lr * ri + li * rr) / denominator);
}

template<typename Vector>
std::ostream& operator<<(std::ostream& out, Complexification<Vector> const& z) {
return out << z.real_part() << " + " << z.imaginary_part() << " i";
}

} // namespace internal_complexification
} // namespace geometry
} // namespace principia
114 changes: 114 additions & 0 deletions geometry/complexification_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@

#include "geometry/complexification.hpp"

#include <sstream>

#include "geometry/frame.hpp"
#include "geometry/named_quantities.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "quantities/si.hpp"
#include "serialization/geometry.pb.h"

namespace principia {
namespace geometry {

using quantities::Length;
using quantities::si::Metre;
using ::testing::Eq;

class ComplexificationTest : public testing::Test {
protected:
using World = Frame<serialization::Frame::TestTag,
Inertial,
Handedness::Right,
serialization::Frame::TEST>;

Displacement<World> const v1_{{1 * Metre, 4 * Metre, 9 * Metre}};
Displacement<World> const v2_{{2 * Metre, 3 * Metre, 5 * Metre}};
Displacement<World> const v3_{{-1 * Metre, 3 * Metre, -9 * Metre}};
Displacement<World> const v4_{{0 * Metre, 10 * Metre, 5 * Metre}};
Complexification<double> const i_{0, 1};
};

TEST_F(ComplexificationTest, Addition) {
{
Complexification<Displacement<World>> const negation =
-Complexification(v1_, v2_);
EXPECT_THAT(negation.real_part(),
Eq(Displacement<World>({-1 * Metre, -4 * Metre, -9 * Metre})));
EXPECT_THAT(negation.imaginary_part(),
Eq(Displacement<World>({-2 * Metre, -3 * Metre, -5 * Metre})));
}
{
Complexification<Displacement<World>> const sum =
Complexification(v1_, v2_) + Complexification(v3_, v4_);
EXPECT_THAT(sum.real_part(),
Eq(Displacement<World>({0 * Metre, 7 * Metre, 0 * Metre})));
EXPECT_THAT(sum.imaginary_part(),
Eq(Displacement<World>({2 * Metre, 13 * Metre, 10 * Metre})));
}
{
Complexification<Displacement<World>> const difference =
Complexification(v1_, v2_) - Complexification(v3_, v4_);
EXPECT_THAT(difference.real_part(),
Eq(Displacement<World>({2 * Metre, 1 * Metre, 18 * Metre})));
EXPECT_THAT(difference.imaginary_part(),
Eq(Displacement<World>({2 * Metre, -7 * Metre, 0 * Metre})));
}
}

TEST_F(ComplexificationTest, Multiplication) {
auto const& v = v1_;
// Complex * real.
Complexification<Displacement<World>> iv = i_ * v;
EXPECT_THAT(iv.real_part(), Eq(Displacement<World>{}));
EXPECT_THAT(iv.imaginary_part(), Eq(v));
// Real * complex.
EXPECT_THAT((2 * iv).real_part(), Eq(Displacement<World>{}));
EXPECT_THAT((2 * iv).imaginary_part(), Eq(2 * v));
EXPECT_THAT((iv * 2).real_part(), Eq(Displacement<World>{}));
EXPECT_THAT((iv * 2).imaginary_part(), Eq(2 * v));
// Complex * complex.
Complexification<Displacement<World>> i²v = i_ * iv;
EXPECT_THAT(i²v.real_part(), Eq(-v));
EXPECT_THAT(i²v.imaginary_part(), Eq(Displacement<World>{}));

Complexification<double> i² = i_ * i_;
EXPECT_THAT(i².real_part(), Eq(-1));
EXPECT_THAT(i².imaginary_part(), Eq(0));
}

TEST_F(ComplexificationTest, Division) {
// Complex / real, the easy one.
EXPECT_THAT((v1_ + i_ * v2_) / 2, Eq(0.5 * (v1_ + i_ * v2_)));
// Real / complex.
EXPECT_THAT(1 / i_, Eq(-i_));
Complexification<Length> const z =
v1_.coordinates().x + i_ * v2_.coordinates().x;
// Complex / complex.
Complexification<Vector<double, World>> quotient = (v1_ + i_ * v2_) / z;
EXPECT_THAT(quotient, Eq(v1_ / z + i_ * v2_ / z));

EXPECT_THAT(quotient.real_part().coordinates().x, Eq(1));
EXPECT_THAT(quotient.imaginary_part().coordinates().x, Eq(0));
}

TEST_F(ComplexificationTest, Norm²) {
auto const v = v1_ + i_ * v2_;
auto const vx = v1_.coordinates().x + i_ * v2_.coordinates().x;
auto const vy = v1_.coordinates().y + i_ * v2_.coordinates().y;
auto const vz = v1_.coordinates().z + i_ * v2_.coordinates().z;

EXPECT_THAT(v.Norm²(),
Eq((vx * vx.Conjugate() +
vy * vy.Conjugate() +
vz * vz.Conjugate()).real_part()));
}

TEST_F(ComplexificationTest, Logging) {
EXPECT_THAT((std::stringstream() << (2 * i_ - 1)).str(), Eq("-1 + 2 i"));
}

} // namespace geometry
} // namespace principia
3 changes: 3 additions & 0 deletions geometry/geometry.vcxproj
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@
<ClInclude Include="barycentre_calculator_body.hpp" />
<ClInclude Include="cartesian_product.hpp" />
<ClInclude Include="cartesian_product_body.hpp" />
<ClInclude Include="complexification.hpp" />
<ClInclude Include="complexification_body.hpp" />
<ClInclude Include="frame.hpp" />
<ClInclude Include="frame_body.hpp" />
<ClInclude Include="hilbert.hpp" />
@@ -58,6 +60,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="barycentre_calculator_test.cpp" />
<ClCompile Include="complexification_test.cpp" />
<ClCompile Include="frame_test.cpp" />
<ClCompile Include="grassmann_test.cpp" />
<ClCompile Include="hilbert_test.cpp" />
9 changes: 9 additions & 0 deletions geometry/geometry.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -161,6 +161,12 @@
<ClInclude Include="hilbert_body.hpp">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="complexification.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="complexification_body.hpp">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="sign_test.cpp">
@@ -220,5 +226,8 @@
<ClCompile Include="hilbert_test.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="complexification_test.cpp">
<Filter>Test Files</Filter>
</ClCompile>
</ItemGroup>
</Project>