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

Commits on Aug 12, 2021

  1. Fix a compatibility bug.

    pleroy committed Aug 12, 2021
    Copy the full SHA
    379e7a2 View commit details
  2. Copy the full SHA
    517b2bc View commit details

Commits on Aug 15, 2021

  1. Copy the full SHA
    faddb6c View commit details

Commits on Aug 16, 2021

  1. Copy the full SHA
    f298097 View commit details
  2. Fill the history.

    pleroy committed Aug 16, 2021
    Copy the full SHA
    74cca3e View commit details

Commits on Aug 17, 2021

  1. Store the start time of the downsampling object as the source of trut…

    …h and reconstruct iterators as needed.
    pleroy committed Aug 17, 2021
    Copy the full SHA
    360db4e View commit details
  2. Cleanup.

    pleroy committed Aug 17, 2021
    Copy the full SHA
    6d7619d View commit details
  3. Merge pull request #3091 from pleroy/Compatibility

    Fix a compatibility bug
    pleroy authored Aug 17, 2021
    Copy the full SHA
    03acbbf View commit details
Showing with 96 additions and 30 deletions.
  1. +15 −8 ksp_plugin/vessel.cpp
  2. +29 −8 physics/discrete_trajectory.hpp
  3. +52 −14 physics/discrete_trajectory_body.hpp
23 changes: 15 additions & 8 deletions ksp_plugin/vessel.cpp
Original file line number Diff line number Diff line change
@@ -503,9 +503,13 @@ not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
auto const psychohistory =
DiscreteTrajectory<Barycentric>::ReadFromMessage(message.history(),
/*tracked=*/{});
// The |history_| has been created by the constructor above. Reconstruct
// it from the |psychohistory|.
for (auto it = psychohistory->begin(); it != psychohistory->end();) {
// The |prehistory_| has been created by the constructor above. Reconstruct
// the |history_| from the |psychohistory|.
CHECK(!psychohistory->Empty());
auto it = psychohistory->begin();
vessel->prehistory_->Append(it->time, it->degrees_of_freedom);
vessel->history_ = vessel->prehistory_->NewForkAtLast();
for (++it; it != psychohistory->end();) {
auto const& [time, degrees_of_freedom] = *it;
++it;
if (it == psychohistory->end() &&
@@ -521,21 +525,24 @@ not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
}
vessel->prediction_ = vessel->psychohistory_->NewForkAtLast();
} else if (is_pre_chasles) {
vessel->prehistory_ = DiscreteTrajectory<Barycentric>::ReadFromMessage(
auto history = DiscreteTrajectory<Barycentric>::ReadFromMessage(
message.history(),
/*tracked=*/{&vessel->psychohistory_});
vessel->prehistory_->Append(history->begin()->time,
history->begin()->degrees_of_freedom);
vessel->history_ = history.get();
vessel->prehistory_->AttachFork(std::move(history));
vessel->prediction_ = vessel->psychohistory_->NewForkAtLast();
} else {
if (is_pre_grothendieck_haar) {
// The history is guaranteed to be non-empty because of
// CreatePrehistoryIfNeeded.
// The history is guaranteed to be non-empty because of the way
// CreateHistoryIfNeeded used to work.
auto history = DiscreteTrajectory<Barycentric>::ReadFromMessage(
message.history(),
/*tracked=*/{&vessel->psychohistory_, &vessel->prediction_});
vessel->prehistory_ =
make_not_null_unique<DiscreteTrajectory<Barycentric>>();
vessel->prehistory_->Append(history->begin()->time,
history->begin()->degrees_of_freedom);
vessel->history_ = history.get();
vessel->prehistory_->AttachFork(std::move(history));
} else {
vessel->prehistory_ = DiscreteTrajectory<Barycentric>::ReadFromMessage(
37 changes: 29 additions & 8 deletions physics/discrete_trajectory.hpp
Original file line number Diff line number Diff line change
@@ -206,8 +206,15 @@ class DiscreteTrajectory : public Forkable<DiscreteTrajectory<Frame>,
// A helper class to manage a dense timeline.
class Downsampling {
public:
Downsampling(std::int64_t max_dense_intervals,
Length tolerance);
// |max_dense_intervals| is the maximal number of dense intervals before
// downsampling occurs. |tolerance| is the tolerance for downsampling with
// |FitHermiteSpline|. The function |iterator_for_time| must be able to
// convert a time to a timeline iterator irrespective of the fork structure
// (it must die if the time does not exist in the corresponding trajectory).
Downsampling(
std::int64_t max_dense_intervals,
Length tolerance,
std::function<TimelineConstIterator(Instant const&)> iterator_for_time);

// Construction parameters.
std::int64_t max_dense_intervals() const;
@@ -226,7 +233,7 @@ class DiscreteTrajectory : public Forkable<DiscreteTrajectory<Frame>,
bool full() const;

// Returns the |dense_iterators_|, giving ownership to the caller.
std::vector<TimelineConstIterator> dense_iterators();
std::vector<TimelineConstIterator> ExtractDenseIterators();

void WriteToMessage(
not_null<serialization::DiscreteTrajectory::Downsampling*> message)
@@ -236,13 +243,27 @@ class DiscreteTrajectory : public Forkable<DiscreteTrajectory<Frame>,
DiscreteTrajectory const& trajectory);

private:
// The maximal number of dense intervals before downsampling occurs.
// Updates the first dense iterator from the start time.
void UpdateDenseIteratorsIfNeeded();

// Clears the start time if there are no dense iterators.
void UpdateStartTimeIfNeeded();

std::int64_t const max_dense_intervals_;
// The tolerance for downsampling with |FitHermiteSpline|.
Length const tolerance_;

// Note that, because of forks, the iterators in this vector may belong to
// different maps.
std::function<TimelineConstIterator(Instant const&)> const
iterator_for_time_;

// The first time may be the fork time of the trajectory, in which case it's
// not in the same timeline as the other times. Furthermore, this can
// change if a trajectory is attached to/detached from another trajectory.
// Thus, we consider the |start_time_| the source of truth and recompute the
// first element of |dense_iterators_| as needed using |iterator_for_time_|.
std::optional<Instant> start_time_;

// The iterators in this vector may belong to different maps. The first
// iterator should not be used without calling
// |UpdateDenseIteratorsIfNeeded| first.
std::vector<TimelineConstIterator> dense_iterators_;
};

66 changes: 52 additions & 14 deletions physics/discrete_trajectory_body.hpp
Original file line number Diff line number Diff line change
@@ -250,7 +250,13 @@ void DiscreteTrajectory<Frame>::SetDownsampling(
std::int64_t const max_dense_intervals,
Length const& tolerance) {
CHECK(!downsampling_.has_value());
downsampling_.emplace(max_dense_intervals, tolerance);
downsampling_.emplace(max_dense_intervals,
tolerance,
[this](Instant const& t) {
auto const it = this->Find(t);
CHECK(it != this->end());
return it.current();
});

// For a fork, the fork point is taken into account for downsampling: it is
// always preserved, but the second point preserved after downsampling may be
@@ -400,9 +406,11 @@ std::int64_t DiscreteTrajectory<Frame>::timeline_size() const {
template<typename Frame>
DiscreteTrajectory<Frame>::Downsampling::Downsampling(
std::int64_t const max_dense_intervals,
Length const tolerance)
Length const tolerance,
std::function<TimelineConstIterator(Instant const&)> iterator_for_time)
: max_dense_intervals_(max_dense_intervals),
tolerance_(tolerance) {
tolerance_(tolerance),
iterator_for_time_(std::move(iterator_for_time)) {
// This contains points, hence one more than intervals.
dense_iterators_.reserve(max_dense_intervals_ + 1);
}
@@ -422,11 +430,15 @@ template<typename Frame>
void DiscreteTrajectory<Frame>::Downsampling::Append(
TimelineConstIterator const it) {
CHECK(!full());
if (empty()) {
start_time_ = it->first;
}
dense_iterators_.push_back(it);
}

template<typename Frame>
void DiscreteTrajectory<Frame>::Downsampling::ForgetAfter(Instant const& t) {
UpdateDenseIteratorsIfNeeded();
auto const it = std::upper_bound(
dense_iterators_.cbegin(),
dense_iterators_.cend(),
@@ -435,10 +447,12 @@ void DiscreteTrajectory<Frame>::Downsampling::ForgetAfter(Instant const& t) {
return left < right->first;
});
dense_iterators_.erase(it, dense_iterators_.cend());
UpdateStartTimeIfNeeded();
}

template<typename Frame>
void DiscreteTrajectory<Frame>::Downsampling::ForgetBefore(Instant const& t) {
UpdateDenseIteratorsIfNeeded();
auto const it = std::lower_bound(
dense_iterators_.cbegin(),
dense_iterators_.cend(),
@@ -447,6 +461,7 @@ void DiscreteTrajectory<Frame>::Downsampling::ForgetBefore(Instant const& t) {
return left->first < right;
});
dense_iterators_.erase(dense_iterators_.cbegin(), it);
UpdateStartTimeIfNeeded();
}

template<typename Frame>
@@ -461,8 +476,11 @@ bool DiscreteTrajectory<Frame>::Downsampling::full() const {

template<typename Frame>
std::vector<typename DiscreteTrajectory<Frame>::TimelineConstIterator>
DiscreteTrajectory<Frame>::Downsampling::dense_iterators() {
return std::move(dense_iterators_);
DiscreteTrajectory<Frame>::Downsampling::ExtractDenseIterators() {
UpdateDenseIteratorsIfNeeded();
auto returned_dense_iterators = std::move(dense_iterators_);
UpdateStartTimeIfNeeded();
return std::move(returned_dense_iterators);
}

template<typename Frame>
@@ -471,8 +489,13 @@ void DiscreteTrajectory<Frame>::Downsampling::WriteToMessage(
const {
message->set_max_dense_intervals(max_dense_intervals_);
tolerance_.WriteToMessage(message->mutable_tolerance());
for (auto const it : dense_iterators_) {
it->first.WriteToMessage(message->add_dense_timeline());
if (!empty()) {
// We can't call UpdateDenseIteratorsIfNeeded here because this method is
// const.
start_time_.value().WriteToMessage(message->add_dense_timeline());
for (int i = 1; i < dense_iterators_.size(); ++i) {
dense_iterators_[i]->first.WriteToMessage(message->add_dense_timeline());
}
}
}

@@ -483,7 +506,12 @@ DiscreteTrajectory<Frame>::Downsampling::ReadFromMessage(
DiscreteTrajectory const& trajectory) {
bool const is_pre_grotendieck_haar = message.has_start_of_dense_timeline();
Downsampling downsampling(message.max_dense_intervals(),
Length::ReadFromMessage(message.tolerance()));
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) {
// No support for forks in legacy saves, so |find| will succeed and ++ is
// safe.
@@ -496,16 +524,26 @@ DiscreteTrajectory<Frame>::Downsampling::ReadFromMessage(
} else {
for (auto const& dense_time : message.dense_timeline()) {
auto const t = Instant::ReadFromMessage(dense_time);
// This call to |Find| is needed because we don't know in what timeline
// |t| lives.
auto const it = trajectory.Find(t);
CHECK(it != trajectory.end());
downsampling.Append(it.current());
downsampling.Append(downsampling.iterator_for_time_(t));
}
}
return downsampling;
}

template<typename Frame>
void DiscreteTrajectory<Frame>::Downsampling::UpdateDenseIteratorsIfNeeded() {
if (!dense_iterators_.empty()) {
dense_iterators_[0] = iterator_for_time_(start_time_.value());
}
}

template<typename Frame>
void DiscreteTrajectory<Frame>::Downsampling::UpdateStartTimeIfNeeded() {
if (dense_iterators_.empty()) {
start_time_.reset();
}
}

template<typename Frame>
void DiscreteTrajectory<Frame>::WriteSubTreeToMessage(
not_null<serialization::DiscreteTrajectory*> const message,
@@ -662,7 +700,7 @@ absl::Status DiscreteTrajectory<Frame>::UpdateDownsampling(
this->CheckNoForksBefore(appended->first);
downsampling_->Append(appended);
if (downsampling_->full()) {
auto const dense_iterators = downsampling_->dense_iterators();
auto const dense_iterators = downsampling_->ExtractDenseIterators();
auto right_endpoints = FitHermiteSpline<Instant, Position<Frame>>(
dense_iterators,
[](auto&& it) -> auto&& { return it->first; },