Skip to content
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
10 changes: 10 additions & 0 deletions symbolic/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,3 +437,13 @@ func (c K) At(ii, jj int) ScalarExpression {

return c
}

/*
AsSimplifiedExpression
Description:

Returns the simplest form of the expression.
*/
func (c K) AsSimplifiedExpression() Expression {
return c
}
17 changes: 15 additions & 2 deletions symbolic/constant_matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ func (km KMatrix) Minus(e interface{}) Expression {
return km.Minus(DenseToKMatrix(right)) // Reuse KMatrix case
case *mat.Dense:
return km.Minus(*right) // Reuse mat.Dense case
case Expression:
return km.Plus(right.Multiply(-1.0))
}

// If we reach this point, the input is not recognized
Expand Down Expand Up @@ -371,8 +373,8 @@ func (km KMatrix) Multiply(e interface{}) Expression {
case mat.Dense:
// Use *mat.Dense method
return km.Multiply(&right) // Reuse *mat.Dense case
case KMatrix:
return km.Multiply(right.ToDense()) // Reuse *mat.Dense case
case MatrixExpression:
return MatrixMultiplyTemplate(km, right)
}

// If we reach this point, the input is not recognized
Expand Down Expand Up @@ -747,3 +749,14 @@ Description:
func (km KMatrix) Power(exponent int) Expression {
return MatrixPowerTemplate(km, exponent)
}

/*
AsSimplifiedExpression
Description:

Simplifies the constant matrix. Since the constant matrix is always in simplest form,
this function simply returns the original constant matrix.
*/
func (km KMatrix) AsSimplifiedExpression() Expression {
return km
}
10 changes: 10 additions & 0 deletions symbolic/constant_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,3 +665,13 @@ Description:
func (kv KVector) Power(exponent int) Expression {
return VectorPowerTemplate(kv, exponent)
}

/*
AsSimplifiedExpression
Description:

Returns the simplest form of the expression.
*/
func (kv KVector) AsSimplifiedExpression() Expression {
return kv
}
5 changes: 5 additions & 0 deletions symbolic/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ type Expression interface {

// At returns the value at the given row and column index
At(ii, jj int) ScalarExpression

// Simplify simplifies the expression and returns the simplified version
AsSimplifiedExpression() Expression
}

/*
Expand Down Expand Up @@ -294,6 +297,8 @@ func ConcretizeExpression(e interface{}) Expression {
concrete Expression
)
switch concreteVal := e.(type) {
case ScalarExpression:
concrete = concreteVal.AsSimplifiedExpression()
case []ScalarExpression:
concreteVectorE := ConcretizeVectorExpression(concreteVal)
// If vector expression is a scalar (i.e., has 1 row), return the scalar expression
Expand Down
68 changes: 67 additions & 1 deletion symbolic/matrix_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ type MatrixExpression interface {
// Power
// Raises the scalar expression to the power of the input integer
Power(exponent int) Expression

// Simplify simplifies the expression and returns the simplified version
AsSimplifiedExpression() Expression
}

/*
Expand Down Expand Up @@ -190,6 +193,68 @@ func MatrixPowerTemplate(me MatrixExpression, exponent int) MatrixExpression {
return out
}

/*
MatrixMultiplyTemplate
Description:

Template for the matrix multiply function.
*/
func MatrixMultiplyTemplate(left MatrixExpression, right MatrixExpression) Expression {
// Input Processing
err := left.Check()
if err != nil {
panic(err)
}

err = right.Check()
if err != nil {
panic(err)
}

// Check dimensions
leftDims := left.Dims()
rightDims := right.Dims()

if leftDims[1] != rightDims[0] {
panic(
smErrors.MatrixDimensionError{
Arg1: left,
Arg2: right,
Operation: "MatrixMultiplyTemplate",
},
)
}

// Algorithm
var out [][]ScalarExpression
for ii := 0; ii < leftDims[0]; ii++ {
var tempRow []ScalarExpression
for jj := 0; jj < rightDims[1]; jj++ {
// Compute the (ii,jj) element of the product
var sum Expression = K(0.0)
for kk := 0; kk < leftDims[1]; kk++ {
sum = sum.Plus(left.At(ii, kk).Multiply(right.At(kk, jj)))
}
sumAsSE, tf := sum.(ScalarExpression)
if !tf {
panic(
fmt.Errorf(
"unexpected expression type in MatrixMultiplyTemplate at entry [%v,%v]: %T",
ii, jj,
sum,
),
)
}
tempRow = append(tempRow, sumAsSE)
}
out = append(out, tempRow)
}

// Use the general concretization function (not the matrix-specific one)
// because it will also convert matrices to scalars or vectors if needed.
return ConcretizeExpression(out)
}

/*
MatrixSubstituteTemplate
Description:
Expand Down Expand Up @@ -234,6 +299,7 @@ Description:
*/
func ConcretizeMatrixExpression(sliceIn [][]ScalarExpression) MatrixExpression {
// Input Processing
// - Check that the input slice is not empty
if len(sliceIn) == 0 {
panic(
fmt.Errorf(
Expand All @@ -242,7 +308,7 @@ func ConcretizeMatrixExpression(sliceIn [][]ScalarExpression) MatrixExpression {
)
}

// Check the number of columns in each row
// - Check the number of columns in each row is the same
numCols := len(sliceIn[0])
for ii, row := range sliceIn {
if len(row) != numCols {
Expand Down
53 changes: 53 additions & 0 deletions symbolic/monomial.go
Original file line number Diff line number Diff line change
Expand Up @@ -775,3 +775,56 @@ func (m Monomial) At(ii, jj int) ScalarExpression {
// Algorithm
return m
}

/*
AsSimplifiedExpression
Description:

Returns the simplest form of the expression.
- If the monomial contains no variables,
then it is simply the constant coefficient. (return K(m.Coefficient))
- If the monomial coefficient is zero,
then it is simply the constant zero. (return K(0))
- If the monomial contains variables BUT all exponents are zero,
then it is simply the constant zero. (return K(0))
- If the monomial's coefficient is 1.0 and it contains one variable with degree 1,
then it is simply that variable. (return that variable)
- Otherwise, return the monomial itself.
*/
func (m Monomial) AsSimplifiedExpression() Expression {
// Input Processing
err := m.Check()
if err != nil {
panic(err)
}

// Algorithm
// - If the monomial is a constant, return the constant
if m.IsConstant() {
return K(m.Coefficient)
}
// - If the monomial's coefficient is zero, return zero
if m.Coefficient == 0.0 {
return K(0.0)
}
// - If the monomial's coefficient is 1.0 and it contains one variable with degree 1,
// then return that variable
if (m.Coefficient == 1.0) && (len(m.VariableFactors) == 1) && (m.Exponents[0] == 1) {
return m.VariableFactors[0]
}

// - If the monomial contains variables BUT all exponents are zero,
// then return zero
allExponentsZero := true
for _, exp := range m.Exponents {
if exp != 0 {
allExponentsZero = false
break
}
}
if allExponentsZero {
return K(m.Coefficient)
}

return m
}
65 changes: 56 additions & 9 deletions symbolic/monomial_matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,30 +310,42 @@ func (mm MonomialMatrix) Multiply(e interface{}) Expression {
return product
case VariableVector:
if nRows == 1 {
// Output will be a polynomial
var product Polynomial
// Output will be a scalar expression
var product Expression = K(0.0)
for ii, monomial := range mm[0] {
product.Monomials = append(product.Monomials, monomial.Multiply(right[ii]).(Monomial))
product = product.Plus(monomial.Multiply(right[ii]))
}
return product.Simplify()
return ConcretizeExpression(product)

} else {
// Output will be a polynomial matrix
var product PolynomialVector
//TODO: Add thorough tests of this.
var product []ScalarExpression
for _, row := range mm {
product_ii := row[0].ToPolynomial().Multiply(right[0]).(Polynomial)
product_ii := row[0].ToPolynomial().Multiply(right[0])
for jj := 1; jj < len(row); jj++ {
product_ii = product_ii.Plus(
row[jj].ToPolynomial().Multiply(right[jj]),
).(Polynomial)
}
product = append(product, product_ii)
product = product.Simplify()
// Enforce that product_ii is a ScalarExpression
product_iiAsSE, tf := product_ii.(ScalarExpression)
if !tf {
panic(
fmt.Errorf(
"error converting product row to ScalarExpression; got type %T",
product_ii,
),
)
}
product = append(product, product_iiAsSE)
}

return product
return ConcretizeVectorExpression(product)

}
case MatrixExpression:
return MatrixMultiplyTemplate(mm, right)
}

// Unrecognized response is a panic
Expand Down Expand Up @@ -676,3 +688,38 @@ Description:
func (mm MonomialMatrix) Power(exponent int) Expression {
return MatrixPowerTemplate(mm, exponent)
}

/*
AsSimplifiedExpression
Description:

Returns the simplest form of the expression.
*/
func (mm MonomialMatrix) AsSimplifiedExpression() Expression {
// Input Processing
err := mm.Check()
if err != nil {
panic(err)
}

// Create container for simplified matrix
dims := mm.Dims()
nRows, nCols := dims[0], dims[1]
var simplifiedMM [][]ScalarExpression
for ii := 0; ii < nRows; ii++ {
simplifiedRow := make([]ScalarExpression, nCols)
for jj := 0; jj < nCols; jj++ {
simplified := mm[ii][jj].AsSimplifiedExpression()
simplifiedAsSE, tf := simplified.(ScalarExpression)
if !tf {
panic(fmt.Errorf("error simplifying monomial matrix entry %v,%v", ii, jj))
}
// Save the converted simplified expression
simplifiedRow[jj] = simplifiedAsSE
}
simplifiedMM = append(simplifiedMM, simplifiedRow)
}

// Return the simplified matrix
return ConcretizeMatrixExpression(simplifiedMM)
}
28 changes: 28 additions & 0 deletions symbolic/monomial_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -731,3 +731,31 @@ Description:
func (mv MonomialVector) LinearCoeff(wrt ...[]Variable) mat.Dense {
return PolynomialLikeVector_SharedLinearCoeffCalc(mv, wrt...)
}

/*
AsSimplifiedExpression
Description:

Returns the simplest form of the expression.
*/
func (mv MonomialVector) AsSimplifiedExpression() Expression {
// Input Processing
err := mv.Check()
if err != nil {
panic(err)
}

// Simplify each monomial in the vector
var out []ScalarExpression
for ii, monomial := range mv {
simplified := monomial.AsSimplifiedExpression()
simplifiedAsSE, tf := simplified.(ScalarExpression)
if !tf {
panic(fmt.Errorf("error simplifying monomial vector entry %v", ii))
}
// Add the simplified version of the monomial to the output
out = append(out, simplifiedAsSE)
}

return ConcretizeVectorExpression(out)
}
8 changes: 6 additions & 2 deletions symbolic/polynomial.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,10 @@ func (p Polynomial) Simplify() Polynomial {

}

func (p Polynomial) AsSimplifiedExpression() Expression {
return p.Simplify()
}

/*
DerivativeWrt
Description:
Expand Down Expand Up @@ -794,10 +798,10 @@ func (p Polynomial) Substitute(vIn Variable, eIn ScalarExpression) Expression {
var out Expression = K(0.0)
for _, monomial := range p.Monomials {
newMonomial := monomial.Substitute(vIn, eIn)
out = out.Plus(newMonomial).(Polynomial).Simplify()
out = out.Plus(newMonomial)
}

return out
return out.AsSimplifiedExpression()
}

/*
Expand Down
3 changes: 3 additions & 0 deletions symbolic/polynomial_like.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ type PolynomialLike interface {

// At returns the value at the given row and column index
At(ii, jj int) ScalarExpression

// Simplify simplifies the expression and returns the simplified version
AsSimplifiedExpression() Expression
}

/*
Expand Down
Loading