Skip to content

Creating Functions for Easily Computing the Linear Constraint Representation Matrices #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions smErrors/equality_constraint_required.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package smErrors

type EqualityConstraintRequiredError struct {
Operation string
}

func (e EqualityConstraintRequiredError) Error() string {
return "Equality constraint required for operation: " + e.Operation
}
9 changes: 9 additions & 0 deletions smErrors/inequality_constraint_required.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package smErrors

type InequalityConstraintRequiredError struct {
Operation string
}

func (icre InequalityConstraintRequiredError) Error() string {
return "Inequality constraint required for operation: " + icre.Operation
}
16 changes: 16 additions & 0 deletions smErrors/linear_expression_required.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package smErrors

import "fmt"

type LinearExpressionRequiredError struct {
Operation string
Expression interface{}
}

func (lere LinearExpressionRequiredError) Error() string {
return fmt.Sprintf(
"Linear expression required for operation %v; received an expression which is not linear (%T).",
lere.Operation,
lere.Expression,
)
}
48 changes: 39 additions & 9 deletions smErrors/dimension_error.go → smErrors/matrix_dimension_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@
*/

/*
DimensionError
MatrixDimensionError
Description:

This error is thrown when two matrices do not have the appropriate dimensions
for a given operation.
*/
type DimensionError struct {
type MatrixDimensionError struct {
Arg1 MatrixLike
Arg2 MatrixLike
Operation string // Either multiply or Plus
}

func (de DimensionError) Error() string {
func (de MatrixDimensionError) Error() string {
dimStrings := de.ArgDimsAsStrings()
return fmt.Sprintf(
"dimension error: Cannot perform %v between expression of dimension %v and expression of dimension %v",
Expand All @@ -28,7 +31,7 @@
)
}

func (de DimensionError) ArgDimsAsStrings() []string {
func (de MatrixDimensionError) ArgDimsAsStrings() []string {
// Create string for arg 1
arg1DimsAsString := "("
for ii, dimValue := range de.Arg1.Dims() {
Expand Down Expand Up @@ -60,7 +63,7 @@
dimsAreMatched = dimsAreMatched || IsScalarExpression(right)

if !dimsAreMatched {
return DimensionError{
return MatrixDimensionError{
Operation: "Plus",
Arg1: left,
Arg2: right,
Expand All @@ -83,7 +86,7 @@
dimsAreMatched = dimsAreMatched || IsScalarExpression(right)

if !dimsAreMatched {
return DimensionError{
return MatrixDimensionError{
Operation: "Minus",
Arg1: left,
Arg2: right,
Expand Down Expand Up @@ -116,7 +119,7 @@
// Check that the # of columns in left
// matches the # of rows in right
if !multiplicationIsAllowed {
return DimensionError{
return MatrixDimensionError{
Operation: "Multiply",
Arg1: left,
Arg2: right,
Expand Down Expand Up @@ -148,7 +151,7 @@
// then return an error
dimsAreMatched := nRowsInSlice[ii] == nRowsInSlice[ii-1]
if !dimsAreMatched {
return DimensionError{
return MatrixDimensionError{
Operation: "HStack",
Arg1: sliceToStack[ii-1],
Arg2: sliceToStack[ii],
Expand Down Expand Up @@ -182,7 +185,7 @@
// then return an error
dimsAreMatched := nColsInSlice[ii] == nColsInSlice[ii-1]
if !dimsAreMatched {
return DimensionError{
return MatrixDimensionError{
Operation: "VStack",
Arg1: sliceToStack[ii-1],
Arg2: sliceToStack[ii],
Expand All @@ -193,3 +196,30 @@
// If dimensions match, then return nothing.
return nil
}

func CheckDimensionsInComparison(arg1, arg2 MatrixLike, comparisonType string) error {
dimsAreMatched := (arg1.Dims()[0] == arg2.Dims()[0]) && (arg1.Dims()[1] == arg2.Dims()[1])
dimsAreMatched = dimsAreMatched || IsScalarExpression(arg1)
dimsAreMatched = dimsAreMatched || IsScalarExpression(arg2)

if !dimsAreMatched {
// Return a specific type of error based on if this was a vector comparison
// or a matrix comparison
bothAreVectors := (arg1.Dims()[1] == 1) && (arg2.Dims()[1] == 1)
if bothAreVectors {
return VectorDimensionError{
Operation: fmt.Sprintf("Comparison (%v)", string(comparisonType)),
Arg1: arg1.(VectorLike),
Arg2: arg2.(VectorLike),
}
} else {
return MatrixDimensionError{
Operation: string(comparisonType),
Arg1: arg1,
Arg2: arg2,
}
}

Check warning on line 221 in smErrors/matrix_dimension_error.go

View check run for this annotation

Codecov / codecov/patch

smErrors/matrix_dimension_error.go#L216-L221

Added lines #L216 - L221 were not covered by tests
}

return nil
}
25 changes: 25 additions & 0 deletions smErrors/vector_dimension_error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package smErrors

import "fmt"

/*
VectorDimensionError
Description:

This error is thrown when two matrices do not have the appropriate dimensions
for a given operation.
*/
type VectorDimensionError struct {
Arg1 VectorLike
Arg2 VectorLike
Operation string
}

func (de VectorDimensionError) Error() string {
return fmt.Sprintf(
"vector dimension error: Cannot perform %v between expression of dimension %v and expression of dimension %v",
de.Operation,
de.Arg1.Len(),
de.Arg2.Len(),
)
}
12 changes: 12 additions & 0 deletions smErrors/vector_like.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package smErrors

/*
VectorLike
Description:

An interface for all objects that can be treated as vectors.
*/
type VectorLike interface {
Len() int
Dims() []int
}
23 changes: 13 additions & 10 deletions symbolic/constant_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@ func (kv KVector) Minus(e interface{}) Expression {
return kv.Minus(VecDenseToKVector(right)) // Convert to KVector
case *mat.VecDense:
return kv.Minus(VecDenseToKVector(*right)) // Convert to KVector
case KVector, VariableVector, MonomialVector, PolynomialVector:
// Force the right hand side to be a VectorExpression
rhsAsVE := right.(VectorExpression)

// Compute Subtraction using our Multiply method
return kv.Plus(
rhsAsVE.Multiply(-1.0),
)
}

// Default response is a panic
Expand Down Expand Up @@ -297,14 +305,6 @@ func (kv KVector) Comparison(rightIn interface{}, sense ConstrSense) Constraint
}

switch rhsConverted := rightIn.(type) {
case KVector:
// Return constraint
return VectorConstraint{
LeftHandSide: kv,
RightHandSide: rhsConverted,
Sense: sense,
}

case mat.VecDense:
// Use KVector's Comparison method
return kv.Comparison(VecDenseToKVector(rhsConverted), sense)
Expand All @@ -313,11 +313,14 @@ func (kv KVector) Comparison(rightIn interface{}, sense ConstrSense) Constraint
// Use KVector's Comparison method
return kv.Comparison(VecDenseToKVector(*rhsConverted), sense)

case VariableVector:
case KVector, VariableVector, MonomialVector, PolynomialVector:
// Pass the rhsConverted object into a container marked as a "VectorExpression" interface
rhsAsVE := rhsConverted.(VectorExpression)

// Return constraint
return VectorConstraint{
LeftHandSide: kv,
RightHandSide: rhsConverted,
RightHandSide: rhsAsVE,
Sense: sense,
}

Expand Down
2 changes: 1 addition & 1 deletion symbolic/polynomial.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ func (p Polynomial) Multiply(e interface{}) Expression {
// Multiply each monomial of the polynomial by the polynomial
var productOut Expression = K(0.0)
for ii := 0; ii < len(right.Monomials); ii++ {
fmt.Println(fmt.Sprintf("pCopy.Multiply(right.Monomials[ii]): %v", pCopy.Multiply(right.Monomials[ii])))
// fmt.Println(fmt.Sprintf("pCopy.Multiply(right.Monomials[ii]): %v", pCopy.Multiply(right.Monomials[ii])))
productOut = productOut.Plus(
pCopy.Multiply(right.Monomials[ii]),
)
Expand Down
24 changes: 24 additions & 0 deletions symbolic/polynomial_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,14 @@ func (pv PolynomialVector) Plus(e interface{}) Expression {
pvCopy[ii] = sum.(Polynomial)
}
return pvCopy
case Variable:
pvCopy := pv
for ii, polynomial := range pv {
sum := polynomial.Plus(right)
pvCopy[ii] = sum.(Polynomial)
}
return pvCopy

case Polynomial:
pvCopy := pv

Expand Down Expand Up @@ -417,6 +425,22 @@ func (pv PolynomialVector) Comparison(e interface{}, senseIn ConstrSense) Constr
// Expression: pv.Plus(right.Multiply(K(-1))),
// Sense: senseIn,
// }
case *mat.VecDense:
// Convert the vector to a KVector
tempKVector := VecDenseToKVector(*right)
return VectorConstraint{
LeftHandSide: pv,
RightHandSide: tempKVector,
Sense: senseIn,
}
case mat.VecDense:
// Convert the vector to a KVector
tempKVector := VecDenseToKVector(right)
return VectorConstraint{
LeftHandSide: pv,
RightHandSide: tempKVector,
Sense: senseIn,
}
case KVector, VariableVector, MonomialVector, PolynomialVector:
rightAsVE, _ := ToVectorExpression(right)
return VectorConstraint{
Expand Down
Loading