Skip to content

Commit

Permalink
Merge pull request #1569 from pleroy/ForkedPrediction
Browse files Browse the repository at this point in the history
Fork the prediction at the end of the psychohistory
  • Loading branch information
pleroy authored Sep 21, 2017
2 parents 6c7b951 + 62b98b7 commit a74810d
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 67 deletions.
2 changes: 1 addition & 1 deletion ksp_plugin/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ void Plugin::SetPredictionAdaptiveStepParameters(

void Plugin::UpdatePrediction(GUID const& vessel_guid) const {
CHECK(!initializing_);
FindOrDie(vessels_, vessel_guid)->UpdatePrediction(InfiniteFuture);
FindOrDie(vessels_, vessel_guid)->FlowPrediction(InfiniteFuture);
}

void Plugin::CreateFlightPlan(GUID const& vessel_guid,
Expand Down
4 changes: 2 additions & 2 deletions ksp_plugin/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Vessel const& Renderer::GetTargetVessel() const {
DiscreteTrajectory<Barycentric> const& Renderer::GetTargetVesselPrediction(
Instant const& time) const {
CHECK(target_);
target_->vessel->UpdatePrediction(time);
target_->vessel->FlowPrediction(time);
// The prediction may not have been prolonged to |time| if we are near a
// singularity.
CHECK_LE(time, target_->vessel->prediction().last().time());
Expand Down Expand Up @@ -109,7 +109,7 @@ Renderer::RenderBarycentricTrajectoryInPlotting(
if (target_ && begin != end) {
auto last = end;
--last;
target_->vessel->UpdatePrediction(last.time());
target_->vessel->FlowPrediction(last.time());
}
for (auto it = begin; it != end; ++it) {
Instant const& t = it.time();
Expand Down
99 changes: 46 additions & 53 deletions ksp_plugin/vessel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <string>
#include <vector>

#include "astronomy/epoch.hpp"
#include "ksp_plugin/integrators.hpp"
#include "ksp_plugin/pile_up.hpp"
#include "quantities/si.hpp"
Expand All @@ -16,6 +17,7 @@ namespace principia {
namespace ksp_plugin {
namespace internal_vessel {

using astronomy::InfiniteFuture;
using base::Contains;
using base::FindOrDie;
using base::make_not_null_unique;
Expand All @@ -36,9 +38,9 @@ Vessel::Vessel(GUID const& guid,
prediction_adaptive_step_parameters_(prediction_adaptive_step_parameters),
parent_(parent),
ephemeris_(ephemeris),
history_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()),
prediction_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {
// Can't create the |psychohistory_| here because |history_| is empty;
history_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {
// Can't create the |psychohistory_| and |prediction_| here because |history_|
// is empty;
}

Vessel::~Vessel() {
Expand Down Expand Up @@ -141,6 +143,7 @@ void Vessel::PrepareHistory(Instant const& t) {
CHECK(psychohistory_ == nullptr);
history_->Append(t, calculator.Get());
psychohistory_ = history_->NewForkAtLast();
prediction_ = psychohistory_->NewForkAtLast();
}
}

Expand Down Expand Up @@ -192,6 +195,8 @@ void Vessel::AdvanceTime() {
AppendToVesselTrajectory(&Part::psychohistory_begin,
&Part::psychohistory_end,
*psychohistory_);
prediction_ = psychohistory_->NewForkAtLast();

for (auto const& pair : parts_) {
Part& part = *pair.second;
part.ClearHistory();
Expand All @@ -200,10 +205,9 @@ void Vessel::AdvanceTime() {

void Vessel::ForgetBefore(Instant const& time) {
// Make sure that the history keeps at least one (authoritative) point and
// don't change the psychohistory. We cannot use the parts because they may
// have been moved to the future already.
// don't change the psychohistory or prediction. We cannot use the parts
// because they may have been moved to the future already.
history_->ForgetBefore(std::min(time, history_->last().time()));
prediction_->ForgetBefore(time);
if (flight_plan_ != nullptr) {
flight_plan_->ForgetBefore(time, [this]() { flight_plan_.reset(); });
}
Expand All @@ -228,19 +232,30 @@ void Vessel::DeleteFlightPlan() {
flight_plan_.reset();
}

void Vessel::UpdatePrediction(Instant const& last_time) {
// TODO(phl): The prediction should probably be a fork of the psychohistory.
auto const psychohistory_last = psychohistory_->last();
auto const prediction_begin = prediction_->Begin();
if (prediction_->Empty() ||
prediction_begin.time() != psychohistory_last.time() ||
prediction_begin.degrees_of_freedom() !=
psychohistory_last.degrees_of_freedom()) {
prediction_ = make_not_null_unique<DiscreteTrajectory<Barycentric>>();
prediction_->Append(psychohistory_last.time(),
psychohistory_last.degrees_of_freedom());
void Vessel::FlowPrediction(Instant const& time) {
if (time > prediction_->last().time()) {
bool const finite_time = IsFinite(time - prediction_->last().time());
Instant const t = finite_time ? time : ephemeris_->t_max();
// This will not prolong the ephemeris if |time| is infinite (but it may do
// so if it is finite).
bool const reached_t = ephemeris_->FlowWithAdaptiveStep(
prediction_,
Ephemeris<Barycentric>::NoIntrinsicAcceleration,
t,
prediction_adaptive_step_parameters_,
FlightPlan::max_ephemeris_steps_per_frame,
/*last_point_only=*/false);
if (!finite_time && reached_t) {
// This will prolong the ephemeris by |max_ephemeris_steps_per_frame|.
ephemeris_->FlowWithAdaptiveStep(
prediction_,
Ephemeris<Barycentric>::NoIntrinsicAcceleration,
time,
prediction_adaptive_step_parameters_,
FlightPlan::max_ephemeris_steps_per_frame,
/*last_point_only=*/false);
}
}
FlowPrediction(last_time);
}

DiscreteTrajectory<Barycentric> const& Vessel::psychohistory() const {
Expand All @@ -263,9 +278,7 @@ void Vessel::WriteToMessage(
message->add_kept_parts(part_id);
}
history_->WriteToMessage(message->mutable_history(),
/*forks=*/{psychohistory_});
prediction_->WriteToMessage(message->mutable_prediction(),
/*forks=*/{});
/*forks=*/{psychohistory_, prediction_});
if (flight_plan_ != nullptr) {
flight_plan_->WriteToMessage(message->mutable_flight_plan());
}
Expand All @@ -277,6 +290,8 @@ not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
not_null<Ephemeris<Barycentric>*> const ephemeris,
std::function<void(PartId)> const& deletion_callback) {
bool const is_pre_cesàro = message.has_psychohistory_is_authoritative();
bool const is_pre_chasles = message.has_prediction();

// NOTE(egg): for now we do not read the |MasslessBody| as it can contain no
// information.
auto vessel = make_not_null_unique<Vessel>(
Expand Down Expand Up @@ -319,15 +334,20 @@ not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
if (message.psychohistory_is_authoritative()) {
vessel->psychohistory_ = vessel->history_->NewForkAtLast();
}
} else {
vessel->prediction_ = vessel->psychohistory_->NewForkAtLast();
vessel->FlowPrediction(InfiniteFuture);
} else if (is_pre_chasles) {
vessel->history_ = DiscreteTrajectory<Barycentric>::ReadFromMessage(
message.history(),
/*forks=*/{&vessel->psychohistory_});
vessel->prediction_ = vessel->psychohistory_->NewForkAtLast();
vessel->FlowPrediction(InfiniteFuture);
} else {
vessel->history_ = DiscreteTrajectory<Barycentric>::ReadFromMessage(
message.history(),
/*forks=*/{&vessel->psychohistory_, &vessel->prediction_});
}

vessel->prediction_ =
DiscreteTrajectory<Barycentric>::ReadFromMessage(message.prediction(),
/*forks=*/{});
if (message.has_flight_plan()) {
vessel->flight_plan_ = FlightPlan::ReadFromMessage(message.flight_plan(),
ephemeris);
Expand All @@ -353,8 +373,7 @@ Vessel::Vessel()
prediction_adaptive_step_parameters_(DefaultPredictionParameters()),
parent_(testing_utilities::make_not_null<Celestial const*>()),
ephemeris_(testing_utilities::make_not_null<Ephemeris<Barycentric>*>()),
history_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()),
prediction_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {}
history_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {}

void Vessel::AppendToVesselTrajectory(
TrajectoryIterator const part_trajectory_begin,
Expand Down Expand Up @@ -404,32 +423,6 @@ void Vessel::AppendToVesselTrajectory(
}
}

void Vessel::FlowPrediction(Instant const& time) {
if (time > prediction_->last().time()) {
bool const finite_time = IsFinite(time - prediction_->last().time());
Instant const t = finite_time ? time : ephemeris_->t_max();
// This will not prolong the ephemeris if |time| is infinite (but it may do
// so if it is finite).
bool const reached_t = ephemeris_->FlowWithAdaptiveStep(
prediction_.get(),
Ephemeris<Barycentric>::NoIntrinsicAcceleration,
t,
prediction_adaptive_step_parameters_,
FlightPlan::max_ephemeris_steps_per_frame,
/*last_point_only=*/false);
if (!finite_time && reached_t) {
// This will prolong the ephemeris by |max_ephemeris_steps_per_frame|.
ephemeris_->FlowWithAdaptiveStep(
prediction_.get(),
Ephemeris<Barycentric>::NoIntrinsicAcceleration,
time,
prediction_adaptive_step_parameters_,
FlightPlan::max_ephemeris_steps_per_frame,
/*last_point_only=*/false);
}
}
}

} // namespace internal_vessel
} // namespace ksp_plugin
} // namespace principia
9 changes: 5 additions & 4 deletions ksp_plugin/vessel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ class Vessel {
// Deletes the |flight_plan_|. Performs no action unless |has_flight_plan()|.
virtual void DeleteFlightPlan();

virtual void UpdatePrediction(Instant const& last_time);
// Tries to extend the prediction up to and including |last_time|. May not be
// able to do it next to a singularity.
virtual void FlowPrediction(Instant const& last_time);

virtual DiscreteTrajectory<Barycentric> const& psychohistory() const;

Expand Down Expand Up @@ -168,8 +170,6 @@ class Vessel {
TrajectoryIterator part_trajectory_end,
DiscreteTrajectory<Barycentric>& trajectory);

void FlowPrediction(Instant const& time);

GUID const guid_;
std::string name_;

Expand All @@ -187,7 +187,8 @@ class Vessel {
not_null<std::unique_ptr<DiscreteTrajectory<Barycentric>>> history_;
DiscreteTrajectory<Barycentric>* psychohistory_ = nullptr;

not_null<std::unique_ptr<DiscreteTrajectory<Barycentric>>> prediction_;
// The |prediction_| is forked off the end of the |psychohistory_|.
DiscreteTrajectory<Barycentric>* prediction_ = nullptr;

std::unique_ptr<FlightPlan> flight_plan_;
};
Expand Down
2 changes: 1 addition & 1 deletion ksp_plugin_test/mock_vessel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class MockVessel : public Vessel {

MOCK_METHOD0(DeleteFlightPlan, void());

MOCK_METHOD1(UpdatePrediction, void(Instant const& last_time));
MOCK_METHOD1(FlowPrediction, void(Instant const& last_time));

MOCK_CONST_METHOD0(psychohistory, DiscreteTrajectory<Barycentric> const&());
MOCK_CONST_METHOD0(psychohistory_is_authoritative, bool());
Expand Down
4 changes: 2 additions & 2 deletions ksp_plugin_test/vessel_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ TEST_F(VesselTest, Prediction) {
50.0 * Metre / Second,
40.0 * Metre / Second}))),
Return(true)));
vessel_.UpdatePrediction(astronomy::J2000 + 1 * Second);
vessel_.FlowPrediction(astronomy::J2000 + 1 * Second);

EXPECT_EQ(2, vessel_.prediction().Size());
auto it = vessel_.prediction().Begin();
Expand Down Expand Up @@ -293,7 +293,7 @@ TEST_F(VesselTest, PredictBeyondTheInfinite) {
60.0 * Metre / Second,
50.0 * Metre / Second}))),
Return(true)));
vessel_.UpdatePrediction(astronomy::InfiniteFuture);
vessel_.FlowPrediction(astronomy::InfiniteFuture);

EXPECT_EQ(3, vessel_.prediction().Size());
auto it = vessel_.prediction().Begin();
Expand Down
8 changes: 5 additions & 3 deletions physics/forkable_body.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,10 @@ std::int64_t Forkable<Tr4jectory, It3rator>::Size() const {
// Go up the ancestry chain adding the sizes.
Tr4jectory const* parent = ancestor->parent_;
while (parent != nullptr) {
size += std::distance(parent->timeline_begin(),
*ancestor->position_in_parent_timeline_) + 1;
if (!parent->timeline_empty()) {
size += std::distance(parent->timeline_begin(),
*ancestor->position_in_parent_timeline_) + 1;
}
ancestor = parent;
parent = ancestor->parent_;
}
Expand All @@ -307,7 +309,7 @@ std::int64_t Forkable<Tr4jectory, It3rator>::Size() const {

template<typename Tr4jectory, typename It3rator>
bool Forkable<Tr4jectory, It3rator>::Empty() const {
// If this object has an ancestor surely it is hook off of a point in some
// If this object has an ancestor surely it is hooked off of a point in some
// timeline, so this object is not empty.
return timeline_empty() && parent_ == nullptr;
}
Expand Down
12 changes: 12 additions & 0 deletions physics/forkable_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,18 @@ TEST_F(ForkableTest, ForkSuccess) {
EXPECT_THAT(times, ElementsAre(t1_, t2_, t4_));
}

TEST_F(ForkableTest, Size) {
EXPECT_TRUE(trajectory_.Empty());
trajectory_.push_back(t1_);
EXPECT_EQ(1, trajectory_.Size());
not_null<FakeTrajectory*> const fork1 =
trajectory_.NewFork(trajectory_.timeline_find(t1_));
EXPECT_EQ(1, fork1->Size());
not_null<FakeTrajectory*> const fork2 = fork1->NewFork(fork1->timeline_end());
fork2->push_back(t2_);
EXPECT_EQ(2, fork2->Size());
}

TEST_F(ForkableTest, ForkAtLast) {
trajectory_.push_back(t1_);
trajectory_.push_back(t2_);
Expand Down
2 changes: 1 addition & 1 deletion serialization/ksp_plugin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ message Vessel {
repeated fixed32 kept_parts = 15;
required DiscreteTrajectory history = 16;
optional bool psychohistory_is_authoritative = 17; // Pre-Cesàro.
required DiscreteTrajectory prediction = 18;
optional DiscreteTrajectory prediction = 18; // Pre-Chasles.
optional FlightPlan flight_plan = 4;

// Pre-Буняковский.
Expand Down

0 comments on commit a74810d

Please sign in to comment.