Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fork the prediction at the end of the psychohistory #1569

Merged
merged 5 commits into from
Sep 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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