├── LICENSE ├── README.md └── src ├── algebra.maude ├── assumptions.maude ├── compute.maude ├── lib ├── gen-tree.maude └── list-cons.maude ├── simplify-sys.maude ├── simplify.maude └── tests ├── algebra.test.maude ├── assumptions.test.maude ├── simplify-sys.test.maude └── simplify.test.maude /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Matthew Rocklin 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Matrix Algebra 2 | ============== 3 | 4 | A small language for Matrix Expressions written in Maude. 5 | 6 | Code 7 | ==== 8 | 9 | `algebra.maude` 10 | --------------- 11 | 12 | defines an algebra for matrix expressions, i.e. 13 | 14 | transpose(Y X) Y + A B 15 | 16 | This language includes multiplies, adds, backsolves, transposes, and inverses 17 | 18 | `assumptions.maude` 19 | ------------------- 20 | 21 | defines rules for predicates like 22 | 23 | X is symmetric , Y is orthogonal 24 | 25 | We group these predicates into contexts (here called Facts) and declare rules 26 | like the following 27 | 28 | ceq Facts => X Y is invertible = true if Facts => X is invertible 29 | and Facts => Y is invertible . 30 | 31 | We include predicates like symmetric, orthogonal, invertible, singular, 32 | positive-definite, triangular, diagonal, etc.... 33 | If you are interested it is very easy to add more. The existing code should 34 | provide enough examples. 35 | 36 | `simplify.maude` 37 | ---------------- 38 | 39 | combines these two and includes simplification rules like 40 | 41 | ceq simplify(X transpose(X) with Facts) = I with Facts 42 | if Facts => X is orthogonal . 43 | 44 | Other than a few Maude keywords (like `ceq`) this code is intended to look like 45 | mathematical statements. This allows for easy extensibility (you can contribute 46 | to this project without knowing Maude) and for easy verifiability (the code is 47 | clear.) 48 | 49 | `simplify-sys.maude` contains simplification rules that include branching 50 | paths. I.e. for `X Y Z` there are two ways in which we could group terms 51 | `(X Y) Z` or `X (Y Z)`. This requires a search mechanism rather than 52 | straightforward equational rewriting. 53 | 54 | rl [right] : simplify(X (Y Z) with C) 55 | => simplify(X with C) simplify(Y Z with C) .` 56 | 57 | rl [left] : simplify(X (Y Z) with C) 58 | => simplify(X Y with C) simplify(Z with C) . 59 | 60 | As a result of all of this we can perform simplifications like the following 61 | 62 | Example 63 | ------- 64 | simplify(transpose(Y X) Y + A B with X is symmetric , Y is orthogonal) 65 | 66 | reduces to 67 | 68 | X + A B with X is symmetric 69 | 70 | Tests 71 | ----- 72 | 73 | The `src/tests` directory contains a number of examples that are used to verify 74 | the correctness of this code. It is a good place to start. 75 | 76 | After you have Maude installed you may run the tests as follows 77 | 78 | maude src/tests/*.maude 79 | 80 | Install 81 | ======= 82 | 83 | You can clone this repository with 84 | 85 | $ git clone git://github.com/mrocklin/matrix-algebra.git 86 | 87 | You will need the [Maude system](http://maude.cs.uiuc.edu/) which is available by apt using 88 | 89 | $ sudo apt-get install maude 90 | 91 | 92 | Author 93 | ====== 94 | 95 | [Matthew Rocklin](http://matthewrocklin.com/) 96 | 97 | This code is under a BSD style license (see LICENSE in this directory.) 98 | 99 | Future 100 | ====== 101 | 102 | There is a file, `compute.maude`, which is the starting point to translate 103 | matrix expressions into BLAS calls. The goal of this project is to wrap and 104 | isolate the complexity of the BLAS and LAPACK libraries so that users can write 105 | `A x with A is symmetric , x is vector` and have the correct `SYMV` call 106 | written for them. Additionally, using the search mechanism in Maude it should 107 | be possible to consider more complex expressions / contexts and select optimal 108 | computation strategies. This is a work in progress. 109 | -------------------------------------------------------------------------------- /src/algebra.maude: -------------------------------------------------------------------------------- 1 | fmod MATRIX-ALGEBRA is 2 | 3 | protecting INT . 4 | protecting FLOAT . 5 | protecting BOOL . 6 | protecting TRUTH-VALUE . 7 | protecting QID . 8 | sorts MatrixExpr MatrixSymbol Vector RowVector . 9 | subsort Vector RowVector MatrixSymbol < MatrixExpr . 10 | 11 | vars n m a b : Int . 12 | vars alpha beta : Float . 13 | 14 | vars A B C X Y : MatrixExpr . 15 | var S : MatrixSymbol . 16 | var M : Qid . 17 | 18 | *** Vector sorts are conditional 19 | cmb A : Vector if (cols(A) == 1) . 20 | cmb A : RowVector if (rows(A) == 1) . 21 | 22 | *** MATRIX OPERATIONS 23 | ops I Zero : -> MatrixSymbol . 24 | op matrix : Qid Pair -> MatrixSymbol . 25 | 26 | op _+_ : MatrixExpr MatrixExpr -> MatrixExpr [ctor assoc comm prec 30] . 27 | op __ : MatrixExpr MatrixExpr -> MatrixExpr [ctor assoc prec 25] . 28 | op __ : Float MatrixExpr -> MatrixExpr [ctor left id: 1.0 prec 25] . 29 | op __ : Float Float -> Float [ctor assoc comm prec 25] . 30 | op _\_ : MatrixExpr MatrixExpr -> MatrixExpr [ctor assoc prec 25] . 31 | 32 | op transpose : MatrixExpr -> MatrixExpr [ctor] . 33 | 34 | op inverse : MatrixExpr -> MatrixExpr [ctor] . 35 | 36 | eq A (B + C) = (A B) + (A C) [metadata "Distributive Law"] . 37 | 38 | eq alpha beta = alpha * beta [metadata "Rely on mul defined in FLOAT"] . 39 | ceq X (alpha Y) = alpha (X Y) if alpha =/= 1.0 [metadata "Scalars to Front"] . 40 | 41 | eq transpose(transpose(A)) = A . 42 | ceq transpose(alpha A) = alpha transpose(A) if alpha =/= 1.0 . 43 | *** eq transpose(A B) = transpose(B) transpose(A) . 44 | *** eq transpose(A + B) = transpose(A) + transpose(B) . 45 | 46 | eq inverse(inverse(A)) = A . 47 | eq inverse(A) A = I . 48 | eq A inverse(A) = I . 49 | eq I \ X = X . 50 | eq I A = A . 51 | eq A I = A . 52 | 53 | *** SHAPE 54 | sort Pair . 55 | op _by_ : Int Int -> Pair [ctor prec 15]. 56 | op first : Pair -> Int . 57 | op second : Pair -> Int . 58 | eq first( n by m ) = n . 59 | eq second( n by m ) = m . 60 | 61 | op shape : MatrixExpr -> Pair . 62 | op rows : MatrixExpr -> Int . 63 | op cols : MatrixExpr -> Int . 64 | eq rows(A) = first(shape(A)) . 65 | eq cols(A) = second(shape(A)) . 66 | 67 | op is_square : MatrixExpr -> Bool . 68 | eq is_square(X) = rows(X) == cols(X) . 69 | 70 | eq shape(matrix(M, n by m)) = n by m . 71 | eq shape(A B) = rows(A) by cols(B) . 72 | eq shape(A + B) = shape(A) . 73 | eq shape(transpose(A)) = cols(A) by rows(A) . 74 | eq shape(inverse(A)) = shape(A) . 75 | eq shape(A \ B) = cols(A) by cols(B) . 76 | ceq shape(alpha A) = shape(A) if alpha =/= 1.0 . 77 | 78 | op valid : MatrixExpr -> Bool . 79 | eq valid(S) = true . *** all symbols are valid 80 | eq valid(X Y) = valid(X) and valid(Y) and (cols(X) == rows(Y)) . 81 | eq valid(X + Y) = valid(X) and valid(Y) and (shape(X) == shape(Y)) . 82 | eq valid(transpose(X)) = valid(X) . 83 | eq valid(inverse(X)) = valid(X) and is_square(X) . 84 | eq valid(X \ Y) = rows(X) == rows(Y) and valid(X) and valid(Y) . 85 | ceq valid(alpha X) = valid(X) if alpha =/= 1.0 . 86 | 87 | *** Catch alls 88 | eq valid(X) = false [owise] . 89 | 90 | op _in_ : MatrixExpr MatrixExpr -> Bool [prec 33] . 91 | eq A in A = true . 92 | eq A in B C = A in B or A in C . 93 | ceq A in alpha B = A in B if alpha =/= 1.0 . 94 | eq A in B + C = A in B or A in C . 95 | eq A in transpose(B) = A in B . 96 | eq A in B \ C = A in B or A in C . 97 | eq A in inverse(B) = A in B . 98 | eq A in B = false [owise] . 99 | endfm 100 | -------------------------------------------------------------------------------- /src/assumptions.maude: -------------------------------------------------------------------------------- 1 | load algebra.maude 2 | 3 | fmod MATRIX-ASSUMPTIONS is 4 | protecting MATRIX-ALGEBRA . 5 | sort Predicate . 6 | sort AppliedPredicate . 7 | sorts Context NeContext . 8 | subsort AppliedPredicate < NeContext < Context . 9 | 10 | op no-knowledge : -> Context [ctor] . 11 | op _,_ : Context Context -> Context 12 | [ctor assoc comm id: no-knowledge prec 49 format (d r os d)] . 13 | op _,_ : NeContext NeContext -> NeContext 14 | [ditto] . 15 | 16 | ops symmetric orthogonal invertible : -> Predicate . 17 | ops positive-definite singular : -> Predicate . 18 | ops lower-triangular upper-triangular triangular : -> Predicate . 19 | op unit-triangular : -> Predicate . 20 | ops diagonal tridiagonal : -> Predicate . 21 | 22 | op _is_ : MatrixExpr Predicate -> AppliedPredicate [prec 45]. 23 | 24 | var P : Predicate . 25 | var AP : AppliedPredicate . 26 | var C : Context . 27 | var D E : NeContext . 28 | vars X Y : MatrixExpr . 29 | var alpha : Float . 30 | 31 | *** IMPLICATION 32 | op _=>_ : Context Context -> Bool [prec 50] . *** Implies 33 | op _<=_ : AppliedPredicate Context -> Bool [prec 50] . 34 | op _in_ : AppliedPredicate Context -> Bool [prec 50] . 35 | eq AP <= C = C => AP . 36 | 37 | eq C => no-knowledge = true . 38 | ceq C => AP = true if AP in C . 39 | ceq C => D , E = true if C => D and C => E . 40 | 41 | *** Scalars don't matter (mostly) 42 | ceq C => alpha X is P = C => X is P if alpha =/= 1.0 . 43 | 44 | *** SYMMETRIC 45 | ceq C => X Y is symmetric = true if C => X is symmetric 46 | and C => Y is symmetric . 47 | ceq C => X + Y is symmetric = true if C => X is symmetric 48 | and C => Y is symmetric . 49 | ceq C => transpose(X) is symmetric = true if C => X is symmetric . 50 | eq C => transpose(X) X is symmetric = true . 51 | eq C => X transpose(X) is symmetric = true . 52 | ceq C => X Y transpose(X) is symmetric = true if C => Y is symmetric . 53 | ceq C => transpose(X) Y X is symmetric = true if C => Y is symmetric . 54 | 55 | *** ORTHOGONAL 56 | ceq C => X Y is orthogonal = true if C => X is orthogonal 57 | and C => Y is orthogonal . 58 | ceq C => X is invertible = true if C => X is orthogonal . 59 | ceq C => transpose(X) is orthogonal = true if C => X is orthogonal . 60 | ceq C => inverse(X) is orthogonal = true if C => X is orthogonal . 61 | 62 | *** POSITIVE DEFINITE 63 | ceq C => X Y is positive-definite = true 64 | if C => X is positive-definite 65 | and C => Y is positive-definite . 66 | ceq C => X + Y is positive-definite = true 67 | if C => X is positive-definite 68 | and C => Y is positive-definite . 69 | ceq C => X is positive-definite = true if C => X is orthogonal . 70 | ceq C => X is invertible = true if C => X is positive-definite . 71 | 72 | *** SINGULAR 73 | ceq C => X is positive-definite = false if C => X is singular . 74 | ceq C => X is invertible = false if C => X is singular . 75 | ceq C => X Y is singular = true if C => X is singular 76 | or C => Y is singular . 77 | 78 | *** INVERTIBLE 79 | ceq C => X is invertible = false if is_square(X) == false . 80 | ceq C => X Y is invertible = true if C => X is invertible 81 | and C => Y is invertible . 82 | 83 | *** TRIANGULAR, DIAGONAL 84 | ceq C => X Y is lower-triangular = true if C => X is lower-triangular 85 | and C => Y is lower-triangular . 86 | ceq C => X Y is upper-triangular = true if C => X is upper-triangular 87 | and C => Y is upper-triangular . 88 | ceq C => X + Y is lower-triangular = true if C => X is lower-triangular 89 | and C => Y is lower-triangular . 90 | ceq C => X + Y is upper-triangular = true if C => X is upper-triangular 91 | and C => Y is upper-triangular . 92 | ceq C => transpose(X) is upper-triangular = true 93 | if C => X is lower-triangular . 94 | ceq C => transpose(X) is lower-triangular = true 95 | if C => X is upper-triangular . 96 | ceq C => X + Y is diagonal = true if C => X is diagonal 97 | and C => Y is diagonal . 98 | ceq C => X Y is diagonal = true if C => X is diagonal 99 | and C => Y is diagonal . 100 | ceq C => X is triangular = true if C => X is lower-triangular 101 | or C => X is upper-triangular . 102 | ceq C => X is upper-triangular = true if C => X is diagonal . 103 | ceq C => X is lower-triangular = true if C => X is diagonal . 104 | 105 | ceq C => transpose(X) is diagonal = true if C => X is diagonal . 106 | ceq C => inverse(X) is diagonal = true if C => X is diagonal . 107 | 108 | *** Catch all - ask for direct membership in the context 109 | eq C => AP = AP in C . 110 | 111 | eq AP in (AP, C) = true . 112 | eq AP in C = false [owise] . 113 | 114 | endfm 115 | -------------------------------------------------------------------------------- /src/compute.maude: -------------------------------------------------------------------------------- 1 | load lib/gen-tree.maude 2 | load simplify-sys.maude 3 | 4 | ***( 5 | view Statement from TRIV to COMPUTE is 6 | sort Elt to Statement . 7 | endv 8 | ) 9 | mod COMPUTE is 10 | protecting MATRIX-SIMPLIFY-SYS . 11 | *** protecting GEN-TREE{Statement} . 12 | protecting STRING . 13 | 14 | *** sort Statement . 15 | sort Array . 16 | subsort Qid < Array . 17 | 18 | vars A B C D : MatrixExpr . 19 | vars X Y Z : Array . 20 | var Sym : MatrixSymbol . 21 | 22 | *** Some utility functions 23 | op TRANS : MatrixExpr -> Char . 24 | eq TRANS(transpose(A)) = "T" . 25 | eq TRANS(A) = "N" [owise] . 26 | 27 | op LD : MatrixExpr -> Nat . 28 | eq LD(transpose(A)) = rows(A) . 29 | eq LD(A) = rows(A) [owise] . 30 | 31 | op Side : MatrixExpr MatrixExpr Context -> Char . 32 | ceq Side(A, B, Facts) = "L" if Facts => A is symmetric . 33 | ceq Side(A, B, Facts) = "R" if Facts => B is symmetric . 34 | 35 | op UPLO : Situation -> Char . 36 | ceq UPLO(A with Facts) = "U" if Facts => A is upper-triangular . 37 | ceq UPLO(A with Facts) = "L" if Facts => A is lower-triangular . 38 | 39 | op DIAG : Situation -> Char . 40 | ceq DIAG(A with Facts) = "U" if Facts => A is unit-triangular . 41 | eq DIAG(A with Facts) = "N" [owise] . 42 | 43 | 44 | vars a b c d e f g : Char . 45 | vars alpha beta : Float . 46 | var Facts : Context . 47 | var Q : Qid . 48 | vars transa, transb : Char . 49 | vars side uplo diag : Char . 50 | vars m n k lda ldb ldc : Int . 51 | 52 | op compute : Situation -> Array . 53 | op valid : Array -> Bool . 54 | eq valid(compute(Sym with Facts)) = true . 55 | 56 | *** SUBROUTINE SGEMM(TRANSA,TRANSB,M,N,K,ALPHA,A,LDA,B,LDB,BETA,C,LDC) 57 | op GEMM : Char Char Nat Nat Nat Float Array Nat Array Nat Float Array Nat 58 | -> Array . 59 | eq valid(GEMM(transa, transb, n, m, k, alpha, X, lda, Y, ldb, beta, Z, ldc)) 60 | = (valid(X) and valid(Y) and valid(Z)) . 61 | 62 | *** SUBROUTINE SSYMM(SIDE,UPLO,M,N,ALPHA,A,LDA,B,LDB,BETA,C,LDC) 63 | op SYMM : Char Char Nat Nat Float Array Nat Array Nat Float Array Nat 64 | -> Array . 65 | eq valid(SYMM(side, uplo, m, n, alpha, X, lda, Y, ldb, beta, Z, ldc)) 66 | = (valid(X) and valid(Y) and valid(Z)) . 67 | 68 | *** SUBROUTINE STRSM(SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB) 69 | op TRSM : Char Char Char Char Nat Nat Float Array Nat Array Nat 70 | -> Array . 71 | eq valid(TRSM(side, uplo, transa, diag, m, n, alpha, X, lda, Y, ldb)) 72 | = valid(X) and valid(Y) . 73 | 74 | 75 | *** This should be replaced with something nicer. 76 | eq compute(matrix(Q, n by m) with Facts) = Q . 77 | *** rl [Symbol] : compute(matrix(Q, n by m) with Facts) => Q . 78 | 79 | rl [GEMM] : compute(alpha A B + beta C with Facts) 80 | => GEMM("N", "N", rows(A), cols(B), cols(A), alpha, 81 | compute(A with Facts), LD(A), compute(B with Facts), LD(B), beta, 82 | compute(C with Facts), LD(C)) . 83 | eq GEMM("N", transb, n, m, k, alpha, compute(transpose(A) with Facts), lda, Y, ldb, beta, Z, ldc) 84 | = GEMM("T", transb, n, m, k, alpha, compute( A with Facts), lda, Y, ldb, beta, Z, ldc) . 85 | eq GEMM(transa, "N", n, m, k, alpha, X, lda, compute(transpose(B) with Facts), ldb, beta, Z, ldc) 86 | = GEMM(transa, "T", n, m, k, alpha, X, lda, compute( B with Facts), ldb, beta, Z, ldc) . 87 | 88 | 89 | crl [SYMM] : compute(alpha A B + beta C with Facts) 90 | => SYMM(Side(A,B,Facts), "U", rows(C), cols(C), alpha, 91 | compute(A with Facts), LD(A), compute(B with Facts), LD(B), beta, 92 | compute(C with Facts), LD(C)) 93 | if 94 | Facts => A is symmetric or Facts => B is symmetric . 95 | *** This has issues. BLAS over-writes solution onto B. need to make copy 96 | crl [TRSM] : compute(A \ (alpha B) with Facts) 97 | => TRSM("L", UPLO(A with Facts), TRANS(A), DIAG(A with Facts), 98 | rows(B), cols(B), alpha, compute(A with Facts), LD(A), 99 | compute(B with Facts), LD(B)) 100 | if 101 | A is triangular <= Facts . 102 | 103 | eq TRSM(side, uplo, "N", diag, m, n, alpha, compute(transpose(A) with Facts), lda, Y, ldb) 104 | = TRSM(side, uplo, "T", diag, m, n, alpha, compute( A with Facts), lda, Y, ldb) . 105 | 106 | eq valid(Q) = true . 107 | eq valid(X) = false [owise]. 108 | 109 | ops T R S U V : -> MatrixSymbol . 110 | eq U = matrix('U, 10 by 10) . 111 | eq V = matrix('V, 10 by 10) . 112 | eq T = matrix('T, 10 by 10) . 113 | eq R = matrix('R, 10 by 5) . 114 | eq S = matrix('S, 10 by 5) . 115 | op gamma : -> Float . 116 | endm 117 | 118 | search [10, 10] compute(3.0 T R + 2.0 S with no-knowledge) 119 | =>! X such that valid(X) . 120 | search [100, 100] compute(T \ (gamma R) with T is lower-triangular) 121 | =>! X such that valid(X) . 122 | search [10, 10] compute(3.0 transpose(T) R + 2.0 S with R is symmetric ) 123 | =>! X such that valid(X) . 124 | ***search [100, 100] compute(U transpose(U) V + 3.0 V + 3.0 transpose(T) R + 2.0 S) =>! A:Array . 125 | 126 | search [10, 10] in COMPUTE : compute(simplify(U + transpose(V) U U transpose(U) 127 | with U is orthogonal , V is symmetric)) 128 | =>! X such that valid(X) . 129 | -------------------------------------------------------------------------------- /src/lib/gen-tree.maude: -------------------------------------------------------------------------------- 1 | ---- from the book All About Maude 2 | ---- by the Maude team 3 | 4 | load list-cons.maude 5 | 6 | fmod GEN-TREE{X :: TRIV} is 7 | protecting LIST-CONS{X} . 8 | 9 | sorts Tree{X} Forest{X} . 10 | 11 | op _[_] : X$Elt Forest{X} -> Tree{X} [ctor] . 12 | op empty-forest : -> Forest{X} [ctor] . 13 | op _:_ : Tree{X} Forest{X} -> Forest{X} [ctor] . 14 | 15 | op root : Tree{X} -> X$Elt . 16 | op children : Tree{X} -> Forest{X} . 17 | op #children : Tree{X} -> Nat . 18 | op length : Forest{X} -> Nat . 19 | op leaf? : Tree{X} -> Bool . 20 | 21 | var E : X$Elt . 22 | var T : Tree{X} . 23 | var F : Forest{X} . 24 | 25 | eq root(E [F]) = E . 26 | eq children(E [F]) = F . 27 | 28 | eq length(empty-forest) = 0 . 29 | eq length(T : F) = 1 + length(F) . 30 | eq #children(E [F]) = length(F) . 31 | eq leaf?(T) = #children(T) == 0 . 32 | 33 | ops depth degree : Tree{X} -> Nat . 34 | ops depth-forest degree-forest : Forest{X} -> Nat . 35 | 36 | eq depth(E [F]) = 1 + depth-forest(F) . 37 | eq depth-forest(empty-forest) = 0 . 38 | eq depth-forest(T : F) = max(depth(T), depth-forest(F)) . 39 | 40 | eq degree(E [F]) = max(length(F), degree-forest(F)) . 41 | eq degree-forest(empty-forest) = 0 . 42 | eq degree-forest(T : F) = max(degree(T), degree-forest(F)) . 43 | 44 | ops preorder postorder : Tree{X} -> List{X} . 45 | ops preorder-forest postorder-forest : Forest{X} -> List{X} . 46 | 47 | eq preorder(E [F]) = E : preorder-forest(F) . 48 | eq preorder-forest(empty-forest) = [] . 49 | eq preorder-forest(T : F) = preorder(T) ++ preorder-forest(F) . 50 | 51 | eq postorder(E [F]) = postorder-forest(F) ++ (E : []) . 52 | eq postorder-forest(empty-forest) = [] . 53 | eq postorder-forest(T : F) = postorder(T) ++ postorder-forest(F) . 54 | endfm 55 | 56 | fmod GEN-TREE-TEST is 57 | protecting GEN-TREE{Int} . 58 | endfm 59 | 60 | ***( 61 | red postorder( 62 | 1 [ 3 [ 4 [ empty-forest ] : empty-forest ] 63 | : (2 [ empty-forest ] : empty-forest) ]) . 64 | ---( 65 | reduce in GEN-TREE-TEST : postorder(1[3[4[empty-forest] : empty-forest] : 2[ 66 | empty-forest] : empty-forest]) . 67 | rewrites: 26 in 0ms cpu (0ms real) (~ rewrites/second) 68 | result NeList{Int}: 4 : 3 : 2 : 1 : [] 69 | ---) 70 | ) 71 | -------------------------------------------------------------------------------- /src/lib/list-cons.maude: -------------------------------------------------------------------------------- 1 | ---- from the book All About Maude 2 | ---- by the Maude team 3 | 4 | fmod LIST-CONS{X :: TRIV} is 5 | protecting NAT . 6 | 7 | sorts NeList{X} List{X} . 8 | subsort NeList{X} < List{X} . 9 | 10 | op [] : -> List{X} [ctor] . 11 | op _:_ : X$Elt List{X} -> NeList{X} [ctor] . 12 | op tail : NeList{X} -> List{X} . 13 | op head : NeList{X} -> X$Elt . 14 | 15 | var E : X$Elt . 16 | var N : Nat . 17 | vars L L' : List{X} . 18 | 19 | eq tail(E : L) = L . 20 | eq head(E : L) = E . 21 | 22 | op _++_ : List{X} List{X} -> List{X} . 23 | op length : List{X} -> Nat . 24 | op reverse : List{X} -> List{X} . 25 | 26 | eq [] ++ L = L . 27 | eq (E : L) ++ L' = E : (L ++ L') . 28 | eq length([]) = 0 . 29 | eq length(E : L) = 1 + length(L) . 30 | eq reverse([]) = [] . 31 | eq reverse(E : L) = reverse(L) ++ (E : []) . 32 | 33 | op take_from_ : Nat List{X} -> List{X} . 34 | op throw_from_ : Nat List{X} -> List{X} . 35 | 36 | eq take 0 from L = [] . 37 | eq take N from [] = [] . 38 | eq take s(N) from (E : L) = E : take N from L . 39 | 40 | eq throw 0 from L = L . 41 | eq throw N from [] = [] . 42 | eq throw s(N) from (E : L) = throw N from L . 43 | endfm 44 | 45 | fmod LIST-CONS-TEST is 46 | protecting LIST-CONS{String} . 47 | endfm 48 | 49 | ***( 50 | red reverse("one" : "two" : "three" : []) . 51 | ---( 52 | reduce in LIST-CONS-TEST : reverse("one" : "two" : "three" : []) . 53 | rewrites: 10 in 0ms cpu (0ms real) (~ rewrites/second) 54 | result NeList{String}: "three" : "two" : "one" : [] 55 | ---) 56 | ) 57 | -------------------------------------------------------------------------------- /src/simplify-sys.maude: -------------------------------------------------------------------------------- 1 | load simplify.maude 2 | 3 | mod MATRIX-SIMPLIFY-SYS is 4 | extending MATRIX-SIMPLIFY . 5 | 6 | vars X Y Z : MatrixExpr . 7 | var C : Context . 8 | rl [right] : simplify(X (Y Z) with C) 9 | => simplify(X with C) simplify(Y Z with C) . 10 | rl [left] : simplify(X (Y Z) with C) 11 | => simplify(X Y with C) simplify(Z with C) . 12 | 13 | *** rl [give-up] : simplify(X with C) 14 | *** => X with C . 15 | endm 16 | -------------------------------------------------------------------------------- /src/simplify.maude: -------------------------------------------------------------------------------- 1 | load assumptions.maude 2 | 3 | fmod MATRIX-SIMPLIFY is 4 | protecting MATRIX-ALGEBRA . 5 | protecting MATRIX-ASSUMPTIONS . 6 | protecting TRUTH-VALUE . 7 | 8 | sort Situation . 9 | op _with_ : MatrixExpr Context -> Situation [prec 55] . 10 | op simplify : Situation -> Situation . 11 | op matrixof : Situation -> MatrixExpr . 12 | 13 | vars X Y : MatrixExpr . 14 | var S : MatrixSymbol . 15 | var C : Context . 16 | var P : Predicate . 17 | var alpha : Float . 18 | 19 | *** We can treat situtions like MatrixExprs 20 | op __ : Situation Situation -> Situation . 21 | eq (X with C) (Y with C) = X Y with C . 22 | op _+_ : Situation Situation -> Situation . 23 | eq (X with C) + (Y with C) = X + Y with C . 24 | op transpose : Situation -> Situation . 25 | eq transpose(X with C) = transpose(X) with C . 26 | op inverse : Situation -> Situation . 27 | eq inverse(X with C) = inverse(X) with C . 28 | 29 | eq simplify(S with C) = S with C . 30 | 31 | *** Bring scalars out of simplify 32 | ceq simplify(alpha X with C) = alpha matrixof(simplify(X with C)) with C 33 | if alpha =/= 1.0 . 34 | 35 | *** TRANSPOSES 36 | ceq simplify(X transpose(X) with C) = I with C 37 | if C => X is orthogonal . 38 | ceq simplify(transpose(X) with C) = simplify(X with C) 39 | if C => X is symmetric . 40 | 41 | *** INVERSES 42 | ceq simplify(inverse(X) with C) = simplify(transpose(X) with C) 43 | if C => X is orthogonal . 44 | 45 | *** Remove inactive predicates 46 | ceq X with (Y is P , C) = X with C if (Y in X) == false . 47 | 48 | *** Catch Alls, reduce simplify to sub-terms 49 | *** TODO these are currently ambiguous 50 | *** eq simplify(X Y with C) = simplify(X with C) simplify(Y with C) [owise] . 51 | eq simplify(X + Y with C) = simplify(X with C) + simplify(Y with C) [owise]. 52 | eq simplify(transpose(X) with C) = transpose(simplify(X with C)) [owise] . 53 | eq simplify(inverse(X) with C) = inverse(simplify(X with C)) [owise] . 54 | 55 | eq matrixof(X with C) = X . 56 | 57 | endfm 58 | -------------------------------------------------------------------------------- /src/tests/algebra.test.maude: -------------------------------------------------------------------------------- 1 | load ../algebra.maude 2 | 3 | fmod TEST is 4 | protecting MATRIX-ALGEBRA . 5 | 6 | ops W X Y Z A : -> MatrixSymbol . 7 | ops n m k : -> Int . 8 | eq W = matrix('W, n by k) . 9 | eq X = matrix('X, n by m) . 10 | eq Y = matrix('Y, m by k) . 11 | eq Z = matrix('Y, k by n) . 12 | eq A = matrix('A, 1 by n) . 13 | 14 | var v : Vector . 15 | var rv : RowVector . 16 | op isVector : Vector -> Bool . 17 | eq isVector(v) = true . 18 | op isRowVector : RowVector -> Bool . 19 | eq isRowVector(rv) = true . 20 | 21 | ops a b c : -> Float . 22 | endfm 23 | 24 | red in TEST : shape(X) == n by m . 25 | red in TEST : rows(X) == n . 26 | red in TEST : cols(X) == m . 27 | red in TEST : shape(X Y) == (n by k) . 28 | red in TEST : (shape(transpose(X))) == (m by n) . 29 | red in TEST : shape(W \ X) == k by m . 30 | red in TEST : shape(a X) == shape(X) . 31 | red in TEST : shape(2.0 X) == shape(X) . 32 | 33 | red in TEST : valid(X Y Z) . 34 | red in TEST : valid(Y X) == false . 35 | red in TEST : valid(X Y + transpose(Z)) . 36 | red in TEST : valid(a X Y) . 37 | 38 | red in TEST : valid(W \ X) . 39 | 40 | red in TEST : isVector(transpose(A)) . 41 | red in TEST : isRowVector(A) . 42 | red in TEST : isVector(transpose(A X)) . 43 | 44 | red in TEST : isVector(a transpose(A)) . 45 | 46 | red in TEST : 5.0 3.0 == 15.0 . 47 | 48 | red in TEST : I A == A . 49 | red in TEST : X Y I Z == X Y Z . 50 | 51 | red in TEST : X in W + Y \ inverse(transpose(X)) . 52 | red in TEST : X in W + Y Y \ Z == false . 53 | -------------------------------------------------------------------------------- /src/tests/assumptions.test.maude: -------------------------------------------------------------------------------- 1 | load ../assumptions.maude 2 | 3 | fmod TEST is 4 | protecting MATRIX-ASSUMPTIONS . 5 | ops A B X Y : -> MatrixSymbol . 6 | op n : -> Int . 7 | eq A = matrix('A , n by n) . 8 | eq B = matrix('B , n by n) . 9 | 10 | op alpha : -> Float . 11 | endfm 12 | 13 | red in TEST : X is symmetric , Y is symmetric => X Y is symmetric . 14 | red in TEST : X is symmetric => transpose(X) is symmetric . 15 | red in TEST : no-knowledge => X transpose(X) is symmetric . 16 | red in TEST : A is positive-definite => A is invertible . 17 | red in TEST : A is orthogonal , B is invertible => A B is invertible . 18 | red in TEST : no-knowledge => X transpose(X) is symmetric . 19 | red in TEST : A is invertible => A transpose(A) is positive-definite . 20 | red in TEST : A is invertible , B is invertible => A B is invertible . 21 | 22 | red in TEST : A is symmetric , A is positive-definite , B is orthogonal 23 | => B A transpose(B) is symmetric , 24 | B A transpose(B) is positive-definite . 25 | red in TEST : A is diagonal => A is triangular . 26 | 27 | red in TEST : A is diagonal => A is upper-triangular , A is lower-triangular . 28 | red in TEST : A is lower-triangular => transpose(A) is upper-triangular . 29 | 30 | red in TEST : A is symmetric => alpha A is symmetric . 31 | red in TEST : A is lower-triangular => alpha A is lower-triangular . 32 | 33 | red in TEST : A is lower-triangular , B is lower-triangular 34 | => A B is lower-triangular . 35 | -------------------------------------------------------------------------------- /src/tests/simplify-sys.test.maude: -------------------------------------------------------------------------------- 1 | load ../simplify-sys.maude 2 | 3 | mod TEST is 4 | 5 | protecting MATRIX-SIMPLIFY-SYS . 6 | ops X Y Z : -> MatrixSymbol . 7 | ops n m k l p : -> Int . 8 | eq X = matrix('X, n by m) . 9 | eq Y = matrix('Y, m by n) . 10 | 11 | var M : MatrixSymbol . 12 | var S : Situation . 13 | 14 | endm 15 | 16 | *** search [100, 100] simplify(Y X transpose(X) with X is orthogonal) =>! S . 17 | search [10, 10] matrixof(simplify(Y X transpose(X) with X is orthogonal)) 18 | =>* M . 19 | -------------------------------------------------------------------------------- /src/tests/simplify.test.maude: -------------------------------------------------------------------------------- 1 | load ../simplify.maude 2 | 3 | fmod TEST is 4 | 5 | protecting MATRIX-SIMPLIFY . 6 | ops X Y Z : -> MatrixSymbol . 7 | ops n m k l p : -> Int . 8 | eq X = matrix('X, n by m) . 9 | eq Y = matrix('Y, m by n) . 10 | 11 | ops ctxt ctxt2 ctxt3 : -> Context . 12 | ops query query2 : -> Context . 13 | eq query = X is symmetric . 14 | eq query2 = Y is symmetric . 15 | eq ctxt = X is symmetric , X is orthogonal , Y is symmetric . 16 | eq ctxt2 = X Y is symmetric , X is orthogonal . 17 | eq ctxt3 = X is positive-definite , X is symmetric , Y is orthogonal . 18 | 19 | endfm 20 | 21 | red in TEST : matrixof(simplify(transpose(X) with X is symmetric)) == X . 22 | red in TEST : matrixof(simplify(X transpose(X) with X is orthogonal)) == I . 23 | red in TEST : matrixof(simplify(transpose(transpose(X)) with no-knowledge)) == X . 24 | 25 | red in TEST : matrixof(simplify(2.0 X with no-knowledge)) == 2.0 X . 26 | red in TEST : matrixof(simplify(2.0 X transpose(X) with X is orthogonal)) 27 | == 2.0 I . 28 | 29 | red in TEST : simplify(X transpose(X) with X is orthogonal) == simplify(I with 30 | no-knowledge) . 31 | --------------------------------------------------------------------------------