Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jun 24, 2025

This PR adds the ability to customize solver executable paths through environment variables, addressing the issue where solver names might be different on different platforms or installed in custom locations.

Changes

Environment Variables Added

Each solver now supports customization via environment variables that override the default executable names:

  • RAMS_SOLVER_PATH_CBC - Override path for CBC (defaults to coin.cbc)
  • RAMS_SOLVER_PATH_CLP - Override path for CLP (defaults to clp)
  • RAMS_SOLVER_PATH_CPLEX - Override path for CPLEX (defaults to cplex)
  • RAMS_SOLVER_PATH_GLPK - Override path for GLPK (defaults to glpsol)
  • RAMS_SOLVER_PATH_SCIP - Override path for SCIP (defaults to scip)

Implementation

  • Added solver_executable helper method to the base Solver class that checks for environment variables first, then falls back to defaults
  • Updated all 5 solver classes to use the helper method instead of hardcoded executable names
  • Maintained full backward compatibility - existing code continues to work unchanged

Usage Examples

# Use a custom CBC installation
export RAMS_SOLVER_PATH_CBC=/opt/cbc/bin/cbc

# Use a specific GLPK version
export RAMS_SOLVER_PATH_GLPK=/usr/local/bin/glpsol-4.60
# Code remains unchanged - environment variables are automatically used
m = RAMS::Model.new
m.solver = :cbc  # Will use custom CBC path if RAMS_SOLVER_PATH_CBC is set
solution = m.solve

Testing

  • Added comprehensive test suite (test_solver_paths.rb) with 10 test cases covering all solvers
  • Tests verify both default behavior and custom environment variable usage
  • All existing tests continue to pass, ensuring no regressions

Documentation

  • Updated solver configuration documentation with examples of the new feature
  • Included practical use cases for custom installations and multiple solver versions

The implementation is minimal and surgical, changing only what's necessary to add the requested functionality while preserving all existing behavior.

Fixes #31.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits June 24, 2025 03:16
Co-authored-by: ryanjoneil <6748953+ryanjoneil@users.noreply.github.com>
Co-authored-by: ryanjoneil <6748953+ryanjoneil@users.noreply.github.com>
Copilot AI changed the title [WIP] Make solver paths customization through environment variables Add environment variable customization for solver paths Jun 24, 2025
Copilot AI requested a review from ryanjoneil June 24, 2025 03:18
@ryanjoneil ryanjoneil marked this pull request as ready for review June 24, 2025 03:27
Copilot AI review requested due to automatic review settings June 24, 2025 03:27
@ryanjoneil ryanjoneil merged commit e041b03 into main Jun 24, 2025
2 checks passed
@ryanjoneil ryanjoneil deleted the copilot/fix-31 branch June 24, 2025 03:27
Copy link

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 adds support for customizing solver executable paths via environment variables to handle non-standard installations across platforms.

  • Introduces a solver_executable helper in the base Solver class to fetch paths from env vars with fallbacks.
  • Updates each solver (CBC, CLP, CPLEX, GLPK, SCIP) to use the helper instead of hardcoded names.
  • Adds tests and documentation to cover default and custom solver path configurations.

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/test_solver_paths.rb Added tests for default and custom solver path commands
lib/rams/solvers/solver.rb Introduced solver_executable helper method
lib/rams/solvers/scip.rb Updated SCIP solver to use the helper for the executable name
lib/rams/solvers/glpk.rb Updated GLPK solver to use the helper for the executable name
lib/rams/solvers/cplex.rb Updated CPLEX solver to use the helper for the executable name
lib/rams/solvers/clp.rb Updated CLP solver to use the helper for the executable name
lib/rams/solvers/cbc.rb Updated CBC solver to use the helper for the executable name
docs/03-solver-configuration.md Documented environment variable overrides for solver paths
Comments suppressed due to low confidence (1)

tests/test_solver_paths.rb:30

  • These tests verify only the first element of the command array. Consider adding assertions for the full solver_command output to ensure the rest of the flags and arguments remain correct.
    assert_equal 'coin.cbc', command[0]

def solver_command(_model_file, _solution_path, _args)
raise NotImplementedError
end

Copy link

Copilot AI Jun 24, 2025

Choose a reason for hiding this comment

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

The helper method solver_executable is currently public. Consider moving it under a private section so it isn’t exposed as part of the public API.

Suggested change
private
def write_model_file(model)
model_file = Tempfile.new ['', '.lp']
model_file.write model.to_lp
model_file.close
model_file
end
def get_solution(model, model_path)
solution_path = model_path + '.sol'
begin
solve_and_parse model, model_path, solution_path
ensure
File.delete(solution_path) if File.exist?(solution_path)
end
end
def solve_and_parse(model, model_path, solution_path)
call_solver model, model_path, solution_path
return RAMS::Solution.new(:unknown, nil, {}, {}) unless File.exist? solution_path
parse_solution model, File.read(solution_path)
end
# rubocop:disable MethodLength
def call_solver(model, model_path, solution_path)
command = solver_command(model_path, solution_path, model.args)
_, stdout, stderr, exit_code = Open3.popen3(*command)
begin
output = stdout.gets(nil) || ''
error = output + (stderr.gets(nil) || '')
puts output if model.verbose && output != ''
raise error unless exit_code.value == 0
return output
ensure
stdout.close
stderr.close
end
end
# rubocop:enable MethodLength
def solver_command(_model_file, _solution_path, _args)
raise NotImplementedError
end

Copilot uses AI. Check for mistakes.
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.

Make solver paths customization through environment variables

2 participants