From 20c80068b24663ac367310bfc5ccc6bce57e25b6 Mon Sep 17 00:00:00 2001 From: Kevin Daun Date: Thu, 19 Apr 2018 11:59:28 +0200 Subject: [PATCH] Base ConstraintBuilder2D on correspondence cost function (#1088) - Base `ConstraintBuilder2D` and `FastCorrelativeScanMatcher2D` on correspondence cost function instead of probabilities - No changes in the options of `ConstraintBuilder2D` and `FastCorrelativeScanMatcher2D` - Add properties `min/max_correspondence_cost` to `Grid2D` and `proto::Grid2D` - Provide backwards compatibility for `proto::Grid2D` - Step towards [RFC 0019](https://github.com/googlecartographer/rfcs/blob/master/text/0019-probability-grid-and-submap2d-restructuring.md) --- cartographer/mapping/2d/grid_2d.cc | 35 ++++++++++----- cartographer/mapping/2d/grid_2d.h | 19 ++++---- cartographer/mapping/2d/probability_grid.cc | 3 +- cartographer/mapping/2d/proto/grid_2d.proto | 4 +- .../2d/pose_graph/constraint_builder_2d.cc | 16 +++---- .../2d/pose_graph/constraint_builder_2d.h | 7 ++- .../fast_correlative_scan_matcher_2d.cc | 43 ++++++++++--------- .../fast_correlative_scan_matcher_2d.h | 26 +++++------ .../fast_correlative_scan_matcher_2d_test.cc | 32 ++++++++------ 9 files changed, 106 insertions(+), 79 deletions(-) diff --git a/cartographer/mapping/2d/grid_2d.cc b/cartographer/mapping/2d/grid_2d.cc index e17260f..ed9870d 100644 --- a/cartographer/mapping/2d/grid_2d.cc +++ b/cartographer/mapping/2d/grid_2d.cc @@ -20,11 +20,16 @@ namespace cartographer { namespace mapping { -Grid2D::Grid2D(const MapLimits& limits) +Grid2D::Grid2D(const MapLimits& limits, float min_correspondence_cost, + float max_correspondence_cost) : limits_(limits), correspondence_cost_cells_( limits_.cell_limits().num_x_cells * limits_.cell_limits().num_y_cells, - kUnknownCorrespondenceValue) {} + kUnknownCorrespondenceValue), + min_correspondence_cost_(min_correspondence_cost), + max_correspondence_cost_(max_correspondence_cost) { + CHECK_LT(min_correspondence_cost_, max_correspondence_cost_); +} Grid2D::Grid2D(const proto::Grid2D& proto) : limits_(proto.limits()), correspondence_cost_cells_() { @@ -39,6 +44,19 @@ Grid2D::Grid2D(const proto::Grid2D& proto) CHECK_LE(cell, std::numeric_limits::max()); correspondence_cost_cells_.push_back(cell); } + if (proto.min_correspondence_cost() == 0.f && + proto.max_correspondence_cost() == 0.f) { + LOG(WARNING) + << "proto::Grid2D: max_correspondence_cost and min_correspondence_cost " + "are initialized with 0 indicating an older version of the " + "protobuf format. Loading default values."; + min_correspondence_cost_ = kMinCorrespondenceCost; + max_correspondence_cost_ = kMaxCorrespondenceCost; + } else { + min_correspondence_cost_ = proto.min_correspondence_cost(); + max_correspondence_cost_ = proto.max_correspondence_cost(); + } + CHECK_LT(min_correspondence_cost_, max_correspondence_cost_); } // Finishes the update sequence. @@ -51,21 +69,14 @@ void Grid2D::FinishUpdate() { } } -// Sets the probability of the cell at 'cell_index' to the given -// 'probability'. Only allowed if the cell was unknown before. -void Grid2D::SetCorrespondenceCost(const Eigen::Array2i& cell_index, - const float correspondence_cost) { - LOG(FATAL) << "Not implemented"; -} - -// Returns the probability of the cell with 'cell_index'. +// Returns the correspondence cost of the cell with 'cell_index'. float Grid2D::GetCorrespondenceCost(const Eigen::Array2i& cell_index) const { if (!limits().Contains(cell_index)) return kMaxCorrespondenceCost; return ValueToCorrespondenceCost( correspondence_cost_cells()[ToFlatIndex(cell_index)]); } -// Returns true if the probability at the specified index is known. +// Returns true if the correspondence cost at the specified index is known. bool Grid2D::IsKnown(const Eigen::Array2i& cell_index) const { return limits_.Contains(cell_index) && correspondence_cost_cells_[ToFlatIndex(cell_index)] != @@ -136,6 +147,8 @@ proto::Grid2D Grid2D::ToProto() const { box->set_min_x(known_cells_box().min().x()); box->set_min_y(known_cells_box().min().y()); } + result.set_min_correspondence_cost(min_correspondence_cost_); + result.set_max_correspondence_cost(max_correspondence_cost_); return result; } diff --git a/cartographer/mapping/2d/grid_2d.h b/cartographer/mapping/2d/grid_2d.h index 2a7df93..530ffef 100644 --- a/cartographer/mapping/2d/grid_2d.h +++ b/cartographer/mapping/2d/grid_2d.h @@ -27,23 +27,24 @@ namespace mapping { class Grid2D { public: - explicit Grid2D(const MapLimits& limits); + explicit Grid2D(const MapLimits& limits, float min_correspondence_cost, + float max_correspondence_cost); explicit Grid2D(const proto::Grid2D& proto); - // Returns the limits of this ProbabilityGrid. + // Returns the limits of this Grid2D. const MapLimits& limits() const { return limits_; } // Finishes the update sequence. void FinishUpdate(); - - // Sets the correspondence cost of the cell at 'cell_index' to the given - // 'correspondence_cost'. Only allowed if the cell was unknown before. - void SetCorrespondenceCost(const Eigen::Array2i& cell_index, - const float correspondence_cost); - // Returns the correspondence cost of the cell with 'cell_index'. float GetCorrespondenceCost(const Eigen::Array2i& cell_index) const; + // Returns the minimum possible correspondence cost. + float GetMinCorrespondenceCost() const { return min_correspondence_cost_; } + + // Returns the maximum possible correspondence cost. + float GetMaxCorrespondenceCost() const { return max_correspondence_cost_; } + // Returns true if the probability at the specified index is known. bool IsKnown(const Eigen::Array2i& cell_index) const; @@ -80,6 +81,8 @@ class Grid2D { private: MapLimits limits_; std::vector correspondence_cost_cells_; + float min_correspondence_cost_; + float max_correspondence_cost_; std::vector update_indices_; // Bounding box of known cells to efficiently compute cropping limits. diff --git a/cartographer/mapping/2d/probability_grid.cc b/cartographer/mapping/2d/probability_grid.cc index cc1ef1c..448eb31 100644 --- a/cartographer/mapping/2d/probability_grid.cc +++ b/cartographer/mapping/2d/probability_grid.cc @@ -22,7 +22,8 @@ namespace cartographer { namespace mapping { -ProbabilityGrid::ProbabilityGrid(const MapLimits& limits) : Grid2D(limits) {} +ProbabilityGrid::ProbabilityGrid(const MapLimits& limits) + : Grid2D(limits, kMinCorrespondenceCost, kMaxCorrespondenceCost) {} ProbabilityGrid::ProbabilityGrid(const proto::Grid2D& proto) : Grid2D(proto) { CHECK(proto.has_probability_grid_2d()); diff --git a/cartographer/mapping/2d/proto/grid_2d.proto b/cartographer/mapping/2d/proto/grid_2d.proto index 62de74f..c6a0e2c 100644 --- a/cartographer/mapping/2d/proto/grid_2d.proto +++ b/cartographer/mapping/2d/proto/grid_2d.proto @@ -35,4 +35,6 @@ message Grid2D { oneof grid { ProbabilityGrid probability_grid_2d = 4; } -} \ No newline at end of file + float min_correspondence_cost = 6; + float max_correspondence_cost = 7; +} diff --git a/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.cc b/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.cc index c6445d0..e7df860 100644 --- a/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.cc +++ b/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.cc @@ -130,7 +130,7 @@ void ConstraintBuilder2D::WhenDone( } void ConstraintBuilder2D::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem( - const SubmapId& submap_id, const ProbabilityGrid* const submap, + const SubmapId& submap_id, const Grid2D* const grid, const std::function& work_item) { if (submap_scan_matchers_[submap_id].fast_correlative_scan_matcher != nullptr) { @@ -139,18 +139,18 @@ void ConstraintBuilder2D::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem( submap_queued_work_items_[submap_id].push_back(work_item); if (submap_queued_work_items_[submap_id].size() == 1) { thread_pool_->Schedule( - [=]() { ConstructSubmapScanMatcher(submap_id, submap); }); + [=]() { ConstructSubmapScanMatcher(submap_id, grid); }); } } } -void ConstraintBuilder2D::ConstructSubmapScanMatcher( - const SubmapId& submap_id, const ProbabilityGrid* const submap) { +void ConstraintBuilder2D::ConstructSubmapScanMatcher(const SubmapId& submap_id, + const Grid2D* const grid) { auto submap_scan_matcher = common::make_unique( - *submap, options_.fast_correlative_scan_matcher_options()); + *grid, options_.fast_correlative_scan_matcher_options()); common::MutexLocker locker(&mutex_); - submap_scan_matchers_[submap_id] = {submap, std::move(submap_scan_matcher)}; + submap_scan_matchers_[submap_id] = {grid, std::move(submap_scan_matcher)}; for (const std::function& work_item : submap_queued_work_items_[submap_id]) { thread_pool_->Schedule(work_item); @@ -227,8 +227,8 @@ void ConstraintBuilder2D::ComputeConstraint( ceres::Solver::Summary unused_summary; ceres_scan_matcher_.Match(pose_estimate.translation(), pose_estimate, constant_data->filtered_gravity_aligned_point_cloud, - *submap_scan_matcher->probability_grid, - &pose_estimate, &unused_summary); + *submap_scan_matcher->grid, &pose_estimate, + &unused_summary); const transform::Rigid2d constraint_transform = ComputeSubmapPose(*submap).inverse() * pose_estimate; diff --git a/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.h b/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.h index 703e1ad..adf315c 100644 --- a/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.h +++ b/cartographer/mapping/internal/2d/pose_graph/constraint_builder_2d.h @@ -105,7 +105,7 @@ class ConstraintBuilder2D { private: struct SubmapScanMatcher { - const ProbabilityGrid* probability_grid; + const Grid2D* grid; std::unique_ptr fast_correlative_scan_matcher; }; @@ -113,12 +113,11 @@ class ConstraintBuilder2D { // Either schedules the 'work_item', or if needed, schedules the scan matcher // construction and queues the 'work_item'. void ScheduleSubmapScanMatcherConstructionAndQueueWorkItem( - const SubmapId& submap_id, const ProbabilityGrid* submap, + const SubmapId& submap_id, const Grid2D* grid, const std::function& work_item) REQUIRES(mutex_); // Constructs the scan matcher for a 'submap', then schedules its work items. - void ConstructSubmapScanMatcher(const SubmapId& submap_id, - const ProbabilityGrid* submap) + void ConstructSubmapScanMatcher(const SubmapId& submap_id, const Grid2D* grid) EXCLUDES(mutex_); // Returns the scan matcher for a submap, which has to exist. diff --git a/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.cc b/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.cc index a2eaeee..d0075a0 100644 --- a/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.cc +++ b/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.cc @@ -25,7 +25,7 @@ #include "Eigen/Geometry" #include "cartographer/common/make_unique.h" #include "cartographer/common/math.h" -#include "cartographer/mapping/2d/probability_grid.h" +#include "cartographer/mapping/2d/grid_2d.h" #include "cartographer/sensor/point_cloud.h" #include "cartographer/transform/transform.h" #include "glog/logging.h" @@ -89,11 +89,13 @@ CreateFastCorrelativeScanMatcherOptions2D( } PrecomputationGrid2D::PrecomputationGrid2D( - const ProbabilityGrid& probability_grid, const CellLimits& limits, - const int width, std::vector* reusable_intermediate_grid) + const Grid2D& grid, const CellLimits& limits, const int width, + std::vector* reusable_intermediate_grid) : offset_(-width + 1, -width + 1), wide_limits_(limits.num_x_cells + width - 1, limits.num_y_cells + width - 1), + min_score_(1.f - grid.GetMaxCorrespondenceCost()), + max_score_(1.f - grid.GetMinCorrespondenceCost()), cells_(wide_limits_.num_x_cells * wide_limits_.num_y_cells) { CHECK_GE(width, 1); CHECK_GE(limits.num_x_cells, 1); @@ -106,26 +108,26 @@ PrecomputationGrid2D::PrecomputationGrid2D( for (int y = 0; y != limits.num_y_cells; ++y) { SlidingWindowMaximum current_values; current_values.AddValue( - probability_grid.GetProbability(Eigen::Array2i(0, y))); + 1.f - std::abs(grid.GetCorrespondenceCost(Eigen::Array2i(0, y)))); for (int x = -width + 1; x != 0; ++x) { intermediate[x + width - 1 + y * stride] = current_values.GetMaximum(); if (x + width < limits.num_x_cells) { - current_values.AddValue( - probability_grid.GetProbability(Eigen::Array2i(x + width, y))); + current_values.AddValue(1.f - std::abs(grid.GetCorrespondenceCost( + Eigen::Array2i(x + width, y)))); } } for (int x = 0; x < limits.num_x_cells - width; ++x) { intermediate[x + width - 1 + y * stride] = current_values.GetMaximum(); current_values.RemoveValue( - probability_grid.GetProbability(Eigen::Array2i(x, y))); - current_values.AddValue( - probability_grid.GetProbability(Eigen::Array2i(x + width, y))); + 1.f - std::abs(grid.GetCorrespondenceCost(Eigen::Array2i(x, y)))); + current_values.AddValue(1.f - std::abs(grid.GetCorrespondenceCost( + Eigen::Array2i(x + width, y)))); } for (int x = std::max(limits.num_x_cells - width, 0); x != limits.num_x_cells; ++x) { intermediate[x + width - 1 + y * stride] = current_values.GetMaximum(); current_values.RemoveValue( - probability_grid.GetProbability(Eigen::Array2i(x, y))); + 1.f - std::abs(grid.GetCorrespondenceCost(Eigen::Array2i(x, y)))); } current_values.CheckIsEmpty(); } @@ -159,38 +161,37 @@ PrecomputationGrid2D::PrecomputationGrid2D( } uint8 PrecomputationGrid2D::ComputeCellValue(const float probability) const { - const int cell_value = - common::RoundToInt((probability - kMinProbability) * - (255.f / (kMaxProbability - kMinProbability))); + const int cell_value = common::RoundToInt( + (probability - min_score_) * (255.f / (max_score_ - min_score_))); CHECK_GE(cell_value, 0); CHECK_LE(cell_value, 255); return cell_value; } PrecomputationGridStack2D::PrecomputationGridStack2D( - const ProbabilityGrid& probability_grid, + const Grid2D& grid, const proto::FastCorrelativeScanMatcherOptions2D& options) { CHECK_GE(options.branch_and_bound_depth(), 1); const int max_width = 1 << (options.branch_and_bound_depth() - 1); precomputation_grids_.reserve(options.branch_and_bound_depth()); std::vector reusable_intermediate_grid; - const CellLimits limits = probability_grid.limits().cell_limits(); + const CellLimits limits = grid.limits().cell_limits(); reusable_intermediate_grid.reserve((limits.num_x_cells + max_width - 1) * limits.num_y_cells); for (int i = 0; i != options.branch_and_bound_depth(); ++i) { const int width = 1 << i; - precomputation_grids_.emplace_back(probability_grid, limits, width, + precomputation_grids_.emplace_back(grid, limits, width, &reusable_intermediate_grid); } } FastCorrelativeScanMatcher2D::FastCorrelativeScanMatcher2D( - const ProbabilityGrid& probability_grid, + const Grid2D& grid, const proto::FastCorrelativeScanMatcherOptions2D& options) : options_(options), - limits_(probability_grid.limits()), - precomputation_grid_stack_(common::make_unique( - probability_grid, options)) {} + limits_(grid.limits()), + precomputation_grid_stack_( + common::make_unique(grid, options)) {} FastCorrelativeScanMatcher2D::~FastCorrelativeScanMatcher2D() {} @@ -324,7 +325,7 @@ void FastCorrelativeScanMatcher2D::ScoreCandidates( xy_index.y() + candidate.y_index_offset); sum += precomputation_grid.GetValue(proposed_xy_index); } - candidate.score = PrecomputationGrid2D::ToProbability( + candidate.score = precomputation_grid.ToScore( sum / static_cast(discrete_scans[candidate.scan_index].size())); } std::sort(candidates->begin(), candidates->end(), diff --git a/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.h b/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.h index 41dae4a..a625df5 100644 --- a/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.h +++ b/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d.h @@ -30,10 +30,9 @@ #include "Eigen/Core" #include "cartographer/common/port.h" -#include "cartographer/mapping/2d/probability_grid.h" +#include "cartographer/mapping/2d/grid_2d.h" #include "cartographer/mapping/2d/scan_matching/proto/fast_correlative_scan_matcher_options_2d.pb.h" #include "cartographer/mapping/internal/2d/scan_matching/correlative_scan_matcher_2d.h" -#include "cartographer/mapping/probability_values.h" #include "cartographer/sensor/point_cloud.h" namespace cartographer { @@ -49,12 +48,11 @@ CreateFastCorrelativeScanMatcherOptions2D( // y0 <= y < y0. class PrecomputationGrid2D { public: - PrecomputationGrid2D(const ProbabilityGrid& probability_grid, - const CellLimits& limits, int width, + PrecomputationGrid2D(const Grid2D& grid, const CellLimits& limits, int width, std::vector* reusable_intermediate_grid); // Returns a value between 0 and 255 to represent probabilities between - // kMinProbability and kMaxProbability. + // min_score and max_score. int GetValue(const Eigen::Array2i& xy_index) const { const Eigen::Array2i local_xy_index = xy_index - offset_; // The static_cast is for performance to check with 2 comparisons @@ -72,10 +70,9 @@ class PrecomputationGrid2D { return cells_[local_xy_index.x() + local_xy_index.y() * stride]; } - // Maps values from [0, 255] to [kMinProbability, kMaxProbability]. - static float ToProbability(float value) { - return kMinProbability + - value * ((kMaxProbability - kMinProbability) / 255.f); + // Maps values from [0, 255] to [min_score, max_score]. + float ToScore(float value) const { + return min_score_ + value * ((max_score_ - min_score_) / 255.f); } private: @@ -88,6 +85,9 @@ class PrecomputationGrid2D { // Size of the precomputation grid. const CellLimits wide_limits_; + const float min_score_; + const float max_score_; + // Probabilites mapped to 0 to 255. std::vector cells_; }; @@ -95,7 +95,7 @@ class PrecomputationGrid2D { class PrecomputationGridStack2D { public: PrecomputationGridStack2D( - const ProbabilityGrid& probability_grid, + const Grid2D& grid, const proto::FastCorrelativeScanMatcherOptions2D& options); const PrecomputationGrid2D& Get(int index) { @@ -112,7 +112,7 @@ class PrecomputationGridStack2D { class FastCorrelativeScanMatcher2D { public: FastCorrelativeScanMatcher2D( - const ProbabilityGrid& probability_grid, + const Grid2D& grid, const proto::FastCorrelativeScanMatcherOptions2D& options); ~FastCorrelativeScanMatcher2D(); @@ -120,7 +120,7 @@ class FastCorrelativeScanMatcher2D { FastCorrelativeScanMatcher2D& operator=(const FastCorrelativeScanMatcher2D&) = delete; - // Aligns 'point_cloud' within the 'probability_grid' given an + // Aligns 'point_cloud' within the 'grid' given an // 'initial_pose_estimate'. If a score above 'min_score' (excluding equality) // is possible, true is returned, and 'score' and 'pose_estimate' are updated // with the result. @@ -128,7 +128,7 @@ class FastCorrelativeScanMatcher2D { const sensor::PointCloud& point_cloud, float min_score, float* score, transform::Rigid2d* pose_estimate) const; - // Aligns 'point_cloud' within the full 'probability_grid', i.e., not + // Aligns 'point_cloud' within the full 'grid', i.e., not // restricted to the configured search window. If a score above 'min_score' // (excluding equality) is possible, true is returned, and 'score' and // 'pose_estimate' are updated with the result. diff --git a/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d_test.cc b/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d_test.cc index 6bc5b29..9a48bbb 100644 --- a/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d_test.cc +++ b/cartographer/mapping/internal/2d/scan_matching/fast_correlative_scan_matcher_2d_test.cc @@ -41,13 +41,17 @@ TEST(PrecomputationGridTest, CorrectValues) { std::uniform_int_distribution distribution(0, 255); ProbabilityGrid probability_grid( MapLimits(0.05, Eigen::Vector2d(5., 5.), CellLimits(250, 250))); + std::vector reusable_intermediate_grid; + PrecomputationGrid2D precomputation_grid_dummy( + probability_grid, probability_grid.limits().cell_limits(), 1, + &reusable_intermediate_grid); for (const Eigen::Array2i& xy_index : XYIndexRangeIterator(Eigen::Array2i(50, 50), Eigen::Array2i(249, 249))) { probability_grid.SetProbability( - xy_index, PrecomputationGrid2D::ToProbability(distribution(prng))); + xy_index, precomputation_grid_dummy.ToScore(distribution(prng))); } - std::vector reusable_intermediate_grid; + reusable_intermediate_grid.clear(); for (const int width : {1, 2, 3, 8}) { PrecomputationGrid2D precomputation_grid( probability_grid, probability_grid.limits().cell_limits(), width, @@ -62,10 +66,10 @@ TEST(PrecomputationGridTest, CorrectValues) { probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y))); } } - EXPECT_NEAR(max_score, - PrecomputationGrid2D::ToProbability( - precomputation_grid.GetValue(xy_index)), - 1e-4); + EXPECT_NEAR( + max_score, + precomputation_grid.ToScore(precomputation_grid.GetValue(xy_index)), + 1e-4); } } } @@ -75,13 +79,17 @@ TEST(PrecomputationGridTest, TinyProbabilityGrid) { std::uniform_int_distribution distribution(0, 255); ProbabilityGrid probability_grid( MapLimits(0.05, Eigen::Vector2d(0.1, 0.1), CellLimits(4, 4))); + std::vector reusable_intermediate_grid; + PrecomputationGrid2D precomputation_grid_dummy( + probability_grid, probability_grid.limits().cell_limits(), 1, + &reusable_intermediate_grid); for (const Eigen::Array2i& xy_index : XYIndexRangeIterator(probability_grid.limits().cell_limits())) { probability_grid.SetProbability( - xy_index, PrecomputationGrid2D::ToProbability(distribution(prng))); + xy_index, precomputation_grid_dummy.ToScore(distribution(prng))); } - std::vector reusable_intermediate_grid; + reusable_intermediate_grid.clear(); for (const int width : {1, 2, 3, 8, 200}) { PrecomputationGrid2D precomputation_grid( probability_grid, probability_grid.limits().cell_limits(), width, @@ -96,10 +104,10 @@ TEST(PrecomputationGridTest, TinyProbabilityGrid) { probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y))); } } - EXPECT_NEAR(max_score, - PrecomputationGrid2D::ToProbability( - precomputation_grid.GetValue(xy_index)), - 1e-4); + EXPECT_NEAR( + max_score, + precomputation_grid.ToScore(precomputation_grid.GetValue(xy_index)), + 1e-4); } } }