Skip to content

Introducing the two stacking functions HStack + VStack #13

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 5 commits into from
Dec 15, 2024
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
68 changes: 68 additions & 0 deletions smErrors/dimension_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,71 @@ func CheckDimensionsInMultiplication(left, right MatrixLike) error {
// If dimensions match, then return nothing.
return nil
}

/*
CheckDimensionsInHStack
Description:

This function checks that the dimensions of the left and right expressions
are compatible for horizontal stacking.
We allow:
- Stacking if the number of rows match
*/
func CheckDimensionsInHStack(sliceToStack ...MatrixLike) error {
// Check that the size of columns in left and right agree
var nRowsInSlice []int
for _, slice := range sliceToStack {
nRowsInSlice = append(nRowsInSlice, slice.Dims()[0])
}

// Check that the number of rows in each slice is the same
for ii := 1; ii < len(nRowsInSlice); ii++ {
// If the number of rows in the slice is not the same as the previous slice,
// then return an error
dimsAreMatched := nRowsInSlice[ii] == nRowsInSlice[ii-1]
if !dimsAreMatched {
return DimensionError{
Operation: "HStack",
Arg1: sliceToStack[ii-1],
Arg2: sliceToStack[ii],
}
}
}

// If dimensions match, then return nothing.
return nil
}

/*
CheckDimensionsInVStack
Description:

This function checks that the dimensions of the left and right expressions
are compatible for vertical stacking.
We allow:
- Stacking if the number of columns match
*/
func CheckDimensionsInVStack(sliceToStack ...MatrixLike) error {
// Check that the size of columns in left and right agree
var nColsInSlice []int
for _, slice := range sliceToStack {
nColsInSlice = append(nColsInSlice, slice.Dims()[1])
}

// Check that the number of rows in each slice is the same
for ii := 1; ii < len(nColsInSlice); ii++ {
// If the number of rows in the slice is not the same as the previous slice,
// then return an error
dimsAreMatched := nColsInSlice[ii] == nColsInSlice[ii-1]
if !dimsAreMatched {
return DimensionError{
Operation: "VStack",
Arg1: sliceToStack[ii-1],
Arg2: sliceToStack[ii],
}
}
}

// If dimensions match, then return nothing.
return nil
}
2 changes: 1 addition & 1 deletion symbolic/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (c K) LinearCoeff(wrt ...[]Variable) mat.VecDense {
// If the user didn't provide any variables, then panic!
// We cannot construct zero length vectors in gonum
panic(
smErrors.EmptyLinearCoeffsError{c},
smErrors.EmptyLinearCoeffsError{Expression: c},
)
}

Expand Down
2 changes: 1 addition & 1 deletion symbolic/constant_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (kv KVector) AtVec(idx int) ScalarExpression {
// Input Processing

// Check to see whether or not the index is valid.
err := smErrors.CheckIndexOnMatrix(idx, 0, mc)
err := smErrors.CheckIndexOnMatrix(idx, 0, kv)
if err != nil {
panic(err)
}
Expand Down
115 changes: 107 additions & 8 deletions symbolic/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"fmt"

"github.com/MatProGo-dev/SymbolicMath.go/smErrors"
"github.com/MatProGo-dev/SymbolicMath.go/symbolic"
)

/*
Expand Down Expand Up @@ -70,7 +69,7 @@
Power(exponent int) Expression

// At returns the value at the given row and column index
At(rowIndex, colIndex, nCols int) symbolic.ScalarExpression
At(ii, jj int) ScalarExpression
}

/*
Expand Down Expand Up @@ -215,18 +214,118 @@
}

// Create the resulting Matrix's shape
var result [][]symbolic.ScalarExpression
var result [][]ScalarExpression
for rowIndex := 0; rowIndex < eIn[0].Dims()[0]; rowIndex++ {
var tempRow []symbolic.ScalarExpression
for stackIndex_ii := 0; stackIndex_ii < len(eIn); stackIndex_ii++ {
nCols_ii := nCols[stackIndex_ii]
var tempRow []ScalarExpression
for stackIndexII := 0; stackIndexII < len(eIn); stackIndexII++ {
nCols_ii := nCols[stackIndexII]
// Add all of the columns from the current expression to the row
for colIndex := 0; colIndex < nCols_ii; colIndex++ {
tempRow = append(tempRow, eIn[stackIndex_ii].At(rowIndex, colIndex, nCols_ii))
tempRow = append(tempRow, eIn[stackIndexII].At(rowIndex, colIndex))
}
}
// Add the row to the result
result = append(result, tempRow)
}

// Return the simplified form of the expression
return symbolic.ConcretizeMatrixExpression(result)
return ConcretizeExpression(result)
}

/*
VStack
Description:

Stacks the input expressions vertically.
*/
func VStack(eIn ...Expression) Expression {
// Input Checking

// Panic if there are 0 expressions in the input
if len(eIn) == 0 {
panic(
fmt.Errorf("VStack: There must be at least one expression in the input; received 0"),
)

Check warning on line 248 in symbolic/expression.go

View check run for this annotation

Codecov / codecov/patch

symbolic/expression.go#L246-L248

Added lines #L246 - L248 were not covered by tests
}

// Check that all the expressions have the same number of columns
var mlSlice []smErrors.MatrixLike // First convert expression slice to matrix like slice
for _, e := range eIn {
mlSlice = append(mlSlice, e)
}

err := smErrors.CheckDimensionsInVStack(mlSlice...)
if err != nil {
panic(err)
}

// Setup

// Create the resulting Matrix's shape
var result [][]ScalarExpression
for stackIndexII := 0; stackIndexII < len(eIn); stackIndexII++ {
// Each row will be made from the rows of the current expression
eII := eIn[stackIndexII]
for rowIndex := 0; rowIndex < eII.Dims()[0]; rowIndex++ {
var tempRow []ScalarExpression
for colIndex := 0; colIndex < eII.Dims()[1]; colIndex++ {
tempRow = append(tempRow, eII.At(rowIndex, colIndex))
}
// Add the row to the result
result = append(result, tempRow)
}
}

// Return the simplified form of the expression
return ConcretizeExpression(result)
}

/*
ConcretizeExpression
Description:

Converts the input expression to a valid type that implements "Expression".
*/
func ConcretizeExpression(e interface{}) Expression {
// Input Processing

// Convert
var (
concrete Expression
)
switch e.(type) {
case []ScalarExpression:
concreteVectorE := ConcretizeVectorExpression(e.([]ScalarExpression))
// If vector expression is a scalar (i.e., has 1 row), return the scalar expression
if concreteVectorE.Dims()[0] == 1 {
concrete = concreteVectorE.At(0, 0)
} else {
concrete = concreteVectorE
}

Check warning on line 304 in symbolic/expression.go

View check run for this annotation

Codecov / codecov/patch

symbolic/expression.go#L297-L304

Added lines #L297 - L304 were not covered by tests

case [][]ScalarExpression:
concreteMatrixE := ConcretizeMatrixExpression(e.([][]ScalarExpression))
// If matrix expression is a scalar (i.e., has 1 row and 1 column), return the scalar expression
switch {
case concreteMatrixE.Dims()[0] == 1 && concreteMatrixE.Dims()[1] == 1: // If the matrix is a scalar
concrete = concreteMatrixE.At(0, 0)

Check warning on line 311 in symbolic/expression.go

View check run for this annotation

Codecov / codecov/patch

symbolic/expression.go#L310-L311

Added lines #L310 - L311 were not covered by tests
case concreteMatrixE.Dims()[1] == 1: // If the matrix is a column vector
interm := make([]ScalarExpression, concreteMatrixE.Dims()[0])
for ii := 0; ii < concreteMatrixE.Dims()[0]; ii++ {
interm[ii] = concreteMatrixE.At(ii, 0)
}
concrete = ConcretizeVectorExpression(interm)
default:
concrete = concreteMatrixE
}
default:
panic(
smErrors.UnsupportedInputError{
FunctionName: "ConcretizeExpression",
Input: e,
},
)

Check warning on line 327 in symbolic/expression.go

View check run for this annotation

Codecov / codecov/patch

symbolic/expression.go#L321-L327

Added lines #L321 - L327 were not covered by tests
}

return concrete
}
3 changes: 2 additions & 1 deletion symbolic/matrix_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package symbolic

import (
"fmt"

"github.com/MatProGo-dev/SymbolicMath.go/smErrors"
"gonum.org/v1/gonum/mat"
)
Expand Down Expand Up @@ -353,7 +354,7 @@ func ConcretizeMatrixExpression(sliceIn [][]ScalarExpression) MatrixExpression {
return out

case isAllVariables:
// Convert to a variable vector
// Convert to a variable matrix
var out VariableMatrix
for _, row_ii := range sliceIn {
var tempRow []Variable
Expand Down
2 changes: 1 addition & 1 deletion symbolic/monomial.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@
}

if len(wrtVars) == 0 {
panic(smErrors.CanNotGetLinearCoeffOfConstantError{m})
panic(smErrors.CanNotGetLinearCoeffOfConstantError{Expression: m})

Check warning on line 401 in symbolic/monomial.go

View check run for this annotation

Codecov / codecov/patch

symbolic/monomial.go#L401

Added line #L401 was not covered by tests
}

// Algorithm
Expand Down
3 changes: 2 additions & 1 deletion symbolic/monomial_matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package symbolic

import (
"fmt"

"github.com/MatProGo-dev/SymbolicMath.go/smErrors"
"gonum.org/v1/gonum/mat"
)
Expand Down Expand Up @@ -35,7 +36,7 @@ Description:
func (mm MonomialMatrix) Check() error {
// Check that the matrix has at least one row
if len(mm) == 0 {
return smErrors.EmptyMatrixError{mm}
return smErrors.EmptyMatrixError{Expression: mm}
}

// Check that the number of columns is the same in each row
Expand Down
2 changes: 1 addition & 1 deletion symbolic/monomial_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Description:
func (mv MonomialVector) Check() error {
// Check that the polynomial has at least one monomial
if len(mv) == 0 {
return smErrors.EmptyVectorError{mv}
return smErrors.EmptyVectorError{Expression: mv}
}

// Check that each of the monomials are well formed
Expand Down
2 changes: 1 addition & 1 deletion symbolic/polynomial.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ func (p Polynomial) LinearCoeff(wrt ...[]Variable) mat.VecDense {

// If there are no variables in the slice, then return a vector of length 1 containing zero.
if len(wrtVars) == 0 {
panic(smErrors.CanNotGetLinearCoeffOfConstantError{p})
panic(smErrors.CanNotGetLinearCoeffOfConstantError{Expression: p})
}

// Algorithm
Expand Down
3 changes: 2 additions & 1 deletion symbolic/polynomial_matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package symbolic

import (
"fmt"

"github.com/MatProGo-dev/SymbolicMath.go/smErrors"
"gonum.org/v1/gonum/mat"
)
Expand Down Expand Up @@ -35,7 +36,7 @@ Description:
func (pm PolynomialMatrix) Check() error {
// Check that the matrix has at least one row
if len(pm) == 0 {
return smErrors.EmptyMatrixError{pm}
return smErrors.EmptyMatrixError{Expression: pm}
}

// Check that the number of columns is the same in each row
Expand Down
2 changes: 1 addition & 1 deletion symbolic/polynomial_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (pv PolynomialVector) LinearCoeff(vSlices ...[]Variable) mat.Dense {

if len(varSlice) == 0 {
panic(
smErrors.CanNotGetLinearCoeffOfConstantError{pv},
smErrors.CanNotGetLinearCoeffOfConstantError{Expression: pv},
)
}

Expand Down
2 changes: 1 addition & 1 deletion symbolic/variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (v Variable) LinearCoeff(wrt ...[]Variable) mat.VecDense {
}

if len(wrtVars) == 0 {
panic(smErrors.CanNotGetLinearCoeffOfConstantError{v})
panic(smErrors.CanNotGetLinearCoeffOfConstantError{Expression: v})
}

// Constants
Expand Down
6 changes: 2 additions & 4 deletions symbolic/variable_matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@
// Algorithm
var variables []Variable
for _, vmRow := range vm {
for _, v := range vmRow {
variables = append(variables, v)
}
variables = append(variables, vmRow...) // Unrolls all of vmRow and appends it to variables
}

return UniqueVars(variables)
Expand Down Expand Up @@ -629,7 +627,7 @@
env = envs[0]
default:
panic(
fmt.Errorf("Too many inputs provided to NewVariableMatrix() method."),
fmt.Errorf("Too many inputs provided to NewVariableMatrix() method"),

Check warning on line 630 in symbolic/variable_matrix.go

View check run for this annotation

Codecov / codecov/patch

symbolic/variable_matrix.go#L630

Added line #L630 was not covered by tests
)
}

Expand Down
Loading
Loading