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: 4c366aaaaa37
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 98edf8879d1f
Choose a head ref
  • 7 commits
  • 7 files changed
  • 1 contributor

Commits on Aug 21, 2021

  1. Renaming.

    pleroy committed Aug 21, 2021
    Copy the full SHA
    3ba2165 View commit details
  2. Support for tracking the root.

    pleroy committed Aug 21, 2021
    Copy the full SHA
    4350af6 View commit details
  3. Proper construction of Child.

    pleroy committed Aug 21, 2021
    Copy the full SHA
    b1662dc View commit details
  4. Cleanup.

    pleroy committed Aug 21, 2021
    Copy the full SHA
    5dbeafe View commit details
  5. Brood instead of Litter.

    pleroy committed Aug 21, 2021
    Copy the full SHA
    4cca339 View commit details
  6. Trajectory sizes.

    pleroy committed Aug 21, 2021
    Copy the full SHA
    5f74d02 View commit details
  7. Merge pull request #3105 from pleroy/TrackedRoot

    Allow tracking the root trajectory (not only forks) during serialization
    pleroy authored Aug 21, 2021
    Copy the full SHA
    98edf88 View commit details
13 changes: 7 additions & 6 deletions physics/discrete_trajectory.hpp
Original file line number Diff line number Diff line change
@@ -173,8 +173,8 @@ class DiscreteTrajectory : public Forkable<DiscreteTrajectory<Frame>,
// The points denoted by |exact| are written and re-read exactly and are not
// affected by any errors introduced by zfp compression.
void WriteToMessage(not_null<serialization::DiscreteTrajectory*> message,
std::set<DiscreteTrajectory*> const& excluded,
std::vector<DiscreteTrajectory*> const& tracked,
std::set<DiscreteTrajectory const*> const& excluded,
std::vector<DiscreteTrajectory const*> const& tracked,
std::vector<Iterator> const& exact) const;

// |forks| must have a size appropriate for the |message| being deserialized
@@ -270,11 +270,12 @@ class DiscreteTrajectory : public Forkable<DiscreteTrajectory<Frame>,
std::vector<TimelineConstIterator> dense_iterators_;
};

// This trajectory need not be a root.
void WriteSubTreeToMessage(
// This trajectory need not be a root. Returns false if this trajectory is
// excluded.
bool WriteSubTreeToMessage(
not_null<serialization::DiscreteTrajectory*> message,
std::set<DiscreteTrajectory*>& excluded,
std::vector<DiscreteTrajectory*>& tracked) const;
std::set<DiscreteTrajectory const*>& excluded,
std::vector<DiscreteTrajectory const*>& tracked) const;

void FillSubTreeFromMessage(
serialization::DiscreteTrajectory const& message,
33 changes: 20 additions & 13 deletions physics/discrete_trajectory_body.hpp
Original file line number Diff line number Diff line change
@@ -329,22 +329,22 @@ DegreesOfFreedom<Frame> DiscreteTrajectory<Frame>::EvaluateDegreesOfFreedom(
template<typename Frame>
void DiscreteTrajectory<Frame>::WriteToMessage(
not_null<serialization::DiscreteTrajectory*> const message,
std::set<DiscreteTrajectory*> const& excluded,
std::vector<DiscreteTrajectory*> const& tracked,
std::set<DiscreteTrajectory const*> const& excluded,
std::vector<DiscreteTrajectory const*> const& tracked,
std::vector<Iterator> const& exact) const {
CHECK(this->is_root());

std::set<DiscreteTrajectory<Frame>*> mutable_excluded = excluded;
std::vector<DiscreteTrajectory<Frame>*> mutable_tracked = tracked;
std::set<DiscreteTrajectory<Frame> const*> mutable_excluded = excluded;
std::vector<DiscreteTrajectory<Frame> const*> mutable_tracked = tracked;
WriteSubTreeToMessage(message, mutable_excluded, mutable_tracked);
CHECK(std::all_of(mutable_excluded.begin(),
mutable_excluded.end(),
[](DiscreteTrajectory<Frame>* const fork) {
[](DiscreteTrajectory<Frame> const* const fork) {
return fork == nullptr;
}));
CHECK(std::all_of(mutable_tracked.begin(),
mutable_tracked.end(),
[](DiscreteTrajectory<Frame>* const fork) {
[](DiscreteTrajectory<Frame> const* const fork) {
return fork == nullptr;
}));

@@ -528,15 +528,17 @@ typename DiscreteTrajectory<Frame>::Downsampling
DiscreteTrajectory<Frame>::Downsampling::ReadFromMessage(
serialization::DiscreteTrajectory::Downsampling const& message,
DiscreteTrajectory const& trajectory) {
bool const is_pre_grotendieck_haar = message.has_start_of_dense_timeline();
bool const is_pre_grothendieck_haar = message.has_start_of_dense_timeline();
LOG_IF(WARNING, is_pre_grothendieck_haar)
<< "Reading pre-Grothendieck/Haar Downsampling";
Downsampling downsampling(message.max_dense_intervals(),
Length::ReadFromMessage(message.tolerance()),
[&trajectory](Instant const& t){
auto const it = trajectory.Find(t);
CHECK(it != trajectory.end());
return it.current();
});
if (is_pre_grotendieck_haar) {
if (is_pre_grothendieck_haar) {
// No support for forks in legacy saves, so |find| will succeed and ++ is
// safe.
auto it = trajectory.timeline_.find(
@@ -569,12 +571,16 @@ void DiscreteTrajectory<Frame>::Downsampling::UpdateStartTimeIfNeeded() {
}

template<typename Frame>
void DiscreteTrajectory<Frame>::WriteSubTreeToMessage(
bool DiscreteTrajectory<Frame>::WriteSubTreeToMessage(
not_null<serialization::DiscreteTrajectory*> const message,
std::set<DiscreteTrajectory*>& excluded,
std::vector<DiscreteTrajectory*>& tracked) const {
Forkable<DiscreteTrajectory, Iterator, DiscreteTrajectoryTraits<Frame>>::
WriteSubTreeToMessage(message, excluded, tracked);
std::set<DiscreteTrajectory const*>& excluded,
std::vector<DiscreteTrajectory const*>& tracked) const {
bool const included =
Forkable<DiscreteTrajectory, Iterator, DiscreteTrajectoryTraits<Frame>>::
WriteSubTreeToMessage(message, excluded, tracked);
if (!included) {
return false;
}

int const timeline_size = timeline_.size();
auto* const zfp = message->mutable_zfp();
@@ -640,6 +646,7 @@ void DiscreteTrajectory<Frame>::WriteSubTreeToMessage(
if (downsampling_.has_value()) {
downsampling_->WriteToMessage(message->mutable_downsampling());
}
return true;
}

template<typename Frame>
28 changes: 17 additions & 11 deletions physics/discrete_trajectory_test.cpp
Original file line number Diff line number Diff line change
@@ -736,31 +736,37 @@ TEST_F(DiscreteTrajectoryTest, TrajectorySerializationSuccess) {
serialization::DiscreteTrajectory reference_message;

// Don't serialize |fork0|.
massive_trajectory_->WriteToMessage(&message,
/*excluded=*/{fork0},
/*tracked=*/{fork1, fork3, fork2},
/*exact=*/{});
massive_trajectory_->WriteToMessage(&reference_message,
/*excluded=*/{fork0},
/*tracked=*/{fork1, fork3, fork2},
/*exact=*/{});

massive_trajectory_->WriteToMessage(
&message,
/*excluded=*/{fork0},
/*tracked=*/{massive_trajectory_.get(), fork1, fork3, fork2},
/*exact=*/{});
massive_trajectory_->WriteToMessage(
&reference_message,
/*excluded=*/{fork0},
/*tracked=*/{massive_trajectory_.get(), fork1, fork3, fork2},
/*exact=*/{});

DiscreteTrajectory<World>* deserialized_root = nullptr;
DiscreteTrajectory<World>* deserialized_fork1 = nullptr;
DiscreteTrajectory<World>* deserialized_fork2 = nullptr;
DiscreteTrajectory<World>* deserialized_fork3 = nullptr;
not_null<std::unique_ptr<DiscreteTrajectory<World>>> const
deserialized_trajectory =
DiscreteTrajectory<World>::ReadFromMessage(message,
{&deserialized_fork1,
{&deserialized_root,
&deserialized_fork1,
&deserialized_fork3,
&deserialized_fork2});
EXPECT_EQ(deserialized_trajectory.get(), deserialized_root);
EXPECT_EQ(t2_, deserialized_fork1->Fork()->time);
EXPECT_EQ(t2_, deserialized_fork2->Fork()->time);
EXPECT_EQ(t3_, deserialized_fork3->Fork()->time);
message.Clear();
deserialized_trajectory->WriteToMessage(&message,
/*excluded=*/{},
/*tracked=*/{deserialized_fork1,
/*tracked=*/{deserialized_root,
deserialized_fork1,
deserialized_fork3,
deserialized_fork2},
/*exact=*/{});
6 changes: 3 additions & 3 deletions physics/ephemeris_test.cpp
Original file line number Diff line number Diff line change
@@ -1071,16 +1071,16 @@ TEST(EphemerisTestNoFixture, DiscreteTrajectoryCompression) {
/*excluded=*/{}, /*tracked=*/{}, /*exact=*/{});
std::string uncompressed;
message.SerializePartialToString(&uncompressed);
EXPECT_EQ(24'394, uncompressed.size());
EXPECT_EQ(24'405, uncompressed.size());

std::string compressed;
auto compressor = google::compression::NewGipfeliCompressor();
compressor->Compress(uncompressed, &compressed);

// We want a change detector, but the actual compressed size varies depending
// on the exact numerical values, and therefore on the mathematical library.
EXPECT_LE(18'825, compressed.size());
EXPECT_GE(18'825, compressed.size());
EXPECT_LE(18'836, compressed.size());
EXPECT_GE(18'836, compressed.size());

auto const trajectory2 =
DiscreteTrajectory<ICRS>::ReadFromMessage(message, /*tracked=*/{});
7 changes: 4 additions & 3 deletions physics/forkable.hpp
Original file line number Diff line number Diff line change
@@ -209,10 +209,11 @@ class Forkable {
// |tracked| are nulled-out as they are used.
// Note that prior to Grothendieck/Haar all forks that were not tracked were
// implicitly excluded (so the serialized-but-not-tracked case didn't happen).
void WriteSubTreeToMessage(
// Returns false if this trajectory is excluded.
bool WriteSubTreeToMessage(
not_null<serialization::DiscreteTrajectory*> message,
std::set<Tr4jectory*>& excluded,
std::vector<Tr4jectory*>& tracked) const;
std::set<Tr4jectory const*>& excluded,
std::vector<Tr4jectory const*>& tracked) const;

void FillSubTreeFromMessage(serialization::DiscreteTrajectory const& message,
std::vector<Tr4jectory**> const& tracked,
99 changes: 62 additions & 37 deletions physics/forkable_body.hpp
Original file line number Diff line number Diff line change
@@ -471,66 +471,91 @@ CheckNoForksBefore(Instant const& time) {
}

template<typename Tr4jectory, typename It3rator, typename Traits>
void Forkable<Tr4jectory, It3rator, Traits>::WriteSubTreeToMessage(
bool Forkable<Tr4jectory, It3rator, Traits>::WriteSubTreeToMessage(
not_null<serialization::DiscreteTrajectory*> const message,
std::set<Tr4jectory*>& excluded,
std::vector<Tr4jectory*>& tracked) const {
std::optional<Instant> last_instant;
serialization::DiscreteTrajectory::Litter* litter = nullptr;
for (auto const& [fork_time, child] : children_) {
// Determine if this |child| needs to be serialized.
auto const it_excluded = excluded.find(child.get());
if (it_excluded == excluded.end()) {
// Apologies for the O(N) search.
auto const it_tracked =
std::find(tracked.begin(), tracked.end(), child.get());
if (it_tracked == tracked.end()) {
// The caller wants to serialize this fork but doesn't want to track it,
// let's record this fact.
message->add_fork_position(
serialization::DiscreteTrajectory::MISSING_FORK_POSITION);
} else {
// The caller wants to serialize this fork and track it, let's record
// its position in the vector.
message->add_fork_position(it_tracked - tracked.begin());
*it_tracked = nullptr;
}
std::set<Tr4jectory const*>& excluded,
std::vector<Tr4jectory const*>& tracked) const {
// Determine if this object needs to be serialized.
auto const it_excluded = excluded.find(&*that());
if (it_excluded == excluded.end()) {
// Apologies for the O(N) search.
auto const it_tracked = std::find(tracked.begin(), tracked.end(), &*that());
if (it_tracked == tracked.end()) {
// The caller wants to serialize this object but doesn't want to track it,
// let's record this fact.
message->set_tracked_position(
serialization::DiscreteTrajectory::MISSING_TRACKED_POSITION);
} else {
// The caller doesn't want to serialize this fork. Don't traverse it.
excluded.erase(it_excluded);
continue;
// The caller wants to serialize this object and track it, let's record
// its position in the vector.
message->set_tracked_position(it_tracked - tracked.begin());
*it_tracked = nullptr;
}
} else {
// The caller doesn't want to serialize this object. Don't traverse it.
excluded.erase(it_excluded);
return false;
}

if (!last_instant || fork_time != last_instant) {
last_instant = fork_time;
litter = message->add_children();
fork_time.WriteToMessage(litter->mutable_fork_time());
std::optional<Instant> last_instant;
serialization::DiscreteTrajectory::Brood* brood = nullptr;
for (auto const& [fork_time, child] : children_) {
// We don't know if this child needs to be included in the serialization, so
// we write it to a temporary object and swap if appropriate.
serialization::DiscreteTrajectory candidate_trajectory;
bool const included = child->WriteSubTreeToMessage(
&candidate_trajectory, excluded, tracked);

if (included) {
// If this is the first included child at this fork time, create the
// |Brood| message.
if (!last_instant || fork_time != last_instant) {
last_instant = fork_time;
brood = message->add_children();
fork_time.WriteToMessage(brood->mutable_fork_time());
}
candidate_trajectory.Swap(brood->add_trajectories());
}
child->WriteSubTreeToMessage(litter->add_trajectories(),
excluded, tracked);
}
return true;
}

template<typename Tr4jectory, typename It3rator, typename Traits>
void Forkable<Tr4jectory, It3rator, Traits>::FillSubTreeFromMessage(
serialization::DiscreteTrajectory const& message,
std::vector<Tr4jectory**> const& tracked,
Timeline const& exact) {
// There were no fork positions prior to Буняковский.
bool const is_pre_grothendieck_haar = !message.has_tracked_position();
LOG_IF(WARNING, is_pre_grothendieck_haar)
<< "Reading pre-Grothendieck/Haar Forkable";

if (!is_pre_grothendieck_haar) {
std::int32_t const tracked_position = message.tracked_position();
if (tracked_position !=
serialization::DiscreteTrajectory::MISSING_TRACKED_POSITION) {
*tracked[tracked_position] = &*that();
}
}

// There were no fork positions prior to Буняковский, but we don't maintain
// compatibility that far back.
bool const has_fork_position = message.fork_position_size() > 0;
CHECK(is_pre_grothendieck_haar || !has_fork_position)
<< message.DebugString();

std::int32_t index = 0;
for (serialization::DiscreteTrajectory::Litter const& litter :
for (serialization::DiscreteTrajectory::Brood const& brood :
message.children()) {
Instant const fork_time = Instant::ReadFromMessage(litter.fork_time());
Instant const fork_time = Instant::ReadFromMessage(brood.fork_time());
for (serialization::DiscreteTrajectory const& child :
litter.trajectories()) {
brood.trajectories()) {
not_null<Tr4jectory*> fork = NewFork(timeline_find(fork_time));
fork->FillSubTreeFromMessage(child, tracked, exact);
if (has_fork_position) {
CHECK_LT(index, message.fork_position_size());
std::int32_t const fork_position = message.fork_position(index);
if (fork_position !=
serialization::DiscreteTrajectory::MISSING_FORK_POSITION) {
serialization::DiscreteTrajectory::MISSING_TRACKED_POSITION) {
*tracked[fork_position] = fork;
}
}
12 changes: 8 additions & 4 deletions serialization/physics.proto
Original file line number Diff line number Diff line change
@@ -81,8 +81,8 @@ message ContinuousTrajectory {
message DiscreteTrajectory {
// A marker to indicate that a fork doesn't have its position tracked.
// Added in Grothendieck/Haar.
enum ForkPosition {
MISSING_FORK_POSITION = -1;
enum TrackedPosition {
MISSING_TRACKED_POSITION = -1;
}
message Downsampling {
required int64 max_dense_intervals = 2;
@@ -97,13 +97,17 @@ message DiscreteTrajectory {
required Point instant = 1;
required Pair degrees_of_freedom = 2;
}
message Litter {
// All the trajectories forked at a given time.
message Brood {
required Point fork_time = 1;
repeated DiscreteTrajectory trajectories = 2;
}
repeated Litter children = 1;
repeated Brood children = 1;
repeated InstantaneousDegreesOfFreedom timeline = 2;
// Pre Grothendieck/Haar.
repeated int32 fork_position = 3;
// Added in Grothendieck/Haar.
optional int32 tracked_position = 7; // Required.
// Added in 陈景润.
optional Downsampling downsampling = 4;
// Added in Haar.