highs

package module
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2024 License: BSD-3-Clause Imports: 11 Imported by: 0

README

highs

Go Reference Go project version Go Report Card

Description

The highs package provides a Go interface to the HiGHS constraint-programming solver. HiGHS—and the highs package—support large-scale sparse linear programming (LP), mixed-integer programming (MIP), and quadratic programming (QP) models. The goal of such solvers is to minimize or maximize an expression subject to a set of constraints expressed as inequalities. The basic form such an LP problem in HiGHS takes is as follows:

\begin{array}{ll}
  \text{Find vector}    & x \\
  \text{that minimizes} & c^T x + o \\
  \text{subject to}     & b_L \leq A x \leq b_H \\
  \text{and}            & d_L \leq x \leq d_L
\end{array}

where "minimizes" can alternatively be "maximizes". A MIP problem additionally constrains certain elements of $x$ to be integers, and a QP problem additionally includes an $x^T Q x$ term in the objective function.

A detailed example of formulating a problem with highs is available on the highs wiki.

Installation

highs has been tested only on Linux. The package requires a HiGHS installation to build. To check if HiGHS is installed, ensure that the following command runs without error:

pkg-config highs --cflags --libs

(It will typically output something like -I/usr/include/highs -lhighs.)

Once HiGHS installation is confirmed, the highs package can be installed. From the directory of an application or package that has opted into the Go module system, run

go install github.com/lanl/highs

Documentation

See the highs wiki.

Copyright © 2021 Triad National Security, LLC. All rights reserved.

This program was produced under U.S. Government contract 89233218CNA000001 for Los Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC for the U.S. Department of Energy/National Nuclear Security Administration. All rights in the program are reserved by Triad National Security, LLC, and the U.S. Department of Energy/National Nuclear Security Administration. The Government is granted for itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide license in this material to reproduce, prepare derivative works, distribute copies to the public, perform publicly and display publicly, and to permit others to do so.

This program is open source under the BSD-3 License. Its LANL-internal identifier is C21038.

Contact

Scott Pakin, [email protected]

Documentation

Overview

Package highs provides a Go interface to the HiGHS optimizer. HiGHS—and the highs package—support linear programming (LP), mixed-integer programming (MIP) [also known as mixed-integer linear programming (MILP)], and quadratic programming (QP) models.

The highs package provides both a low-level and a high-level interface to HiGHS. The low-level interface, provided by the RawModel type, includes a rich set of methods that work directly with HiGHS's underlying, opaque data type. The high-level interface, provided by the Model type, is a simple struct whose fields the programmer can modify directly. The Model.ToRawModel method converts from a Model to a RawModel, enabling models to be specified conveniently at a high level then manipulated with the more featureful low-level API.

In terms of the names of fields in Model, the highs package solves numerous variants of the following core problem:

Minimize    ColCosts ⋅ ColumnPrimal
subject to  RowLower ≤ ConstMatrix ColumnPrimal ≤ RowUpper
and         ColLower ≤ ColumnPrimal ≤ ColUpper

where all variables in the above are vectors except for ConstMatrix, which is a matrix. "ColCosts ⋅ ColumnPrimal" denotes the inner product of those two vectors, and "ConstMatrix ColumnPrimal" denotes matrix-vector multiplication.

ColumnPrimal is a member of the Solution struct and is what the preceding formulation is solving for.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NonzerosToCSR

func NonzerosToCSR(nz []Nonzero, tri bool) (start, index []int, value []float64, err error)

NonzerosToCSR is a convenience function that converts a slice of Nonzero values (as used by Model) to compressed sparse row form, i.e., the separate start, index, and value slices used by RawModel's AddCompSparseRows and AddCompSparseHessian methods. Pass true for the second argument to check that the matrix is upper triangular (required for Hessian matrices) or false to ignore that check.

Example

This example demonstrates how to convert the sparse matrix [ 1.1 0.0 0.0 0.0 2.2 ; 0.0 3.3 0.0 4.4 0.0 ; 0.0 0.0 5.5 0.0 0.0 ] (MATLAB syntax) from a list of nonzero elements expressed as {row, column, value} tuples to compressed sparse row format.

package main

import (
	"fmt"

	"github.com/lanl/highs"
)

func main() {
	// Define a matrix in terms of its nonzero elements.
	nz := []highs.Nonzero{
		{0, 0, 1.1},
		{0, 4, 2.2},
		{1, 1, 3.3},
		{1, 3, 4.4},
		{2, 2, 5.5},
	}
	fmt.Println("nz:", nz)

	// Convert nonzeros to compressed sparse row form.
	start, index, value, err := highs.NonzerosToCSR(nz, false)
	if err != nil {
		panic("failed to convert nonzeros to CSR")
	}
	fmt.Println("start:", start)
	fmt.Println("index:", index)
	fmt.Println("value:", value)
}
Output:

nz: [{0 0 1.1} {0 4 2.2} {1 1 3.3} {1 3 4.4} {2 2 5.5}]
start: [0 2 4]
index: [0 4 1 3 2]
value: [1.1 2.2 3.3 4.4 5.5]

Types

type BasisStatus

type BasisStatus int

A BasisStatus represents the basis status of a row or column.

const (
	UnknownBasisStatus BasisStatus = iota
	Lower
	Basic
	Upper
	Zero
	NonBasic
)

These are the values a BasisStatus accepts:

func (BasisStatus) String

func (i BasisStatus) String() string

type CallStatus

type CallStatus struct {
	Status int    // kHighsStatus value
	CName  string // Name of the HiGHS function that returned a non-Ok status
	GoName string // Name of the highs package function that called the CName function
}

A CallStatus wraps a kHighsStatus returned by a call to HiGHS. A CallStatus may be an error or just a warning.

func (CallStatus) Error

func (e CallStatus) Error() string

Error returns a CallStatus as a string.

func (CallStatus) IsWarning

func (e CallStatus) IsWarning() bool

IsWarning returns true if the CallStatus is merely a warning.

type Model

type Model struct {
	Maximize      bool           // true=maximize; false=minimize
	ColCosts      []float64      // Column costs (i.e., the objective function itself)
	Offset        float64        // Objective-function constant offset
	ColLower      []float64      // Column lower bounds
	ColUpper      []float64      // Column upper bounds
	RowLower      []float64      // Row lower bounds
	RowUpper      []float64      // Row upper bounds
	ConstMatrix   []Nonzero      // Sparse constraint matrix (per-row variable coefficients)
	HessianMatrix []Nonzero      // Sparse, upper-triangular matrix of second partial derivatives of quadratic constraints
	VarTypes      []VariableType // Type of each model variable
}

A Model encapsulates all the data needed to express linear-programming models, mixed-integer models, and quadratic-programming models.

func (*Model) AddDenseRow

func (m *Model) AddDenseRow(lb float64, coeffs []float64, ub float64)

AddDenseRow is a convenience function that lets the caller add to the model a single row's lower bound, matrix coefficients (specified densely, but stored sparsely), and upper bound.

Example

The following code adds three rows to a model, each with a lower and upper row bound.

package main

import (
	"fmt"

	"github.com/lanl/highs"
)

func main() {
	var m highs.Model
	m.AddDenseRow(1.0, []float64{1.0, -1.0, 0.0, 0.0}, 2.0) // 1.0 ≤ A − B ≤ 2.0
	m.AddDenseRow(2.0, []float64{0.0, 1.0, -1.0, 0.0}, 4.0) // 2.0 ≤ B − C ≤ 4.0
	m.AddDenseRow(3.0, []float64{0.0, 0.0, 1.0, -1.0}, 8.0) // 3.0 ≤ C − D ≤ 8.0
	fmt.Println("RowLower:", m.RowLower)
	fmt.Println("RowUpper:", m.RowUpper)
	fmt.Println("ConstMatrix:", m.ConstMatrix)
}
Output:

RowLower: [1 2 3]
RowUpper: [2 4 8]
ConstMatrix: [{0 0 1} {0 1 -1} {1 1 1} {1 2 -1} {2 2 1} {2 3 -1}]

func (*Model) Solve

func (m *Model) Solve() (Solution, error)

Solve solves the model as either an LP, MIP, or QP problem, depending on which fields are non-nil.

Example

Here is a complete example of using the highs package's high-level interface to set up a model, solve it, and report the solution. The problem we choose to solve is as follows: What is the maximum total face value of three six-sided dice A, B, and C such that the difference in face value between A and B is exactly twice the difference in face value between B and C, where B is strictly greater than C?

package main

import (
	"fmt"
	"math"

	"github.com/lanl/highs"
)

func main() {
	// Prepare a mixed-integer programming model.
	var m highs.Model
	m.VarTypes = []highs.VariableType{
		highs.IntegerType, // A is an integer.
		highs.IntegerType, // B is an integer.
		highs.IntegerType, // C is an integer.
	}
	m.ColCosts = []float64{1.0, 1.0, 1.0}                      // Objective function is A + B + C.
	m.Maximize = true                                          // Maximize the objective function.
	m.ColLower = []float64{1.0, 1.0, 1.0}                      // A ≥ 1, B ≥ 1, C ≥ 1.
	m.ColUpper = []float64{6.0, 6.0, 6.0}                      // A ≤ 6, B ≤ 6, C ≤ 6.
	m.AddDenseRow(0.0, []float64{1.0, -3.0, 2.0}, 0.0)         // A − B = 2(B − C), expressed as 0 ≤ A − 3B + 2C ≤ 0.
	m.AddDenseRow(1.0, []float64{0.0, 1.0, -1.0}, math.Inf(1)) // B > C, expressed as 1 ≤ B − C ≤ ∞.

	// Find an optimal solution.
	soln, err := m.Solve()
	if err != nil {
		panic(err)
	}

	// Output the A, B, and C that maximize the objective function and the objective value itself.
	fmt.Println("A:", soln.ColumnPrimal[0])
	fmt.Println("B:", soln.ColumnPrimal[1])
	fmt.Println("C:", soln.ColumnPrimal[2])
	fmt.Println("Total face value:", soln.Objective)
}
Output:

A: 6
B: 4
C: 3
Total face value: 13

func (*Model) ToRawModel

func (m *Model) ToRawModel() (*RawModel, error)

ToRawModel converts a high-level model to a low-level model.

type ModelStatus

type ModelStatus int

A ModelStatus represents the status of an attempt to solve a model.

const (
	UnknownModelStatus ModelStatus = iota
	NotSet
	LoadError
	ModelError
	PresolveError
	SolveError
	PostsolveError
	ModelEmpty
	Optimal
	Infeasible
	UnboundedOrInfeasible
	Unbounded
	ObjectiveBound
	ObjectiveTarget
	TimeLimit
	IterationLimit
)

These are the values a ModelStatus accepts:

func (ModelStatus) String

func (i ModelStatus) String() string

type Nonzero

type Nonzero struct {
	Row int
	Col int
	Val float64
}

A Nonzero represents a nonzero entry in a sparse matrix. Rows and columns are indexed from zero.

type RawModel

type RawModel struct {
	// contains filtered or unexported fields
}

A RawModel represents a HiGHS low-level model.

func NewRawModel

func NewRawModel() *RawModel

NewRawModel allocates and returns an empty raw model.

func (*RawModel) AddColumnBounds

func (m *RawModel) AddColumnBounds(lb, ub []float64) error

AddColumnBounds appends to a model's lower and upper column bounds. If the lower-bound argument is nil it is replaced with a slice of negative infinities. If the upper-bound argument is nil, it is replaced with a slice of positive infinities.

func (*RawModel) AddCompSparseHessian

func (m *RawModel) AddCompSparseHessian(start []int, index []int, value []float64) error

AddCompSparseHessian assigns a Hessian in compressed sparse row form to the model. This is used to formulate quadratic constraints in a quadratic-programming model.

func (*RawModel) AddCompSparseRows

func (m *RawModel) AddCompSparseRows(lb []float64, start []int, index []int, value []float64, ub []float64) error

AddCompSparseRows appends compressed sparse rows to the model.

func (*RawModel) AddDenseRow

func (m *RawModel) AddDenseRow(lb float64, coeffs []float64, ub float64) error

AddDenseRow is a convenience function that lets the caller add to the model a single row's lower bound, matrix coefficients (specified densely, but stored sparsely), and upper bound.

func (*RawModel) GetBoolOption

func (m *RawModel) GetBoolOption(opt string) (bool, error)

GetBoolOption returns the Boolean value of a named option.

func (*RawModel) GetFloat64Option

func (m *RawModel) GetFloat64Option(opt string) (float64, error)

GetFloat64Option returns the floating-point value of a named option.

func (*RawModel) GetIntOption

func (m *RawModel) GetIntOption(opt string) (int, error)

GetIntOption returns the Integer value of a named option.

func (*RawModel) GetStringOption

func (m *RawModel) GetStringOption(opt string) (string, error)

GetStringOption returns the string value of a named option. Do not invoke this method in security-sensitive applications because it runs a risk of buffer overflow.

func (*RawModel) ReadModel

func (m *RawModel) ReadModel(r io.Reader) error

ReadModel overwrites the model with a model read in MPS format from an io.Reader.

func (*RawModel) ReadModelFromFile

func (m *RawModel) ReadModelFromFile(fn string) error

ReadModelFromFile overwrites the model with a model read in MPS format from a named file.

func (*RawModel) SetBoolOption

func (m *RawModel) SetBoolOption(opt string, v bool) error

SetBoolOption assigns a Boolean value to a named option.

Example

Low-level models default to writing verbose status messages. SetBoolOption can be used to disable these.

package main

import (
	"github.com/lanl/highs"
)

func main() {
	m := highs.NewRawModel()
	m.SetBoolOption("output_flag", false)
}

func (*RawModel) SetColumnCosts

func (m *RawModel) SetColumnCosts(cs []float64) error

SetColumnCosts specifies a model's column costs (i.e., its objective function).

func (*RawModel) SetFloat64Option

func (m *RawModel) SetFloat64Option(opt string, v float64) error

SetFloat64Option assigns a floating-point value to a named option.

func (*RawModel) SetIntOption

func (m *RawModel) SetIntOption(opt string, v int) error

SetIntOption assigns an integer value to a named option.

func (*RawModel) SetIntegrality

func (m *RawModel) SetIntegrality(ts []VariableType) error

SetIntegrality specifies the type of each column (variable) in the model.

func (*RawModel) SetMaximization

func (m *RawModel) SetMaximization(max bool) error

SetMaximization tells a model to maximize (true) or minimize (false) its objective function.

func (*RawModel) SetOffset

func (m *RawModel) SetOffset(o float64) error

SetOffset specifies a constant offset for the objective function.

func (*RawModel) SetStringOption

func (m *RawModel) SetStringOption(opt string, v string) error

SetStringOption assigns a string value to a named option.

func (*RawModel) Solve

func (m *RawModel) Solve() (*RawSolution, error)

Solve solves a model.

Example

Here is a complete example of using the highs package's low-level interface to set up a model, solve it, and report the solution. The problem we choose to solve is as follows: What is the maximum total face value of three six-sided dice A, B, and C such that the difference in face value between A and B is exactly twice the difference in face value between B and C, where B is strictly greater than C?

Remove the SetBoolOption line to view HiGHS status output.

package main

import (
	"fmt"
	"math"

	"github.com/lanl/highs"
)

func main() {
	// Define a function that panics on error.
	checkErr := func(err error) {
		if err != nil {
			panic(err)
		}
	}

	// Prepare a mixed-integer programming model.  AddColumnBounds adds
	// variables (columns) so it must be called before any of the functions
	// that set column properties.
	m := highs.NewRawModel()
	checkErr(m.SetBoolOption("output_flag", false))
	checkErr(m.AddColumnBounds(
		[]float64{1.0, 1.0, 1.0},  // A ≥ 1, B ≥ 1, C ≥ 1.
		[]float64{6.0, 6.0, 6.0})) // A ≤ 6, B ≤ 6, C ≤ 6.
	checkErr(m.SetIntegrality([]highs.VariableType{
		highs.IntegerType, // A is an integer.
		highs.IntegerType, // B is an integer.
		highs.IntegerType, // C is an integer.
	}))
	checkErr(m.SetColumnCosts([]float64{1.0, 1.0, 1.0})) // Objective function is A + B + C.
	checkErr(m.SetMaximization(true))                    // Maximize the objective function.

	// Represent A − B = 2(B − C) and B > C as the sparse matrix inequality,
	//     ⌈0⌉   ⌈ 1 −3  2 ⌉ ⌈A⌉   ⌈0⌉
	//     | | ≤ |         | |B| ≤ | |
	//     ⌊1⌋   ⌊ 0  1 −1 ⌋ ⌊C⌋   ⌊∞⌋
	checkErr(m.AddCompSparseRows(
		[]float64{0.0, 1.0},
		[]int{0, 3},
		[]int{0, 1, 2, 1, 2},
		[]float64{1.0, -3.0, 2.0, 1.0, -1.0},
		[]float64{0.0, math.Inf(1)}))

	// Find an optimal solution.
	soln, err := m.Solve()
	if err != nil {
		panic(err)
	}

	// Output the A, B, and C that maximize the objective function and the objective value itself.
	fmt.Println("A:", soln.ColumnPrimal[0])
	fmt.Println("B:", soln.ColumnPrimal[1])
	fmt.Println("C:", soln.ColumnPrimal[2])
	fmt.Println("Total face value:", soln.Objective)
}
Output:

A: 6
B: 4
C: 3
Total face value: 13

func (*RawModel) WriteModel

func (m *RawModel) WriteModel(w io.Writer) error

WriteModel writes a model in MPS format to an io.Writer.

func (*RawModel) WriteModelToFile

func (m *RawModel) WriteModelToFile(fn string) error

WriteModelToFile writes a model in MPS format to a named file.

type RawSolution

type RawSolution struct {
	Solution // Values returned by the solver
	// contains filtered or unexported fields
}

A RawSolution encapsulates all the values returned by various HiGHS solvers and provides methods to retrieve additional information.

func (*RawSolution) GetFloat64Info

func (s *RawSolution) GetFloat64Info(info string) (float64, error)

GetFloat64Info returns the floating-point value of a named piece of information.

func (*RawSolution) GetInt64Info

func (s *RawSolution) GetInt64Info(info string) (int64, error)

GetInt64Info returns the 64-bit integer value of a named piece of information.

func (*RawSolution) GetIntInfo

func (s *RawSolution) GetIntInfo(info string) (int, error)

GetIntInfo returns the integer value of a named piece of information.

func (*RawSolution) WriteSolution

func (s *RawSolution) WriteSolution(w io.Writer, pretty bool) error

WriteSolution writes a textual version of the solution to an io.Writer. If the second argument is false, WriteSolutiontoFile will use a more computer-friendly format; if true, it will use a more human-friendly format.

func (*RawSolution) WriteSolutionToFile

func (s *RawSolution) WriteSolutionToFile(fn string, pretty bool) error

WriteSolutionToFile writes a textual version of the solution to a named file. If the second argument is false, WriteSolutiontoFile will use a more computer-friendly format; if true, it will use a more human-friendly format.

type Solution

type Solution struct {
	Status       ModelStatus   // Status of the LP solve
	ColumnPrimal []float64     // Primal column solution
	RowPrimal    []float64     // Primal row solution
	ColumnDual   []float64     // Dual column solution
	RowDual      []float64     // Dual row solution
	ColumnBasis  []BasisStatus // Basis status of each column
	RowBasis     []BasisStatus // Basis status of each row
	Objective    float64       // Objective value
}

A Solution encapsulates all the values returned by any of HiGHS's solvers. Not all fields will be meaningful when returned by any given solver.

type VariableType

type VariableType int

A VariableType indicates the type of a model variable.

const (
	ContinuousType VariableType = iota
	IntegerType
	SemiContinuousType
	SemiIntegerType
	ImplicitIntegerType
)

These are the values a VariableType accepts:

func (VariableType) String

func (i VariableType) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL