Skip to content

Always populating solution structure#62

Merged
Josh Robbins (jrobbins11) merged 10 commits intomainfrom
feature/populate-opt-solution-fields
Apr 20, 2026
Merged

Always populating solution structure#62
Josh Robbins (jrobbins11) merged 10 commits intomainfrom
feature/populate-opt-solution-fields

Conversation

@jrobbins11
Copy link
Copy Markdown
Contributor

@jrobbins11 Josh Robbins (jrobbins11) commented Apr 20, 2026

  • The OptSolution structure is populated for cases where numerical optimization is not required (e.g., support for zonotopes).
  • Support unit test added verifying that populated zonotope factors are as expected for support calculations.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR ensures OptSolution is consistently populated even for set operations that don’t require numerical optimization (e.g., zonotopes/points/empty set), and adds regression tests to confirm Zono and equivalent ConZono calls return matching support values and factor solutions.

Changes:

  • Populate OptSolution in Zono, Point, and EmptySet operations that previously didn’t fill solution fields.
  • For Zono::support, compute and return the support-achieving factor vector z in the solution struct.
  • Add Python and C++ unit tests comparing Zono vs ConZono support values and returned factors.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Zono.cpp Populates OptSolution for is_empty, bounding_box, and fills z/x/u for support.
src/Point.cpp Populates OptSolution for point operations (optimize_over, project_point, support, contains_point, bounding_box).
src/EmptySet.cpp Ensures OptSolution is allocated and marked infeasible for empty-set operations; marks complement as feasible/converged.
include/zonoopt/Zono.hpp Updates overridden method signatures to include named sol parameter.
include/zonoopt/Point.hpp Updates overridden method signatures to include named sol parameter.
include/zonoopt/EmptySet.hpp Updates overridden method signatures to include named sol parameter (formatting/consistency).
test/python-tests/unit_tests.py Adds a unit test checking Zono vs ConZono support value and solution factor consistency.
test/cpp-tests/src/test_support.cpp Adds a unit test checking Zono vs ConZono support value and solution factor consistency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Zono.cpp
Comment on lines 214 to +233
zono_float h = d.dot(this->c);
const Eigen::Matrix<zono_float, -1, -1> Gd = this->G.toDense();
for (int i = 0; i < this->nG; ++i)
{
h += std::abs(d.dot(Gd.col(i)));
}

// fill in solution struct if requested
if (sol)
{
*sol = std::make_shared<OptSolution>(); // init w/ default fields

// compute factors for support
(*sol)->z.resize(this->nG); // init
for (int i = 0; i < this->nG; ++i)
{
const zono_float dG = d.dot(Gd.col(i));
if (dG > zono_eps)
{
(*sol)->z(i) = one;
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Zono::do_support, when sol is provided the code computes d.dot(Gd.col(i)) twice per generator (once for h and again when filling sol->z). Consider computing G.transpose() * d once and using it to accumulate h and populate z in a single pass (and potentially avoid densifying G).

Copilot uses AI. Check for mistakes.
Comment thread src/Point.cpp Outdated
Comment on lines +52 to +59
if (sol)
{
*sol = std::make_shared<OptSolution>(); // init w/ default fields
(*sol)->infeasible = false;
(*sol)->converged = true;
(*sol)->primal_residual = zero;
(*sol)->dual_residual = zero;
}
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OptSolution initialization block (allocate + set infeasible/converged/primal_residual/dual_residual) is duplicated across multiple Point operations. Consider factoring this into a small helper to reduce duplication and keep the populated fields consistent across methods.

Copilot uses AI. Check for mistakes.
Comment thread src/EmptySet.cpp Outdated
Comment on lines 46 to 53
if (sol)
{
(*solution)->infeasible = true;
*sol = std::make_shared<OptSolution>(); // init w/ default fields
(*sol)->infeasible = true;
(*sol)->converged = false;
(*sol)->primal_residual = std::numeric_limits<zono_float>::infinity();
(*sol)->dual_residual = std::numeric_limits<zono_float>::infinity();
}
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EmptySet now allocates and populates an OptSolution, but the same “infeasible solution” initialization block is repeated in every overridden method. Consider centralizing this into a single helper (e.g., fill_infeasible_solution(std::shared_ptr<OptSolution>* sol)) to reduce duplication and keep the flags/residuals consistent across operations.

Copilot uses AI. Check for mistakes.
@jrobbins11 Josh Robbins (jrobbins11) linked an issue Apr 20, 2026 that may be closed by this pull request
@jrobbins11 Josh Robbins (jrobbins11) merged commit b73b1cd into main Apr 20, 2026
12 checks passed
@jrobbins11 Josh Robbins (jrobbins11) deleted the feature/populate-opt-solution-fields branch April 20, 2026 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Filling OptSolution in zonotope operations

2 participants