Codegen Optimizer API This patch adds the classes Optimizer and OptimizationPass, which define the core API of the codegen optimization. A single (trivial) optimization is added that removes NOP expressions from a graph. Change-Id: I0430d6ffc61a474f997475ff787a81a9c69cfe23
diff --git a/include/ceres/codegen/internal/eliminate_nops.h b/include/ceres/codegen/internal/eliminate_nops.h new file mode 100644 index 0000000..864aa0c --- /dev/null +++ b/include/ceres/codegen/internal/eliminate_nops.h
@@ -0,0 +1,67 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2020 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: darius.rueckert@fau.de (Darius Rueckert) +// +#ifndef CERES_PUBLIC_CODEGEN_INTERNAL_ELIMINATE_NOPS_H_ +#define CERES_PUBLIC_CODEGEN_INTERNAL_ELIMINATE_NOPS_H_ + +#include "ceres/codegen/internal/expression_graph.h" +#include "ceres/codegen/internal/optimization_pass_summary.h" + +namespace ceres { +namespace internal { + +// [OptimizationPass] NOP Cleanup +// +// Short Description: +// Removes all expression with type==ExpressionType::NOP. +// +// Description: +// Removing an expression not at the end requires reindexing of all later +// expressions. Therefore, other optimization passes replace expression with +// NOP instead of removing them. This optimization pass removes all NOPs back +// to front. +// The returned value is equal to the number of removed NOPs. +// +// Example: +// v_0 = 1; +// // NOP +// v_2 = 2; +// v_3 = v_0 + v_2 +// Transforms to: +// v_0 = 1; +// v_1 = 2; +// v_2 = v_0 + v_1; + +OptimizationPassSummary EliminateNops(ExpressionGraph* graph); + +} // namespace internal +} // namespace ceres + +#endif // CERES_PUBLIC_CODEGEN_INTERNAL_ELIMINATE_NOPS_H_
diff --git a/include/ceres/codegen/internal/optimization_pass_summary.h b/include/ceres/codegen/internal/optimization_pass_summary.h new file mode 100644 index 0000000..1e376af --- /dev/null +++ b/include/ceres/codegen/internal/optimization_pass_summary.h
@@ -0,0 +1,51 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2020 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: darius.rueckert@fau.de (Darius Rueckert) +// +#ifndef CERES_PUBLIC_CODEGEN_INTERNAL_OPTIMIZATION_PASS_SUMMARY_H_ +#define CERES_PUBLIC_CODEGEN_INTERNAL_OPTIMIZATION_PASS_SUMMARY_H_ + +#include <string> + +namespace ceres { +namespace internal { + +struct OptimizationPassSummary { + bool expression_graph_changed = false; + std::string optimization_pass_name; + int num_expressions_replaced_by_nop = 0; + int num_expressions_removed = 0; + int num_expressions_inserted = 0; + int num_expressions_modified = 0; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_PUBLIC_CODEGEN_INTERNAL_OPTIMIZATION_PASS_SUMMARY_H_
diff --git a/include/ceres/codegen/internal/optimize_expression_graph.h b/include/ceres/codegen/internal/optimize_expression_graph.h new file mode 100644 index 0000000..8e06e8b --- /dev/null +++ b/include/ceres/codegen/internal/optimize_expression_graph.h
@@ -0,0 +1,74 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2020 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: darius.rueckert@fau.de (Darius Rueckert) +// +#ifndef CERES_PUBLIC_CODEGEN_INTERNAL_OPTIMIZE_EXPRESSION_GRAPH_H_ +#define CERES_PUBLIC_CODEGEN_INTERNAL_OPTIMIZE_EXPRESSION_GRAPH_H_ + +#include <memory> +#include <vector> + +#include "ceres/codegen/internal/expression_graph.h" +#include "ceres/codegen/internal/optimization_pass_summary.h" + +namespace ceres { +namespace internal { + +struct OptimizeExpressionGraphOptions { + int max_num_iterations = 100; + bool eliminate_nops = true; +}; + +struct OptimizeExpressionGraphSummary { + int num_iterations; + std::vector<OptimizationPassSummary> summaries; +}; + +// Optimize the given ExpressionGraph in-place according to the defined +// OptimizeExpressionGraphOptions. This will change the ExpressionGraph, but the +// generated code will output the same numerical values. +// +// The Optimization iteratively applies all OptimizationPasses until the graph +// does not change anymore or max_num_iterations is reached. Pseudo Code: +// +// for(int it = 0; it < max_num_iterations; ++it) { +// graph.hasChanged = false; +// for each pass in OptimizationPasses +// pass.applyTo(graph) +// if(!graph.hasChanged) +// break; +// } +// +OptimizeExpressionGraphSummary OptimizeExpressionGraph( + const OptimizeExpressionGraphOptions& options, ExpressionGraph* graph); + +} // namespace internal +} // namespace ceres + +#endif // CERES_PUBLIC_CODEGEN_INTERNAL_OPTIMIZE_EXPRESSION_GRAPH_H_
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt index 020a183..1611870 100644 --- a/internal/ceres/CMakeLists.txt +++ b/internal/ceres/CMakeLists.txt
@@ -154,6 +154,8 @@ expression.cc expression_graph.cc expression_ref.cc + codegen/optimize_expression_graph.cc + codegen/eliminate_nops.cc ) list(APPEND CERES_INTERNAL_SRC ${CERES_CODEGEN_SRC}) endif(CODE_GENERATION)
diff --git a/internal/ceres/codegen/CMakeLists.txt b/internal/ceres/codegen/CMakeLists.txt index 7362aef..db21f9c 100644 --- a/internal/ceres/codegen/CMakeLists.txt +++ b/internal/ceres/codegen/CMakeLists.txt
@@ -53,5 +53,6 @@ ceres_test(expression_graph) ceres_test(expression_ref) ceres_test(code_generator) + ceres_test(eliminate_nops) set(CMAKE_CXX_FLAGS ${CXX_FLAGS_OLD}) endif()
diff --git a/internal/ceres/codegen/eliminate_nops.cc b/internal/ceres/codegen/eliminate_nops.cc new file mode 100644 index 0000000..f94a873 --- /dev/null +++ b/internal/ceres/codegen/eliminate_nops.cc
@@ -0,0 +1,55 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2019 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: darius.rueckert@fau.de (Darius Rueckert) + +#include "ceres/codegen/internal/eliminate_nops.h" + +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +OptimizationPassSummary EliminateNops(ExpressionGraph* graph) { + OptimizationPassSummary summary; + + for (ExpressionId id = 0; id < graph->Size(); ++id) { + Expression& expr = graph->ExpressionForId(id); + + if (expr.type() == ExpressionType::NOP) { + graph->Erase(id); + id--; + summary.expression_graph_changed = true; + summary.num_expressions_removed++; + } + } + return summary; +} + +} // namespace internal +} // namespace ceres
diff --git a/internal/ceres/codegen/eliminate_nops_test.cc b/internal/ceres/codegen/eliminate_nops_test.cc new file mode 100644 index 0000000..4b196b1 --- /dev/null +++ b/internal/ceres/codegen/eliminate_nops_test.cc
@@ -0,0 +1,110 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2020 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: darius.rueckert@fau.de (Darius Rueckert) +// +#define CERES_CODEGEN + +#include "ceres/codegen/internal/eliminate_nops.h" + +#include "ceres/codegen/internal/code_generator.h" +#include "ceres/codegen/internal/expression_graph.h" +#include "ceres/codegen/internal/expression_ref.h" +#include "gtest/gtest.h" + +namespace ceres { +namespace internal { + +using T = ExpressionRef; + +TEST(EliminateNops, SimpleLinear) { + StartRecordingExpressions(); + { + T a = T(0); + // The Expression default constructor creates a NOP. + AddExpressionToGraph(Expression()); + AddExpressionToGraph(Expression()); + T b = T(2); + AddExpressionToGraph(Expression()); + MakeOutput(b, "residual[0]"); + AddExpressionToGraph(Expression()); + } + auto graph = StopRecordingExpressions(); + + StartRecordingExpressions(); + { + T a = T(0); + T b = T(2); + MakeOutput(b, "residual[0]"); + } + auto reference = StopRecordingExpressions(); + + auto summary = EliminateNops(&graph); + EXPECT_TRUE(summary.expression_graph_changed); + EXPECT_EQ(graph, reference); +} + +TEST(EliminateNops, Branches) { + StartRecordingExpressions(); + { + T a = T(0); + // The Expression default constructor creates a NOP. + AddExpressionToGraph(Expression()); + AddExpressionToGraph(Expression()); + T b = T(2); + CERES_IF(a < b) { + AddExpressionToGraph(Expression()); + T c = T(3); + } + CERES_ELSE { + AddExpressionToGraph(Expression()); + MakeOutput(b, "residual[0]"); + AddExpressionToGraph(Expression()); + } + CERES_ENDIF + AddExpressionToGraph(Expression()); + } + auto graph = StopRecordingExpressions(); + + StartRecordingExpressions(); + { + T a = T(0); + T b = T(2); + CERES_IF(a < b) { T c = T(3); } + CERES_ELSE { MakeOutput(b, "residual[0]"); } + CERES_ENDIF + } + auto reference = StopRecordingExpressions(); + + auto summary = EliminateNops(&graph); + EXPECT_TRUE(summary.expression_graph_changed); + EXPECT_EQ(graph, reference); +} + +} // namespace internal +} // namespace ceres
diff --git a/internal/ceres/codegen/optimize_expression_graph.cc b/internal/ceres/codegen/optimize_expression_graph.cc new file mode 100644 index 0000000..5414dc6 --- /dev/null +++ b/internal/ceres/codegen/optimize_expression_graph.cc
@@ -0,0 +1,60 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2019 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: darius.rueckert@fau.de (Darius Rueckert) + +#include "ceres/codegen/internal/optimize_expression_graph.h" + +#include "ceres/codegen/internal/eliminate_nops.h" +#include "glog/logging.h" +namespace ceres { +namespace internal { + +OptimizeExpressionGraphSummary OptimizeExpressionGraph( + const OptimizeExpressionGraphOptions& options, ExpressionGraph* graph) { + OptimizeExpressionGraphSummary summary; + summary.num_iterations = 0; + while (summary.num_iterations < options.max_num_iterations) { + summary.num_iterations++; + bool changed = false; + + if (options.eliminate_nops) { + auto pass_summary = EliminateNops(graph); + changed |= pass_summary.expression_graph_changed; + summary.summaries.push_back(pass_summary); + } + + if (!changed) { + break; + } + } + return summary; +} + +} // namespace internal +} // namespace ceres