pax_global_header00006660000000000000000000000064125617153440014522gustar00rootroot0000000000000052 comment=d178ec4b728a0061af2d930eb5cebce4545fb54c ejml-0.28/000077500000000000000000000000001256171534400124025ustar00rootroot00000000000000ejml-0.28/.idea/000077500000000000000000000000001256171534400133625ustar00rootroot00000000000000ejml-0.28/.idea/codeStyleSettings.xml000066400000000000000000000006001256171534400175540ustar00rootroot00000000000000 ejml-0.28/.idea/copyright/000077500000000000000000000000001256171534400153725ustar00rootroot00000000000000ejml-0.28/.idea/copyright/ejml.xml000066400000000000000000000017711256171534400170510ustar00rootroot00000000000000 ejml-0.28/.idea/copyright/profiles_settings.xml000066400000000000000000000002661256171534400216630ustar00rootroot00000000000000 ejml-0.28/.idea/scopes/000077500000000000000000000000001256171534400146565ustar00rootroot00000000000000ejml-0.28/.idea/scopes/ejml.xml000066400000000000000000000001611256171534400163250ustar00rootroot00000000000000 ejml-0.28/.idea/scopes/scope_settings.xml000066400000000000000000000002131256171534400204250ustar00rootroot00000000000000 ejml-0.28/.svnignore000066400000000000000000000000051256171534400144100ustar00rootroot00000000000000*.iwsejml-0.28/.travis.yml000066400000000000000000000001071256171534400145110ustar00rootroot00000000000000language: java jdk: - openjdk6 - oraclejdk7 - oraclejdk8 script: ejml-0.28/LICENSE-2.0.txt000066400000000000000000000236771256171534400145410ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ejml-0.28/README.md000066400000000000000000000125361256171534400136700ustar00rootroot00000000000000# Efficient Java Matrix Library Author: Peter Abeles peter.abeles@gmail.com ##### Project Website: http://ejml.org [![Build Status](https://travis-ci.org/lessthanoptimal/ejml.svg?branch=master)](https://travis-ci.org/lessthanoptimal/ejml) ## Introduction Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating dense matrices. Its design goals are; 1) to be as computationally and memory efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime, clean API, and multiple interfaces. EJML is free, written in 100% Java and has been released under an Apache v2.0 license. EJML has three distinct ways to interact with it: 1) procedural, 2) SimpleMatrix, and 3) Equations. Procedure provides all capabilities of EJML and almost complete control over memory creation, speed, and specific algorithms. SimpleMatrix provides a simplified subset of the core capabilities in an easy to use flow styled object-oriented API, inspired by Jama. Equations is a symbolic interface, similar in spirit to Matlab and other CAS, that provides a compact way of writing equations. The following functionality is provided: * Basic operators (addition, multiplication, ...) * Matrix Manipulation (extract, insert, combine, ...) * Linear Solvers (linear, least squares,incremental, ...) * Decompositions (LU, QR, Cholesky, SVD, Eigenvalue, ...) * Matrix Features (rank, symmetric, definitiveness, ...) * Random Matrices (covariance, orthogonal, symmetric, ...) * Different Internal Formats (row-major, block) * Unit Testing Unit tests are extensively used to ensure correctness of each algorithm's implementation. Internal benchmarks and Java Matrix Benchmark are both used to ensure the speed of this library. ========================================================================== ## Documentation For a more detailed explanation of how to use the library see: http://ejml.org/wiki/index.php?title=Manual The JavaDoc has also been posted online at: http://ejml.org/javadoc/ ========================================================================== ## Including in Gradle and Maven Projects EJML is on the Maven central repository and can easily be included in projects by adding the following code to the dependency section of your Maven or Gradle project. This will include all the modules in EJML. Gradle: ``` compile group: 'org.ejml', name: 'all', version: '0.27' ``` Maven: ``` org.ejml all 0.27 ``` Or you can include the required modules individually Name | Description -----------------|------------------------------------------------------- core | Contains core data structures dense64 | Algorithms for dense real 64-bit floats denseC64 | Algorithms for dense complex 64-bit floats equation | Equations interface simple | Object oriented SimpleMatrix interface ========================================================================== ## Building Gradle is the official build environment for EJML. In addition to all the standard commands the following are also available. * createLibraryDirectory : To build all the modules as jars and save them in ejml/libraries * oneJar : To compile all the modules into a single jar at ejml/EJML.jar ========================================================================== ## File System * **docs/** : Documentation for this library. This documentation is often out of date and online is the best place to get the latest. * **examples/** : Contains several examples of how EJML can be used to solve different problems or how EJML can be modified for different applications. * **main/core** : Contains all essential data structures * **main/dense64** : Algorithms for real dense 64-bit floating point matrices * **main/denseC64** : Algorithms for complex dense 64-bit floating point matrices * **main/equation** : Contains source code for Equations API * **main/simple** : Contains source code for SimpleMatrix * **main/experimental/** : Where experimental or alternative approaches and possibly buggy code goes that is not ready to be used by most users. * **change.txt** : History of what changed between each version. * **TODO_Algorithms.txt** : Contains a list of what needs to be added to this library. ========================================================================== ## Questions and Comments A public message board has been created for asking questions and making comments: http://groups.google.com/group/efficient-java-matrix-library-discuss Bugs can either be posted on that message board or at: https://github.com/lessthanoptimal/ejml/issues ========================================================================== ## Acknowledgements I would like to thank all the people have made various comments, suggestions, and reported bugs. Also David Watkins for writing "Fundamentals of Matrix Computations", which clearly explains algorithms and yet addresses important implementation issues. ========================================================================== ## License EJML is released under the Apache v2.0 open source license ejml-0.28/TODO_Algorithms.txt000066400000000000000000000036141256171534400161050ustar00rootroot00000000000000Feature TODO - a = [5:10] - first: b = [1 2 50 69] then: c(b) = 1 Maybe do this by parsing "5:10" and "1 2 3 4 5" into IntegerSequence with specific types range and list? Have an interator in IntegerSequence for generic processing, but allow for specialized for each sequence type? - Add to CommonOps invertSPD() - Unroll symmetric inverse by minor - Unroll multiplication for square matrices - Make QrUpdate more friendly and accessible For some future Release - Block SVD - Block Hessenberg - Adapt QR-tran into LQ - Remove QRDecompositionHouseholder? - Remove chol-block for dense with chol-block64? * reduce cache misses in invert and see if its faster - Merge inner triangular solver code - Require LinearSolverFactory to take in a matrix so it can figure out alg to use? - Improve cholesky block inverse by taking advantage of symmetry - Add a function for sorting eigenvalues. ---------------------------------------------------------- - LU - block - Cholesky - unwrap for small matrices. improve accuracy - improve stability - Linear Solver * Iterative * Add condition(), use Hager's method? pg 132 * Put this new condition into NormOps since it should be much faster - SVD - Save up rotators, multiply against each other, then multiply against U and V - Divide and conquer algorithm - An implementation that just finds zero singular values - Incremental SVD - Eigen decomposition - Divide and conquer algorithm. - Accurate version of symmetric eigenvalue for 2 by 2 - SVD - SymmEig - Fast Matrix Multiply - hard code cholesky decomposition for small matrices - hard code symmetric inverse for small matrices - Matrix Multiplication: - Try a variant on mult_aux that does the vector mult up to block size then goes down a row. - Finish vector vector multiply - Code generator for matrix vector ops - Add matrix vector multiply - Auto switch to all of above in CommonOpsejml-0.28/build.gradle000066400000000000000000000140741256171534400146670ustar00rootroot00000000000000allprojects { apply plugin: 'idea' apply plugin: 'eclipse' group = 'org.ejml' version = '0.28' } subprojects { apply plugin: 'java' apply plugin: 'osgi' apply plugin: 'maven' apply plugin: 'signing' sourceCompatibility = 1.6 targetCompatibility = 1.6 javadoc.failOnError = false repositories { mavenCentral() mavenLocal() maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } } sourceSets { main { java { srcDir 'src' } resources { srcDir 'resources/src' } } test { java { srcDir 'test' srcDir 'generate' srcDir 'benchmarks/src' srcDir 'benchmarks/test' } resources { srcDir 'resources/test' } } } dependencies { testCompile group: 'junit', name: 'junit', version: '4.11' } jar { manifest { // the manifest of the default jar is of type OsgiManifest instruction 'Bundle-Vendor', 'EJML' // instruction 'Bundle-Description', 'EJML' instruction 'Bundle-DocURL', 'http://ejml.org/' } } task javadocJar(type: Jar) { classifier = 'javadoc' from javadoc } task sourcesJar(type: Jar) { classifier = 'sources' from sourceSets.main.allSource } artifacts { archives javadocJar, sourcesJar } // if Maven central isn't setup in gradle.properties skip all of this if( project.hasProperty('ossrhUsername') ) { signing { sign configurations.archives } uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { authentication(userName: ossrhUsername, password: ossrhPassword) } snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { authentication(userName: ossrhUsername, password: ossrhPassword) } pom.project { name 'EJML' packaging 'pom' // optionally artifactId can be defined here description 'A fast and easy to use dense matrix linear algebra library written in Java.' url 'http://ejml.org/' scm { connection 'git@github.com:lessthanoptimal/ejml.git' developerConnection 'git@github.com:lessthanoptimal/ejml.git' url 'https://github.com/lessthanoptimal/ejml' } licenses { license { name 'The Apache Software License, Version 2.0' url 'http://www.apache.org/licenses/LICENSE-2.0.txt' } } developers { developer { id 'pabeles' name 'Peter Abeles' email 'peter.abeles@gmail.com' } } } } } } } } def allModules = [ ':main:core', ':main:dense64', ':main:denseC64', ':main:equation', ':main:simple' ] // Creates a directory with all the comiled jars task createLibraryDirectory( dependsOn: allModules.collect{ it+":jar"}+allModules.collect{ it+":sourcesJar"}) << { // Create lists of .class jars and source jars ext.listJars = files(allModules.collect{ project(it).tasks.jar.archivePath }) ext.listSource = files(allModules.collect{ project(it).tasks.sourcesJar.archivePath }) file('libraries').deleteDir() file('libraries').mkdir() copy { from ext.listJars from ext.listSource into 'libraries' // append on BoofCV so it's clear which jars are part of BoofCV and which are not rename { String fileName -> "EJML-" + fileName } } } idea { project { jdkName = '1.6 (64bit)' languageLevel = '1.6' } } def javadocProjects = [ ':main:denseC64', ':main:dense64', ':main:core', ':main:equation' ] task alljavadoc(type: Javadoc) { // only include source code in src directory to avoid including 3rd party code which some projects do as a hack source = javadocProjects.collect { project(it).fileTree('src').include('**/*.java') } // source = javadocProjects.collect { project(it).sourceSets.main.allJava } classpath = files(javadocProjects.collect { project(it).sourceSets.main.compileClasspath }) destinationDir = file("${buildDir}/docs/javadoc") configure(options) { docTitle = "Efficient Java Matrix Library (EJML) v$project.version" links = [ 'http://docs.oracle.com/javase/7/docs/api/' ] header = file('docs/header.txt').text bottom = file('docs/bottom.txt').text // the quotes messes up javadoc still create bug report } } task oneJarBin(type: Jar, dependsOn: javadocProjects.collect { it + ":compileJava" }) { baseName = 'EJML' from files(javadocProjects.collect { project(it).sourceSets.main.output }) } // Disable the creation of jars for distribution. If you don't do this it will crash [':main',':examples'].each {String a -> project(a) { if( project.hasProperty('ossrhUsername') ) { signArchives.enabled = false } sourcesJar.enabled = false javadocJar.enabled = false jar.enabled = false uploadArchives.enabled = false install.enabled = false } } ejml-0.28/build.xml000066400000000000000000000170501256171534400142260ustar00rootroot00000000000000 Efficient Java Matrix Library API Specification]]> Copyright © 2009-2015 Peter Abeles All Rights Reserved.]]> Efficient Java Matrix Library API Specification:]]>
]]>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-10413214-7', 'ejml.org'); ga('send', 'pageview');
Copyright © 2009-2015 Peter Abeles ]]>
ejml-0.28/change.txt000066400000000000000000000514451256171534400144010ustar00rootroot00000000000000Change log for EJML Date format: year/month/day ----- Version 0.28 2015/07/09 - Equations * Fixed bug where bounds for a submatrix-scalar assignment was being checked using col,row instead of row,col Thanks lenhhoxung for reporting this bug - FixedOps * Added vector equivalents for all element-wise matrix operations * Added multAdd operators ----- Version 0.27 2015/04/01 - Added SimpleMatrix.randomNormal() for drawing numbers from a normal distribution with zero mean - Added EjmlUnitTests.assertEquals() and similar for SimpleMatrix - Removed DenseMatrix64F.setReshape() * Matrix.set(matrix) will now reshape the matrix that's being assigned - Triangle quality now just uses diagonal elements to scale results - Support for complex matrices * Thanks IHMC (http://ihmc.us) for funding parts of this addition * Basic operations (e.g. multiplication, addition, ... etc) * LU Decomposition + Linear Solver * QR Decomposition + Linear Solver * Cholesky Decomposition + Linear Solver * Square Matrices: inverse, solve, determinant * Overdetermined: solve - ComplexMath64F * Added sqrt(Complex64F) - Tweaked matrix inheritance to better support the addition of complex matrices - Added RandomMatrices setGaussian() and createGaussian() - Changed how SimpleMatrix computes its threshold for singular values * Farley Lai noticed this issue - Added SingularOps.singularThreshold() - Added no argument rank and nullity for SVD using default threshold. - SimpleMatrix.loadCSV() now supports derived types - Added primitive 32bit data structures to make adding 32bit support in the future smoother - Equation * 1x1 matrix can be assigned to a double scalar * When referencing a single element in a matrix it will be extracted as a scalar and not a 1x1 matrix. * Added sqrt() to parser * lookupDouble() will now work on 1x1 matrices - CommonOps * Added dot(a,b) for dot product between two vectors * Added extractRow and extractColumn - FixedOps * Added extractRow and extractColumn. Thanks nknize for inspiring this modification with a pull request * Added subtract and subtractEquals. Thanks nknize for the pull request - Added determinant to Cholesky decomposition interface - Added getDecomposition() to LinearSolver to provide access to internal classes, which can be useful in some specialized cases. Alternatives were very ugly. ----- Version 0.26 2014/9/14 - Switched most of the build system over to Gradle - Equations * Symbolic way to perform linear algebra * Similar to Matlab/Octave - SimpleMatrix * Added plus( double ) * Added elementDiv() - Linear Solvers * Exposed inner decomposition algorithms and some data structures - CommonOps * Trace will now work on non-square matrices * changeSign() has a two argument version * left and right double-matrix division. *** WARNING **** The meaning of CommonOps.divide(double,Matrix) and similar has changed * Added subtract() matrix-double and double-matrix - QRP yet again uses a relative threshold. No idea why it was set to a global one - Matrix Multiplication now fully supports multiplication by rows or columns with zero - Element-wise pow, exp, log to CommonOps and SimpleMatrix - High level interface for LDL - Renamed Principle to Principal in PCA * Thanks sergei.skarupo for being the first person to point out this error - Fixed case where SolvePseudoInverseSvd would blow up if input matrix was zero - SVD and EVD can gracefully handle matrix with size 0 ----- Version 0.25 2014/6/13 - Fixed bug in CovarianceRandomDraw where it was modifying the input matrix * Thanks Alexandre Bouchard for finding this bug - Added suffix to low level implementations so that you can tell by looking at the class name the type of matrix it takes in as input * D64 = DenseMatrix64F * B64 = BlockMatrix64F - Moved interfaces into their own package. Before they resided in dense. - Fixed bad matrix dimension check in LinearSolverChol * Added unit tests which can catch the error * Thanks Illya Kokshenev for finding and reporting - SimpleMatrix * inverse and solve now check to see if output contains uncountable numbers. * Thanks sylvain.rouard for the suggestion ----- Version 0.24 2013/12/26 - CHANGED LICENSE FROM LGPL to Apache 2.0 * Don't agree with Free Software Foundation's interpretation for how the LGPL applies to Java jars. * Even if it did behave the way I wanted it to, it wouldn't do much other than scare some people away. - Added fixed sized square matrices and vectors * Auto code generator for standard operations * Matrix 2x2, 3x3, 4x4, 5x5, 6x6 * Vector 2, 3, 4, 5, 6 - Created an interface for Matrix64F and renamed the old one into ReshapeMatrix64F - CommonOps: Added checks which ensure the input matrix is not modified for det() and inv() ----- Version 0.23 2013/06/21 - Modified Matrix64F so that it can be serialized using beans. Added setNumRows() and setNumCols() - Added user configurable threshold in SolvePseudoInverseSvd ----- Version 0.22 2013/04/09 - Fixed bug in MatrixFeatures.isPositiveDefinite() where the input was being modified * Added a check for isModified() flag in this and several other functions * Thanks Eriklan Dodinh for reporting the bug - MatrixIO.loadCSV() now will throw IOException() if an incorrect matrix size is specified * Thanks Ioannis P. for reporting this bug - LUDecompositionNR now returns false for singular matrices. * Thanks Luke Nezda for reporting the bug - Moved LUDecompositionNR into experimental directory since its use is not recommended, but is still a good algorithm. - Clarified ordering of coefficients in polynomial root example * Thanks Rahul for getting confused by the lack of documentation ----- Version 0.21 2012/12/04 - Removed Android build option from ant because there is no need for such an option - Changed behavior of CommonOps.rref() so that numUnknowns <= 0 causes it to be set to a reasonable default - Fixed bug in SimpleSVD where getSingularValue() did not return ordered singular values - SingularOps.nullVector() now lets you specify if it is the left or right null space - Added SafeSvd, which is a wrapper class that ensures that the input to SVD is not modified ----- Version 0.20 2012/08/22 - Fixed bug in SingularOps.nullity where it did not handle wide matrices correctly. * Thanks arnavkumar for pointing out the bug - Reworked null-space * SingularOps.nullSpace() is now nullVector() * SingularOps.nullSpace now returns the entire null space not just one vector * Thanks arnavkumar for pointing out the non-standard implementation - Changed behavior of MatrixFeatures.isDiagonalPositive() so that it will return false if NaN is found - Under certain conditions SvdImplicitQrDecompose will use BidiagonalDecompositionTall instead of the default algorithm. - Moved factories and related interfaces into their own package outside of the "alg" package, which was intended for specific implementations. - DecompositionFactory has been cleaned up by reducing the number of functions, making input parameters more consistent, and improved JavaDoc - Changed CommonOps.set(matrix,value) to CommonOps.fill(matrix,value) - Added function QRPDecomposition.setSingularThreshold() so that the user has more control over this important threshold * The singular threshold in QRP is now absolute and not automatically relative. * To replicate the original behavior do the following: decomp.setSingularThreshold( CommonOps.elementMaxAbs(A)*UtilEjml.EPS ) - SvdImplicitQrDecompose now takes in a parameter which specifies if tall bidiagonal decomposition can be used over concerns of its stability. These concerns are mostly theoretical since a few simple tests show the stability to be almost the same. - SimpleBase now implements Serializable - Accessors in SingularValueDecomposition now can take in an optional storage matrix. - Removed support for LinearSolver with Gauss-Jordan elimination * The provided implementation was very slow and didn't utilize any of the advantages of GJ - Added support for transforming an augmented matrix into Reduced Row Echelon Form (RREF) * Implementation using Gauss-Jordan with row pivots * Added CommonOps.rref() ----- Version 0.19 2012/04/23 - Added example showing file IO to examples directory - Changed MatrixIO.saveXML and MatrixIO.loadXML to saveBin and loadBin because it uses a binary format not XML - Added save/load CSV to SimpleBase - Implemented VectorVectorMult.rank1Update * Before the function did nothing - Fixed bug in LinearSolverQrHouseCol where it was not handled a change in matrix size correctly - Added new variant of SingularOps.descendingOrder() which takes an array of singular values as input - Added reshape(row,cols) because adding false to reshape(row,cols) all the time was annoying me. - Added multInner() and multOuter() for performing inner and outer matrix products. Faster than using generalized algorithms. - Changed behavior of VectorVectorMult.innerProdA so that it does not require 'A' to be square - Improved Pseudo Inverse * Refactored by changing package and renaming * Added QR pivot based pseudo inverse classes - Improved QR Pivot so that it has better stability * Normalization is done on a column by column basis instead of by the whole matrix. - QR decomposition using extracted columns now invokes more generalized code for householder operations * Should improve performance for larger matrices, and slightly degrade for small - Added SimpleMatrix.setRow() SimpleMatrix.setColumn() * Writes elements in an array to a row/column. - Moved decomposition and linear solver factories and interfaces into a factories package. * Was placed in alg.dense package, which is for specific implementations ----- Version 0.18 2011/12/04 - Added support for reading and writing CSV formatted matrices * Requested by various people. - Changed SolvePseudoInverse to use SVD, making it much more robust and will never fail now. * Same behavior as matlab pinv() function * Requested by mwolff. * Updated CommonOps.pinv() to use SolvePseudoInverse * Added pinv() to SimpleMatrix - Added getSingularValue() to SimpleSVD class. - Rewrote JavaDOC for reshape() because it was miss leading * sh10151 pointed this out - Removed one of the CommonOps.insert() functions since it was identical to CommonOps.extract() - Created optimized versions of CommonOps.extract * Seems to boost performance on small matrices but not large - Added QR decomposition with column pivots - Added solver which uses QR with column pivots - BidiagonalDecompositionTall now passes all of its unit tests ----- Version 0.17 2011/06/28 - Moved general and symmetric EVD to DecompositionFactory from EigenOps - Moved show() from MatrixIO to MatrixVisualization to help with Android development. * added "jar nogui" to ant build script which will exclude GUI related files. - Added CommonOps.elementDiv() * Thanks to leokury for the suggestion - Many functions now handle NaN more intelligently in MatrixFeatures * Thanks to kaspar.thommen for pointing out these flaws. - Adding Maven support * Can now download from the central repository * Requested by soren - Added sumRows() and sumCols() to CommonOps * Requested by b.broeksema - Fixed bug in inducedP2 where the max singular value was not always returned * Found by Antonino Freno ----- Version 0.16 2011/02/23 - Removed SVD code based on NR - Fixed bug in BlockMatrix64HouseholderQR.applyQ() * improved unit test to detect the bug - Changed contract for LinearSolver and added functions to determine if the input is being modified or not. - Genericified LinearSolver * Removed LinearBlockSolver - Genericified DecompositionInterface * Removed block decomposition interfaces - Clarified behavior of functions in MatrixFeatures. - Added EjmlUnitTests * converted many internal unit tests to use this class - Changed MatrixIO to take a PrintStream as an input - Adding support for toString() - EVD and SVD now modify their inputs by default - Added unit test for PCA - Added in-place converting to and from row-major to block matrices. - Trangular block solver can handle unaligned input - Modified isIdentical and added isEquals to MatrixFeatures. * Resulting from a discussion with Kaspar Thommen - SimpleMatrix has been made more easy to extend by adding a protected function that declares new instances of SimpleMatrix. Now function calls will return the correct type. - TridiagonalSimilarDecomposition is now an interface and related code has been made more general purpose. - Added a QR decomposition that supports bidiagonalization for tall matrices * Results in significantly faster SVD when U is not needed. * Not used yet in SVD because QR decomposition without column pivots is unstable for singular matrices. - Modified BidiagonalizeDecomposition interface - SVD and EVD QR algorithm take in diagonal and off diagonal as inputs not the matrix. - Added dense matrix copy triangle and isEqualsTriangle - Changed logo to more accurately represent a Householder reflector. - Pushed SimpleMatrix into its own package. * To make it easy to extend, SimpleMatrix now extends SimpleBase * Added dot() and isVector() is SimpleMatrix. - LinearSolverFactory and DecompositionFactory now take in the matrix's size - SimpleMatrix now accepts variable arguments. ----- Version 0.15 2010/11/20 - Minor speed ups in LU, determinant, transpose - Fixed a bug in MatrixComponent. Negative elements were not handled correctly. - More clearly defined what LinearSolver.quality() is and made it invariant of the matrix's scale. - Added wrap to DenseMatrix64F for handling raw data. - Added PrincipleComponentAnalysis example - Changed DecompositionInterface - Added unsafe_get() and unsafe_set() to Matrix64F and implementing classes. - Cholesky and QR decompositions for a block matrix and associated helper functions. - Simplistic functions have had the hand inlining removed. Suggested by Kaspar Thommen. * After marking it was found that sometimes more complex functions had their performance significantly degraded after they started to use very light weight wrappers. * In some cases it seems to slightly improve performance when setters/getters are used. * Yes these changes were statistically significant. - Changed behavior of CommonOps.extract() to make its behavior match other submatrix operations better - Added the ability to create a new matrix if a null dst is provided in several CommonOps functions. - Moved examples into their own java package. Makes selectively running those unit tests easier in IntelliJ - Added elementMult() to SimpleMatrix. Suggested by Nikita Rokotyan. - Fixed bug in the different QR decomposition implementations for compact QR. * Added compact QR to generic tests - Fixed bug in LinearSolverFactory.symmetric() where LU instead of cholesky was being created. - EjmlParameters.MEMORY provides a way for it to select algorithms which are fast but memory hogs or slower but more memory efficient. ----- Version 0.14 2010/08/07 - Removed left over debugging print statement from SvdImplicitQrAlgorithm. - For reflectors (used in QR) code has been added that can switch between two normalization methods. This can significant speed things up and improve accuracy. - Added underflow stability benchmarks for some decompositions - Correct some issues in SVD and Symm EVD - Seed up SVD by removing need for some divisions - Symm EVD now uses the Wilkinson shift - Fixed a bug in kron(). - Added several new functions to SimpleMatrix and cleaned up function names. - Fixed a bug in QR decomposition where compact flag was incorrectly handled. - Added QRExample* to example source code to demonstrate using extract and insert - All QR decompositions now works on matrices with any shape - Added set() to MatrixIterator - Added additional checks to matrix multiply that makes sure 'c' is not the same matrix as 'a' or ''b' - Suggested by xcolwell - Moved IO functions to MatrixIO - Provide a way to save/read DenseMatrix64F and SimpleMatrix to/from a file. - Fixed and added more block matrix operations. - Creates a new class to store transpose algorithms. * Including a new block one that is about 40% faster on large non-square matrices. - Added quality() to LinearSolver to provide a quick way to validate results. - Added MatrixIO.show() for visually showing a matrix's state. ----- Version 0.13 2010/07/08 - Fixed SingularOps.descendingOrder() bug. * Thanks xcolwell for reporting it. - Fixed a bug in RandomMatrices.createOrthogonal() - Cleaned up Matrix64F and D1Matrix64F - Updated java doc for several classes - Added SVD and EVD to SimpleMatrix - SVD can now selectively compute U and V - SVD is computed all at once. - Seems to perform slightly faster than original code and is simpler. - There is a loss in performance for 2 by 2 matrices. - SVD getU() and getV() can now indicate if the transpose is returned or not. - SVD fixed issue dealing with very small numbers canceling out and causing a divided by zero error - SVD changed exceptional shift to use a random rotation - Moved quality() functions inside of DecompositionFactory - Symmetric EVD * Fixed rare problem that could happen if two eigenvalues are identical and off diagonal element is small it will never converge. * Added code to make it more robust to very small numbers - Generic EVD * Fixed long standing issue with eigenvectors and repeat eigenvalues * Made unit test tolerant to small round off errors causing an eigen value to become imaginary - Added a version string to UtilEjml ----- Version 0.12 2010/06/17 - Added PolynomialFit example code. - Updated comments to reflect the addition of LinearSolvers - Added MatrixIterator to provide another way of accessing elements inside a matrix - Can just compute eigenvalues. - Fixed an array index out of bounds error when computing general eigenvectors - Improved accuracy of general EVD when computing eigenvalues and eigenvectors when dealing with nearly identical eigenvalues. Thanks to Ex'ratt for finding this and the previous problem. - Auto code for unrolling determinant by minor. - Auto code generator for unrolling inverse by minor - Created experimental code directory ----- Version 0.11 2010/04/07 - Updated LevenbergMarquardt example. - Added the ability to save the old data in reshape() if the matrix grows in size. - Added Kronecker product - Added LinearSolverFactory - Changed constructor in DenseMatrix64F so that var-args can be used. - Can add random numbers to a matrix - Added null space to SingularOps - Added a function in SingularOps to rearrange the SVD such that the singular values are in descending order. ----- Version 0.10.1 2010/02/18 - Fixed a bug with large symmetric matrices where eigen pairs would be incorrectly associated with each other. - Made the general eigenvalue decomposition algorithm less buggy. It can now handle the case where eigenvalues appear in a different order the second time, but doesn't solve for repeat values correctly. ----- Version 0.10 2010/02/16 - fixed a LU pivot matrix bug - SVD Implicit QR algorithm (much faster than old) - Optimized rank1update for large matrices - Various refactoring and other tweaks. ----- Version 0.9 2010/01/29 - Added the QR Algorithm for eigenvalue decomposition for Symmetric matrices. - improved eigenvalue unit tests exposing some problems with generic EVD - various refactoring ----- Version 0.8 2010/01/15 - Usability improvements - Fixed matrix multiply switching rules for some of the operators - Added automatic switching to matrix vector multiply to some operators in CommonOps - More random matrices: orthonormal, orthogonal, normal span, and with specific singular values. - More matrix norms, including induced norms and all the p vector norms. - Eigenvalue decomposition for general matrices. - More functions in EigenOps and preexisting ones improved - LU now works for rectangular matrices - LU now generates a pivot matrix (I guess it is really PLU) - various refactoring ----- Version 0.7 2009/11/10 - Created a linear solver interface. - QR Update. * Two implementations. One is more straight forward and the other is much faster. - Created a linear solver interface that allows data points to be added and removed. - Made decomposition and linear solver algorithms use lazy initialization. ----- Version 0.6 2009/10/26 - Added QR Decomposition - Added Leibniz formula for determinants. * This required a permutation algorithm to be added also. - Fixed various bugs - Improved SimpleMatrix to make it more useful ----- Version 0.5 2009/9/19 - Added another type of matrix multiplication that creates a temporary column * This significant improved performance in some areas ----- Version 0.4 2009/9/5 - Added two more Cholesky decomposition algorithm; block and LDL. - Moved significant magic numbers in to EjmlParamters to provide a central place for configuration. - Various other refactorings and bug fixes. ----- Version 0.3 2009/8/27 - This is the initial public distribution. Has most of the final functionality. ejml-0.28/design_notes.txt000066400000000000000000000076031256171534400156320ustar00rootroot00000000000000Block Size --------------------------- - Transpose * Q6600 ran fast at 200 for 10k matrices. didn't check higher * Pentium-M degrades performance slightly for 2k matrix. * Selected 60 as a compromise between Q6600 and pentium-m performance. - Block Cholesky * 20 seems to be optimal, 60 slows it down a lot. Matrix Size optimization and Decompositions/Linear Solvers --------------------------- Once a new instance of a Linear Solver or Decomposition has been created no more dynamics adjustments should happen for the input matrix size. This is done to simply the code and testing for correctness by reducing the number of permutations. Block Cholesky Decomposition --------------------------- The DenseMatrix64F based CholeskyDecompositionBlock class is easier to tune and offers equivalent performance to BlockMatrix64F based BlockCholeskyOuter class. CholeskyDecompositionBlock achieves optimal performance with munch smaller block sizes, but its performance actually degrades when larger blocks that are optimal for BlockMatrix64F algorithms are used. CholeskyDecompositionBlock also works directly with DenseMatrix64F and avoids the need to convert matrix types. Block matrix solver is much faster than the row-major solver. However selecting the default class for Cholesky decomposition is not obvious because using CholeskyDecompositionBlock would require an additional tuning parameter making the library even more difficult to use. Block QR Decomposition -------------------------- Saving the W matrix instead of recomputing it each time was tried. For smaller matrices it has a noticeable speed improvement when solving. Anything over 2k it seems to be negligible and almost double the memory required. Block QR Decomposition is only used on larger matrices so there is no point in saving W for later reuse when solving. Based on profiling results W can save about 5% of runtime when solving a system. Block Matrix Multiply --------------------------- - Block matrix multiplication does have fewer cache misses. - Converting from row major to block and multiplying causes too many cache misses. - Two different types of block matrix were created. * single continuous array * N*M arrays - After making the code ugly and barely readable they had comparable performance to multReorder(), when multiplying two block matrices together. - The code currently committed and that resides in experimental has not been optimized as much, but is readable. Unrolled Matrix Multiplication --------------------------- - Tried to unroll either a row or column in either of the inputs - Does result in improve performance of small square matrices - Does not always translate to tall or wide matrices * can be much slower than other orders - Did not integrate into library because of added complexity Combine matrix for DenseMatrix64 --------------------------- combine() is a function in SimpleMatrix that combines two matrices together and grows if needed. No equivalent is directly provided in CommonOps since it is horribly memory inefficient. Why use DenseMatrix64 if you are going to do that. QR Decomposition: Column Major vs. Transpose --------------------------- Two variants of QR decomposition currently exist in the code. One converts the input matrix into a 2D array in a column major format and the other creates a transposed matrix. QR decomposition has fewer cache misses when internally it reformats matrices like this. The column major 2D array format is about 10% faster than the transpose algorithm due to less array traversal overhead. However, it requires specialized code and increases maintenance overhead. It will also not benefit from improvements to more common operations. Deleting the 2D array format was being considered for sake of simplifying the code base. However, it is actually an idea format for QR with column pivots and results in simpler faster code. So it was decided to keep both variants.ejml-0.28/docs/000077500000000000000000000000001256171534400133325ustar00rootroot00000000000000ejml-0.28/docs/ManualEJML.pdf000066400000000000000000005175721256171534400157330ustar00rootroot00000000000000%PDF-1.4 %ÐÔÅØ 3 0 obj << /Length 1085 /Filter /FlateDecode >> stream xÚÍVMsÛ6½ûWðÒp&„ÉöÐQ§c×N4fzhz€)Xb†"5$”Xÿ¾»XÊ–]rH;>\î×{Xìâ—åÅì´‰ÜZe’å}"KÍ…)+ ¯T™,WÉ_ìò“¶n|—*ËBšåB±k‡_R“3G’[†4“¬yÀoÉnš»ÁEÉ!ý{y ‘ŠDjžk«0R©¸”I–®+Eq©*˜Œrp>¿K3´~D Ë!#ñ²4dq½ï<)+û7SB Š——‰,¸’Fc¼LÅE®“ ÖG¿ö]šK<-ã“¥ä•11S1-„žLdšU²«ÛŇ?æï—£²b*æHºÒLˆÔ¤KÞ‡R”lµ¯CqÁPåyÜ ߺ€ì†} ˜íà"~»nE›y»î‡&l¶ðCj£ Øž:”äP“ÃË·Ý!¡™2…)Aüx4O€5c*`Ls­ídÏ·p®¿»vëºwM õ±Aoü3C‰Å ±La‡EˆW³È¼”„yyŽKÁõa7¾UUæµúlùlP0/°iõÓÑUõß@4ç!ê âû>IJ.ªWzN߇I B/ÛTv¼¶§×~žfšÓ[?6ëŽÆbÓ´ýØï6Ø“À˜D©ùÖF0ÇFPËþÜ`»>P×Ýb=íÛÐ@; Iì ÛT2 {Þø3¶õ¿Ïi YBim"¯D%#J…T‘8#ŽÄÝapu˜ Ì©A&•æV£…àêÌ”,qJj)㔌÷ÌÄ{œ’8!qø!y ïOˆËëÛX%Iš‘Öɸm:#5ŠÚµ‡{üqÝÄ1)-Ï-Ì9™s£+Jî¾G3k´f·oá4º5IV¾ýñ'$Wûè*uήÂxT¡òÁýºwmÌ þ'à7WLN)ÃÿÐӊûd“c7>^Þ“¤ê~»ÛSa¸¶ÅRžüÒˆ27Òº‹>ûqlî°ÌTá=0ˆØpO!û°!íq ^'8-Q¥uÃÚ“ìö͹Ôh¼ZÁ!Ë­ŒÈPôˆ ?\ .ÆøîLbZÿÖ)ág×#ª/¨Z£MœæèåÎ?F?</›åÆS°‰{ ÜŸæ=½M à´mÆG‡%&Þð’B_\:·mjâ1ox_ÕT ( O› åÈ;yfD½žä{€BnHîÂ9:‡=ÝŠf‹j¢œ‹ê)?R™Q*¨CKÝzבò|qÅIˆ×„vxEp½¼Ç' Ôì뀇à1¯nR›V˜?œËðùMÍó|J6,¿<×lzúŽ>`Î~ÒÚw«øp–¤póÛâ†$-Ü2#Ÿ»Ÿ›HOØý8›Õ}d~åùšvýžXp®³ÝÌ?ë1Ù瓤³XÏÙ±H6;ÛÒµfgál¸ÕñI š—Ë‹¸U×J endstream endobj 2 0 obj << /Type /Page /Contents 3 0 R /Resources 1 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 1 0 obj << /Font << /F16 4 0 R /F17 5 0 R /F38 6 0 R /F66 7 0 R /F65 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 12 0 obj << /Length 1489 /Filter /FlateDecode >> stream xÚ­WKÛ6¾çWì¥ D²Þô”4›bÞ6MÜ^š¸m1‘Dƒ¤³q}g8¤×N½hä¤ápÈùæÉÑ«õ³å›¼¹Jë8KËâj½¹JÓ$n€¬Ê"ΊújÝ_ýÉÒE”¦YÉnîÞþúîå/ëÅ_ëÛå›´é¸-Ë &WQVÅYSÒ‘õ Í"ÊÚ’õ ¾5ëö“˜@Xb‡íAi-ïÇ­ÔÞo«?Í­ ê>lm”&¨Éïi±H7jöw[9§U» göcÐ0£ˆ;-⢨÷–Ъí(âETä%[/š”7Ï*¶–;$j6>ã™ÿ²”[‰ÜIƒU/œZpyY¶çºwÈî^,—]Õ‹øP§¦ån)>$iÕIÔÑ0}äxìó¢,&nµüΈFy¯¹>,)VçAŽ‚ö¼Û<'íYò¼ÈSf5NY¿ïœÿñëGX.ÈyѰۀͅ9wÐÑ+‚H‹I™\ßÞ­à›3¿þä(gÁµg[gÃÆÉ5.9˜ø,wÑ¥ï!frÞBt °3g6‚VÎ}0úºnØ æI¹‘N ’|ôl®Å@µ K 6î[E›÷.nþbnh"¸ÛS^ð’þ<ñ•³&qÇ3HÃå‚1P1‚XT MЧì@GÌ h‡Ï=#×[AÛÁÒçX É£HF† òx±WÇ;8Dê/`Ç#yUžbÉ«‚ÍÊ¥ê£}§ ¹ŠV5Lh‹~/Ëš‡ÀˆàQïmwH OtèÆNJ3ˆ>¨¢ûÃÌaw’ÝSN6beAV›D{s±¨q ©¦´´Ã„!¨*ò ð÷ÆË£&/«÷4éú“[Ý¥„™”LGÝœ¸Ý(øLœ—ooâ3С <ÐÀœJ£ÊØF ÌëŒ=Hë’Ù‹øo ¬$ù_Õ#p|$26pCo¿ðç5z°rtÎös/4á^fõóÛÕ%/q¨­øÉŽGeMKê‘°ØDd/ „¨³´z@è{Þ!ˆ*úJòºÐü(+© `ÏbÏòð  rÂåãCXÓg§Õåuèà M/°?b•çëÐà€@] Úô.´NË"xwŒ„Ä•´>çB€Ä±ò»¾9Ø„ Bk—§—€p!zB!é-zû˅9plÉuqf½[ÓgR`º+0X¨{¬CöQtþT€n\'DƒjE6ôunäÓ„Õ9o± ¡‘ú®‚û+a©îpáâ!Ó©¹Üõ{ïÿxí7¯å–Rˆ2vÜ‹ïïÉÓxƒVp ¥vZóù“dÓ$pVòë»t1ƒ™Æ¡óàWìû»øDSM¤æÎnÙÙ©Çö %Ÿ;á)mµÅYó kâØ¿ui\'Õ¹/oÜ8ï£Ï}ZAÓÂofíã|Ó^è¨NølŽjýÜz&ŽŽíÂ"'—˜§ŸdŸç0™9 þ¶ÐoÚ4Î!Q ¿³mþt`ëÙõúÙ?EÃíD endstream endobj 11 0 obj << /Type /Page /Contents 12 0 R /Resources 10 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 10 0 obj << /Font << /F38 6 0 R /F17 5 0 R /F45 13 0 R >> /ProcSet [ /PDF /Text ] >> endobj 16 0 obj << /Length 2166 /Filter /FlateDecode >> stream xÚ­YKsã6¾ûWhoTÕˆ!$Ƚ%™LmR›šÚ²÷”Í! >´$óë·€DÛ´+«è"4ñh|躡ïîn¾ù¤Ê•0©¹^ÝíVBdi d‘ëTj³º«W¿$j½BæÉG;ÙõF™<¹†ãv:näoÛÕL|Û<ôƒŸöí¸þõî§o> ,Ó*Ï%rÏVY¤²Ì™ïG×îg; þk¡?­7:‰¹öމ¶'¤dr¿‰ý–¿jƒ3Æ&pè¸ýá§Ÿÿ™2ùcà™‡…5î8˜Ð©Ök ÓzH“m߀2I?ºš»ú·u¼o܈›Hؤ[Ã¬É mš'œ¡ù8uÎQ`;NýYÚÐgÃïÇ<ì0Xäü´„ôˆ3Aô…Ä¥ªPÉЯe™1Ñyš•Õ_ÔL‰²Ö„\Gä—GK•‰´,Íu°© Šîq¶‹†û-­ q%l h­.¶`Ñ "\¦ò+aËMš s ¶¥(¥ ÜìYu%làvY%.¶ SÉT”WòÁA‹ü"l :Õ’ý¼¼Û’¯ëô}/ãïyM @‘€Ãu ÑJ2òSZ ÙŸø;ä× J Nýb&C®Ûö”‡Ö§Äj„ŽIÎ&C"¬C" ‹8¦¤qµÁЛB¢ ¸5oþ-1Is\;ù¾ûÀ> N{JŠ!ïßö!ñÿ:Å9#·¿ljçXî€}÷~üÖ6<°;v[ä™Ú°`²_©&ThŸ'Õ8U–EÒ8;²ï¨f0³r£ ÄØr‰mÇs|w8‚´&*_ X—"Aá÷Õb ÔµgŒ¼¼fb<ÞOƒÝÎF†çÅTÈÖî¹zšö8KÍ¥Ú±vú¾oÛ¾û|yNØC%·aòÖÛÆÿáêÏ@<†ºÈÁñ¼‰T?=wl;Ž.°{ÜCÑcÁÞbñð;Éw©Z ¨$H PYCa¹åϨ³‘?YiHY‚£ Ÿ±’xx^¥Ü eÌ?W^ Èö¤Ã Ô ´Js) ~ #K[ü¸ð`‡)LÜñÈi%‰ŒI ƒdÛQVs¤1=3„8@©l?¢E¼SÆšUšÆÀÃMå­r‘_`ðE•Še¢ ã=L"ÙÑ—ènïHaº š¢µtà'þŠÂÐÖ‚0¡›< Úð€dÜiÅMŒ Öwaå¦ñä¯Èu ÁÀúÖÍ{*z8xíùÁ£^JMj0•!.aOãïпOdå b™hžò¢aˆæÑ@f&ŠóžÁò‘ ØÙÃ.µß,ÙÁà¶=˜,‰'Á Lo!ÐwϯDϵŒçEr·.%¹9 ·!L¾žÌ==¾Q =…5‡¡l»„ Mcx•A(EˆePì†ÂÝè&¦É’áç$ø‘ )a‡…ê)Æ›#G¦CX9{ô¨ñýó?úS4‹‘èÃÚ('¥5ˆ:JUé<±Û-à`/Óá ûOÏ&aƒžg.Ƴé†Óô…Ÿs¡¢lÐŽ›æÌxÉѼš,òd!ÜÛ4ñêæKî«ém—½%GÁ§<ާûd÷ÄËøn(ñnÀÏó|n O6>jÎ_%Ä1€þ¦“r Ê£s«¼8¨a%ÎÁÇÃ]‹²- @¬ÖœÃÎa ±‘pé †g÷(v³Ð¡弤©© ²Éï";wäïÚ¡t5™öÑ_„gZì˜=ÂÒø.ŽNÇô))ñ^Ï5Ó¾#ÏVý¸„À³K  ÜåÁÀ) iÑuñ›.i$H®[7†i»Àñ…j—H©èv0yòLèG)ºƒ(JI­Î(&ÀgËw>p2qž1@ä%‡†qò>bØS é ö ìëqß›°útnühmíâú¥S°o@àhûxé?¸Î ˜®a÷Ë„óUl û¹sœ…ÏÎSÒy ït¢‰’ŠÔ„bþYœ¨…px.üŽçá®Ú¼]´dº’É—îä$:„HÐauNÊ|bŠƒb…ÇÝ—*¦þ˜1òÈ9"!_¿ã^ËMôb܃#a•Ä?H Lx;­®ÑAuç'b,ÈP¢U o@œåVñ#¿‰¶F"†ÎYÁT1lárf‡ ÎUÀ=õcÇkBY…óüt¤jn `ÐAH&£9RÂìêû}߸ñËÓG7ûWÈÇú­˜ßÂð¢ÌÖžÖûðO‡—b‹;cmBÅ)ÔrnFZ‰TaIoòT§ÿâBIÿ?HÎâ endstream endobj 15 0 obj << /Type /Page /Contents 16 0 R /Resources 14 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 14 0 obj << /Font << /F38 6 0 R /F17 5 0 R /F42 17 0 R /F40 18 0 R /F45 13 0 R >> /ProcSet [ /PDF /Text ] >> endobj 21 0 obj << /Length 1351 /Filter /FlateDecode >> stream xÚ­VQoã6 ~ϯð£Ôše[¶³a/wkvW¶ØÃÝ=(¶šh³­T²/íýú‘¢œ6½؆!@DQ¢ô‰üHúÝzñï"ÎÙJˆ,ZßGYZ²ŒgQ)J–®¢u}Šoåhõã2ɳ2î—YOݨ÷]#GmRON[«Øì— ÊúeÇ–_Ö7‹ËõâaÁ£~<â¢b/á΄¨¢¦_|ú’F-,ÞD)ËWutð[û([ Vd vÑÝâ·Å;\žæeyTf+V¦%!þE N첸Z&‚qƒƒˆF<ÏXžQ VÁhPÚ‚ÖK?ð9©dÃÔÿnîbƒÒ{Ó9PóŸüqɹóÞ›¾7Ãǽc=8ÌŸq±¹hŽV¯]Ÿ—Œ×u”ÁDÉÿ‹ëï4Àî÷]@þ¶çE‘²2û/80% T¹Ó/®?u»$=F…ÎK7oúB0¸,TÀEò•ÞNVÑ“³—I‘ ôð^Zí‚/¾ãí–CKÂKpŒnÍëˆW@xQà­‰¨Y¬OòFAË„óLÄ—ÍÝ9¸i”d7u0¹F8«2wŠ…¶ðn4÷ŠV[ÕŒÆ>Í­RóÊç”çʪa™ÕñHJ¼GUÇ·­Dlîiƒ¤áWÙõ2\Ç]â陞sT¶@l¤w({kð诺UmXêŒgˆ=î‚P_ÁÙo“[i&iÛ‘6›ý¨{ýmfª?sk,Ö³s¨Ö;åB|G<ø€&„p¶œCJL¨bŠ·ÙO´´¤¾.ÐÍj35lõ ”=fK«]¹„|Õ)$ƒ«ï€ÝøjŽŠ/£Ta”Py6J¸€Q¢‚ù'”}œ|Hpæ_Vd)…¤¦°Pd^‚ T»” ^‡*ylEB« ô¸òÀ35¯£ÒûXâßSØ6îdX»¼¹ý@Rã)ÆâN“É!°JI<R¹¡È¼ð,ÿÈ 5Æ ±({/åHGPòA¡!WÕxåÑЈ‘‘x=ÌöaϽé:‚ã#Ž*7m¤ÝÚ|àD´jÁ{ÄûihÆc•ÑQós‡Wu‰59âFE¦`yQεÊKY†ºV0 ‘âJ#¨T±?å2ç@å2‡(½Qw2Æ¡VžÖȼŽÕ£#­ÃÔõ²£õÆ ÚaÙªÞÜÒ’j<ê=(Z< † \Q¢àƃ•{¬ïXÞÏù÷ÙE…"Œ9°Œ£pÊbÔ †IƒU[Jœ¼îü¨#þ€0ó÷%¤G”ErØâë³<hh&qàØA Z¼èp¨¤úˆ»”tÞißt¬î¨†¨Êí±0„ãËñä<^º‡ðœñtú}T×ô±‚BHÀоØÔs"€Ð‹Í†&N j Fv–§ÑÀAº‘]÷¬¬"*àdƒ¥(,¨¹âœxÚui¢¨¸Ñø´!¯æL’3´g0€BÉ ÂðU[:­BiÃ@ÖÂQÿ,»²3Ù…ßdÿ2µè°ùô‰¨ËN“átUö\ ¡»¥ã1KÁ² »½#`íäù°$ ÷6“ïÑWÜ"¾ϑت‡ >,¼SSbF3ÏÈyéܯi²·ªU $/åEà–5É›~e}@"ûΰYàg2ÉØ¯x¼µ²ïU0‡nÛº³ À÷ á[ßì‹26ÓHj*8¥ÿlj‚Îíäþˆ7ß÷ú¯QèU«©tƒvö:Näñ¡¿‰ÐûM ’¾ý¯80IDЀÕü¾£ÿ›„Ì endstream endobj 20 0 obj << /Type /Page /Contents 21 0 R /Resources 19 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 19 0 obj << /Font << /F17 5 0 R /F67 22 0 R /F38 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 25 0 obj << /Length 1781 /Filter /FlateDecode >> stream xÚWKÛ6¾çWø@²Ž%QŸŠ´Í¢M›¶@è¡é+Ñ6³’¸åÝu~}çEYÚUÐ\lÎ 9Íã›á÷7¯Þ^ÇÅ*Ž7»,KV7{Xn7e¦Vy¦6‰*V7õêïÈuf}•&yÔX^QçÖI=21è;¤ŒgòtÏ»Û5Í`ï›Éy¿Yÿsóa›,Û­®bµQ*ç{>šÖõgØšQ«;}0­éPÉÀ<ëEæzëʵ÷­ô`jÙÒá ǰÙöÒX0± ¸„,*<qå¡684Ó÷«ëkBí O†QȈ'&mx÷z6Ë;öYc\°3„ßÒ‹8MdB¦Œpü©SŽ©“ÊX«ŠJ ‘›gC8>ûnزç¸&ããâò~æøž€x15šL€hÑ«Þaš'/ |1$Ø ˜+x×ãÓÚ05骈±è¹€¾xÌ6A ?ÑPèöÔ£_^½„00ðWÊ‹¦‘¡%€=Y4œhAûС¬ìæò0Ÿ´`‚ö] O‚ F•bSnK¾/CÑ«÷7¯þh¿ì0 endstream endobj 24 0 obj << /Type /Page /Contents 25 0 R /Resources 23 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 23 0 obj << /Font << /F17 5 0 R /F38 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 28 0 obj << /Length 2235 /Filter /FlateDecode >> stream xÚ}XKã6¾÷¯ðme –õ $+{Xt ° ’E¼ØC’[¦mnëáˆôxœ_¿õ¢l÷¨s1Éb‘.V}õÒwÛ§õiµHÓ¸.Šl±Ý/Òl«4_”…Š3U-¶»Å¯ÑO½Y®”Ê£Ë2ÛDz™UÑ• ~À1‹.£õÂc~KÒ²±¦G^Ï´:óyYpš(º= pæØ9^[Çñ…yÔÙÞvöO#Ô£\®»á,ÿ¾}Y¬Ò*.ŠF+U²´Ã~¹ÊË"êL7ŒWžû£ö<Ã?±öfÇ ÝËdgœ~ ü˜]¼\Emáœë@BØüQ(ÃÙ‡?1<9ÌÓçl Q“G!½í€9ÛäÑ«¨3Û¨¨<¬0›˜Ìî ÂÎ JªÊˆÔ~îP®Wzyƒô]F¯MkÓ܉Yzd÷¼?°©·ºµ’”È'·ƒâµ×¨kæ¹m™Æß1݃7l?'ñ÷/Ÿ~„/Ê EÜ0E$'À²a;í¸vçOyŠᙹòìªZ¦‘iZ=†S6žàkÞŸ<;T)‚ÉÌÉ=wÔ¢7xŸª£ý¹o¼z^ø_릜ªŸíŽšdѶ•Óæ‹MgÚ+3Ú]yÃËqÛZ``}´BEÖOv/b\‹°“—€í€ØcÊÐ4‚[.`ÚÚWÐÔ¨GK¨Ê~6=,ÈÁ†3/H$w¬X^èðOžtÚ®üÂËËÑô#6 VÈÑGÝŒ‹éÈ\ÜxÑÆÍõ*YTq]%)FĬŠUU,TœçfL™ë1pVqY—‹ÕÚ+Å;o h:ØÈÃé oe èjÔ¨­+¯!(¢â¢„i€È2»;Þ @a ·ÓŸ)„µƒ`jÇO_Y\åOßR|Mr@”í4 ˆÁ‡ó=•@\¡Hˆ¤0²›Å3OØaÈÏÀ#;AY–Ñ'4æ¦n—›4’°Ú¾Y¹í!iÌØù·¤H>m_`HgÌ–Cþªk2[ÍüÙœÙê8©*6›°,ë0›‡ ®"rûw*y òŒaîf`o‡ªÊ¢WÎJ†öqÇs½µª”à%4öÁ•Êcˆv—Ç€®Ê$ÚCÇ3Å]—*ö>\’ `äÌÇsÌÆe9 LâÄçy1¯g'sËO3ã^7(î&¯¢gÞYǹxÑh âj8Œºã…¢¼µBXHFÈB°Gĵ-…·‹ì帿±.EvÔ6d42 89$F"s~ŸAДO> ¿ˆfòZ,XS ƒË˨Ow8€ ŠÔ5æÞO(ƒÕ¡2¨E>< )kÓ­ïÔZæuô/ÏçŽ`fÇl”x§ô$—Xq&ªë©Êê ÄÏJ‡nJʸÏàÁÝé“f\Ô˜rÄNn%Àã °šÞé×VSJÅdAøƒd÷^Iö¨&máöSk¡¦T¤‰$ w f ΰ$e'˜줦$½YN<Â+yÂÏ€XôQ•·R k‘³ !Ùtsåm‘‡B2p\¸|À:EFˆý›ã]Ê¡¸áËI!Nx‡žË… g$Ý^2£Ð÷Ú¯~ˆdX¡ìeó.Rݧà4¼,ølgÈ‹ª$„² ŒþÇÙŽ|o:E?0Èfº9G£úÐðÖ3ŽZ³;H–¦ÿEl“š‘‚Dn8¡U”Ð6Ysô†ä 窤è q¾ÄþÍsœ.WišP-óM…ec‡ósë-{2*?T>9¼[#„Ü?æ²ÜŸeqZ†>èä±)! +,PzoS\æðä}@D×Q½Èçw<:à`xJENÃ1ûNÓ3JÝYÒÓx+²¡Qö‚ûÁb¡a=÷¼1 ìm] àW­¬:IÅÈvï-°ôXR\OåÄ '¥9›­¹W˨a¨¾jp•Æ[ @ €ÀU®¢E°ƒÊX‚ôê[Ûˆÿa°ÅMÊn@‘Æ“µlÌ Yér‘.ÒM©dœNXn4‡Áqgû«òò' Ô9šj#±J…‘þ.ÐWÏž†¼6àçvþŸ?ÿGXobàRРmëîøb¨KÔì‡9#Xà ™‚‚¤¢£õ‡Àiž™pÿlX¢lØ2$œBu9Í4o܃D4™œðK*ûpªt¹’sÖliOm¼’6^IÇŒH…bºZÛr:Â}nž05Â^.ðŽ'G{8òVhZ©§Qw`oz5ÂTÕIø"[ØÕnu‰!2=R`ɸyLì@q’l©œ™½ÓT5!?KBâ|ÕÂ1&ƒšéOpENÂW¬PçLwŽ©¯… ÄÎp\¹á(I+GþmºZ4ô Sèô›¤Â<¨evï߯¢V”Thí[ÈDb]ª[oÏÝ2P43qË‚ð‰&»E¢†‡çî¿*àz&ðH{èÍléÊv.vǤ{`ÉqShRN t‚jÇÐÊó¯Å]“†>K$ÐGþ˜À9}Èz‘cfLˆhI @|^p }ÇÜKxoú5}öÀ™~ D¶©BÕ·™‹Ü*Ë ÃK¦dŒã¹ïå“TIÝ/\# )Á H¾î(çÓ÷Û§?žR7Y¤”“xS¨EZäq¥6‹¦{úõ÷d±ƒMxQœ×›Å…X;`)b•0o¿<ýûé;üÊY-Jh ±5ÇoœPA¤XH”q–”M}Y@KX—Y‰Œ ¥КÇe*\GúöèOß®× û1î­óña ¬ÿb6üµÌ€ï9Øèôšï¿—c%÷o žyhQ?¢øJˆ&d‚š¿Ckb¸ëÓš•»ò²Aµ`e5‰ VYÏU>i•ƒ31‰«Jê«2Øåÿ¹§ëi endstream endobj 27 0 obj << /Type /Page /Contents 28 0 R /Resources 26 0 R /MediaBox [0 0 612 792] /Parent 9 0 R >> endobj 26 0 obj << /Font << /F17 5 0 R /F40 18 0 R /F38 6 0 R /F7 29 0 R /F65 8 0 R >> /ProcSet [ /PDF /Text ] >> endobj 32 0 obj << /Length 222 /Filter /FlateDecode >> stream xÚM½n!„û{ JrÄàå8ÚHIáš.JA#qçˆÃ?yû,^_”Šef˜ýxòÝ㋲L)éŒÑÌïqÜÈÑ H –ùOöʳè·`xhðÊW¤q µ¤+¹—”3©%.§\IM3i®g¡-E(þC¿²oÑë‘Çý±Lè‡ù#RäêC›?UŠÖCü«ÇBlŇe‰âÍïØ†õ $À°Òç¶Kw®¥],¡V/‡šoÍ/S¸} µÆÖÀÜ H&o+•SqXoÀI·i³m^÷ì»_´Û^V endstream endobj 31 0 obj << /Type /Page /Contents 32 0 R /Resources 30 0 R /MediaBox [0 0 612 792] /Parent 33 0 R >> endobj 30 0 obj << /Font << /F17 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 36 0 obj << /Length 1892 /Filter /FlateDecode >> stream xÚÝZÝsÓFÏ_¡GyZ÷ýÑN‡I ™)HÚé ð l%ØRìRú×wO'É’s²åÄ1´“ÛçÕ~ïowÏ9¹8ztFT@2BÐàâ2 œ"!e …DØÓàmødÅḧ áå2,’,¥b2œÆÅ$OnÊ“÷ÏN/Ž>‘öiÁAB¨`2?zûSøòy€3:øR’Î.("RÀûYp~ôúèÄ£¥HIHNå¢R-›Ï³ô·Pp#Ãùˆªp9[XeqÚf@±d¸GͺÐTÔ$¿øØ § Éñ‰ ¨J¯i¢têÕ‡S‡ï Î;L„¦O-ƒ¤‘CÔ"{öREÂ…ŒÂÄRh¤” 8b¬J³ ‰$æÁ¸EæµlÌ G\i€ø¶ì¸iæQz|¸4Ùè=Ìzƒ+ëé`'oeœÇB"5j_&Ž#¬Š±ã“ÿr;¼ =¼ÖÔÆH`ÕavÀJßS:ˆ=9c̸BTZ\€Hh>,gNÞ>º~Òˆ*:,Ðrp ªî}P”a¢Ã8Âà°AÑ9žN?‚´iêå/Ò.© ÃûPÝoÔv›è° êM#„ÑÑ÷â=…¶ëÅ ‰FlŸhÝÐ÷ìŸ}`Ž3¥—jØè×N¹“ÿUΪ¥~Û¶³_ {€™õNC ,/¢ÌàamððsÊ~ûáíi‡ì{¬ý¾Añ^3“&ˆ =,YNgñûíV•H¯|qÞ´ÁëÑ1ñ'S,`ˆC¥ì’]=¦1 ïN¬ç.œñ$‰fÉ?ñÔÙˆ“i\¢ã"YØ—¯c0rAO$aG‹n¢´‚Ò[äötî*ÍS_ý‚§ItØÆŸ¬$Ù/–_“0K£™;¸‹ è‡Õccaˆð *i@Rô—Ž`q»7Yž\%V‘Z¸FÀ}»¶f_–€äË!»&bj“¤iŸoÿXÎ84S ¯Œ" 8¹öc9W«ËຖÝßÊ»2fÔÁ÷ÆÌ%f-u½õëÖ­Vî¾Ãûa^¬Í<Ñi ¥mô6`Üg ¼µS‚‘ÄÓì¬Ô:CT¥=íŸ!L`ª¡” O¤WdS&ÝzL…n‡Ô»g3hÆd[<ùÞã)ïÏ®È[ñìé–ÊŽ ÌÞÜl‹Ó$»)1ñÉu”^Åo2ûá‹ýÿ­Âó/vx‹n*8m %wT$­!Z!Ï:ÌŽqyÇÔÁA7ïœÙK@€¹e—Ša^GÅËè% »–*|šþõÙ¹y´BÀIæî†¢$­àßÑX.mÛÿžN²¥kч™•Å9vJ¨u%,Èw¸ÔÃ> §U*¹ƒg©ÝÓº/yúD¯šIñÇHéÂ2“šÐðY(w:ЪyÈj§°Ï=ÞQâ«Q9^%‹ÄñxWêÇ6<’Ut|³_OgÍãîxÚ0¹¯:çñáÛÉhÌÁ›}_ÔÄwª’Ì“Y”û‰Zp6M{¼;àúGî>Àå{l |àv†ü65H¦Ü+zPû*ˆ1ï=Ì?¸qšö1[eC‘ü ±ìA{Ñt}?tWB„QžDé$®ð^ë6  LËxGÅÂ^Xq¾†ŠYB6Á£Ÿj$³Å|xͧ{,ni7Oµ}ò:žØ£OÈ¿·ÒËnÂB†o’«8Ï–UVOêgût±h»ïKu´SGÝEöíKy=#MxVjX,â|M'ÑÖ©[x{ž"ÉÒUÅvšÍ؃‘ï9ÅÐó¨Ýˆ«ÝÀѯC½û|™×ß4(q;ÈNC¦±”!QÀYrµÌ+dzŸ@ &Âól÷¬ íîœUH2Eí›Él9§§JÊÓç/~-5 ÀAkX‘­r±»Æ¿Álì endstream endobj 35 0 obj << /Type /Page /Contents 36 0 R /Resources 34 0 R /MediaBox [0 0 612 792] /Parent 33 0 R >> endobj 34 0 obj << /Font << /F17 5 0 R /F42 17 0 R /F43 37 0 R /F45 13 0 R /F46 38 0 R /F40 18 0 R /F48 39 0 R >> /ProcSet [ /PDF /Text ] >> endobj 42 0 obj << /Length 1079 /Filter /FlateDecode >> stream xÚÍW[oÛ6~÷¯ÐÛ$,bIŠ×{h’å¡@ÖÅ€¶ªÍ8*tñ$9Þöëw(RŽäЉ3 E@f¤Ãï|çÆsx¹\¼¹!2"iÎi´¼ƒ¥@*£— 1ª£å:úßíêU_4u’fDÐxmºU[lû„Äöå—å»ÅoËÅŸ aø#€‘â,âB#¥E´ªŸ¾àh ßEeZEûA´Š¥ ¢a]F·‹ß—Ï0âqÅ£}›o“”q¦ã·eÙ$TÆûèQçîçÚÔyŸ÷mñ—`7öŒ-ãÆ-¿&)<“­òºØîʼ7k÷5ŸcÝÕ¶ô`ÈÚ |SbÂÑ)Ö¦¶ú¢O¨Šÿ†m™ÂñUksĪÝïLV²…“àm^¯› ÄSH9Òs{Ýz_ô÷î£Ýfí­Ü¿¦4•U¬â¾ ªYù\ª$?âíöÛÏM—/Òݘþ½'D¨û`ú][Oº¿÷^/œL{@ÇlŽî߃YÝv^ÓXzž¯Ç—ODíÇæn*A–/ӿЄ½¥N=õ¨š°®DTv1ZÎÕ³ÑÒ`•æÿo°‚)çgEÍWP·ÊKsÒ~…„Ôø,l?§“ø¸Â€ÆÖCUœr€’Hël†Š°#ÂåáÒíÁ>L ІÂK%cÿ!혢%&=$%‚“ûIâቜ€Œ’# ³Ï Uq UÌû½)õi…–½î8ù#˜7°£È¯aHlþ’ýâLûÅ‘ýs] É,‹Ò Ô‰ô” =qg†¨>$œÅЈK¯€©‘d¹ÉfD ä| Yçè[Ð{x°h"w† xÂ2 †Ò˜Î-ûÇ´Í÷7ºŸŠ‡0F©ˆÉ£Ó nZcøDV8<;hãÐr×Ò{òð€NÖÎŽ£xº÷Êø/4Î ?u‡n¿2áùÉt÷ùö0ïÙ™äê>¯7æx ™Šx¶ÉΗ~²‚!b×»Åڬʼ-ꓨÍÞ¿Ïû> endobj 40 0 obj << /Font << /F17 5 0 R /F42 17 0 R /F45 13 0 R /F46 38 0 R /F40 18 0 R /F43 37 0 R >> /ProcSet [ /PDF /Text ] >> endobj 45 0 obj << /Length 502 /Filter /FlateDecode >> stream xÚ”Moœ0†ïû+¸ÔâÅ`Ûª—~ ZTÉZ¸%mäͲ- °ˆ„¥ê/f²n‘²'<3ž™g^¬yŸ¬Öëi£ ¥¶–Æ£…|J4J(ÚXŽ–ìµk½êvyvg˜SýÁÀú1ÛƒÑU{Þ¦7µ>¦e“~åmõ. D”è·Ãk¸¶ÜŽiâ¿oÉ ûˆPW31A„¸Ðy½†’¼iÁñÈOàjà(ø}*=?Ó'רñ.mÀÝ5|—ËÈN&ÇYQå’lb°ÔöJ|Ê À;øÄÙ¨ÆóôXóJ¨q;ˆáÞ^Vr{YÉ­RÒö‘¿ÁªHr(YhË+ëÂ)O Ò€RVv QÑå­8õ‚è*[¥Š*ÉÁ¤uæ+0·—ÑÅ ]8ÑI$&pfÀµ5/›êØLoô U9Œò²¤‘Ï«ø»H4§:—ÑF -;§]à›Ùc”•iÝžƒ¿¨u¯àöЏÑi‰·?£ŸÇ,M4ƒœ–;ÿ#S:‹¼Ïæ}(ÒÔS^e²%(¦@14¿½gªP‹©ŒæÒ*ù#Bë+ëÎs‘M°f:rä½ ûÑÕãžplW§o “8Tÿ0.Û×÷Ò}¨œ"ž¼ ²¼Mkøõè7lo\“Tl­i¯aaÏ4ÙÖÚ`KWŸ’Õ_^&g³ endstream endobj 44 0 obj << /Type /Page /Contents 45 0 R /Resources 43 0 R /MediaBox [0 0 612 792] /Parent 33 0 R >> endobj 43 0 obj << /Font << /F67 22 0 R /F17 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 48 0 obj << /Length 502 /Filter /FlateDecode >> stream xÚT]““0}ï¯À}Y%ÕñÁÕvØe™Â›_“Õ(…ÊG—Öñ¿K¸8kjÛÝ'r¸çæœ{o’›x2]8®‚±1£ÔRâu¿4 …ºÄpgT‰S僺mW9O4bªî4¬–<ÐnSÖdMj¾ÍŠ:{ÇšŠwYˆ(QX§bË> Cø—ö)¾S°gê(:&!èN§ÀØCÎ+@@: P7lbÊù›6o„9uh/_žbÕíJhD²<ÛY²•H²2Ї#ºøàR£Ç–B”œµ$XqÅŠúFpä£è,—¥éügËòZP#´|´„@*!ô¯£Ï"UÇÃHN(ðµˆý/ú°Ëªä¢/¼Ø=Ìòͷª¼‡ŸEv?½-¾Éæ]’m^b‹«ÛBìÌ5ãy–^ý_+=êËkèá ŽÒ‹}Ì¥(x´1Ô˜Nf°¿´Пö´ uGÄÁ–„’‘u«ÿðEš ¥›09ÅÒƒ¡[á¹ù>ýLB­ Z]ºLµ†ÿué†ý-BÓ–Þ Ï6lÇRtÛí¿À[ð¯m•iºm9ªóBÓ‰MÕ7¥ÖwOMÇßëªÜÀ*`ù† ž7Yõ~[ß™f¹ýÃE©Êà­1©aR··‚©ac4ðМÉ<žü¸ƒCƒ endstream endobj 47 0 obj << /Type /Page /Contents 48 0 R /Resources 46 0 R /MediaBox [0 0 612 792] /Parent 33 0 R >> endobj 46 0 obj << /Font << /F67 22 0 R /F17 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 51 0 obj << /Length 337 /Filter /FlateDecode >> stream xÚ¥“MO!†ïýÙ¤KöCãÅè4žÜDãGÌv™¶Ä–5,µöß ²LÚ&­§ÞgÞ0pY&U–#JI)CõÌ¥ )G<„%ª%zÆM *ð…kØ„õèîkÔWQÌ«—D$R­@?Ž©ËéyôZß Å”γ› a/q{,ñ逽ûãa!ì'¾)ýy˜êˆ| µ=ÑçŽk(OÌ~·ÿ&N*úçyºiNÒ_©ùÚ@³"Ź#E1w ½È°TZ»Ü†-›ˆ¸3ïJÏAÙEØh¦ûp1Ç`«:´ÙZ·Žî…~줒á•wßBÿ{Úp׌ÁÁl£)eYhã `V UcÕ@¿^ÚÞ/rw] ‡S]ˆÓ`-”%´ËÆ€$?iQNK3Æ/‡K™/Ž®ëÑ7ø Ñ endstream endobj 50 0 obj << /Type /Page /Contents 51 0 R /Resources 49 0 R /MediaBox [0 0 612 792] /Parent 33 0 R >> endobj 49 0 obj << /Font << /F67 22 0 R /F17 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 54 0 obj << /Length 559 /Filter /FlateDecode >> stream xÚTÛr›0}÷Wм¦ #lÜN’ÖŒ&3ŒaúÒKF9¦åârq°;ù÷HK IÓV{Žöhwµ—þhlO¦„`†±!ùk¶Õ…‘„-èp*ù¡ôEÞV«8  C,ï(gQ(Œj’’~Õ±þ‰¦½!eÕds/’ª@õù–Œ…û·òÍ¿– žHD!,âŽÇ±œÂ:KÖBXus‰Þò'‚/b~¦A™å7U\‚„-\íB­Õ=Wð¾VT+:¨û' ÃÖÌèjó:ÚZ5nk ó­0—ÃÛõ¨ñ¶HH ¥.K¸ü-?Ã÷s’—œ¨ Î÷KÂpþ«"qÁÑžº|ñÁNçÁîâÜûΩl*Ú!Zs¿€¿ 6¼bÒ K¶YÑ4wj†ãÉå&ÏîÅaJïÛ®©Ò2Jè¼è¶Œ²”“Ï®ÒÍK\“(¦á‹1˜°`ôô³†Ø*¸ÒÝ`ކs|Á+Å¢‹ÕÜ£†¯»éTmW yµœ‹PwŠPwÚÌÙ¿ê/8¬ÍÉ`¶:íQ?ö)s;Ê8ëJû¹à´®ÇíüâFHJsšÄºCÍõßßçßøŽpþê¹YqÊû'Pë›hÜ5¶agæZ`Iš9f{­ÝU9U4Ó˜ÈÖ;EC&–?f ˸¶Çë> endobj 52 0 obj << /Font << /F67 22 0 R /F17 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 56 0 obj [1055.6 944.4 472.2 833.3 833.3 833.3 833.3 833.3 1444.4 1277.8 555.6 1111.1 1111.1 1111.1 1111.1 1111.1 944.4 1277.8 555.6 1000 1444.4 555.6 1000 1444.4 472.2 472.2 527.8 527.8 527.8 527.8 666.7 666.7 1000 1000] endobj 57 0 obj [826.4] endobj 58 0 obj [618.6 718.8 618.8 1002.4 873.9 615.8 720 413.2 413.2 413.2 1062.5 1062.5 434 564.4 454.5 460.2 546.7 492.9 510.4 505.6 612.3 361.7 429.7] endobj 59 0 obj [569.5 569.5] endobj 60 0 obj [514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6 514.6] endobj 61 0 obj [531.3 531.3 531.3] endobj 62 0 obj [622.8 552.8 507.9 433.7 395.4 427.7 483.1 456.3 346.1 563.7 571.2 589.1 483.8 427.7 555.4 505 556.5 425.2 527.8 579.5 613.4 636.6 609.7 458.2 577.1 808.9 505 354.2 641.4 979.2 979.2 979.2 979.2 272 272 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 272 272 761.6 489.6 761.6 489.6 516.9 734 743.9 700.5 813 724.8 633.8 772.4 811.3 431.9 541.2 833 666.2 947.3 784.1 748.3 631.1 775.5 745.3 602.2 573.9 665 570.8 924.4 812.6 568.1 670.2 380.8 380.8 380.8 979.2 979.2 410.9 514 416.3 421.4 508.8 453.8 482.6 468.9 563.7 334 405.1 509.3 291.7 856.5 584.5 470.7 491.4 434.1 441.3 461.2 353.6 557.3 473.4] endobj 63 0 obj [777.8 277.8 777.8 500 777.8 500 777.8 777.8 777.8 777.8 777.8 777.8 777.8 1000 500 500 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 1000 1000 777.8 777.8 1000 1000 500 500 1000 1000 1000 777.8 1000 1000 611.1 611.1 1000 1000 1000 777.8 275 1000 666.7 666.7 888.9 888.9 0 0 555.6 555.6 666.7 500 722.2 722.2 777.8 777.8 611.1 798.5 656.8 526.5 771.4 527.8 718.7 594.9 844.5 544.5 677.8 761.9 689.7 1200.9 820.5 796.1 695.6 816.7 847.5 605.6 544.6 625.8 612.8 987.8 713.3 668.3 724.7 666.7 666.7 666.7 666.7 666.7 611.1 611.1 444.4 444.4 444.4 444.4 500 500 388.9 388.9 277.8] endobj 64 0 obj [833.3 833.3 277.8 305.6 500 500 500 500 500 750 444.4 500 722.2 777.8 500 902.8 1013.9 777.8 277.8 277.8 500 833.3 500 833.3 777.8 277.8 388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 277.8 777.8 472.2 472.2 777.8 750 708.3 722.2 763.9 680.6 652.8 784.7 750 361.1 513.9 777.8 625 916.7 750 777.8 680.6 777.8 736.1 555.6 722.2 750 750 1027.8 750 750 611.1 277.8 500 277.8 500 277.8 277.8 500 555.6 444.4 555.6 444.4 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6 500 555.6 527.8 391.7 394.4 388.9 555.6 527.8 722.2 527.8 527.8] endobj 65 0 obj [869.4 818.1 830.6 881.9 755.5 723.6 904.2 900 436.1 594.4 901.4 691.7 1091.7 900 863.9 786.1 863.9 862.5 638.9 800 884.7 869.4 1188.9 869.4 869.4 702.8 319.4 602.8 319.4 575 319.4 319.4 559 638.9 511.1 638.9 527.1 351.4 575 638.9 319.4 351.4 606.9 319.4 958.3 638.9 575 638.9 606.9 473.6 453.6 447.2] endobj 66 0 obj [312.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 312.5 312.5 342.6 875 531.3 531.3 875 849.5 799.8 812.5 862.3 738.4 707.2 884.3 879.6 419 581 880.8 675.9 1067.1 879.6 844.9 768.5 844.9 839.1 625 782.4 864.6 849.5 1162 849.5 849.5 687.5 312.5 581 312.5 562.5 312.5 312.5 546.9 625 500 625 513.3 343.7 562.5 625 312.5 343.7 593.8 312.5 937.5 625 562.5 625 593.8 459.5 443.8 437.5 625 593.8 812.5 593.8 593.8] endobj 67 0 obj [571.2 544 544 816 816 272 299.2 489.6 489.6 489.6 489.6 489.6 734 435.2 489.6 707.2 761.6 489.6 883.8 992.6 761.6 272 272 489.6 816 489.6 816 761.6 272 380.8 380.8 489.6 761.6 272 326.4 272 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 272 272 272 761.6 462.4 462.4 761.6 734 693.4 707.2 747.8 666.2 639 768.3 734 353.2 503 761.2 611.8 897.2 734 761.6 666.2 761.6 720.6 544 707.2 734 734 1006 734 734 598.4 272 489.6 272 489.6 272 272 489.6 544 435.2 544 435.2 299.2 489.6 544 272 299.2 516.8 272 816 544 489.6 544 516.8 380.8 386.2 380.8 544 516.8 707.2 516.8 516.8 435.2] endobj 68 0 obj [748.9 748.9 249.6 275.8 458.6 458.6 458.6 458.6 458.6 693.3 406.4 458.6 667.6 719.8 458.6 837.2 941.7 719.8 249.6 249.6 458.6 772.1 458.6 772.1 719.8 249.6 354.1 354.1 458.6 719.8 249.6 301.9 249.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 249.6 249.6 249.6 719.8 432.5 432.5 719.8 693.3 654.3 667.6 706.6 628.2 602.1 726.3 693.3 327.6 471.5 719.4 576 850 693.3 719.8 628.2 719.8 680.5 510.9 667.6 693.3 693.3 954.5 693.3 693.3 563.1 249.6 458.6 249.6 458.6 249.6 249.6 458.6 510.9 406.4 510.9 406.4 275.8 458.6 510.9 249.6 275.8 484.7 249.6 772.1 510.9 458.6 510.9 484.7 354.1 359.4 354.1 510.9 484.7 667.6 484.7 484.7] endobj 69 0 obj << /Length1 1478 /Length2 8518 /Length3 0 /Length 9504 /Filter /FlateDecode >> stream xÚ¶PZ6Œ»·´@qww+ÅÁ½¸{ñ¢-.Å­Xñâw×mqëG{ï}íÿg¾o2“œÝ}v÷<+gÂ@£¡Í&e±ÉCœ`l\ìœÂ5i.N'';''7ƒæúGÁ ‚º‚!NÂÿ‚€°',öTƒ8”Ý\<.~a.aNN7'§Ð?@T t[ÔØÊ'+ƒ ÄÙ ¶±…=åùç`²dp °þqH9‚ `K @ ³9>e´:´!–`Ìë¿B0‰ÚÂ`ÎÂì@GWvÔFœ™à†Ù´@® ¨;È ð›2@èú›;@Çìú—Ab óBA€'…Øääúäâæd‚ž²´•T¯œANUÿ°þ.€‹ë_áþöþìôÇhi qt:ylÖ`à•¼*;ÌÆ :Yý\!Oþ@w Øhñøsu @^J|bø7?WK(ØæÊî vøÍ‘ãw˜§2Ë9YÉ@AN0WŒß÷“CA–Ou÷âø»¹öN'Ÿ$k°“•õoVnκN`7’ìߘ'Æ¿u6 €““S€_r€<-m9~'Ðñrý1rýV?qðóq†8¬Ÿh€üÀÖ § W ;ƒºü|þÓðßÀ l X€lÀNÿŽþ¤Yÿ%?õ öq>€ó÷ç_'“§ ³‚89xýþ§Åš†*Z²j/ÿ¦ü/£´4ÄàÃÆÇ`ãæãpqñóž~ÿç_ø‡ý­ü÷íþ#¢’“5 ô‰§êýCÄýïÉ`ú{m˜ÿAò4Ï Ó¿Çߘ“Óòé‹ëÿy þ¸üÿÍþï(ÿ×ñÿßÉ»98ü±3ýøÿØŽ`¯¿Oóì{Ú 5ÈÓ†8ý/Tô×BKC¬þצ>mˆ”“ÿÊv•{‚¬4À0KÛ¿†èŸ.<w;4 ®à߀‹“ólO;giÿô¨¸>õê ô´RÿRÎÉbõ{÷¸Ÿú„B^O­’ø>\OKjòü3Ûv'ìÉðDÎ` büî(?€Cê·ê$$àþ[pXü[pXþKâââp@ÿC|Šãú"?€öGü¯ÛZºA¡O›ügžž¨ü#ÿy6@ O%ÆÂ,ÄR$Ä®6¤ýºFŠÂƒmgLlšaG?™ÍgúÉí5•¹:ûÍôR*u¨oyKŽéBr‘úÁ稥5¼5Y³íÎ÷Þ,Qkr§ c~‚¸¼èHª® ’MGr×÷ÁÅW/ȱ¾S™!ÏÅMG£€àÚ£WÁ³®¯li$lvGs·š_ó¾lŠ-V7Æ8¨ø+C¾EÎ )- Œ åÙ™'î׋Ëég¹ã¿¨•_bøÇò¼÷1\玻™ñ^©Ðáví"£'3$¥B¼x62Éè#½ÿV™dΧäCÌšØÜ;ÈøÁÅÞ¤=2Z RhH)›XV j'}W®‡eÔAÏr\Àø‚ºÍ'”¡DÁ:¹Šn¨Ä,‡pó@G¥doõòS÷ó®ãÝNߤxRa®Ø½1Çç—b›9þü÷7(åÀIUäTk¸UºEõWÄS£Úù~rZC®±õE>F}¿òÙ?\±Ù!Ú…û~€9¯ ÷bz ’hŒÝYhÔï'Ÿ~{xß™`;dÔPCxAÉ®îT¨7]ウªüÒlÍnº~öøÚ]e¡€úÈØ -CõLÓ%NT/IIj6”üðFØŽj¶ú‚ñP^¶IHN¯íý¤»}Ô¬™]ŽÒ×»¼Ó°œ%òNý#Ö+jÁ[2Ú3´I¼RE©EŽY qÚòw…9$°ã·C",“;|˜˜òòØÒúÛ·\¡ÚÏiûЏYŽ)P¾ŽšSÄ $´ýpÐ-'GmQ*8—0ò(G ß±Dg4Ü3/&›,ÍíX­ÁrµRÉH{AÜÌ⺻=5¤c%ôU¸^÷&tÑ(n˜HÿÖ¦–«íÞÕx?•ó]àÛs Ö¸)>Sæ½*‰>ÝGUî6º6§/Ð zßè_“:Ͼ©¢¦$›Lø”›ÿºåícWHõ h¬Ø^òÕ¸æ–>´Y®÷øiaß%_ó3H½¢ØÚN$ÎJ‚.Áö%ÿq9U Ân¼ÏÍ>ËÍêÉ·4²ILVmÍmîmwŒ/Jœ*ÉŒÍkM4£C‚…÷q6WZzøÈœ8-„ÂMÚϾ³q,–¼7~MÏOnô2HW.Š®¿9F-ÿÕ1öx-»ìý†jõf©ñˆäµ7ϋ〈üBθӖQ¢:_2¥žgÚš×’Ê®=rÔ"¤Ú3=JŠ‹·OÇs®Æ™_šH¾ 'Ýœùh¬äøšÀì²ôKRý#Ú%C®?!Í"†²ûœ+®_ú€Ë¬ÇîĺÏVسª1×±d|µ ôkFM¶ÏÎoö^D2Fe¨1Ö Ôã·à¿…®Ý!C©|ùRÕŠ›ùhëÞ°tTãvR/ŠÖÄŒ¥ÊÆÅÔ±¶©þ´¶{™’x<Üñ©ó üåQîP­'gÏ•-bùš›‘ä¢ßÆþíl0Æ•R¢ :+À®s×d·Ï½æÙ‚FTŠ~šd/×ýÚ¡ úƒŸU8;Hs¯nàB&!5àƒu©Êqƒ,¶Sµ­¡A8Ö²l£ï5c{~Äç {ñ}pN{ÏÂ1!gMÌ‘E‹[ҰÉIƒÖŒS½×ï®Ôû)Kì€6l…çÓXý¢–¥ý§ãϽµe›¬?ªÆ–ð#å¼õuQ#,›Lä :Ø|EþdŸdòšy ºp,øâ´U|m]@17¯Í¾7µ=àEo#3>£u³q*®.Wah¶á}¢¡–Ì^F´.;¶\´LÛO.²ß¬-Èémoñ¦AbÍM̽‘çȨg•SŒ ]¸•ï|­?Çñ¼Ã,¡b¾8ô.¿oáâ—ßÈXgb-nE²dѧñYÅêÀŠî£»›ÓÒ%G'¡®Œ[¶ð«¼;¢R#¼$øŠo}ØŸ±ö`v˜h<}j+^›ÞBvY7$ Ïš$woµ5¤Áâ?·'ŽÞŸ/¹GèÉÏKÙÚ„¤7V!¯ãe "Q£ d ž² töSEª+‘kº ñ"x·ýŠä»r Â8 2SÉæ®Y˜ ,¼Cý%z:ªËd³s1³ÊTdþŠ;-ºå¡ˆtÉÛ‚™s óË©Ž^O{5úµ™âiB´i¸QˆÀAz`s;-Žêž7Fý{(`»ë6‚¸E\¼S ”[Ì£™<Á–ù‚Ókrí[)inÝ…2š>€mm%‚BÀø.ô쌯j™Œ'6EŒ:îóX;Ù|+I nϬ¯‘VæÆGq¾ ¥X‚²hÓ–'žm•­Í–½ÞíÁ*p%ÌkÛA Nòá äh(è*$Ž© KßÊUWéZìÔäv:OÍw93ÑJùÚøu™N¹‚W n¯Þšzüe³-±ÃqÀÄ~°JP#ãþôLêTLlüzÐÛ6 ¸dÙqô¼`]UPþ3¹yÌû,ÝøÎB0p¢eÒ{6C­´æS}Lå³ùâÍg` ç¸õôhæèi)Vžÿö ×ÏLÌž¹øLTQ‘+ÖjÓiþ÷;Ö9¬]Îc%¾gUöíZ‚­ çÏÅÁ˜(AÓκìõ©JɶÛgû9æÕFÒò᫬ª _u)³Û÷ ê¥Aí,ô5ÔNÏ ÞEÏO=ú££î˜‡Ðtk]2ÞÇèØÚwdš(v-?“nCê£PlÚ©mÒÖ «ËØ4 Tºä„]í¶‘ïKÛ–™¾æ¸/ö[ærë:?³6ê×3>½"5šˆH33–ˆÓ‡} åi‰Åj ÝÕ¢¬t\é©ÊÍb®º,%Ì’‹3†êsauOO&ARÞOÀymÍF.0KDwH.ÚÄŒ+K8ä\\RBÎyMg'‡7q;'es)÷BX[EÍ]>•CÅYÏÊ iêÍÌÙ ‹ ñ,§m.ðo²HßmS.´ÎGåðTeàm¦0„,”Ñ#nU[{]âÉS {v|¦½BˆeêZzuʸ{• ¢õ Nµ Çã5¯ûSÝa³oŸ/!Eðö7Go‰ºÐêäEò¥J®‘Mî ‘Ÿ×^PX“yxyù*æû†éú‹:tŽÕ¾S!§cÁu⟸.͵̯ãšM¶÷Þ͈ËE÷¦E¹'i†Ùáæ>â“#$ÝVåð1¼³ D¤+ðoHÀL‹úòj„0™þ¸ Í•ùcØí‘ÇtÃv5Ó’†zÕ{$°¦4û£Ëœ½OòßÔêO2og¥x°£ ~¹0X¡b‹­ÉG™=¬\f÷å^.ì»…ó n5nmlXxƒÇÁŠû]݆/= ;ïa2‹ä´«Äø:bܮޢoÓŠ+„#UþyÝPôÆýeÙ0JµªÌv[êØËª%A„x·”7^Ñìž2S ý¹Œo:uKRýŒ•vÈ# Ô9÷Ã$Ê6X9]»K²¤ä¥Ã€$T¦¬äøÝìo©øb ´°Ì9–n?•ø  ™W ®áÆGoö.Ê?“eT}3âk6óÈ>T‘—ä<\×ÞIÐe±AÜRÅ’–6?Ùù¡Ëõìà6G(ja÷ÒÊg~3À« ÷]ö?uóßÑÄ·-·ïtçÕC.ʃ':x¦¢ß:–#ø½$% ‡‡ þæõ½é|"Û7õ&¿t*?Ì™döŸ‰úàr"`ÑT…¼Gp±e9¹ÿH¶!"oàä¤áToTÜSdg£Ø?"Û’#Oq¼üåó¸iǃF6 ,âwڙܧa,ßûäR .ÏE:#fÚÆ9vñãZùJ°TñfOð ÍÝM:X?–ÑJóå#SjÅÅÚñ¾Ï ž5FÑ'¼ËµÚ‰f¤ã¤ž„\§ÀÜŒê§5GGîäth(Iû¾S¯&¸xÈýúy]Q½pÌßZ®?‹F )ˆŽý­N‹ÁÓ1ˆ¢cö¼ïÄ_ÚvSl]¾¾`–۸ńu;`ú£$ÄT‚ã ¿ÇÒõZà~!vqÞ¼ó£³¶C3Ø÷Kô ÌÎíŠØBô†B@Mì&{J€Äuh©üÍ^ãd™7ï*Þ\h—‡Å‰¬¿sõ ª oq>ÏþÊ#‡³zpn*Õ‚He;,y>M>†Ôyÿëð¦ÇÏC-“ŸÎýýxE`!'»EiÚ–áVœ¤htÑ.ö›ËGo¯Y‡¯Ì¿hkKg*ùã[Á]+ºŽ©Œ´î"8K„4?æÀœ­=ïäua2QüW§K!ò7Ôèyž³¾`¼ÒwÛû ª¸^Ã:‹?Då–N7»\"õýeê n_“ýÛm±[1ÜbírŠÿú ²FÐßÔD¿ýÝt !Oœõu6;•üÝrJ|f.|ŠÂg’VB»VF¸b]Æ1íŠ2NÜÃ Š˜òtíÊQ›ã­æž»¨Œ£•I¤—¶‚ìá„4CÅõ‰¿xý_ö ç§ŸZÉŒÌæ‹\=Wèí¨) ,êï3¤“ªO"Í/­;¹ȵˆã"tj©–¡¿y T™—¤÷]կ̈ž>çÐP¯C1HåaáT¹Ø:è}Xîobö›F¬R>P³¡¢ç»ünÖaS.ãÊ-Ó Àª’“‹;óNm¬mlœ9o75‚wëg™‹¾ÒZþ¶¥‰„H‰ÚÀ2GãjÞ?²‰ Px€üñfÛô}ïÑ?Õt ³Õ«‹@"@/ÛâõkšW>Å(D°–y¶7PÎPÐ)*ê±Y"f/‘2†¸ôh'Y¡áKiIÀ[(ÿxæêÇbððy^åƒ]qÆOKg“ÿ AÑ.É­„îtžÆB»–îœð7 ©ðBêcgôÞþ ¦=ÝQ⎪ŸUÕ·„®¼"êºÉÂŽÑàÀ9f”qjÝ{fYv‰ÑY¸Y¡öœjk^­Kî²Ó¸Iƒ––l4ºç¸fZÞh†#nÌ.ë>€[‚Kœ 4Û-í㵬= ¢u|Ùá¾$OfA´éã^´d†Ù´žMѯÞë‰hÿYë,1—ìOM„ʽå²4†K3*²CS–ÝW‡L;¢¤ ¤ì9ûÔŠ-Ø<ŠÄp¡¥Êñ=ˆ×I©t_žÇk½l¶ÔÝ(§ÒÑÙ€gzÇLÝx/§bjµÄPßEûãQ;š]¥¯,—ÑWÀ%ÜcFál>ëöýº^ä¤z~Çü£ƒã¿ ·±RXÀzZLë2Ühçqm„$‡¹#^]`_Y Žéë—@éάJ½7‹œéÚÍð()¾9„Áõ9Á–#1‰W7ID™~ššÞBŸLéè õè—›ÎýRkFÖAãùÙÓŸë¢Æ½ÇKõD•üIñ“Ï f«y÷³ŽgÉT—ÛŽÕh˜¦rÞžjÝ}•igµ­ñÓšùűû=oÔxy·œ²^À˜‘P§ã{„ˆch&t’qP‘h' ÿá.«n* e5en¸nh UZO)`¼Mb´­T¬/%*Ù¼¿•%VÃ)QMp`‡C­3¬Pzô,?ˆSÝU•ïbnì Q•ú§[[<ÿ¬™û-†ê.ä½\us¿s½ Á÷1OÏ0áT5¯vžù\u§ÃÆ@)ì—–ýÆlhÅR¹RéÝ/àxÔp‡|Wj·V@E¥Îç]‰LU¸Òï¼Xl8RN{K*µX¢`B#»ÁËÞ}w•÷èdƒK•žýtJPh̸®Ëeü™ ÌeËMá¡—ÚÏ;ƒÛP˜iûÎÀâ5$ÚãAWÆ´ê¥M“lûŸßz´ëUO½ŽWÍí®¿¤kÍ5Šžn~Œ´Ì A9šÊ»I²lP»—½¨¶VU Y‰z „|ÚŠØt*¹¸$FŒXs¤»ç–}XydÈ?DD³¬Z¨ñ>×®möK-¼8xI)(é奩}ä6Œš2nàýøÎñ`Çsî<¬B[éê=‘d]· %•ùh ñÓ¡=8uD/@ßÊke‰O7¡nrß~ùˆóhòS»µÍV{E¥e;–¹™9ðyàÜmydjƒC³Å†ëEÍ£ü‘°’O½9#@Ûùqæ+V-|AzbÕëU›bDq¡Ò«‰QÞ2tÔš&X¸pŽÈcÝ ‡zQ·%p )u«‚ž)a׃¤žèv˜†Ä W+ˆÇܯó~½Ï®ëÙJIº–v˸Êð¨ð‘=oáOÂem´·~ "<¢o—‡DÓÚº¦cÑñçs¼ú_Ö´|’RÑè»ß-\áM(/;ôgYô^Å?W«„-βjŸÙ˜¡™™4äq†FU²) Ì\{×í¿TðMBË·6K‚šÈ)$.­]–²ãlŠÑgLÔœ ¥¡¹3ÕÈÖrÔŸ/ªZ”ãDÏYmž.hUŠ,)dIH•?ëéàn˜¦Ò¸¯}(œKÁ›;ŒöìÏ–‘l{ŒIVs5Šå—(y ˆ êžÇ¿ -Õ2*°¿¶é/ŽýEH{ƾ¥è,ÊE;$ç›s¼ÞH’ÊpàØ'Bñòêƒ"£•56¤Å‘ 06_Óíyt=\0Ù~vË šÑ}ûÅ[ÝÈl ÖÙ›6­Ÿj!¸aóÌKö(pYïöm”‡b›1–å“E0½öÇÌ·VƒVUñŸx+'L§Ùô„Ç2áCû6†Ñ.òYÌ,E]+õÅéÝ`~ÕüVgì´QŠÈ}|)—ew$O“Ø;¤™‹QÍŽ]ÌE{|Ù·+o%tƒÈÙ¾ÕµRÒÿÔâ®.£Ã ðòp¬á¦ò{ÉóÙûoÉìÝ5OÑdžçz(†§xü'åqH?éM"+øúº†¿´ª`[®ô}ERfúúíD§©MavèCþ=YÙ{U¥Ë³FyÛÛ šÂŸzisþ·êtÛð_ŽL \ħ¨=ÉÏMt§æyÂÂÕ‹­cðj±8ƒå,µbô¯–¾­§qù‰k~|ræÉ]+©ódå>ý¤=on¦gƨ¿äA1÷6gVVŠÝ{óšK·¯Cþ ®@¤„[¬&w]˜»ˆ<øÖ²-Œ“&‘¯&kDMœ&¿ÊÏ¥¸‰|·`ÇBE¬PŽg\ñ¼a,¢ë>¯S‘¢æ¯^! ™›`L=¢Ž–”>VÙ‰°ísJ~´ÿÕväŠC“Ñ< ?h\=pÜû .*ˆîv¢ûöŠ„†¼/§s‘xÁþ[‰ôP3j¬ùÎ-ž“P uî~ôšø&êM¦KKE?–“­}Eß›Aî·¨xŒâ-¬9—‹Gï{¶P„¬íÍÄÞ¡5åk x*÷Cœ´¾ÒD¾jsþyqºè›§0æRŸÌpºï§UE± > ±y nG& t‹¿-iô\Ãïø ‘ð=Uodžï$]Ím¶+‚GÌ´‡ï[çɸüŠÁ+¤d{íσ” {ÛÍü–äs™‡SÚaåÒhï±ÖáDý” ¢u¹Ì ™pYÖ £ÚïÒ0g·‘X¿‰Zé¬õ‰¸¦Ò#w˜WX×i¯W%jãLÛã—¸¦”]ئêòµ&vþ ×7qik’âxiÆl!8– -©—4ýô P,® ˆã`Ä3„_ÙúJÊÀcIº÷ˆ,Žž&ϺS%ÕÆ!9¸pøNàÍ*K£p+ÿÝ—8vc:M{¥ãbí¼e˜×ï1°h=(}4{°g¦‚•s¹+;MÓvã§. mz}ô}Ÿgö[8Z¾c?oºÑZ<¶©¬m÷o¯Ü(ÔUÆÜiëùÅ?iÕÔÁps_d=†Ô3f衾Å^òs'9ù‘À;`Ó=n¬³ÇX^ÇeémÒ@Áà÷hŽ×E’“GÔþ;níòÓ/4=EÜò—ÜwÝï2_F÷$~°»-GÖ?I¾x¿hbQkÝÂ{õÙ­ú|ØÂMEÞô™ ½)“Ô\]Ì読*»—~ÓÃ3R[Áð(tȲ±A‡^KUâGüAq&G„׆û+w³ƒ¿8«YÁ•2_2·U}šnÓ¼ÄeK‚x`8êzôêºÄÕöœvÁïzÔm1¶¢EË}¡cé1TÚC1½ ©9Z8@¶È–yG<_ÚR½Ð)„4y¼öQ ‘ð\ÊÊÚ'2™(ʉÁdŸÑ®HIJ9»É0’Üé3kZLïÓs¸Ù=%æzÙÎâ(ÌÿÉ$§C÷*d2=:+I˜ e€C­çGs£Ì˜1{Òyé–¿Ê ]?NI ËEÌœ°#&g¢·¼œ×ǯÕpña9çèÞ¹‹¯„.øP¯ÇðšÄ‡w{·‰ÇÅñ,Ý_%‡EH’„Hò÷´úÏÇ,öoŒÆ˜ÈwíB&JðÝxMâÁŠOÙG÷JÕR’!†¨L§#?dFÚ†iÙxFÑüà¬;Áº„ë§k‚Rp 6Ç15M Þ9ö7e̱ràÃÍîÐêÝ©WFjúlI§,F§›ŽÑªÏºœäp6Î9\P\kk»žÐJn?ØE“ZÝâÊ;doÆ´ñ¦¶¼_·ê^k?T\;¥Ýw”Û+ˆwùyT¼Š²XÕ ­ñÖ¼ßfmk§J¸°nÃVÍiù Æ]­ÄÐ%5ùl>xP‘#–`ÔJõç £¦Î’‰ÁÊã×@¯öñî6ï—Ò+û×3©ãÌüH~W^ï7A^x”ø_à¤/|-ÀÚe…ÊÕ>á úH™/¸ºâ‚HEQ'ºú1\öÍ…’߸«õHQdÀ;L^›ü Ü'í dßNÂ2ÊPðLÐûïŽ;`éÉP†îv+;Ù®K,^êSç>¥éU¾º‰«Iò‘¼ˆža¯Ï“*Þtn ÓžŠg1}MuûqÀ(‰I:Õoâ(qµ½Dÿrïsm†§ÎŽ)}XïÔû“ä¨ÐK_·_Û´Oæ¢è6x\XøF]²/þþÓŸ{æf|ÞÆC4h…ƒZ)¥Pù¨ÛÔi°®•˜€yÁh—¬ç¶æÓ_ºÅ/­Œ1LDtî˜õ燋֙½Gk½5‹^Cö¼B‚Ñ1¹ ÷ßÞ‰É;Èu±'SQ ·FËTšÕ›(J¦™oï­Qø¥$ål•DݨC¨wÐٮ˴޲~†}qÑ …‰FJ§Þr¾Ñíþ 0'r~Ït°‘y/—’µ”Ü,1à+¶¤DEGbGÒ]ëCEï«€»`ý"B)žqG×k-T–ïm'!§PiúâAŸ •&’‹[,zUómÕ—8xº8kU¿ÕB…掞„[©aAQ ‘gÄõÓ„ÃÜR“{]ŠäÌr½¼«‚ìÑBìvðúͰ܈êF»‘sFA•!Ú]ç/΃¤MÞHì¸ÛËC"VHi´ì6Šä?ÓªÑÀÖ!1ÙÏiÐ}÷hŠùY0+Si}Ïd%&¢Yв129w›o±øŽĺ]…D³¶æÆØÄ%#”#WãÕ=››qÈí/Ⱦ´uÍ»Ò*7Ç`íõ—Õp\)×ÝHÃnüG°íà‘šÞÈ#’߬‡˜` Ïj»ûZo­§çõ}Ͼ¯ze×?ê ǹ‘SzϨZÃõZ¥î­èIùý°7‹.‘ÿ¹x!K‰ßÃüFjÑÍ´Ùfu’af—ŸLŠ>.›ï§"R±–ëï€;N‚¤ß#f_²«teÝÍFi§Ž`&ÁC‡J§t¿f«™¡¯jÛADÚŒ‡Ëwð…ºç 5$sú¸e%Ë„uìÀôÖÈz­ü’¾üÔÛ[Ã"BÙ4ÒÅð2¼x\¦±pÑB ¬øÆ†À]‹@Œê1"þ‡h' endstream endobj 70 0 obj << /Type /FontDescriptor /FontName /QZKRDM+CMBX10 /Flags 4 /FontBBox [-56 -250 1164 750] /Ascent 694 /CapHeight 686 /Descent -194 /ItalicAngle 0 /StemV 114 /XHeight 444 /CharSet (/A/a/b/c/r/s/t) /FontFile 69 0 R >> endobj 71 0 obj << /Length1 2009 /Length2 13490 /Length3 0 /Length 14707 /Filter /FlateDecode >> stream xÚ·P\Û-Š»wwwwî\www'îîîÁÝ!¸·ànáqäžœ{ÿ¯z¯ºª{éc®9×®&'VT¡Ú™HØÙ:Ó330ñDåD4™YLL¬ LL,pääªÎÖ&ÿ‘Ñ«›8:YØÙòüËBÔÑÄÐù]&fèün(gg v±0³˜9x˜9y˜˜,LLÜÿ1´s䈺Zr i;['8rQ;{G 3sç÷<ÿyPS˜¹¹9éþtÛ˜8ZÚä ÍMlÞ3ZTìŒ-Lœ=þ+Ÿ¹³³=#£››ƒ¡ƒ£™5ÀÍÂÙ lâdâèjüA ohcò758r€ª¹…Ó_ ;Sg7CGÀ»ÀÚÂØÄÖéÝÅÅhâxÏP‘’(Ø›Øþe,û—àïæ˜˜ÿ ÷·÷,lÿt646¶³±7´õ°°5˜ZX›$dœÝ醶À? ­ìÞý ] -¬ Þ þ,Ý !¬0|gø7?'cG {g'' ë?82þæ½Íâ¶@Q;[g'¸?ê³p41~ï»ã߇kekçfëõdja 4ýƒÐÅžQÍÖÂÁÅDJìo›wÜo™™‰3€‰‰‰“ƒ`â0q76gü#ª‡½ÉŸJæ?Äï|¼ìíì¦ï4L|,LMÞ༜ ]MÎŽ.&>^ÿVü7‚cf-ŒF&f¶p¿£¿‹MLÿÂïçïháÐfz?fÓŸžtß' hgkíñÛüÏ#f‘Vû¨Hû7å”""vî/zvV= ;3€™™•ÀÉÎðùï8ÿtà?ìÿ”*Zü]ÓïˆR¶¦vî¿H¼wï?D\ÿž ª¿×†ðßäíÞçÙ@õ{üu˜Ø™Œß¿˜ÿŸ—àO—ÿ¿Ùÿ#Êÿuüÿ·" kë?õTüô†6Ö[¼Ï³‹óûnÈÙ½oˆíÿšj˜üµÐ"vÖÀÿÕI9¾oˆ°­™õ?m´p’°p7*Z8›ÿ5Dÿ9…÷àÖ¶&ŠvN\8zf&¦ÿѽÕû¥âô~VªLÞWê¿SŠÛÛÿØ=v€¡££¡Óû€±°³¼˜ß—hâþçllíœß]ïä|¦vŽpœ(;€QøÑ_ˆÀ(úqÅ~#n£ø?ˆ“ À(ñ±¥~£÷˜2¿Ñ{L¹ßè=¦üoôSáÄõSñ7b0*ÿFïT~#6£êoôžAãÄýŽ £÷ Æÿ ?:Ìüd0šü߇ÑÔÂõ_‚÷Lí\ÿåðnbö/ø^‡ù¿à;q‹A£å¿à;uëÁ÷Êl~Cæ÷Êlÿß+³û²½Û¾¿\þ¥~¯Ìþ·ú=‘ýû.Ùý¦Æñ^èû–;ý9Y¿ÝÞëýæ÷zþßÃ8ÿ&ÿ^³¹£É¿Úñ^¢³›Ý¿Þ[íò/øNÐõ7dy7wÿ|çñ'ü¯6vqt|¿Üÿ¼bÞ§û?øÏ7‰‰‰»‰1Üò‚1o°e]pÇC0žýÞ$ÿwò=jz¯eÇo.OHÐIÔÕ›ŽwÂI#½(k;âT·B+D¯^'­ Ðam‰JíÏÞ/úŸ•göÚá–¦1§ N„ë`ñéU…ö½_¼Õ¬À[A»¤És\¸óÐÜú%ÝëÊVÇCö”ö«9dà_ÊfécÔ¢uŠçÈs2ç±I œé `hP/Ü‘çnï¾£fO½I¦…óùÃZè¥õƒ%öqÞs½B•Å©‡ G ›üu|†ÂKä0YkÑ«¤(N:4ªÈ”@o¡Yಡ[-q×2_ÙØÔÖö‘~€hòÎLhœ±Ò6¹ÈÈ‘µJv'6jN=gñì+³~>œ“RçÁ+¦gTå\†cà •ó©"KXj_‚5að-• TçaØaò"ÇNÞà·ï,eC›ŸÐç%£\gí/CwÄÓN0·KŸ©)I[˜,íÕO§ªÓ ø#¤†£ÌæÄÙ¼P§YÃU¨oV x¥13`2–ãµ›Ò]žHo}òY'ÆA‚+z|ûB`?T÷\‚—€eÚ&3±i–<Ò=¶c2Ï‘¤,*y5Ú_N2EŒPÇ+ä@í‚ë8«K ’#ò(q[ÂÌnŠï x&fJgÃá€Õ"À全é³znárÈUåS&¤bbç̙嬉ùÝ ãÓ×]Ò ˜‹Us|)ª8r#?I‚±©p*ä‡0²’¶ƒHÓšµ,{îÌóFiSÔ~¹U¿]îÀ½4ÅïöMoëliÈ3ˆR©ÏêœËïïãç|ëmaý€9',xe­âÔS*ªØ|_ßëaªâQ²µÐeôãÃDŸ· }ìàâöp|¼‹ãµ,¿‹yiì|àì°Øärn[â\”^±vs dw÷Ü.}ɤ§ÍÄ*!kÅïÝÎÇB7¬ Ï=%°ùèv"¤…­ †/3Æîme˜ù®Ø_Ëp©ÒQù´ø"9–ÒØeVçÒêA¿Óz¾|ü–ËJÝíçø©"1’g±}Ä8S±4—SJ}>àra/Gã­5]Y±1ƒ»RK+ÀÆÛË.8¬6>`$PJÇ&T$Ô×6õËñÞ)Â]“Ϋ©,Bº#ÄÒDRG€Bÿ›/ÌÊúÄilze72(8/h0Õ(åÊ>QÀ×ÓÚ ÄÆBc¯Ab)C¯8%\ A£OʃT:È%Ám“hyý˳]i/döh‰ÄÓ$k×ÜõÑÊ~N­+ŸÒŒµx]ÚO“luhíÔQX\(›FúNšÍîlEèdË_ÔÅ´è«“{ªRç4Vd’í«ÎòZšr}U]î /Nê™1>W?àû¦Sp²@F­Ív @Óñ·ÑŽ•©K`ï³°ÖŒá qY À›ÿÔ‡<…²nÇ8¶…‰ß4LÛk l¾“ïBœëâ¹È-ÖN%›ÈòL[c,¤Z¾Š>˱쌳;VÉÆ]óäcïÖ ?ý¨ìœðýñË8uQζäG±)·¾€âqµŒDAé]¥äÒ~ ZRS ô [b—§ ˜ ­4ö)ä#ŽÕ>º¾UzåàjÕ¾P7|©!¸±’%³éÑõƒi§æÂ ¾²Tþ!šŠ·ø ȾÀ—·¡ÉVÙÎŽFw )šU#N(}[ÞÙŒ¢³4§«™‹ŽÝ–LØP•þ²lMÓ27ŽÇó ¿‘^ß~„ó.©E¶í¹ahI+kHÔ·~Èúöñ¶"µ˜Ê\0ÁÃð0#¦C‚û¶æ“‹¤4I{ÍͪîèLRб^8‘¬jlÚFä!æ%õp ÝÚ/¿Dœ•nHò>„‚Ýw½·dtœž_ÉÒ"PD¡f«1] U°×Ôwö°'kÇ)k‘ñ™çˆn¸¥|#º|fSFûâfnÔå÷ñ‘ÕBÜ'8°Q¹Ðæ§ç}’2ÆÁ÷pmñ6/´~{OeFÇ#$zØö€C})ÈýÆDóÄ2Ó+ÊŽÿm‡ôæb†ÌQ&|µ¼{‚Ÿß(ÊöVé„g`ÝèIhÙêÉ6 f[ RøI«L„dh4À:Ä#ª!ôG西}‚7"˜ÌË¿ÖÆ]”š‡%Ç×EÅõ ¸ËŸ–æmØïÄ9e¶JÊú/+š \g·‹¹ù~’S’‰Û ²"Í{!M«c7I„/óÌ=Úk…ƒ»`ÀM%0›íÑþv84çpóF6æãߨrõIGV-Ü„™¥‰ôv^üúÓTfö¦’™8 2¦8QÅö±``Ç—4ÆOÿM¨.AV£ŽÅ1Æ£ô„EƨÃXŠ4@¦`ú-'܃FåÉç.ÂBRÃͰk‹Ì¦.Ô•ÅSK OOvþ€IþXÙ!íŽx•†sÄEV¡c’ßÈoÂ÷ìE]öU4PJý²^ÁÓ©¸áÔÇEÖ YnÉ¿¬“„3K¦ó;<øÙýAûÕnè:—‡ Êëê*¾À;ÇÕ€š°—A,Ÿ5wy?I†, =ÿ6µ@ÇêW—–<»îÔ—)†Õþã»ò[Dba¯*b“ÿ¸q-t9ËÏÏAä/b:r T¸?.](ÅtÌg:šÞHë½è°³‡%‘î,»bh‡|šj Æ8À”ÙU)ÔÃoðµmM­”ÃÕ|¦ã¢Èç4D’ýúºž¯ç̨°ä1Õå×Õ] s]ÁÖ¢$ãE½Ì?¢!Öh·Ã59^ÑJ·_Nµ¦7ARL}3Šó®¸#µ‡$áè’‰A’%RÔÛô4B*ÊÖ 5ž½÷y 8¥&Ç’]’1U`A^¯ Øþ ’ŸkP‹¯¦o0yûæè—}å‚ \Þê­je)ÐFù£îãéw„ î™@ú/Ô]Ï.µpÝ.´èÖ ÀÛ]¶Æ£ÏRcY§°DÌUi(mÈ ×IÜ—ýhAù‡(9 š6ÄyH‹ó3YÓkS‰9ÆbAø|ñ/v(“ãú†Ä9kˆÛ"Çκ·ž:ß°Ò!+6¾(3¦:²œž`Ê=•$c΃¤/J¸ù Ÿ›°SÆê^ù5hu+NÚƒÆ..69V +Æ OÊ&RÒƒã ÀMc|(‹Z»g•ô)TÅ9 L[ɳí&Ö‹›ÍY Ì¡Ooðßð_“xèt“SP¯s’NSÂkkxê ò‚†}ø¦ºÑÙ|ÃR¥Žó¹JÞis6öù Ù¯“\$hÅ<új• ‘nëZ {? ÷ÚîHæë ÉÇÌ©j¤9ä@K9ˤJ‰Ú'¥t-UÓy;ÁPúÌU¥1³¢ÔzüÖ=ƒuŽÒ¨åˆ¹ev‰bóY»§ËHU­†ÿ†­Lspëà)É#«o~5ïó]2g#gO%ÿ˜ý2¹äþÛd|i‘&|!Û}Ð7a¦£^ónte îšlÕ¯xª<Š” ²Íx?ž±ó.Üû·Û8¹7Ëîè’l„%¼Ÿäñ`XêÁo+á’ÛîÍP‚*ÝkÛmª¼Ú‹=Aÿþ£sk!ˆë˜ì©‹”ÄfšuÞŠžàÒtÃ4879.:{ ¾ µ4°AÑ O¼‘»øvŠL¾=x…/ïµä-œÄR²]Ó üUÎwéX¼ºágæ¼ì É!ñOSlÚtbP5áˆÏS£`t‚¬¨Ý;îœÉ—¤x]o†Äבüá;¤Ãhϯð#I#.…XQFy-Œ‰›’]õk¤€Š÷:¥:F[;ódwŽüÔ‚ñŒE¸÷ܱ|évh"j(Ç'ËœU 9ì¥;Ø"M;ÊR€ÔúBnClub´ ÷ÌfûÅ')VIüÉ¡?£éZÌ¡1ÕëµÏ«Òv% ÁÛT\…fó-ŽšÜf=H_io`½cç¡(äN£›¾é:à&ßu©bÏWàxö® YÚ gÐÖÖ¼Bröv$³²`„êxs­+žœ ÷¹—;%ÛfÕ#MÛo¤?tä®užŽKò´žÅÒ žÝêòÒ_Ÿ`BIú¨z#ÜoÙ!,6Y¹Pž»¥£¼Võ‘8N Þ°ïk`!DoMì÷‘¢ÙhÀðLSÐ…ì`ûŠú³Tk$~£®ÌÜ4«~ñhDD&c'Á4Š7Ämû‰ó6ž½aÊ&©7^a•@åuÐ7Á³“ÚøkC—ÞDºyÉ7iÌ8`^£6ûeÜ|äÞ‰u2Ï/òiP¿Ñ)=kP¥+ó€ÎйÄôörfÜñW+yÕ+΋JaváFEžœÏÒjÉ0k¶˜Õ°¹AŒN¶£ P`ó’÷Þ¢UO¿ó,ÎNB&ÕØêV>}.êÈÖ ïÉucžš%-i55a—Œô‘ãqÆë×9ÌKùÁvU“Ž„ë­ÚO ø.ë38rwHm³†9”ÓKßBTQø9Œ5’„=+kѺsä¶5rü_DÔÓä¶Mó Œ èr(©•~#ès¾×ZßNKWˆ,¤òBÈŠ²EÇTÓi܃ÊtŸË’©oˆ,²AAÙ´Ò“ÕAætmö"Ô¿ƒ|^QxN ð¯ºí 6±øÕ wEN&­6˜£mZ£ªÉ9ÇÈ€b†£NwoÎyÎ%—Ç6uŒëyÈͳ3^¿eùËÆÑõ6]ñ&–Q !ÆÈßýª}Gÿ¾½hL¶¯¥?Þ£<´,1¨æfŠyFYˆÑËôDIôÒ§8Ú 3¼xç»´ãXD\ ÎÖþš=Ûmª˜o×|êß%÷V’.éŒCŸqUÃË|ibä|„1b&íxÜò ^Ågöשt˜'üŒShä|ÓnäÖ‚%lÉF½¯gº¬—ƒ°ˆò¬9u§¼Š´ìº¾¥^Vÿ—¡‚FÐøA|BêYÕißi-paŒ'E&ȸ@(iEL_*_îmŠ¾Â ×žm½7˜ ÈNêoašìxüæàò³†ò(Ku¥ä1ÌÛ ®PÌkf®‚þlõœï>cžÿºn”¿yí±ÌÛV`#(ù†¾Üi´þ¶WÐêœ+qåqµ_¿w{Iqîuí¦¤M«)çÐGÛº%¾ccK·i)g+n*…`_¢,IP­QÙð ©š«7íA>«$ÿ-S%’O·¿@„¸lK^Ð_#òü€rQ˜áΪۋOq¸÷«à£QÞ¹±rC@è–m1MÐÎUZ.7::W$Ñš<²‹¾jæqsÅ ¤I¼E±‹”÷íc0íÛSi# <34ïŽN 0mrf{f-ÐôrP¹e¼“Ú IËh-’3ã‹îrO¿Ÿß)™¡¦aÜî7v-è׫NôÕ!ã-ªpÆWUî&G—ãêûé×2-›íôÉ+B¬” þ!HÌ˰TÇ’·™Ì¶8šM91!#ŽLiŸ¸‡`øðnM_ô(ó éeôÅP\i¤«ˆOûx¤Â’ÓŸ“|©-õÀߊ‘EªÉ*‚²²Ø ܈o\$ õÎ{ˆ÷Óögøª.ën ¯¥2:Œ»ŒýBn84J: ëü|-¡ÌltѨš3:$œï+5œÃ:m–¡R¯‡–ñ½}¯ýzüÈ÷á¶ÎìÐMY¯Ø ‰Ï h!f`r>¢®(ŒG1½¸Ÿ»æL‚еž±M“sÛÓäË€÷AìzÈm¹ØpÃf!måñ›îàØÈ]dûøXS8gåxé+ "[hs3w™æZQmD׫æ^°5Œò)D¨9å‡#¾,Vs7åëA¡0§hœ¯&­þ~J§2©ä®°z¿³n¤Ø±³vÉ›&ÀerÕóÆh«&0¥ï¤ÜñÓÌiQ|dMvùõ Ž ÈÕ0®š&…ùD8Gü’BçÁõÓ9I–Z½ì‡xP$OÉêÓ€…|Îìdù뫇é7}•7’eg3ƒ;\ɸ×á‘$—a æY|#úml«¦¸HmÆiHȾ‰j»þa¶µµR)Ç+”…]Ip@‚_}<.ë\ê‹ø¯õmyrÌ %(=·Iìõ ¨>¯t ñÊhž<+~rÄÞe¾HIm³”wa\¶ïüJzµ©L©…•{! î̳Ǧ±ÿõi¹Þ×æÔ N9Ÿ¾Ð¯yDZýcí‰SòJÄÊ‹Vñ^E„î¯]¬<>â& sêq@Ÿwº©öGŒ2ëµPÖÕ€QíÍ0ÏA¤FTñyЧ×âödºCàL˜Îu‡]LÊiõÜR÷a+®x/ˆä¼6Ê,’iC±‡?§¦vJ(ôUƒ’£]Z¸äYòVšñžÌW” –¸aÛ'qÇBN¦^¸Y‹ç.§³ñóg;ôñ* ¥Ü ž(•hÌÄfEshÌÉý×Ö×4µ|‹zP®rì•ó]½û/Rã}‰A.È!4iÊ|=›WÛM$ç< à'¾“©0•ϡ˪°_@dñä¹ë%}ùi '¿æ2>-†¶S5À½Áu~sä.3o™Þ'ØÎ·ý6K/ãË·6æž²íâa(Oz©dŒÅ5mûH–¬­_Ø[ÙöË-4BM»Gxpz¢Ô™úkô!zºÑg}t ‰B÷P®7¦™ãóí˶ž\ï¬Ç³$°õV¿˜ƒ¸ŽœPfÃþÇgº´[ûLBY_ 1Zo§Q †$GU3´Q9:´&¤ŒdaiÿçÌë<½#& Êg6[ÄIádéëeT<¨¤-" ^_Ð81™yб5»@­¢iÞ|7#÷ëŽÌ â—à^ F›¤ÞÑ®A¼¯â?:˜Ï1ÑE±\uáX£äæ/hõ8î—¦îͳ:‰Tü¤~Ȫ¶a>±xқàA—ÍU3ÔC„ëU¹:ò~Ûb¸©ÝnóŒ‹Çk;RØÍhlµAé˜>aÍv ¢U `/¹‰N]¼¡>I×EŽpBLŽbOE¦–5²H“ÓÓ¶ÆhñŸHé3ÜÅì„ ‚Êï÷aÜ_ÕÄ‚q{´Þa$‰¨ò„§úÒ¤â꼟t5 §.lSvh¸G^u®[ÝJO¯+2Œ¾pÞ¨ÁmoÖ§k#›CñZÑp R8ãl¯—Í©F™)a&à{ÿhîÇÊ|<¶õý‚BÙ‰œ·çmß{†è²Ø…¨ß=Z«’LX> xÖÇQ #þ„üfùMKLw-ª00—ˆL3‡xëY Ê™¥R›—ù°è®´³¨gB9©Å4®+¶ì‹æ öÉzÊ^¶T¾3èÇ]Ù´èÂë~%#J)Ç‘OÖ‹9é %™’Q>½ÍÕÏ|蹟RŸ0³¹¶#šãUF‰Ü¾v©(þ:×÷cf(ç]ÓQÇ TE\Òvè¸o¿+WJŠÌR=š½ðA²Ö*¨Ûô{ÝdÕâ‚Û‘E£îö=Ø …¬·w€ä«I½;Ï¿¸ÙÙMálÁÄm ôÁ)hZ¡òÕaH h·¢ßP¿#ë•âjkx㡾I‡±è–-•ß=Hî  [9 6ŒÇ)“«,$,ehäyùÙÓ±Ù‘pà ¶xš°(P~³­4Q%)äUñVM¾fƒ4¼ó÷š‰Ë_W;‘„‘‰S/žÄud ©±|Á]Û ŽisØqç»^!³Z´Þ\ª6Ž2…«ò PèÛÅEÝp“uÏi»e‹^ Õ’åHCóÕ"x&Í,V-„­¤Éë·yaØÌå(CÔ–HÊ~sݧ°%àµ[ÕœÀ!Ü×j/&eµ4Û‡^«ÀsœëL¹‰näÀêÓÀa:iJÀà¶Qs¾å t^ˆäé¶^‡ËƒÚšéN<¯dÒ’›A{ÄL‡‚*{jÈ0Â|DëÿNظ#¹ÂzêùªZ¶íÝãoÃÊç¬ù°pW ˆ ñQ¢ß»²¦ÊFBÑ%­+ƒRøDŠ“¤žŠi‡˜lùЇ¶ž±ãÊ?¢âb‡yÃn­áðT¯8s8PàÑÔõ‘ åü”+?¹ö|¸aP9@Ïê4cRÇCï?ýlVs(œKu•ehÒðl‰÷¦BwÞP<›Ú¨NF¯,ŽÄšÍEáÇëd€°¹Œ*^aë ìg+o8—C†)$›)oíyØ´ÙÔ:`HÃlâr*v@j&´¯”'½ZÔ€´ @€2ue%ðºX"^ ö[Ìv²kUå%²–Ïÿx\èâ ój³&rÌpübÚ?°÷ötu;ÜîR¯Kù$‚±Ý1¸ª;•ö´îÀ8îª]ý+À¾U_ͬ°! ý–E›³Lr’åák Ô×\" âzJý Z¼pÆUm`5Fšþ|/H=‹öµ"'Òùl⤊Sí^ð,†¬ž¢oˆe">¬w­é%€qŠéY¨’w0ízïk¬b Q„³º·¬VR‹ÖfíZ㟠ó‚NÌîmÈ)ÁçŸ>”kSåmŸØ•}þfìUáKDr³·Ú¾Ù»o¿”te¨uÏÒ´‰gŒ{^U? Ëá±ÞdöÄÔBÎe™–ˆ9Î8q:oƒ«qÓ‰§A¢W›6þ¢fZw!ζ6zh;ð1fþÔß.þ|Ьù…þTÅ;ãQ€h%UdhS|©_3|.g*R§©§n%~W êj•EðÔ<Ëîåëa52,Êù#•ô-"šÿšÎ-°y‹IÏ'„¶,e¥O…½ÿü‚ôG'JÆØ„¬QòàçŽ<œ|„îaoë8¢m^ý¯ß¬÷”`ë”2°÷Ù<ͼöŽ”„á)% T¹ÙÃåץتd¼ár}Nñ•BRlªn â\ÑËblnÃ$tDjŸ3ÓuÛ#¹~ð\ª*^ç`Örë, žBjjçê2ÅHdÞ¬æT3øådt{GÅøE¶"”ÀÍ>‹íx”LŒ¥Ò$Íš„ßòÚ€Ï—Í q¦ÐÔÞWCÕÞkªž¤l¸l¦±$ìdÏmúspõ,J›Î¶PXÙd¸ö¾Nk0R0¬_-¦#ûWd‘ƒÔy ÂH}Àh7WJ€‘N!žÌ ÕÍRÎ u³YÁÞÙVZÎ*ùØ…6«/Ÿ-KÜ-fóŠq3DÞy’•dêíEÕÀ*y@K®¸±©'}°U×eÄChåÑ*ª_xPØZI•uÝÛݯlÈ™‚õ0ãŠ;«íaù+6Óª:,ð|+È ì^ E¨¼Ô¿¢Ý†«±˜ßRrQyLÈŸ»iÖž'nöšõ#¥Ø@ÑÚ¹¡äW…,KêCø\˜s°zÍ©_së o¢j1Ÿ9Û¨Y~úç1<‰¶Q-úÁòåÁ¸]¡–¹¨Ó>:GöXS)Ž~­Cä6–x@ÿ98€g_n “aL9æâN×ñ‹ÚàÙŸaðq4C©„9²‘¼ Ï*´kª‰þÐ4D–k<";Ü)yq€æñcl¯,>l»KIö#Ç-Â| ÊT¦ÇŸég¿3Òð(')_I£+kæ÷ƒoˆhÖ 1Ù%Xº›ûP$%­Kª|¯*OßÔ:S7Ñb•­&1„ÛÜ®KÂî:ó¡RÜÁv°¡¯IW™©ŒM·kÌÊÌk}¾Õ0Ã4~hÍÕÂÑBšhÄŸ n*äÔwnÌýhmÈFÒ™]±§2JNÐ’NnYã˜,륑HÀPTçÀÜíuØÍƒ ZÀ„!ÎÇ\ˆ_É3MÄ·[¦hÀáÇžUÇ9Ç‹d ̇3=WíüÎ9Q¬$Òns@ë+»}$fKÖ®ïÈeŒÛ‚©ĽOVÉH-®"følmÁ5Õ‡'—êÆbqÙ‰ƒÙ΂I5ÜÕ£ãÅÿ”œœ‹Ò3«v¨0ÅfåOÄ/Å•§d@ d¬k%’=Z¬lúž¦~Éd—)|×÷¬"ß¡¡eö8Á‹l¿ ¶£Æ7«Ó[ªg<Ê÷]‘ÈõX4îí¸+‹å ¨)ï%;3"ô2öº“‘dx¶|R5O rùºÊÙŒŠ:Ú¬‡ë/-'™$«ü­h$¿"U,A¾Ò‚Uù%Ço“=¨†ì‡™û÷TÍUÉ[d;AUÔ׳møxÂçáb;(Íyp¥ïç'M­ $³6”û¢ ¹†Ùl{.žÇ78¡G»ò)¡¯‘ÝÛ×uŠ¢™æ½ Žù®® JѨ`PìXÖ±&`¾ŠéÌCÈ÷ #ÖMGV™°õ÷*o—ðâºÛöz€/$ü‹¸õ÷ûAóäÕ Ã>|ø´ig¦¹–Yšþ³¥Ý!bÆØÐÂ9JcêrsíyB]kÕ') ƒtw¿J¯6Å~Ó0òyÚe§&] ‡‘6ÐÕ}‚ObÊË–Ý6R?˜W‰—)(Cµ© ÷\viÖË©o>l¬\¸“-Ê€ª=ÐÅBÙèO¸j§9lMBr¢x¸-ÉÙ×-DÈO2ÏÁÄ UïǯâªWFëÚôB禆%)ú¬Þcñ|Ê]  þ©ú;Ò_õÓUŸ‘ÎLB^:h‰ËŒ€ƒ‘Õì~áüÕèêpaN•›v,ÒfÌÌÁЉîÓñ–AϪ^Àx.iˆ¿d] 7ˆO¯ ’[‘•åGP¬çY¨ȲÊ(7Òpèfû¤hru‚Vƒ:­hÂ/8âI÷¨²øÃþˆ5jz«úÒ6Ô½ö–Ç¡èØ]Sl²NwHÒë‰ÛR|*­XCbÊÌx_©Þ]æPµ‹1¤WÆÚZ‘>øc°ù ›ið!ŸÖ#÷3åDÖÚ…<ò{®á¸3f`ÁbÎÊ¥ ľlœ÷nÁYWqV‡PÀš¾÷D_¤*¿»ïNe¾g?š½LþÈ?û€ÃÌ®ºý3õ¤8/$ß1¥üâà3†ADdw7¥ÜÛI3â6Ÿ|!Ãõ¼«Å–†‚¥„4¶Žäóºã}¤õa}ÓS5…™èÄ#aÓ2 ñcÜ š>ˆšØÁñÉ-ön<‚x%„N/Œ€Üh^ï/îl—)÷{(ÏJz޵á!ûm±Ë¸j*]åÍ‚Êw·‡·Šf±ÏìLüÝPÄC½]öÉZvIK²øÍcPyº!lz_­ÖÙÚ©äÊëÁƒy‡SÌ×ÈÑPCìì¿uPÉ*‚ãµ-èM‘·0Á‚A«@ˆðÿ†‘xþ…a½¼û¸ÑêòéÇeL >öœš†*m=`¾bLa«ÿ¾— ×'<ÿÁJ9½2*Ì씡~°… _¬NËàÓý\×i!±Çéx— õLFSüm^æ•“œSkL<Ѽšör÷Óô¶²b˜¯,e~uP0¥íEr-ЬPD¢D Ñs*8õÖ€- R(ly¡­¶s±Ô À1¼„¿Ïò…£¯w¯9×å<_TQ¾Î4-/_”äi˜9Õ<2ÌiPŽv++«š„Ô[%¡%¾½‘‰B“]| ؾEçÀ‘žS) ŠÐ7ê0ýºúKbË ž0ÀCIŒs Mq×f’’»Ù«Žun7E³`]ñ#Äwðì6ýëcè6:ñ/%«†óë-書œÞ)9.¿ ‰û‹}wŒ-׉¯p)WÍ3u¥3¯ ‡76mƒ!MÞ‚ëWüù€HKÁçÛ€gåž V)­ÚªõÉnm&9‚› £½Ä][ßß©o°wÓ“EBmƒ{gsñ]#ÕæxÄÚý׉­fê8Óabá‘k怚éBÖf¶ £…{I¯|xx–ц@ÜËcÁ 3ìÌ/*†.†‰cÙ³IW˜æ)©¸àš¾²^ßgy‘” ‚Sò"kms‚*ÈßÕ}ÀÊ„Æ8%ìïi. ÏÄêPAþyçY)ÇsM¯Ñ«óù&ðu1Úá¡àdh×ZkztKï§jiuÄXHÁ\n‰/4>eÍ“Ò÷­áXp°SæÛAwt|Þ¹#´Ýg_&®¸¨^„ùù˜jý¤2ËU<¤sIs§öåD¤ŒÇtú³›t;×'¼¥p¤nóWá8TÓ¢Z÷ )ûxÞ†Ud5˜B88Ýuꯖ:ØB;GØJMøæ=ææðD_sýI Ô®åiÕ«šó}úôÇÙÀßä'"º¨kŒx†–:â¿6§\ ;`»Ýžß­ž?°Ô†M 4€Î ñ›ö¸-¦”” ïÜJúž[Þm¨»¸Lë:݉¾­/ÕN†–Ø•¼;¸Ú¼~s"Qk)Ü@eÀpkUA0ÐvêÒô½¿öHnÝ6D¨÷ÑK›t:9+:³DŠ2MŒ5Kà]¨_Þ…¾^ÙÂLæñGCÅRjK|ñð‰îrû(Wõ ûj“ÁMypzh<äõe:ÊÙl7£Úh씌áŒ/Ò÷­÷­ð ê’d{? beƒ>®æÀq‰Ë„™O8¤´JO †]{ßôE i’¬ä†:D·Ò+—pÚ,pGQâ¤-7á´¬4Z³RÀ¢G*¡àÚãÂ> HÝÓ¶ô ´`„F5a» ;Úbe ‡þ•šáªû‹Ÿç-g±|‚¾¦yÖGÁ¼¢ï½(k‹x§æö¯b¨ßœ( ^£^[÷±ª@ä IIBÁn]ïB¯fœµŒMh ]sºiø˜˜j°Âau»‰Ãe•kƳ™Ï½QÕW‹†~Ùº’S°_®ã1z‡cœÏ¾^®ò{®³EG æÌòRbˆ% çæÍE!A$‡ýR4©úÉmä~u,g'är)BŽ^ÕN"š»È„"ÏËŽj‰ÀôÞLC »¡r¢6ðÕ]- þ*pãÉ7*¨â»W ÉÞ8u—Šn ¸Z[1‚¡Ü °â»X• %JíˆßÚ;òcÈ~H@‚2|2ò)lGE9$¥€TØ2Ûy>×@·» 7 ŒæÉIBâ™®Šû`©j虓ñ%¸Øžà0[¥™€/œóƒ)¡Ó**9ô뮫Dè‘0dv’Qüð¹ˆô·8ãÙzåõdéq2Dˆ•¿Äú¬¬üˆëIxÈôÛúXÀõ:¾kMcŽ‘p³ ¿õ?ž:'œÀ1¯ø×›~F g?ÈÓ'¼Ÿ?¯ÜÑw€ß]Åä-‚k’â5xö\ó;ºí@ ùYŽ´ªX;×öÅIçåú¾‚Euõéʯô)ªš5Øhé‰6ìe£0 xÌ1:¶ (W4µâØ÷N,ï«‘(W>ÀðÚ¿%È­¾bO*ؤ)W»_T@Ù®’l4à ªY⯵öR©¨Ht¥:ÇX'T«?(‘´|.’v¤Ô ÃE%³%·7ß ¾òzLÊk“;þ —‘ C°QÀ[—7‰·ý(ãzã  hÿîø©=Uú¬Å‰¯Ppp\ÒÍbÖMùįÍ ²åö/fOh¨f“(ŒGªxmóªÒSb‰l›Æ p=½ ö¡°™êëê»NWti‰Žø’e"àøY8•ã[LDëœOýÄe{ z¨k (¿ ¹DipM¥ÎAÅDúqÇø#3œ±õçšcJ®¨€!KÚ¸ëäà˜‰ž?Cz3»7C_Ã8avõ8˜¼}N˜bäkâ„•=üNðàÒa½ß~zÛ¶H<í$ß¶Ž=…v©Ø"t' åQFái‘~¹,å\Üä?¡o£w¯¯&© †ÝV‚ e @|à–ð³*‹B YJðÍ>Íyp+up©žàBãFç!/÷®×åšõóþà†· kÿXÉï4ËÝ(yÍ>Óàê‚ ðÈ2 ¼,´EâûÑpÅ”c”í‹qfà«q¤%¼gGOÌùõSô†ã’ËtÃF[xÇ-M_ÇÔÄÀåáPƒûzܤ68@äñt•'Àæ9œƒ ÈåÑgºP¼€k`;ñ»çšV£&mcÿÉ”`dÀNç%®»Ó‘&ScýåÎø’×[íP©,k$¾˜H+x¯É¨÷;Df Ô•4v–FÊM"gâsöNà°—º€¤|u県¿zp¤Ê(ê¶Ë"2åæí æ™{ZIJBA2G4ÀJ_ó‰âBÔÿ;ôÀnÒ1™Ñ¹?Ôdo/^a¼ö}§ t=}2ÄQQ©_y‰žÓõÝé–…{¤¤“½z«¯áZ0F<蔣 ì(²Ãä~AÆ)uÇlš£ô.Øý, ,E"÷n ‹O̧Ã¹×Øff˜ÖŒ±ç £éðäp¶“z¼Íö0Y- –­"Æó®ÉÚŒ£{HfW$«áIGc9,>ëè’F=0¯êÖ–’^Í5÷  ðuæ‹ûÝpç;Wx–0qÖnÎ&/;2ªÓh&4Õ‡ª]W|;…X8õW94_k §ß\ë À’cq4˜ÆÇvùF«âr¡é÷­=Û°ÊO¥ùNi$Qm›Wa˜íë2"äžkrœ‡¢†58Ÿ¹½['“Ï—‚;Ý`©MÓSUI¬!À(Ø—à¿­2öJŽ»$¥Ô鯥,ˆzÎÃ_“¹Mç·¨ðSÍ­P˜ÃPÉú^ðÚ©@s÷žžx ¨öÊ‹øã‡o£à9Å@Q^=ßS—aÆãó%®bJõ*îÛ&Ô¬6NçŠÙÍghuÍÛ8Ødp¯k»¡ä°DQÒ`m|,þºÀ>šdM/k‡bO‰ÿV‚CÊ|<ãa¦)SéeиËù¶ SÁÈŒÓᲂªä]2š;Žx™éK‘Ô-‡‘_ë Ãþ¡;þ@!Ã{ö¼9ÀÂú¦¨˜ ¿ÙÀ™8c{Oî­LÞ+DWùœ-”ñ•%c’ÐEl·ôDRæä-&¹Ô7Ál`1¾ø÷œTãÓ;Éž¾ù3*²ŽûáIgRu£F³›Êtî+*þAv dPšsðU½ºwˆÔ)ÆlùUô­fÂõÏ0&÷Ãá 9íÝz²á‹¯!Ðʸh'k’v®´ €¸ù2;†ü °߇ÆsÙ™›#´IÛóc5öú…‚¼ðVC>$a!Ø}nQOt t’M£{Ðlº_ûBJ»ùS^ø§±Š†"E8ä3¡°rv–3ÿĘ Ö§©e ¨ô3­½VW~Ú¯*2º¸Uk))d÷˜gg§ònÒAÜ[K2OÕ¸ˆutsík*N٢Ўä ÂgçAJ¤F> endobj 73 0 obj << /Length1 1430 /Length2 6037 /Length3 0 /Length 7009 /Filter /FlateDecode >> stream xÚuT”íÖ6]Ò¡ÄÒ9twˆtw ÃCÌÀ0äÒH‹”Ò¥H·"  ‚€¤„ !JJ}£¯ï9ç=ÿ¿Ö÷­g­yž{ïkï}_»†E߈_ÉîQ‡Ãü@!i€ŠŽš9P $$" $$LÄÎn EºCþ–±›BÞP8Lú?*‰–©‚h xà㊀âÒ@ i!!€°Ôß@8B  ò…:tà0ˆ7» Ü3uvA¢ãüý às€RR|¿ÍJ ‚t@Hˆ:"ä0‚ƒ¡dÀ?\pɺ ‘žÒ‚‚~~~ o8ÂYž›àEº !Þ„/Äð‹2@äùCM€ˆ`ìõþKawBúZàC`Þh˜#@GijôHôpèÀÑ#ûo¨䯉Ö8B}<þ[«‰¡‡D æìþ¯DB½Õ¡þG}(ìòWý]´{w( ¢÷†þÚ9~ ÐéÐcvCïotµ~« è©úgH5îøkü„ÅÄ @„.>ú$@ÑsêñÿÝÞA‰6 éœà¢_5¢—› äø+ùÊPç_ÊßrI!€ ·‡Çïuˆ„ø#kþìƒ@ 'ów{ ïõ÷ù÷€@ü!`¢Ù)8X&Òµ>²í¬Vé®ÿÚˆÜ'ö5³,n~Ô,¢Ýç')~:wMNøĉRúû²ù5®cÅÏÌW¨í–Fü˜7O Z/‚.펭µÍŒÒô,ÙVjèc$dà7V\ºò 2 sÃnÁì|À^àå#Iª_Dyæ÷Vÿ¡¯|îCôÔšÁz¸Ö­ËòqþD“ë°ì…¹“t¬xH~FŠÿÛÇ'Ÿ(ò?Þ0?xÌK¼“(Rв\N:Ÿ \¨4öGoILj}LñaŒ¥¼‘ñ€vUVºX<Á’ääy£¡`ub†tóÉá£Ñ#Ö¿[ T+¿WNßQ† ¥ “|0…hÈ„÷Ëß¾{\©¢ã¨…Ï€ÍamaŒbó­$ñxhÃS“x£ò¥˜7\Ν4ê™D‚H_.4‡n¡ò*áù­’‘kß‹.Н±X04IÕõqÝ,¹U°ž»…= ¬xÊ#Qjîãë÷ì-I‹Ùè3gŽ©øJ“Ë=*^Õ*3¥Ò¾¥/ L»Œ«“ú¹þ2Åì6ˆ\rÅ’%Lü›¤|òB üôꥇ»k!N?ˆFnKΜ£|ÓÔuŽŠÎBϾ¾bÍ©ü†›ºå÷Ì·òëÀDÌ55°iûúí¶&±Çs·;„n8IT“›}b@jռĨEº~«!3¸§ûŠ-×î¾ õ¸_ø²¬Ù•žù<açC‹g€H¼9¿ÂéeÅ'ØàÌ—œšÔc»i?;)Š^…Õõq/Úûh“+¥á;ÃwØñakÉlì—tÜÚú5ÕÂ4±¯^ØíÐÙdÂLù&~žR2D´»ZMP߯Ÿh0ÒIuu,Ö A[*¯=ã:Û€.—:åð·…5Yéj”pw?<“ñ#ÚO\ 4ëXçdvU’'µVÇ›:Ò <½õ²6à^fÑ=.qãÝYÁ:×aI‘l2üã¹½eùˆ@ù;ëí·¥NuÇr|ù?÷-^â¾46.VåalÕÔÎoöb¨ýZ6çà?-zÂèCÜžRͱ)=²-çn3É´ót .ýêUcÌV‰Ú“ø*èÜ‹]«d%ÛŒW'$±V™‚·×Ô ‡eÞn&ʤ‘²ö‹sõ½lк« Â2,/ãìÂÝ1I¬jÙ'”‚¼d^è’ W¤]?ˆÎå¢d–ýŒ›˜}7ˆ7š;xR¿(†J˜ãe#S†—øò ÛŠ&©K}óFïšú Dó‚?Ö¨‡1o–8’¶úíCªÌëà›(*T}ѳmã«£p¸oIññÑ .›æ^5'¦µÔ¼ßû‹Þ(ýjlÏä׸oì·Ú¡U;8\«ÂCº¸ô˜N¥Eßk”Ú[)<=¼ Î ý$¡;ÇÝÇ<æ.±­PÓä²OÕ±ºý0ÞþzÛØ©Ìªc»óîPàÂ&ª`þ‚LeJ¸ºÓâø«J_Éni_%SÖ¹ÓÚí¹ï¬ÊxÏÙXÙyÖÖéM¤U‰Yå­(²­ço PŸƒ™'ù»'çº-Q)Óég•Ï™O½Ê€3FCSE¼ÉmBï…Ê.Ÿ¾°iþà›W=åoyºWZðž8»†ùB®ÝÌÔÅâ6‡á5ªŠE8tn¾mƒs[!Îø¾.Ù!±À­Ä.‚îó˱‚ÍÚkš|Ú®—w†—·9»céýÔË"M(Ò­…”‡v'v³o5@ ÆJؘƒqÃB–eʨՒBÇ©µv<á'Õ«ò ÃOF´*%–q²¦“SÆfh»ÉdÞÕnìTñZ‰¦(ÿàÁ`Hï$ð ‘‘(h@ÿ[cG™)`¶rL‹¤—-Zi¯ížWœØr¢.õ¹M?4†*óe…,m/'U„© 2rŠŸ$a?kĉ‚èó'™æùÔÈà š~†ó¶²×ü°#U&y#ÁÅ}+ú"ÊŸZKüiÚ¥WO¯ÁÕ¥û‚4m5áó÷ö^»ûÐüvzÅ8›T_u´X:Åj¹¼·èœdÕ„Zïû-ZnË;7¾x;|¯”ÆÈ¬/Ų&#yKñó—§Ò?Vrlñ's©F ½:(;prSaħ² ˯Θ÷§OXà”óî6 ½ÿýå-h‘7é‹8 ê«J¿˜óÄÄâ½’ö‡¦[Õ±QÐì‰ÑÚKtŸ~²§¦Ó£&²°Ô1è/Y¥‰ªg€Vó×½û¹·­H`SÞQ¼e~Õ5ŒïY9`$‡]†Jß½¼•\MÕ™¬þŠr΢äÈÇ#û'ª1Fxo î?ôļ[>Ù‰/.{óí¬6ÿ€Uu³Óy2HµDŸÀä•üQ¶,?o‘ÛŽuÇ<‡·úãèVmÕÉxTÇ£Žni'Ú srîùÒÂp.Š!H¼ÿ„·Gà2ÞrûûàÇ«¾T¬9¼£Ø,ëÎ+IØŒîdt2ìn#-$lá Ï|wX Ã_³Ïé¼ìÁQJŸŠÖE…F½c“n“H§zQo/³.¯¹ÝÖ°^Ü¿æÜÌ’S¨bݘéÍ‚;8ÓÆ¹ÓùHÃE 2MЦ¬Aù¸4Ý2¸;œO–9U(.g?õùZwmyUãzKW¹Þ&¢”ê@ à5ôØL¤÷‚P ›ðî+¥ÌÝÍi‹K›Š$û(ðuY_gY »ô£2ÒԈϷF|¾ï«ÀÈã^Ð ;Õ¬üØø×]nãP•Îon¬ÅE˜©VàõŠ<†&Ó|ISⱫ²wÙD{D ìüUûÞbÂ¥Õ¦sL(Hq6é˜Ìèêg6~ßó޳U”ÊóÒ9]m å..´Dcq÷Ô”zåJêF¤‡tô&@ý㼦æï­Vž;ð-0z€fyZâèR‡Å¥2-ãjmKZÛb#‚jì™?*PÑÄ#}Õ7ŠüfFÂÜý£ŒÌ˜¦WùW°õ|ëİûÈ»B_ƇKlÞ°Þ`N½;ÿéÂØg!*|/k‰q O@: (;½¹s`м’7ØSTË>^idM¬ ÕâÑe?Ùf$­@Ùs8Ìæ9!dVXá÷ Sž ¼ýYÿ™(¯0¯S @t‹9éuËbÔÝlû!MÛ3!zÜ+™‡µy ÷ui_¡–v×±]îæ÷kfγ¹C÷7žÐÎÜ»AP~‘mDÒgÇAÍ1A½»©ð„óe¯2R!sÏÂ?JÖ\#y¹4M°fƒÇø™®¶›[ýÇ©tíý™Ô)w õŒûF¡{ÔP†wïÄuÑK§kPY¬]E¾ù®Ñ€¸‹ñef‰a´Z}ÛLhÎZFiüyºé§´cçë:H‹N^øônÍ`¯6Žñ­çôéÖä«Sè16çl™zMÁÍ-Á_CÄ‚Y6žÓ¼iiÐm"$PK-Oš¼eêù4e{ÄãÇÿ*áòPAzLâÝUZµ˜Æ‰„*©”Iš:¡•$&Š`>Á"Ö´:³ùQw‡6â’| 'CzÉÜAIzÓjck»î5íÌо[®6ðÙ(gÆ¢·¼½ã<%Agm®„ϜӈÃdò¡¼\NK”{.–ªÄŽa-o„Xw×[‰}Šsù{ë.sâvÞSŒ ÇÒÐÓ U‰77Ûï—wPOΫÆéWÌÔß#t<)£  ŸÃ¸( Oy­ùhI<-m$_uöµTùÝíÔîìÌ\v½y¨Åv÷|zâS]wO3ÅVÕ39 žœ¤)D„Á5€ÅÌ`þS$¢ï¸üÄsÉQGŠ©ëìO«~= ±ƒ! +g)Îá‹HdŦòœÛ2âE ¡‹ž+îY AÔ¹õiÖ°rØ4+&—´Ð@ijúôéþ´BJß&E#aºI:A•çæµp†Û«Ï©*ÝB4ŸT/Ee§6[iWç”·Þœ[n[wb)S3UD‰¹„ç"š£oÓ«DR;ÚRöù•÷ÄaÍB›^yŠdð…‰éXú¶ˆlìíêh^Zèð%õ™0­7GŽü²r¸Ã"¤Ø¥ Èid;F‰‡NЛ'*G'ð®äi¿·({ðÑ6@x>¸AÊ ØærA™Ôß¹…ÔÓ{Tìò© :®f1ÆM0²Þ—¸£ÐãJœc~’!L´îN¤×èîÀ¥n!9¬AþóKÝ®h­@ Ĉ”£Þ¦L¶®>•ÊAõá}‰3¦€Q,É{'ùx׉vq¡x¦à·δÞ>J½ûե咜£62i×½5¢F‰[¥]âM·,V»Fm }› ¸´ºgS¦ãšc³À¦çþ¶¹úJ›#“7_B*×Ïò´r™q}©F7í-#–4 홌ÓEvîw‹.çNsŽA´ IìËçÃÜry_U,Ò//’‘»-·HÌ×ZïëêãyQimC¥oC< 뜘z½5uFF¹· -„—ßÊW;>’Ãy1Bßjr;ý§²»=sù½C2Z‘G–G¡iuå89E`' ßFß%‰Vwj´b HùÁëaïþ:‚Òy¯¾V'©Ñpà«`<)ÅV7Ñ‘ùû™‘ÕÖŽm„§ÒO%ïÐ{ |y¯h€Ùws6qÇýØÓK²T’ÎCš RIÎeÌ AxÚñáÏã–³¢÷»ûv1Q=®¶ñüëcœV°Xµže±´Þêõ„‚IRZyè‹”‘@uh¹œ çEpŠ I6ÿÒ¨j>'¼ž…AoÕ€3~°N{äD1‹øåŒ‹‰ÿè÷ÛCW9¹‘RU¯õ:­ç_R9ò|¤6/p†½²GTe¥¿šjâÉ—µÚDÚoB#Á«×¸ìŸým*¦ÉàTWu¿Å&> m_í6gDç“ÌY~–žLìuœÔqbv›$#eD\š$<Çš|¾'ÊÝç¢÷*U_Çñí0YËzjèõñ6Pô¸QÐüâÑ+oP-ëŽRÅveÓÀ1ñt¹9Õ= [Y÷v\"_2wl¡Öâ["@*Þ%¾Oa ì2›—Áò3’LDeó-!J/¬}î'¸„âx>Øëv‡n~f†uóÏ ®7“,4ÉWÏm¿Încsi¿h¾™uõ –W©W&TQ*÷x>»Xi„õ°cŠ&nèEu°ñ–<Ég•74ä'—f{o®ÍÞi‘G]”ò^õ‘cEŸÕ"ÞeeuuŒz‘ñVAIX¬ó98|´®³]º„.5“nÚ‹¬:¸isa÷•:æDÒà/˜0)S•6–ô¥sDüT¿ñì›(›à“4‹_ÛÎl>ÙVoù¨ž–õ¤‹ß DͬmTU­>pLÌ;MÀOHf(¹WY'}qo!˜7Á³Ye–š—}‚ûp±ÚÄ¡3ÇÚF­Ì×?¨WAÛ ^_’¤W]2q PO|çŸ>Ì%ù(¸|NíÑûSÒŸP ÷ÎÃCÖœZv-[¨XT¯T·JЩ ãƒo«X´¢…žH×¾¸ÞÇ*iYïbÒÂ⇉ÞVÝ™Ð`†l–j‹ÌÌÀì)Ö¡«õ/n†ÃO›'GÖøªžÙ»-³Çgiú8€.aÖ׆Ÿc|èéqI†¥‘ó ¯jw,ž%ý¼(43w§ÑÛL&­¶éF•¹¦uÕ9e¦ÇÚ=ò J[Û’³ÔËàÚç-¿²ß¾OHôFŒ$äYÎSŒ„£ Á;¬Î© Ó9`ãäDäNŽpù¨*׈™U¯ RƒÈ ÆÕD²X¯u†S3•¸ÑM^.bÉÏ(”¤ý"þ‹Ù4ˆTý…Lu¸_‘Ðâ*¸³aƒQ)£6m>|gx^›Öª’Y©%–EÌÙâ>ÅyI4?â³oHÁzô–<+ZªÄz§¹§œr=ûÎVAK¼œoèÿwÎMUu2g9wúwz ë„~ƒ2ɲZ»ÏÍm‰FCH¿r$[Ü?``ª`¹Ž»î÷Qÿ¸S¾Òƒùãv}¨óp÷-ÍÄÊÉüXJI(eï.MÜùE³˜ÞÔýÜÅᲶɽU»ç¦Î=S:šo0O> >yÛ“%̵㪪tïôª«Åû4õƒB'ì½oJ1²uBH³Ñ(l†¬X»~‘(áqt2d¢·ø4ìùx4Ä»âh¯)û‘$ÈfÅ>ä•´Û½ƒÜ˜Ö€”6^dŒu8 H›`'”ÉS ’š\¿o­­âûMs#É-z/BÀ¿c'nCwT–¯2åÄ©ÍùM›Û+žc »ýÛâ˜?©:uº…a¾áßSèÓ»Q.ë‹?m •´g¾ù( 1À`Ï{÷ú¼pÕ~f´u ÏTAÀÈ`çð ™9†£l=­VüLÖ9zëÁä×*S:ÄYòظËéçå/È/Þú"§pûW·Å‹E’1ù×ÊÛIΘ…Úgc%DÛ´¯uö3—è<ò> endobj 75 0 obj << /Length1 1630 /Length2 9863 /Length3 0 /Length 10929 /Filter /FlateDecode >> stream xÚ·PÜ-Œ»Cq ZÜÝâî.B!Xp(n¥¸»»k‹»¶P¤¸‡âRŠ?úé½÷ÿgÞ›Ì$gí½ö>[ÏLh)Õ4Y$¬-€²Ž` +» @JYYžƒÀÎÎÅÊÎΉBK«‚Øÿ–£Ðê]\AŽ`Áÿ`H¹Í!/2isÈ QÙ Pp³pp8x9øÙÙœìì]Òæî +€2+@Á tE¡•rtòrÙØB^îùû ·dpð1ÿapº€,ÍÁesˆ-ÐáåFKs{€¦£%ñú/ô¶ˆ“ ›‡‡«¹ƒ+«£‹(3À±h].î@+Àï”*æÀ¿RcE¡hÙ‚\ÿTh:ZC<Ì]€€=Èv}1q[]/·4啪N@ðŸd¥? Ì€¿Šà`åøÇÝ_Ö¿À›[Z::8™ƒ½@`€5ÈP•Ub…xB˜æ`«ßDs{WÇ{sws½¹Å áÐͲêó— ÿÊÏÕÒäqeuÙÿÎ‘í·›—2Ë€­¤€`ˆ+Êïø¤A.@Ë—º{±ýÕÜ·`G°Ïßȶ²þ†•››6äì”—þ‹ó"BùWf„xØùù¸øy@gÐÓÒ–í÷Z^NÀ?”¿Å/9øù89:¬_Òú¬/?(>®æî@ÄÅ èçóŸŠÿF(+%`´Qþõþ"Zÿ‰_úïò²¿Œ€ý÷矓ñË„Y9‚í½þ¥ÿÑb6Mm©7rL¥üRRÒÑàÃÂÅ`áäap°sòø^~ÿíçŸ üýR5sÐ_ѱÿëQlíøâçÏ,^Ê÷w&îý_{Ãøï+T_ ÿwþØyØ-_¾8þŸ·à“ÿ¿áÿíåÿ:ÿÿ‘¬›½ýzú? ÿ½¹ÈÞë/ÆË@»A^–CÙñeEÀÿKÕþ¹ÑÊ@+›Ãÿjå!æ/K"¶ytnVvî?å WY'ÐJ ±´ýs˜þîÆËö 0PÍÑôûáy±bgÿÝËîY¾}y\\_zö§ÊÜõe!´÷7¾¬ÚÇ!¶t´ú½“œ<¼ss/”—‘xA<Ž—åµzþ1ó6V°#äÅð’³ÀÚÑåw£yyl¿E"^›ä¿ˆÀ&õâç°éýƒ^tæÿ —`3·w²ýW"ð¶øWÏù‚€ÿP Ø,ÿA<¿ÑËòÿ‡Cö—¸@ÿ_³ûøâÝþÈù‹+Èæ?Í9^îÀÿª–¥›‹ËK9ÿó—Rþÿx΀@O %Ê✣¥Pˆ]CHǯ: – aøÓ´_zœ,E&HA™iÓï šÙYKв‹²&vÝ*’οrÖæ/}¶)𼏲PÈîÛPXÄÍ=ÿ„þ–èsCJ5‡ù *_7E’\°ÔeJ, «YÌÊfP“Ó÷uCÿB¢^™,ŸBh‡JWO]Y–>©€ÎѦ¤ÕbDk‡çŠðuî¦ClðÖ£ÈT• *Eá®[”Z¬á±‘ì²Þ¨@÷ 3š0¶ŒÐ©47b­ÎJÆCn©û  9\)|Må|J B”©‚¤ÖSB£jD=»¬HÛD”„˜{ŶŽ©·\<}Áü©¹ß¨ÂmÞûX ¯ÊjtµÎ‡MÜ,ÂoŒmÛ£öL¶ÓgQûÚV•]ø¿û,¡e—VciÀª›œÃÍÀaô°dG½i•ãHöÌ,ºHë ÔM/& Ñô|¬ë'ÙßFéèlR-uL‰êduÖCZ)o_MêµøìRšØøV»_­qøuxr%`×$šJ;Q´Á V)b²= `2†sÓÙ,Þ˜E[[šSåt}Næ¶4ñ FivÜÈ`jÿ˜DZô®…éÔ€,¾ b5 ;%IXÿP"±ÔfyO;é?ËïËåGiüNZÀ‹@\X±ZŒMWúµÙ—‹!€ è8Žì!·Et¤õ ©­,ƒìLæDdŒ¸šiE.ç™}ãäòeÕÆeÉ’‚¯¢Ö·¼>m xB1:„Ï]%µM öU¥ŠDuøª³?–Ù ¶$ñh—s7v€DŽ~^xY²"биTüö¼]ÿ §š  ¡QÔÅ5z€Þzue¥ÁWPokÅHË+±ÜjÙãHËPm 7M¹ñ¾N*qà‡ê1²ß]¥+q¦Ãár Óý,ý–cÐ5UÒ`Ê¥1+¨ž" uÆ1W)iÑæ+¡Í[¶·H*]8?K„5Lp…'âH#}•NÛ>HÿÄ8S <çq‚ Zìš4T~æFɹW~Rö'}à“¤¸›=üÐÙÙ|ö¤æãÕ@Â*÷©_ΔO+îK…'µoÀ Π]ׂ(Ð¥ðSæXnËOÚEu™—¶ÊCŒŽÃWËÙY}G*†â‚ùœ{2„ÄþkT¾|û!ðè]'ƃ¶z.\êqJ¢’Ïe´’÷Ò¼6Ù+zoÛ3l‹Û´@ªv ³+ñyÙ*@¡†Í ‚4(Ó‰†°ŠÄ5†¸Ì¼Ý›wÆ8-·o BöU϶d¹+i[/J~­ÃÁƒÅU’K*oŒZÊ4ûm‡»,Í—wÞTönñÙ=ž™†í¶¸ãp¼ÙnÔºH´Í´ç=7L´‘Ñ®†¼U1O‡¾Åâà½øf6+µ¹,šUÛ³äuÛ.:…¦å‹É…ùÊ,‡Æh°8vnl¨þªYá#Ô&xÌÓyQ\gÀ"{ó½¼#ó÷:ù­Ÿ;d}qNQŠª@iðtpÅçúûøkK}~S‘xù׌«k6 G?WS ZZC:¾@FIe‡(ǶRàˆ–yøËü§¯ˆGŽ>ævôè ÙõÆqv¼ ìË×o–%SÅ<«†dʈZ n¬¬%Ä1"Zkä% +ðbËVÔ44ŸßÝÍc}'F£qäæáDTôk?aºN Ùñ,Ëkf[’˜ÃÊÞ,‚BX¸Z,I²ƒSytÂ’¥Öèoý¢È>F´oY‚ qrµýß|É9MU³Ô•Çkï˜H„¶•œøl;ÜTƒƒÿæ—ψЧÏù²Êï€Ì÷§ubžw0¸ûã¿è•fê±’á°ÍÕ_£\èѳF&½·O»–l IëkΤԃC£=R‹ÑzêÚHüW¿{ŒËG2löuï@ v° Þä~%•…±bŽCíçé¥ÈÓ)é»ÅzÏBð×…ý'£æ Ž)WpR·-e‚;I^ÑÚOk|uãNbá¹Ñð1¼ç GÖŠQ†÷" ™Ÿ~l§§!è#Q. Ð¤:8·ÃI91 üî©ùbÂ&­£*—€'»©ÓëÁ¯úó>GK1PûÞ1‚¯W2Knª+íœH|1~Eˆ“jSc è÷—‹1ªœü>VøqÑ¿<á-ŽT›SÓÝÊP—˜ñÛÑõ­“D‹ièbe>ófÞ§®‹9ÿyÀ|Î&Z$7n|ƒÍSÑ&d6½á…e„s-°/˜PqÐwqZBóeœ{B|ö2&Æeÿô®~óKZZÅÊÅ©öÑðùh£æžÞe(ú$Wù!zq·èS)ÍÖÕ)õÇÅŠ*W$Wcyºô1¦£gãÀ7­¬OYÃ3åŒ\AÖËf$?zÖ$Iò#âdiý—pgQäç¯?šq0ˆ¡”Éøl,¬!X_ÒÛ“{Eq^)H§^8´O/±Ÿ, Ú°Øsï÷(»(K¸ºÅ™ £™ÔTY×4ŒÅãF/k¼!]0 h16nòÔa +û‚ÞwLö=xUð\Ž7˜\}|ãÉ£gV—sÓ@¥è“i™µVVPêýp£¡Ò\ˆck†íK’°Æ‰z£^Tq¥ä¡JBèÑó)4ó—“îtnˆY#nXt¿ ú[?D3•Š+{чñ¨b’8ø=üÅ”8Û¥xöb• Õ¬úÁ/°Ð´¦PÁ¡OIH²ïÖnìâwLΰT.v•äÖw[¶sIœÙð4Üj–'u÷òž›Yø¶Ñ Œ`øC MãdÛÎé5.ӺʬÒÁÃÄ[œd)ïѹ*ÿ]A ç'Ù¥)ýFŠ+6Ïv-¡Å`Å:y’ä#cÝFà0Áuni 5)åçæT&ªÄí{[¾šÝ0Œ»S“ÊbèU)íéVä*Sø>ª’ˆ›‡ÅŸRæ÷5»¯<Œãc‹Íô…ÞäãÉ2ùWƒžƒæÄ¯·É¥/ö?)Yn—µê:­ûU`™tK´ÍÏÞåd4–iˆ¦!»B~wZöÌ0Ö²öúV.Y\2Œ$q°ÃÇ%aH•bc—Ôm@´h3°”Z´5yíY`ÎÆðÇ>*^ åå«´ ®I8CD¸¥g±}7ŶrAXÙbÙá=r`•1\÷ ŒOÅÕ ñl³mæi×z ï@ê xâΚþ®Ûˆúê•­'åÓTõ{ÏwbTjrxªÙP2¾^ÞqŠ“’9÷)pêÇ4©1š >%GƒatØ‘¥¢¼òŸònžÔìî–s~œ"hDJ¶2IR/.Möb8ÎEˆ˜<®“eŸ›s Ÿb–Èíe¥Ua©¿>ÁX}¯€ *µr•oIð±¨!.ó´&½Å=ƒ°ÿäŠÕÖ‚ŠÌwÐfY§‡²ÿ†O–šÓ«Ü¨O2T8=œŒB;;$ß¾{}‘­YKþ#ÉПžë-]Z›4ó Â-È"+80äE2ËuLs>X¡)¥­ì¾ÂŠŽxŠG'µ9ä·\²ãȪN5=‚Ÿ•â7J©ÓÈ•¦Ö6÷ùÖqf Ë:¿Ÿr örX^@í ´êW ™TŸÈ”îA—}©_Á¿<ðEº%1wÅ+Cu˜~çÚWÍ{L¥jËÝׇ—cÙͱ ØØ²6ÂuºÙYÞ3yŒRØX.Ú' îùcQ—e>ü5m]•âAI5Qm%r)"èµû©–ƈ¤O/T©šÓw¤yeñзýèwÚ]çÂgî?Oa½îN br޼çÊYéXșҖi1¿Éñ‚òŽ—©C  ¨Ìu§«Â7¨•uÃȃ.cä/Øj‡®=JN3ÚéÌB—x3ï†ü"¢Ô]I„äd®>„ëhêÃ\tŒrÜÇÆ ö®’«ÔW‡Uÿ¨›¿JQCÔXÛm‹b&çÆµƒ(3)X¬“tþà›Ü°™•µ¡Ñܶ¶wK•†Ÿ¬h:cMǘí‚ÊXˆhoéåq#x »ÛÓ wQUL;ÛÉB.Ä­~¨=‰Æ‡Ü±…âftó´Þ?Ùàº7ÿzVZèûÌE(¬Þ­bÏeê‘å†:8„šÒºó+zêç|Ùqìòi?ŠáׯHáâ¸ÓAö؈èíàV‹±ûˆŸÁ2„⣡0b|Ö= 3{F±CçÉØPÏ´L8Ùyµx Pá‹2ÀÐ>nî r= 3„ ¶}TþœáF¦”ÙÙ¥Ò–‘Ãef½fåm´êÖ.ŠâÚ)?F&  ôJû÷Èêc÷oUÏÄ<ç>í8‹º&$Û™@¸«rh?ümÀ‡¾`&LŠÕLÝ#e«@PçW]"ñ·a)õNóþ Gi»ô›ïȼ¨fvŠˆ³Î|‡\»ú ‹+˜u›º¶u“à ¢?ÊnµcÛÚÓð9bûB·ôÇ…l«™Ô—G-é1I¾Î{ Qù‰ ³,‚ü™+vjà<Ú$Rθ†­$Vä {ò-f:ýNvu»•Y–»2|j%¾…yäL T¦nÊXÂb/Ö=Ìp`¿*ááJH1yÞmçÈÁÙxÖ=J6Ü—Ÿ¤Ž(>„É]a•åM´ÞˆÆå^t™ÿ~\ à¦ýƒÍs¦²y¹îÙ\ÿ§iñDºÏ…µÌ+ºŒÄŽ»=Bó2u±<d§.õÐïR¾HZ—dè_óÅ¢}Ó¦rt<Êj© MáõßbË׉á:óÑÜP% Q6$?µþuC\رú-ˆu‹3!Jì »Qï8Õ¥»8µ&F_¿ÝðjÿáõÙ’¼rHQdɦÃ,-AwÒ6•—ô“©õ·'&¯²¦"72‘–¼§ýU˜k‘.=¿Ê¥H«÷s>i>=΢C­_Õ+w§¨i 0;¹îæ¸{;û±yÎñN¦Ð ’c!Qw)Q%sœ’½÷²®VÂ4òæŠ%ä~×›]s˜¾âR­çJµ 1|XÐ{>ÎÍ;J ê#;!ü¬ ïƒ`QãäÉBÏ8ô†Rçf%Ъ…²%@ÈŠ;O½dÉ€6`¬M:î'GW|ߦóª.}¶HT×ÛÅ'SÓB߸š¶ÁœgU#k÷Â1Ü;o¿?iŽ­ù^.³€ç¢»Z ’·S†|»S–.Ìb‚T6qK˜â“©’;Ü{…Þ¬”Ò©!gUISj’Ǥ«²Oc~vDðG¶b*Xõ› !œ[ l_ˆwÎ㬸tœälÒÒLãU²ÚMxŠ}Ûöu-_šðäÌèÃ6´ïÚícHóhu¾H)põ¡Äª/¿¼Ž&>9È–S†ê›8FV®Ñˆp‰Í“·~6qOj}5T ûLůeá ºR߆·èä"õ#½µÌ.W|”ÔHå/Dq‚uÆ ûà<˜u*n üÕÕ·)« Ãë–M6ÜŠɉ†´ùØýM" œ[uŸÍI§“†ßÝ÷¤+œF¥¥ÂJ1úzØÈ1l±˜ÑÇY•išúD‚“åòŽÓ·¿ŠæQ¸·£YH¨Å<3Œ/>öb' ª›åÌnnÇ—rvå/•»¨ûñÿ PuZûgÖO²ŒZÔÐŽÆ9 nÌrïWx>†š«µ‹(ÓáØLºïØzÂÎ3~±×Fí8¢9:èª'r.íÈJóv *Y¯D¶’&lžð$±ùaˆDêƒAOÑëí>–ŸÃæ¬9"m?€ qø¸Ì‘$·=o¡Jxb‘°©(kcäµÔH»úA”¸_^*¯2ˆËC¢äÄf¯j²8 y³0ñ$ÍHTÖP'2i õ»pìv©É…ßПÓ×IÑ¿“{ÑT>Ô Ÿ~¡8ö~~F3AGfGòÊÇûˆÖ„(b×OÇE!Þó°ùY€{H̨üglÒ‹O¸1•”brBŠÁXÚ†%~Ÿç·r}™:6Tóê¶i _دrä êòVßÆË§‡Y®¿€DdQÒçu?ªª÷ ™ô^6(G¡>€ÚK]áiaw¡ë~¥ŽýLVäµÃõqä¢Xùq/¤wW¬Œæ ¹°¾¿z&Ît½wÁöU’MZ›Žb¨ÈdN“dMYÙÅ9÷k©tçO’ïŸLºgzYsy²ô®9Œ÷ö`Q2ÏIëùÕ¨óð>9és(r1U<û’_Ûèú_~¡ ªÈ­­Ä˜™œÓzGW[LIA-ªQðêMúr¿Vó-¾D–·aRµÃÜ¡ þ”µŽF¬1È‚š´@Ag‰´ôýû¹WØ¿Vl¢®D‚Çάu)‰ìGÖäw:üÅÚ\Yt&Q4„Õc?¾<Ã2nDÒÔÚÕV_'[h8 ‚‚”:ÇK±Ý‘b œþ¸Žžïâ6ÌV2n`©±÷%£ÜÇJl3}݇DZ9O3ÂæÝ|üÅAo ºò­ýFú®‡fѫڊ=à%Y/ ;ÜÆùo«EšuVW)-=•ƒrè+ÎÑG ;­Y_’ŠÆ[˜ÃwÞrN7Ù žéš|©Æ«i„Ï0=àý0‚_þN p9z–¥Î9¦Á{·œcÀÙÑRK´ËzmKé| R*éñ>`û©·{± ÄŒ˜:Ñta*X½ª*Z¾þÆÇødPº/@|`O¯šOü™‡Åç§]½¡¢ÄhqïÅ×$TLçͦÙñJúœ·¯ÌÞuµ¿‘<Œd\¶ˆ]'þƒÒмé?þ­MšºH¾Êòq"n“9„8³™@‹®Dvm i)1ÂßèëÝbôT¥Èáw] ÆÓk: ÉøF+ÝšgªNã|þo„53<ØÛ =¡9+·”‡ÏqÑŸeJÜŠ^‡ÈÇÁXӦܖË1LtÔãp¢_nE9A7ŒÇaš¸v…ÑÕÌã²=t:½rÈ9\€oêýòk_;B¢0%Ôš—% Ö(r…“ñÞH-«&†¯ÆÉÝúZ/È;ÉÔæ<µîCêµ;’Ú;I³rr¥òSÝÔÆc±V‹°t),,ÚMÊ"=FX¶š}TÄ[+? Š£8ßý(²ÉM“›j<Êæc%á‘8ÛFçcÙì€ÀÒÜg#{¦Ö'¾‘!{â»dC"B~'5…xWØsð”'ý{™§d9Hý‡Vö€VZblŽ.0B©hÛÑõòû(·¡€þ}@ ÿý=•¨ÔeS½åUì mï0u8®ó²[S¼Üô‡!DÔx;:´‰ÓïÂDì”.Ì­ð¯rõ‹wï,¤÷&æî§‡s¢ˆ…ÊU0ý–¼ Z#ÙÉIrµWÔ~,ÔYŒ¨­ŽÒÕ‚Ïs7L¥âkÏá¶Zäz‰éÖ''åûð&x—± éyŽ<ÔþáM5{czß@Í3êed@Øœ_ ‡“ÀÑÉ7àÔlnŒ7ß.‚Ä7 "†5‘ÅŒÏÄåD"2¶7 º÷ÑPVŸ3˜ Ãô¾¤ˆÎµ‘fÑ%_˜æhaü®´áŠßø9k¿‹çK¸R‡>½¯ kùná•C{<¨ÊóÜŠ¨0¶dy¿wÁc`è?à¤Xà}'HÔ2n´ûeIF ž+Zv9§Äàß”'TÍ=‡kŠ©Õ/VƒÚ@ Íd” ÇèHºû~þdeÐV6¾½µfØ\u#¥6›Ùþ­ªEnn𙀗©Z‡·+º`¦ueŸyã9Ìño?p•Zu©Ž2ë²!P¹„hϾ5š.KÈác§·E60VÕŒ±\×/º‡ýNä#ǦBݘ͂·çu ©’׌C¬}x·Ö=³šÏÔRØqsM­ß:I…q³ Ÿ·Æã8‘ºMǽ\z“UÓh"MµÓ@®!ƒ,}…⵺(s¥|àü;“ÇÃ~$©7Áé=›4Ò A7øé{kˆL3‘J¹õgÊõt›.¡Ù•곓Mi1`áUÑíÛ(.I PÚú,¶'jjë/‹îˆ€n ':…½jºÁ*ªA#n3F®~¯Òy÷õëêËÑò£mÂo™¸BçÖ\r+ä׊lì µéÈéÊHÇY"L±ä—æèMpOÕ³&%¶åbè {yœ`"h®eù¸SüòRd®VêÅ ¾Îû¨c?ÔE5ºr÷*aÌð“‚d~öm’æ5áþ›Œóµ™œ¼›þ’ÀJ™"÷51|óåÈÜÓòñŠº¯4r? åý\_cú†v±¡îþ̟ᨻ˧íØGÇXL:aôŸm\©Ô\¯-.B…Û3¥Yß¶twÙL ŸJp¶Õ¸²0ׯà˜’+oœe<І3|d'\ ¹ý »Íé³Ü´wÊk$/ TêqˆËn›69øJ:¯Z€ã@Í¡Ýòùñ‘›—]–Iäg!n°Ö§ôVU”CºÑ¨%6eiì‹(†.šhé_J•Øê# J0û ¼Ñò˜Ñ3}d nš)mÕ‹ôäDßßåë¼G£×›ôŠ‘cdŽÀ¡Ò aºM+z`¹ÂžÀyïâ(OYp¥ŽNWQ3ÆÓàFƒ`ÈÿQ¨¶Áœ°bÚl•²¼6à˨\0îQÍ._N`I¥Sê6‰q8‹Î¬i&ºê4ž©±Ï0uËðÚ:ïØVç’/ôn…?n\r½ü×Ëv“Ò¢!K4†ODJ pï“D³D£Úð(äPªò^œ²al%>ˆWù  é]U¼Æž'²ôzÞH0²DÆ©qÑNz¬ëQ°u±ÓÔ-Ã×ý©¸î,=•kJ•Û´½Ðt™ÍåÉ[@èŸ<™† ÅÞ¥,j4¯x68ä«ûÝ;âÿyžOA endstream endobj 76 0 obj << /Type /FontDescriptor /FontName /SUCHGR+CMMI12 /Flags 4 /FontBBox [-31 -250 1026 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 65 /XHeight 431 /CharSet (/A/B/C/X/a/alpha/b/beta/c/comma/i/j/l/sigma/v) /FontFile 75 0 R >> endobj 77 0 obj << /Length1 1437 /Length2 6522 /Length3 0 /Length 7499 /Filter /FlateDecode >> stream xÚt4œíÖ¶HDKÔ$º<Œ^g0¢Eï½·hƒÁ(3˜Ñ£÷%ZôNH„$D‹^¢× ‚Aôˆo’¼ï9ç=ÿ¿Ö÷­Yë™{÷}ÝûÚ7+“¶¯Œ-Ê®ˆBbx!|`1@NCCEƒùÀ`"VV}Æþ—šˆÕîŽF bÿá ç‡a°:yë§BªÎD€‹Aî‰Á€,ú·#Ê] ‡y"l >@…„£‰XåP®>î{ ¶ÌßG€Ã†€ˆŠÞãùȸÀÝ60$ Ã8À]°m`΀ÊÇøü#‡„ã*ÆÏïååÅsAó¡Üí%9y/ÆÐ…£áîžp[à`@æÿƒŒˆÐw@ ÿèõPv/˜;À*œ6p$á´…»Øâ€žŠ: å GþqVÿãÀüu7„ò¯tEÿJ„@þ†ÙØ \\aHÒ°C8Ã-Eu>Œ7†€!m9œÑ(l<̆p†Yc~wetà_ðÐ6îW špþ‘ÿWì-+ måP..p$Mô«?y„;Ü{í>ü&ë„Dy!ýþìH[»_ l=\ù 7¸Šü_.XÑ¿uöp ‹ÜànÜÛÆÿWz}Wøo#ä—‹ÀßÏå ØaAÀývpì‘æ 0îp¿ÿ4üS"‚@[„ °†Û#DÿÎŽUÃíþÈØá»#¼`,÷ ø×ï_'s,½lQHgŸ»ÿž/¿ž¢ª¶¾÷Äÿ²ÉÊ¢¼?^!€W  ¸‡=øÿ3Í¿.àoð¿µÚ0Ä_ÍÿQi‡°Y~ƒÀÞÞß@<ÿâÇ_;à ü³„& Kf8Àño`ìòÞ€ß!ÿ?âÿÊò¿qÿ¿RôpvþmæømÿÌ0„³Ï_X.{`°{¡Ânò¿]àvYn‹ðpùo« †Ý¤=–ã¼!>°Ð=­ˆð†Ûj#06˜ô÷,°5œH¸6 øõä`£Ààÿ²a×ÎÆ û¬ ±ûc‚¡±;ˆù=Ü_2»eÿìCiƒ²ýµŽPaæîó!Â+A?vomáÞ¿ ðó!Ql€Åìء܉~YDà×ÿ¥ú-AÀP€ñ¢0Àïø[üGQwwlW¿¹‚íèoù÷ƒ‡{Ãmˆf§P6âa޵aÍ'52t^¼kï%ðv3NŒxß[`ºÆ,—“õr²çÔ*g;!ŠŽ­š²n'¹‹Ó~«uwë}„Žxï*nØßµNœº<º2ñØï˜žyŠôNQš,£X™{Ž6C,Y¡”­}—+éCöÚw3½Øn•+ÞS oÖli«)ÏV¿C/jøuEóÚºW úš=oÅ%!ôSœYtºf&³šDË)Q²W5ÙROï|в “‚ËËL|üZ ’.áÛU¼ŸÑ.fà‹Ü×9VOß÷±bô¢/¿ž@ÊKç¡â´N.ã™×ﯷ<„ˆ(Ö.§'0tˆ¥¿ý)ò{côÔ'16…iö)޲H‘¹r¿j͘¤€®ø‡Ïo‰ÞE“ÜWεepó³^‘¾û‰Â$(gä_z¬@pr—…Ë9Éûì]ÓŒ;/T*©9ž³Žbß fÃ39hbÀ!§þþãnMí‘à›‚ŒôWü­­V/äÈï}7tfîšÛL<:µÆ«˜¤Ò„k3H«5áÚäꆉÈ;ˆˆV|9?,Ìwõý”Ÿ©¾›¥˜h>¹šÑÜìò€ÎäÇQÁÆéd½ù»”càà(ÆrßÁÐjZ²­z´z14[QÊ%Ñéšçç)u|ÃŒ¾I©5Ýüds3[R ¤Á ”‚~îŠ Q…òTÍÃßn(ñœS¹K!ІèÊdƒl@zEʆ|¬Š5ÁÏÃë–ÄÂ<î‹ÏÇ¢xF4U4²-x¢pÖX{É ÊzuW€×YPc‰ÅîŠgÎÁ™êt¡a„Gäow“o­àIÀ’_Ÿk‹eÕŸ[Kç⺀pØO¨>ÌÛ ×Ç>g†¯B™8÷Ô”i´ªbÙß½XÈÎJHБ©ëë[ŸIX}Ï}ùd²‚õòf–sõW/C¯Z°ê“Ÿ9f–s5 ÍËt ;vûaݤÚä„› ~Œ[[£‡¤ ˜›¥ß&Ol{R4(¨ËípÅçŠ ôEÕÅŠ€ZØÓ†Ðú#—µ­#_>ºBû5&Çx™k´LJ=‰¦Ãɯ¹ ,tû(>pë˜%íîHÇuv 'Úí3º}ÆenüTêü¦Ô13Žšé«¨ÐGiöPøbfŸéeðÆ+‰ù;$3§o¾¤:­“ùõ¡yMqó \ÜÜÂÝ;U(\&Üp0ü¢°¼Í[±×ímLwïL(FÚU1È?t.ßRO49m—u<¶~^“UæoUý-äSv Uæ:Kf‚¾r/»Ä;{KEc_1—ÕãÁãóVPƒ±Æ¢ûfå G«‡ã•Ö=øx¤ø_f+–½hêù\°Žï}Õ³«£C*#úâ)âläfgI„×}çô8¢®œ¾ŠQ-…X8®ZoÀC…B¸«Å¤^ܬîd»\åý¦ðÖxŸÿAóE‘g{–o£´Ú^Kœh«é"ÿû<7Z1Q|Ð\®¦“WmFÝ:_hJ–MÇ4(°!Äzôáã%ý’"Ùå¹ÒóQ2Í[´1ÁÉ¢!*‰²Ÿƒ Âû OçÏA¦‹P6föˆ£¹jòðvûg> ^®kZQ¾Êé¿­7:µ½=AçÃUØ­H´ëõôÒ?ä´ êrVZ6ž9í[­=Ú¯Ïãóoç÷£5/Nœr¦®j ¤-#g¾Ã¢ã©06nø–~©Û$Oz`»÷³?=7«èéø…9xŸ¦ûã⥆ ổΦ°·‹‹êÓä¶•ô&ÔÙCŸ†VJüønBžwGL«XB†—åZm"{ßB\;™–ÙòÓY¹k«!5½âD–ë ²ÆÛòŠu¥_HóÉæù—_+‰. è/ÒÓ*ïúIBÓ¸wÓ|=ÙP³Gf•MebP@rp>C?· ]Þ†? ›GÃ<ýU.Ù2$›Ê>ÁC.´Ç(ÙØA¹+æ™:ßö «¾{=º÷\¦Šî ucL}?û”ñŒí{á*ö4‹}ÉXܤ£$Ý¥6ÃioÐ~¶¤K웩,¶¥ë‡Þo®çíÆ¦à%f3~'ðÉp:mh¹œpòV»'hûe&zò¥¸À4$Qo˜u!m®ò~ºãuo¨±‘‰|vá>SÔá+ ŽàSø”Ã;áøè¢—ù Ó² çÒø·i"ó×´¶útos0mR«Ý⪙¯f|t‘ñ*ó®ßâ3þ ÉÞ6³8˜‹®Ÿè:F©îœ¨å’ʹZDÕ„4ñaòÜ]¢7•P5ÑØ°†ÝIŠù½}—l|“ñ§=ƒÈ[€bï±$¯gsoÙõFQÔžëôã\¥ñ^Ž7'(ìOæRiÒâPÙêkí¬&¸¦í€ØÍ’ÜúÄWƒ7šº?·ááÃߎßÄÝÊÝhfÒfjvއ€ýÛ1[ìÆ[ŹIMŸÕp;4®N‹Œ-¯a§¢8~àäéÞu2-'&̈ZÌÚ*ªÍAXŠÞfdó)ŠB÷;ËLô§ rE­àJ{;ñHã>ôn[çÏ›ïO›æÔš’ ï !7þn8iwM,<ÂÙܱCÈY׉âŒÔ;Ø-1·Øló‚Ì™{:T‹®ùLJ1Ť f4´£ìš³UPkæœ;ExOÒæ)×¹<\¡„ñ!¡Ýšü+Jž$”fxa‘#$í"_˜ßvæŒ0º@aà ‡ð™F;¹ÞInÜìÝÂDèÒ×(~>jófKšÅE¬Sv³åG¥›çzz e¯Oá¢üÚ7õ$’ ˜8n·9^‰x¾ ù¨Üí°Lú9a]-ÜŽGÝÅxa4{3·Å:\íÝíìU§Ê³ï¡ßA‘á/)ˆÎ¯`N—w×—¬êf.ŽÏ(ÑÊìø¢+;ð‘_lž \–" ñ¦B üþ‚ìm¥Ï;5Þ7—DìáÚOÙädèl”×o>à[Nãc¦yÖTWâMDãdÚòýÅÒ ++¥¥¢«j™öýŠ«¯{+I#烗¾°ÏuÓØ&‘s|P^vQ*&~€Ó5 ¥õƺ~ë˜Lk„­LÝ}CgÄõÎÚõŸÇÈ÷êuL8%¶Ôí¾ô)‚w;ÍØÜ ýÖò™•„HNïAôÞl%’Fþ á~ì¹À½6g̾ú¢_¨4|v½c~¦;÷b˜º@I}ñ_¬Èˆ‹éão–‘2þ¼¾óû7ælwÅŽ±+ÿÄ5½g_˜ÊþÊÚºáîÍ7Ó"Zʽ \yYþµtÎO¦GˆæØ7ž3Ï&V¡8²Š½¹Êi+UŽƒâÎÀSAöÝõa6qCN1_|99i¤“™J=iÒЙt$i޼ì¦vä{”v–}$šä¯óíg·Kžâ]ÑIùÉ‚§ßªV oÆ;ã¶Þaz:·f¢WwÔ¼Z²·¾’‚x±ð ׫xg‘_´¾4(6 ß73öô~óû¥Îí¯6S\ú–N1[5sðÖ‡ŽÊaÅÌ>IðY0OtÔ¨ìæ1ßÀÁ©Á`ÎYBv¤D¼I©šÐFWŸÊþ­+†fÉEx•Æ1T—{"LíG‚ñÅmÇÏ‹bEåæ tºAæSí»¦ÕùžôýÏàO»SÓI^ÅKí%µ’è>u5@:„Å ãºÒkU¦…\«mÇñë7ŠIʨ–Ê=Øß¼w©8¿²fkROÏ·éÑW¤AëÉ`WúµÄnMó|¾?L©îÄWzs^Jþ|Ï0 (‡†UíV¼“&D…î_|2®“v¶6"íÙÒËâÊ4ñœJ/Du6–ÊZ/ ûè8Î;µŒ æò$ó2DÙ(¤6PÄ&ÿÙ#èÃà ~*.^ŒÉÙ©ƒßtnø0kë¾w’y¨g—D Ü@ÎMº+Žmó“ß9;Ò¨8”vßPÒŒê áÐåÞŒj¡Ùñ7÷þâ©k×ȉ)"+B«¿ß(>_CçÄ[I‚:7^ÜCh¥µ´ö—Í.¥`Øüðƒ¬c…MM&HÃv·k¯B󗘌Ci ¶‡®yý°Ü˜+¥—VG)ÍGIóU…ò#·ÆÜõ^ ÝàÆ©âyIN}Vš&oôS±–9"RîrH1¿þ`"Púêv€Hp í‘7Æ31·‚/†ÒΠŽå&±…w§ŸË&NUÄ£˜³» `Ók:ÁÞj?BqúÂü#$ç>‡e8)íÎÈg@[÷ (I\is•˱†ÇÏw;wè«‹+T‹kBP_c,®õ%»4G0¢b[b%\wñƒU¤_W â°v¥/,ä:á nyèG¬ÎÇÑá†!æoT*ð÷ÖǼZ;¬rD®Eé´b:ßÎh)þ “kÈ\a6žÝÊz5x5Ï/kqÚÎq5!.UšÉŠ#¥ÚUn_\Ø(N|ªo²kŸrç™ZµÅa\Žßœg~öe×íí wú‡1²¸œâm@\ï©|2y†z\õ>¡o²Ü,ð<;ö|%ùQœO¹œÂÀÏ=Õ…3#Þ•cÕ™ªèã,¦²ý# ©’+söhóã÷" VâY×'žß1Ĺÿj!ÁÁ©6<çq‚>¾êÉ‘±WªÈ Å¬ïø“xŠÚÑpÎ ÝÔ­LéÂ׺¼ö ÂWöîÒeM¦‘¿egfF÷µ¸l†2¨XÝÛ°ÚxŸ…Ú}£Jà°‡l“ýÄ[×a£º "ÿ™é¥×ppÕÓD:_™ærÂ:)ð|2JéÁñ.Ëh¦™:´¿0íÖû³¹óIœ("»\þRar­£#Ÿ”¤ÑèPýOƒ¢ãÏ͵¦ðz¬RŸoÎÖAȸ£"3n‡²Û–jf~š}ÇWæü± RQ%Û7'Oma¾\ÔìK°ÏÝ®.TI(¤Ðyb@áFÇXqxK)ó±,5cóåÍùdž2ì;z‡e?ÜÆÉSo8z®´‡r>ºSG!´S³G2N2ÛLC 8Ièj¥s¶ò å]OÁC5yHZÎÔéãrZèáò2†#½ü/xˆ£L5_)Ü‘»ò½ú˜Ø„8^þÒ·câè›`ó ºÁ5h䬋åÆÎ…@ø®²Pà^šjçÖ$ë J?[€Kjï¹S8Péeõ¡þr*} ç)’·²¦¤ªsEOèÅlGÄ_ãû©ø“o¨©Þií8„•(<ýˆˆËÛ4#§á¢õŽÆ•›yz:È0ºßÝN;œtóðñ»nc³²Þ)Ÿ%÷ Ðͯ–®lºÐŽh=Õ) óýêD£û÷TãÖuiš˜ÂG‹7³“?åræRt§@žñÈ–ÝÛ!U {¡5)ßCª¬½wjy?`V7¨Þ[¶oB'}â€ÌHãÚ+[¯‘Ö‘ÊL }©­@-¤w`V{öt X˜É_Í+© «–«£>;?ÐpÐÑyœ7æ­1œþDÞsÆ|3®)úè¬j¬´rYµ‚ëµþJ!hžù`Ìá]øôÂÈJÙÿ$•–¦6¤_^A{À2 ŠÄ‰|͇·µw§#6¹ Ãsùôî>nâ°Ý¾Ñ ¨óeÂ&¦Û‘Í×9\eÉXš“ÜõñÕRCJ mp ×ÙîÎ[\vI+÷~cF†L²—†ÛWÑ¨Š«áJaº%8á{m“pöúŽ•³übžÜ 7áGp1â;Pç¥óŸ£Ú;o;IØRïEŸò߮ʦ©Í<úJ¤ðØ›Ë$‹ÿx·œef­£k¡´m9~¼°4;÷`'°"b’½ì¥Î6“¼]:~äPZ‡Œ*Æ›åZÉs?û¶c•'>aêe¢¢=ÂEL¬ŸÓí¶±qr·‹¼ÿ`Xòù™ÓHPÍ×þïݻñ™½b:ÄÍÓAK™F~öêw)®Äu¯/ªŽäVú{È}H;ú3«íowY“ßoW .µðÙÞÙ~1ûå%ÑÜA¾•­¸&»"±Ê;otà öGo-þgÝ:xÖLÚBò1Eïy²¡ Ao‰{Ž×g…8Äý‰¢¾…Kñ¤èrâ…Vn´4šæi¤gÕÞˆOž`€ý¹æ{55gOR’ÝàÜàÚÍOâ[ _ÉÙ‡L“1RÖ’jkY›«Ú9&YgÕN•y7ÅKô˜NÃen2êÎi3*¾ÚžzA×R‘ÝS¶×˜K©`"ÅiN—Uæ(cïÓlJ,©xÝš©ïà—/=â8Ü“V-6•Œ«Y`ñ¤åËq¹ý^Ç,–9ìÀ0Hhm!ìZF²FÒè1ØUsCgHºq@uÛë6…òƒ¯®LÒr`r×À„ ÍŠÁ[óBŠQy›Ò.²W–3Û&I9íÌÓçoD»mDÎj)¼²Uf¡öÌàUàiVH1}È@ðÇXýZTËÕDR!1SîÍ“À|¥ýPPþòÝ·Úy+š] ç}“߸´/M<Æm—¡¥-sW¨ÓØ4\Ë^ÐhÇ(s¾æ.84š;ŠbÅM³ñF•^âkU‘&Ù'ä×p߇>‘·¼n~¼4±÷1õãà$‡ïW1Fð߈zη#'8¿aå/×)L8±BàFN,÷ðbˆ0dÄ#=Þ'¦‡qñéõ€a:kÝ)ÝV©Ä—r¦®†f‚šj¨Gà Àða‡ÇC±ÛÞÌԶŶuxŸn±á«ˆ)5QD7˜uºiMÙ(8ÙS pïk Ù )w÷]á4ÞJšŸAñ° ¢8Öèd£K&B„ïð§kèW|é¯2ž·î—þLæ%úq7ùôÈÕ9 #gž£ú?«Z‚ endstream endobj 78 0 obj << /Type /FontDescriptor /FontName /SFJPTC+CMMI8 /Flags 4 /FontBBox [-24 -250 1110 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 78 /XHeight 431 /CharSet (/T/i/j) /FontFile 77 0 R >> endobj 79 0 obj << /Length1 2098 /Length2 16406 /Length3 0 /Length 17674 /Filter /FlateDecode >> stream xÚŒõT%zû gk²ÛY“1Ù¶íÚir;Ûnr“kr3Ù¶mÛ®iâ„·ƒç9çùßZï»Zk·¯Û×ߦ$URe6³7JØÛX™y¢ò*,Ìff6FffVJJ5+ ðo1¥ÐÉÙÊÞŽç_¢N@cлLÌôn'ooq±°°X8yX>ñ03X™™¹ÿchïÄ3vµ2È3dìí€Î”¢öNV– ÷4ÿù  1¥°psúø§;@Øèdejl7Ymß3šÛTíM­€ ÿ AÃg 9ð01¹¹¹1Û:3Ú;YÐ~¸Y,*@g “+Ð ða€‚±-ð/fŒ”5K+ç¿äªöæ 7c' à]`ce ´s~÷p±3:Þ“T¥åŠ@»¿Œåþ2øø»7F–ÿ†ûÛû@Vv:›šÚÛ:ÛyXÙYÌ­l€E 9F;è#ÀØÎìCcgûwcWc+c“wƒ?+7H+Œß þMÏÙÔÉÊäÌèleóE¦?¼wYÜÎLÔÞÖhrFø£>1+' é{Û=˜þšìg;{7;¯¿¹•™ù$Ì\˜Ôí¬]€Òb›¼‹þ‘YAffæOÜl #ènjÉôGx5àŸJ–?Äï |¼ìæï$€>VæÀ÷^ÎÆ®@ÈÉèãõoÅÿ"€™•)`´°²Cø'ú»hþ~¾“•;@—ù}÷XÌüý÷›þûz™ÙÛÙxücþç|™´ÅÅ•dtèÿbü_ˆˆ½;À‹ÀÀÊÁ `ùcÉ>½ñùß0ÿmÀÈÿ)U2¶ú»¸E”¶3·pÿÅá½yÿááú÷ZÐü}2´€ÿÍ `ÿ¾Ë@Í?«¯ÇÌÁlúþÁòÿùþtùÿ·÷Dù[ýÿ[„‹ÍŸjš?õÿ?jc[+¿ ÞWÙô~òöïÇa÷M5²<ÐÌÊÅöÿj¥AÆïç!lgaóß6Z9KX¹Í”¬@¦–íЦðÞÆÊ¨dïlõÇc`xØÿѽœéç÷Åù}Vª€ï÷ô¿)ÅíLíÍþ8g1l…^:[¬±óžë?ÔX»ð(ðtp‰ oÑǦ©¼DŽRdp½J ×–Ü›ù Ir?¦®1 1±fTZ©DÙ5öV»Ž-w°ìå&‚© 0ö«K1 ȱ*[ £0@ÕlŸDGæ"ëmwÝæÖ©„+Ü3µo€9dmËSÿ¦n¯ßuŽëÃ# ÷¡©-Ã#»Ý>šÅ‚ý‚„n,tâ–º‘k«<D©Ðe qˆ.M 4&ÚÇ×d®ghã>¯Àk‘'|–ff.è^ð1 Ž\ïëXŸòú+…Ž­¹‹6nèúAoAœ o&©WWx–lâF™¡4yâÝy_¨•yk€õsAeLW[åØŒb¥$r ;K׃…ìÒ’½û‹ÑzÖÜùŒåê­qùʤ{gQ ãGõC"A!}ÜwfG;wß¿‹`Ûk<^•»…‹ Çn«} ΋èPñÏérVL“Ž‚(ºßï…7!?Wq%µmü‚ª©Æÿ´;ÞUôìö±LZŒ’ºpY¾_ö˜/Ì{YI¬°¯Ê_;â¶ÑŸµ¦]ñ )m=–2ó`’ܰ}¸Qãú_„@Uíá¹çXïâÌø.éèô.…—M¹^1{_€—#: Ò&žŠtq×?ýf“Ÿ&:òÕ<²iCÝM¸n…°:cn¸y64%BÛÎÆŒ)0q&((¥ÎÜ+¤Ç|[H̶ÞñÌz"ùÒÄ_á¬W³yËò_¯KœbSL0\ý~êà™39gÆ]2OÙnð;Az$ÞžU%åBR6éâ4‚+Nµnvú‡_»…~´¤Ñæ!Zp¦G¢àÀvùæ©1‡j¾¤\«`(±‰ç‘3ðT þ°õ:%Œ"ƒZɽÜW#*3&*£êõúÇY@ 1Õ;Õu:¿ 5OxÅT:‚"±háF&Á‘ôÅíZ5œÂ»ò-À^™oâp"qÚÈ·/‹˜…¹Ô.í¯õØö²®ñq)scØòj#7x³üØ®¾¾ª*CpÏHðæSÊ)6¢áX.´nrÇ —»;Ë<Ñ ?hòA l™—3­¹ÉÇIÖ…å˜íwºº(´U:v¨¼fzÖçΗxáÕ×”˜RoÓñÒ_¯¥å€]‘Ý•T7Ãð^ºå[Õemå3ÖÀi>ó&Ñ÷Ÿò2ò9ÚÌ?ƾ¸zqnâ&-è=ô œr‡ÓÉØðøï!“²Ôf´e×dqO†i»?âHŽÈz‡‹êˆHf·#y¬Ò DÊR‡ö²*2Ïj¤VpJ+QPØü>~úÑĈ³¥Û…{:ŽzćÓ[¤b¥´H2©ô »—ÃKûèbï+ÿƒµ×sÃ%!-7lŽ“.½•®¹¿ùûôwçDɦ`_¾l¶)-îèäý¶Þ•E¨œJ°t7v²ï×o;µS·öă6Š\3=ѦŒ‚‰Å»…I¡BMVw’#.GR9³™Š]ûSß= ¦è!~¡ê_Oç¤Ì ÝÚyöžçS÷ƒþ”}åÓÃXnÛÛ¬úöe½›€ ÃAiËQT—£<Û žz¸¥3¸Ò!ÎûÀ®• ‘rI0®œ‡êO7ªR†ÓÙªÊlIχî\þ!ê„=š±—6égK…§º¯=EtÊWH9WÓy[,h«ú¢.ª!2ù³Û>¡FÍùÐrÜ‚rÛ5Jæå¯ÐtOFé§°}y‰›‰Læ·½Y6í”Jâ¬y<Ä´ª"rL|eØe¢ÙÂù›÷Y6¼^£]ˆ4ä-KZÐv0 dpQ`_Á‚¹¼T–ì>t÷©áÐìj^A˜¿úÉzÛË#b,̦j~Ø|%ŒoGöØ“?zãôÿž[mÐ~o Ê&Rd9ÍcÊ“¸&Ij`ó &OÛ5E•—_œ’ì×yY×…´ýñÖâ9-ánSöø¬GF µ¤!òES„ÐçPƒ6jMuhÕ ïcÞeÀFñ¥ :vva{«DÌ dY»RãQ»Ô´¿ûT®¡î„–FøœÁ›_ʹ•ÈjJo·®A¹À‘ ¯+øAN~–‰OM‰.Ø×qÁÑFô6^øp÷@åû…8C!sN6|©M%c×iO<õq,êœqÌï,Äte{ƒ1è•_äéMüCy½ÖËÆàʕٰ44x—òÚÆÃgQÑ+³·¬>¶qq}_ :ë ±Èá×ãß"“Øz’•xPË3ùý5¾C# Ö†ÆÆ¢¢;kÅd¦e~Toûåј]™§jÌð{ÇQ£°©x¬àlðùü›³Yl†Šg|7lyþaÏ¡\¶'ž~쇫2'ÄÈÂoeA® bQò’Ÿ¸)¤å¬^©…—,¶íl8=ÀÃdà¿H(Öÿä“…ß?U/PŒÆq MôÛ˜±ùFuXÿ ½¿XG½<¦¹2µDÕõ9@ðŠ‡•Îdoµ<ão’ß#ŠÀ5Øç),U8ŸÃŽàÁøS7×½ygÄ"ìR^–…ä <ɨ˞¯ºÄjâ–Do •\(ñq- ÅÆjÖûÉÒH‰}÷¾óÒrÐ+psÇC×Þ‘D0Xç¯_;JÄB'Ì1\kN‘¬¿ß¾:ö§!F²iƾ`1Zãra¼q¡¿Ø]&{ºà½úèç9\7M‰`ßZ¹™ë9ÄüÕ9ðú&‹„ûäÅÜQê&ÀâÕ6>¦Þ]Ãã¶~åÃt™>¹§/nj±ƒëÏnä,¢Ðø´»¥þF'î ,»&mÑrQ–§>P™™ù} ØÔg…°¹(Ù*ðÜYÞü®“¹D›‰'Ä¥h…›È"pÞ­íB³×=¿ÏÁÊÑž7éÚ"ùŠò’wû1‚1Ê »Š¸ùê%¿ ‹Š…h³Üjî£ÄRNœ(´WjïÛ™þäGQ×N6ÍÆÖv¯Ä½È}¦ãÌNm´[NŒ|æ´¢ùÈ£Tx6ä<{;˜ÔH"c„”i@¤¹BÅÊî†^jã‰x@1Ǫy‰Qã¶2p¦Èmò–¿O¦X”ƒ12®ÙK'®¿ÎTdäQ­\ >œ¤§œÜC AW¶f¥†}sd ¸33Ì—7 *U¥T«Uh‘ýô¥Ž^%máLש0ãyHû¶ã\ÛèÓV½DˆTu¿¤¦ôô aB\]üÛÙÍkôÕ¬lP×<ªT4uM½¸Ž²Ðªôòˆ2ï-%³K·„öSUÇs®å„]R5Þ±6õܪqOƒZï5µ–“ßÜf“¡]2¤Œ\6"MŠBÍaîèT:By½‘—¬Dýæê•Áç “»_ìs#¹Ê|}¸Uãõ<ðæ~¯çpt×K¹Íµ–ƒo쉿X¾Røa8Ù ¿]8'cö Üü´ÓÙ„¤Kkå/½q¾½²ÏÀ4òŠ÷X@„#%‰òÂ1…cÔôÓi8»$>`ƱCÜ2q±pVújFÁ0­wW91—A%ÇçÐ …Þ„jƒäÝì›QÇuôÄ8Ü—Ò@o>1èéQâD²mX#âY1–ú‹UÐu® âä¦ív1¬W Ü8Ÿ” o¾À!e5 ×Âm™îáÓ¾¼¶‡ª¾ïuHDZù£½ÈÂñDx’”,WRæÇ£ÆH‰¤@¤õͧ‹RñMcÝð@ó%wv©\,ïXÍç:ÞUIâL4m 26‘_Ë7ÏÛRzd³ßuaXR&ÒÎM9¸ËX?ɴмÜÔ;3A^D6XÐü*uÇRþˆЭØáO”tîo à!Q¡àÖçĤ ²õ¨ µªÇ‹t>¶î¹Ó,‰’ëS1 R1¶éÇ8~*‚cübŸãLa€à^Ô”'‹¨*}a¾K¯/1pB•u‘í»LŠüÊHp² Íõl=q pXyŸÉÖACö¸æ 0Ò›¶wuiÃ8R*¥|K§y¶’Ý%Fݧ³¿ï°÷W ¦:`št4E;ùìì‘t\nN{¿d6O–òÈ´P¼²éŒøw¿Èò˜´>¿* Ë=€üf¶åƒ%ʘ®r¨œe™6Ã~ ¯ªÓ«‡1@^I[²t~Š—˜*†PªtG ;*DˆÃ?a}sšá!3^1«7¨qXLÊ:ìÚ®3–V ûZ ÂcÀÊÔBeeÞäçÔŠ›>^ª”Jr¾Ã•ôªŸÀ8Zóé= Ï £ÆÁFÁo»Ò¦`BªRT)|oÐm P@W;0.Œ€,‰@B½]ê2¶þãraR¶]žëYzÌlSÒ|÷+è”@“Iù×…ˆm&s¶Í”ŒÓÑ¢Á]2ÉÒ”å‡ÔæòÎÓ°s$Zšê/>ÏwõMÚ}õ1ˆþs‹”ÖヤR—QŠRopÃã±$† Q¼Ga5?ýâwdš\óPjô×È(–aËPW©E-8Òø‚Uq_ˆZÏG«º¯…Ëq³àÓÔù3`¦ û™F†ÛØk‚×ÉÓüüãÖXL¾j´8e§íe½jÄæmáJTaÔB-m“ûâ·UMº_÷œw;«Ô3ræ•ô F¼òë%ÿ„ƒñ‘bÀ’å©âgH£¬Æ‹Œ]‡‡'¤r.5 §Ÿ)ë7É.æ>¦Ž½ôݾ¤/ëúóYO]g(êËÁ;@¹´V 2”Å}ĤÝi1.+n±Ü™äÖ+vyƒS=Äå–MÀ þЧ&[j¬E±çf1œØ ¤»áEà8”ï%M“òÖfÆ!W\&ÝeZïãmIÜEï)¶ƒ¡>ÙçÖªCßþòC‡gâò°o² ?“¥óg½ß2°‹`ÜÈåAßêÇ ÖÂZøQ]ú€Á 'ÁS¶Çôo#ã«<ô¢!äHÝʉH4£™Ž1ñìü7ünè3cb¤<Ï«ŸrÆÁ8è>Ö#U‡ÃB¿ó#÷}úýÜQ.5 aÓöíœc¿2ÛÑ¡x¡TÚê”zÞD% G 4r“80ÈMS åÿ†¼”5Õ•Pö¥|»Xïv.lqm0Ð{Ž KÀZxQÙ.Q01¡_mëØζ'ƒY.V‡o󜾱8±7Þ‹s©“ÈNãëÅÐzòXo*û1ñD×1dq÷Æ.¨ÅªßÇ^"•>þ-cñgºA÷”£о&ó«úù/Ò}aBÂÔ'3Ú‚›4)»¸lˆ–’ráOdÇ^b¡*|L¬ ùþÁ_ÎûEþ¿?sKkýJ0Ï/Íœ†Üy›|ùM±\¤%~Vœ‚6Äx²MÚ5ÕKF'³ªú ¥kE›¸ŽðúÒz™ˆjfYøH‰þûAxgs+ú :ÿmŠBÞ>§k*¾šö‡òUÜ ¹Ô7ö‰â‹CÁ °I껳ûÞG? 3 I¹…ô‡ØÎX?$_ ¶ ˜šJëz¡†ïÀ-£ûQ<>êÿð + !±ÝÑÓ3rŽä—„¬iù4-öäÛÂÞ¿ ¿ùn·Î5Ädæ½S[Z´P}¦‹E"‡pÔ†„‡ŽÍq_ ¾æ'$)ùðBG’ͶÉÞÍ’OÄ«å6¢HÜ?éâ¿ÜÌ%BáC"ò¦ÁwyŸ¨Äôú‘¥\æ8ß”û_¦¾Rg)³ ™ðº“7Å’°Ý¨Žñ”Y›|8_¥lÉÄÃ2 Œä)¾]d9ilôà¹ëW5ô Ðî\æt×ëûÛd=BrØw éæMIð¢}T *¡Æ°*Ô«VPî–þ)57þkФKPç\hIâçPá VU«{¹šïm«å–æL@;»y³„X£å—UÆ¥Z5ZUèiâ;7Ÿ—ˆá: MâXS¢à¿*ïµcT õž=swWlm3z K ó×Wím£/8¾†îÝ1AêÙÞQÔZ õƒaÁ’B¨ê hœÒˆz$iÁ‡kwÏ<Æ¿!†拸餙}°gëõȼ–°à.ÙÔW<®‡]ö$2Í!Ç– Bn•6KFhÅã¹PŸÕ 3ŸÜh+®,0"G±çx¶Ì¬É ›+×°Â-a 3ۜ푚…d!%?}Ù%+÷Vž ƒ8({Úèüôtö ôÉï“›¯Sň,äñ7/›·m+îf»ü²p¥ŠÈÚÇ¿ [kÖ¸”ø,“©·V‹M\NøÛôl×ÿùÕfÔaÍ2=!|èô‰UÑ5]ñŠ7&ãÚóQ–Äþg]Èd²ÆF\\&Â×ç åà:ݵ >õn-B¨À•UASú;Ê­jøs…Ö5UîЇ îZð˜²l²Þ…¾ÌZ‹#µã¶õ=“RÍ~8˜Uš: @´̇#Z¬ÈèÄÝLR§ò^mÏB¾ÂP*§T^a3iQ#¦ðk8§§Þ¨ÍOÔ±—ÈLYv|ºñY¼ÅuÍBÕ}¥¨ñ á2Iê >ì¾µ'œÚ©™1ñKÖ¥))¥OÝ8•ÄçÚ{šÃ 5Ãèâòñ‹úéC";9è`ú׬”|ÊÍ;¾–ÛÄ»ÇcgU~ùƒä+ƒ^fEnÓÁD`VOV'$öpÜN‰ãê^vž£>œªú7üJ†»çØõj€6e5åBÝâÈ{Eû‚MEÎ2F³ír|!ÒÃÅÔ#aü œCYÄŠ5ÑF^JÐÚØBH+ô*}“怉.~­Èçð/ä¶š«L:Jµ~›šMø ðû[e©©ZVÚ\.`Køá´B~Íl€zÁ½©ZïGo$¼ü¤ù¡ìG³ÑLëäwÐð‰µb ÇA%cåž+"Ò–Ð}ìgî}ñ:)§ÄÃÙÉ•GA¬«åžHc“ºÍÞ™<è ÆåAX_ZCLyJH=)xúÊÓ9‰Ò³ÜBþºHÔ.ë2­á\·F#¥*—=;D´‹òúÙ“î*Œ®±5%´°¸[!­ë.Í1q|vOj^1²þø6½gÞ#mM®ÝÛY°OhU2K×®žò©ÜMÌÔsu=i«—§²Œ¾?P±Ý511%FDß¿_‰Šz,øv5èT)­%¦•ï5ËPlóð®Ê{Ý8Fô2„|…²»óÉì¥=¶QzE~ýl¾><ǺéÕݘNœòëîW.~©ª 5×z ÷–‹¶_}¥ºOöy¼Ëüp|z‘²=Š[¿¯gÚ.¸qa Ž©dp}oÔÕ¼ép|ž¢°~°äÙ=¢ÅꜹhkÍòü4s¶G'× fû¯½Ï(ɽºFš•mæ Zhm¬CäMx§Üyz¨”±~¢gÌj9 ç" «ºê)Œ•6ÌHSv0›o¨GÊ–v/èËÒƒdÄ:ŽMŽ>U^L»s¼þÞ^u ü dÈÙO_òröç„jyÖE§:‡Ÿ×NK•(âTìÇôŠÌÈ*`‡‚=…3 Cõ=íjôüÂÓ…Ú‘"ÞF„ý)`c‡¬ÙQ\©Ý|¶¶,¦‰Î(ñÅÇÁŸ‘2cšãßC?yÆD-`ÆYŒ~ßH_P¦ŽY’I’Ã6^FùŒžÿ|Súkkà”‡ÑÄÅ'O@•tòô áÉ ƒâ\”æDÆV€¶yúQÒV×ÕÖS¶}¥P³#«8ÄÁ­Ü•ÏQ/hYò@cðúuÙj?Í8ì4Gô%GÏÎ;[¼×—6b÷C óÒpf­ÀüÈ­m<¬Òo³Bk-eÜ?¦ l¸Œ+™å¿Ô/hgrHtˆëÃ;u˜z¡Ç ?¼¢@z¯¬á$Ékˆe’=âãõëXoH]ðÜ‚)ëI¹zzƒ÷ÛVàëlH·¶Î“ã AɶÞl›¦và$wÓ©Ã͹3μ1ß§).é[ð¦'°º ¯Ü4ÉØë÷ Ù¡ Ó=ìæ©Ùç$ 7Ÿ%ŽK„ŦmÀɪC¿5|aþN{týù4¼hò*5zÖ c¸”rݹoXïgœÍVt=§›j|ÔÏärS+ läNæÀ?H•Õv2ì>§e¹ÜpóÛTSðÓKºQ~ß$"ÖÊÔó8¯þ§ße»$΃^/Ô†Öž¹¼ãÎ {'ºgt%3É k…j0Ä!X"ÿi]!ð`“$4î31_¬‘‹“a²&]ÿMxÉi$f„¢Ÿ‹Ÿíâ[â^…qŽÞ}WÛóJa‚]¡Ejü¨ у{Ž!?¬¥í–Ïl4ä7áþµÏa™ŸïÊ)pƺš¦šgh{v7›§Em°ÁkÚòçõ<·'y>D; uRÅ[…^Kò„¼©åXòÞÇ«W#3­iÕr.•5z ÙAâ;BœÑ_q0.!¶fl”ü,À5â—6â’Œxç‹F¤q‘ì{©X_=÷AªñÖ>96²cü¾ÑåûÚƒO¯“dŽéc£<´ÁŽË]êZm`ˆ\ZÙýÕ4ùÛh!ÓŠ9úˆºˆ@ÿŠÂ÷ÎÓº!µÌÍÏZKн „™Ì÷8Y—p5Ïžb…/ç1X½ÞRËâUWœ°Íj°¿×S$¶°†´ZUÆ×É+Ê]SÜ)Q–ð¶1KÚ‡ù…ûQâ¼ )1ò¸Û¬6Œ»­ÃvY"ì‰MVÔ“S¤ Á•Á•!î¡^A“¾ÄðzÕ¡d+Úû ÝÔáG¾»€X¸Y ©hÿÏÅ»À¼ÊF©/½z¢È:бA«BýÕܸŒš {犿ÑÇèPî…ÐTÀº 3/åÂ´Šªúqîå_Ñýjòƒ; º’ÒðØOèþŽT»}ÓS );¥4Ù3IUUÐÙÍFðCt% %ŽåL¥ÖUÖŒùª¿/q4Ö›q½ §ŽÄ(Íë$]FÝ0t²²°Ë‰`Ξ-jY£=ÀDD„™!#·· =µ ¢Ç21eZÔSEŒ4 ŒzÄ”Á¼»zWõìD cgÓg,¹ì4`ܶyú̦kl,iN"¿ô_™—›&¨!¥äSû €Fׄ s £kïeÜ>¢—y$1¶‰ù°!J{9ikzD/78CDÉ&ãj‚Ó•hÀöBlLΑ­TkЫ,¾0KØSl;zÀöX5LJ‚ôþ€—}Ibþ &Áf˜úí-7•¬œÑ2ÃÙ›¯–Qé{½s÷6°3&çGÐõóÊ>°ì³ªŠªÂ*:L@ wYÆ<¿Â¬Ó&~¨!òï´MÃ|TaÑ“•þLø#g-ÿø’+ŒñR4qýgÞÓ²hõÇ•o×Ji¶)Ö[åê´B—" œö[CÎæ jY{E¥äõ]-Ãtóé¾&tâžþ¹ü é¬Z ?š„¯E9®¸fáIÊ–P¿gìWÖáÓk÷ç$!øÍ88¬nèœÓxRbª‡tW?Ï eG_!bYÀ»47{ÐB9…˜)‡ž:–p¿5Hîß¼¹…”#[î\ÞlÎOÚÊ™{½ù3†~ÝWNw»ÆÄ„ı‹ïØÒéÍÏÓ˜`MóÅCeSž!†Øùã¢ÈÅÛGåîˆ×D‰LŸÿ¹+÷&æ¢ù®0N®f&·z½øM¬û<}¨E4£\†ÉˆÅÛ®ÓÔXÂÜKb‘‡Øî+8æ'Oæm‡¶½ö3?ĸTÁ¹;pV·ñ¤7 Ï4õmð/æý>Ônuȱ¼VeÁ>äÉMxPïT’î q×áºn ??Âá®3Þ»ú*õÉeл¦cI^/`¢ÓbP¼uíG¯ ß`‰V:™ëûá4}–³«Ú‡•wâ/—A-nR„yšj‡·9=†z-t,ì€j‹ E,ib Øí ß¶yBmoü;4ÒÔ¼!G…°Ý«¥²”„[ï"¹žûê_´^ëEŠ«,‹Cm."CŠÂž° ƒ87ý£à_kôqï ±dtËËy*[t^Mžeùe Ê®W1L­BâGBZ.­ZH¦<íÝj[S ~Ö¢â´Å.¨®=u¿(ƒnÏܧE‰0ˆÉg;qd N1“Õ+R¡Ÿ—mKÜÈ`߇-áKœ³›sñ¦š'ZG-P’‡^@™cr´fÄò….‰TY*Í ëƒ%P=žÅ!öۻబ(Yen€&,.ô'‹ æ‰Íy]GǤ §eîaî18Ý♳ֺ¡\ .LMʆ`c ƒT£‰$©òvü¬Kê rœYËã節×ãÉ-èËÊûéû 9Lƒ¹sì?²JwË'<ÔÁªk L@°Ö3æ’Ùñ:ZØu‹‚÷‹Æg® 3œ3ˆéóh!6FîÈ$™82ÍQ^yNy N#q£Ùió¼ÕÙ”*d¼ûÞ"•à,WºEÓr{e—ްcWW#¤N(¨=æÉyQ5MtsŸÁrœ®ˆ~©XWëþÁù¨Æ¬©*‘0ëx“Š™ äS³p-¨5¸8ÃèÛ/ WdÒ:®l§9P¥ ÎìÁq»%–â3þá¢B4ídÈ^¿±íRãJO³Np6©fF¾õÀÙša01eï&#Ź'lu0äjðWC0l'Еy „õ ,D>m¡ÂØí©~=ϘdBŒŸ~ñvÐï#‡!Ê(”sY›,(ô+K:“åˆ)Ëó¼d“92BE©ODöÏ÷\b„ÈG÷oÚ²ÔŒš ÍòüV3¹¾‰ ‡ù®S5¯y0à|äÚïX“=£ªúq?^fÊ×5µx¶pt3Í>ÕØ–GÞ–í‹E¿B(ç¸3[n$")[R§>C éRËê(´ §¿gïÓ»ú[BJì‘øÎA§ˆÞ¥)îÊaÔÝ,Ç÷³ságe†]¨eFk°Š˜µåíNAB+‘…CÙVbôºn8Wôö~™^ÎrpnYÖlFS#Zê:ýü3ôl»›©‡CSçÊVas(‰"¤þ¹{{ZV´•é¡¥!›Ú*¾NDQ†¹5Ï`=b†¿a”«³Þjë ÖáTÐ&UpÕãHJB¬¢þKe¢Êœ%Öž¥'å—¯A÷5%¯æ·˜x‘‰ý7h~ð‡K5ä’'ø5á7âdy]¼ l§îØØ×u ODÎ5OH}+z{è5Ó¡TO‡?Ën¸0-2‚øòïî×p ^aŸ ägóàaZ|ÈXܰ§û`NߢJe£%6~bêO"mscË¢ ÖX\K8Q­‚ðua2¤Sçjbvuè:òM¡Ùaâw“*"[÷‡”ß"0´d)É(¿g”!¡`Í©ü ½s'ƲÝ3*{¼íõеc.)>¿,V' †œ4lgW::þÒ'ë­¿Œ9Dk!ýBn^,1„i#›ËyâG2®½  t<¶´ErÉ‚ýíQ^ðƒÓrn½²õ|¸ëÅgœ!›”À(+ûÔInÉÝѽfX›Ãª§Â3t¥$ñ¹ºB§û£kç¨mBç ]éÅ}¡'4— ûï2ÃŽ¹>óÃ!±ÜmV~zû-Çâ«ÅaÑ mîu­gú·‰—Kꘓ¾D[Yd<;#˜N,yšuK±f¿mFU©î  Î Íwé«É¡ÍtŒ#ÕF ¡Z„ÄXBç‰âÁý•BwR˜¤e¹.ÀÒês„•à[.«QéP+êÓþ;}¹.h@Q|@È[»üˆ4@ºmhÖ{!\‹%>þuìu»%8¾S §è7 ¦-ß,kɾ%:èWÅcbÁã:î™F"µOå/‹¨L3dW$vNMY¢à0<jN¨ÖiI³è“bmðlª›FŒ5ÈîyŠSéÝnC!샺µ]¢C]e*ëˆÓµi0U5zQª¾˜’öáívÅKä _|˜tEÃÅ:—¦(a òÿV¤ÜTà,àï´µVy5¿[¯k-EÃ2;}¬ÉgO­ ›»D.eX€ó9›Å=ìp˜hàÂ@`ÍžÙœþJNã0f ­=«_RHº(qôÒ7F°+µÅ(ßâ{ÜURØObP:Fp’f{TÀ }ŒC4?JzÄ^QR¾X}±Ã'‘¶O'Ü’'JwqNn‘XßP:çÍ­(¤³÷i¸'QÌõÖóô¶ô/¡ˆO¥ÉIæ×ÑL”(=\IÊiÈ߫ώãi´tld@›š4›¹òdÐEÀ^^µ{,´zjr_nä¤s‚nª2ŽS|ŒÐ÷ÚæOHÑLDÑ{gäßàÆ¶ÓgyÅ×¼>XpÇLÑH8æj¶÷Ê9ê¦ýÄ ^|m–,1Å>üä$<ÀÕtY’Ü aÙªKŸÐ%­š–4wä%íþ8Ù! Ñ$¡¯Cûfv«šBzIpÖþ¦);ÞÎL»ŸÒ2.J‘8$Îz/ü”%CÁ£ÅòÛSõAá‰,x\Üä€Qp´óìeC,TöAºòh&×ÿ<³³âåC‹Z™¼ƒ²«²:`*Þ¬)?áâå~òbvscäÅ/šX]ù•hq‚N.O(â›)˜éd‰vÛ/F¦`àÆåPíÛ^ÍrÞKùáÕN·¯³³k5=1Ù!¥fA¾aà wä ´`áÑ(l÷z…ú N"ª ÷/þ[©ÔÚŽºªˆµÔ|$ñçs™á8%¹ÃΚcbˆ´&µ™7¬&ñ—ßJrÉ}‹6ËØ»Òͦ8l¶àÚSUÝp…8˜*˜ÓœGÑ_#ü}é-¹:>!P§6¼ÅõÍÅ™· ptîé®}I¼Z'õKFŽc ßÿ¾Å2òÀ\u¯D^2qaÝ™NóñJŠĸµï&ظþíL`‰—BëÀø3 IÚðˆÍ7“a±¹Üù×çà ŒWí-’9Ut&'š«l¡m/,0¾'?OXn˜oßš €Ï&QaJŸí^s'i¼îM§Œ€¯¿«^Èw£™\y×§l&ôo|]ãxO³–.×L­¤ÁìEŽ˜Øù‚Ñߌ…‹ÑŽÃÍ»†aJ&ˆ›ã7r’Íx³™êF¦Ò×TçÌÓvÛªÁß´M’ìk[…d¹k|[â2F=‡¡àYšŸ—·Ê?¹rè5©#8 1Sïì›·3ûmÞÎîÜ5T±\ε•xóžÓÚ´[~xRù´ÏÌulŸ^"ëv@¬)#êq£“ç×ÎÁ~r°ê؈¡v´õ‘|9ÇQ ÂhQsa…ÖG:îœ×£¾ð»ÙJQyõ·<†çþðp¶â§ƒk½Ô­,UÞNÕ&ü¶‘G0ŠsˆIa¸nB¤;c¨]HØÜÈ`Ïóu4ÑnªíÁÿ¾w¸øˆUQ‹ë,~d­oЄ(À~.xæéNβjí»GfŽ”õw4¶düa/Žs‡ýÈŸUÚ&ŸåW»N*9› ýýò隉–¦»$È*¡>ƒ²IOÆ6nÂÉö9¥ôjcõbe¸×ŠÝ›îjxÑûš…ViªxVîdì]ŽÝ·fðbê‡íq©²1˜x›þÊ;½¿—.—§Àw-ñ<K˜ž»P÷Â=ÓæsÖl*N“< ×¶$«™3%¸DüY…SBû6ó+ù&]Oílê‚ÅUŒþýQ'u¿ðù ; ˆýL(|ᣟ…ðp£€H‡Cš©_¾OYyõA^>È ^Í'œ¢#i~ËvžÎŽp"‚ z\ºõüÙü˜@M üP,œ!¬f)|7n¶/ޝmB. (+ÊÜ N¦×½ýDÅ·ºãÖz$¯ßSŸ;Lç·ðÉ2 uu]3Œ5’P¾Lˆ+=602NvÀªÎ%Ãëm¢€sU-Jë7÷‰¶ r‘1Û{Šóp-2¼7Û<¶ÀëÌWØnq0½P—gËf^üEÚcÿÈIŽÖzhPÉÞK3p\ñÎê#xO¬¤Ë¨'=â š|æ¹'×Z—Éýë6×(3ÂŽe}耇ëqnÃd1¯ÇÕ)÷Æòk#Õ*ÞS2v×SGÔÚÊ3_õURéÊZ¢×‚Z¢c]”¾Ïå±–ÑñÄüª×v*Ÿ’ݾ!r^|žp‹GIƇ«¬É™—9îôû`úÁ'’£ÿ„«–çÀl “+ªülŒ¨6.4(,-BŠï`:›Û›·8*lÆ#êWv…w4¾Ó*®pØË)?^a`aDZâÒtÐa¼¬b¿ÿ›Zgó'éÍçÎçb1«g{ò>œù!(׫¦Kßv4²TØ€ô÷æ³&ÑÏõ+²‰ÐY91j‚`ˆì lM¢º_ +6™˜[‚õBXø9‡’óSH³¯Õïñ,/Iýø~ð:ªo'’é‡UÁ†¢èÎô«Y˜fÊÒ–.6Ì~®âbD‰ŠÍíBÁ&mhU”÷!oQÍLp¢ ´±G i¾>å}&' ®×€vURÚ,Ô¿»Cõ’Æ»ðó¶³SQð§¹|cƒDìÔðE¥œ‘Ýð+p#Ïè"¥pm ób"‹:#8Y4?Ù Ú¿ØM²Ý~­]­^µÃ‡áhæï-âý¶“ºÐÆHGÛRŸÌ\ÔˆÍÎw¹;KdB Ê'"GY…ˆ°—ä{(§Øä§*‚ÙÞoÿ"¾\ò+ÿ+Š u¢yš3Ìã8Û3šÏ5é¬÷ÄRJÇý áÆåð+ÛîÇb¿:Z““ò’ÖõGS%mÒ/¨Ú¦×„ë©àÍ?lžÍ³ŽŽd‚^^”šò4;B®˜ »h¿l{ 8 7ÇQb°P}áh#p¡1жWàw!Þ-õX»fîÁÚOöûôq•©XÁ†(dAgÌ ±øËÇùHXÍ#’ îYûËZÛzç`AÊ·º¢Û½¤‹–'w¡Šrny¡‚æ×5£rZÌ'83Wo³Å®Âžq?ÅX›åõëˆÑQµS‘[½?Ùh¬àÖŠ®oûÙA—T{¯Ct+„MÜ©ë“ù†–[:SÍk ²*il£õÅ¢ƒ Cç·ì_0ñSLƒw¢SËziåC¡š,‚iñãX"gX‘}m,‚ý¬Š6ÚÎïi²Ð¸fÿ8‰O¹òµi^Þ®IÃýäJMÎîБͷoOý$ùs¡jú¨ª9ÔÆ%hB1`‹Š¾ãsV|*Tæª"«g¯š˜ÄK/mRž~kÚïõ{ó!ûpÞwp%žšÁ¥d‹Ë–EmŽ[G7s²7^¾2åF–ÈÚü0¬ Y©^ò“Œm€snŸ]åjó¤`u»~ÕÖÃÍú5¤#’ENµÿºˆ6ŒÕ3¦c&Ù¦‰âøö‡/öEPm ÀX•Ôï|Š%<%2Ãõ¤ÂyÿW ÇM_¯Bœs²ÊI™dcó$"5jNð‰¢¬Æöµn &cç]D=Œ3BºÔtŠ'©¼2msY€pஈˆ]rxÚ ¡#˜íA}>§`ÚbYQ„šÛº”’)ÚX6…“ s‹Ò¿ ЗöJ…çwÃ5û¹Å5ÌÄ„>VCLr›³ë(Ý„’´É?&;úðË“ êØVš.×ûr­ÎÎRΗDÎ'tRüŠIe/CC®UÎωZ“Qˈßñåª8øgtz&¿â볼ꆓøšù+£ˆxjÊ•D׺®xÄ@ë\ŸìfJÍ¥‚íÄÆ–¬õpU(1‚+»v]̵n{µPgSåï´%z•¡¬ì ‡òðÜðÙ¿sÚðœbAj§Õ‰©“Z¶@•‹>;8ï˨Ø¢Ö¸\><|—×ÉK‘Zg }(®þù7e]ñ9î‡ÕÖݪ2q—¬×‘áìó gˆ Ùhæí+»¡¨8$ßÛ¯jwk|¤.œþg=Æ`z)Ì¥‚HÎw+õzO\í¡‘0™èhª]l¡^|± Ý7™˜QõÍΦáØ¿nvѽGë(T ¹a·W¬Ýq>Ã2µÍ ™!JH鯛4gXxèÓb?™ÿ(PaØif¹] ¨‚¿r `Öõ9«ºe¶èØÖòÎj xzûuê8iONæx"ƒD—w?r]’Sy;½ íØ>jªÃôb}‡Î•ºÌ)6ê$$hQhHŹàbšÒïXqår*l¤*‰0RSµ`(Ý3Îrý¹%õ#Q¹Ü¹ t£.‰ÔšN9rï’¹Ü³ÎÆ„ù“]ŸgMè8®D5Ãó­FÍY´²ÏÄôöò°,‹øçt/æ…lYËC뢃GRlÿm‰uošý¢ÌÏêgÉ6Ѭ&½]¯I–ç?ÇŠ _ÈDv ð¿,²x¿Šç‘é´AEUò0k#ÅÒ F‚²‚¨Œì¡P€Ï;¡Èeü9&ÆäZâfÚh¯+táLA¶š¨%—EywÞv›ª–89º-„¨|È·²‘L ÇõB.Ær+7špþf=âRyS#1[w»jâ?³è›²ÍnPÊèé`JtØ!ç‰B§ »—wt ß׺—¨GŽkTåE´ˆ©gè^6¯aû¢6JWïåúŽ6bØSîdW4A^œK¨C‡þ4 ô†‰FîÈá9±£ Ëég ¡W^¬0ÅÅY¤¦Q4×b&F9íXïE¢ß¿d´ÅLëø¸1¢xU|%„Ä^SÝóé îLð>¯Ç‹?tè=ìÄgÛ> XhF}…ªXß{~qÑ d¹kôàáN”ˆÀzò“Æùf‡6f1ki fÑ”Y{Të<É¿qªbyX4Xeͺ| \ù-¾õ kKþÌ” ÁͺHÎG"À¿ø\¨ð(‰âæÖíÌÜ*l‹qP«Kd£aÌîâd­ÆZªò?L¨ÿýùŠÅ¦~EÁòvœÙŠá˜îÅ”Qׄh£áGåÚP“ Ð;ø;Š–Ý˜QÄ3]0Æ×q°ºÎÍC\ÚúWÓ/M÷# ×K# $G¾ŽU¼C­LìÍGг6qõ¡¯¿óŒáOEÊCÖ”]Ò=EÖ¯–¡ tÐÊ䔟ˬeÓž>mB ÞUÍv0¹k:7Hñª(–ž\)ˆÃ#øeOVì[>^”›j»µk`¤ã{•ÆÀÝŽérÍÑM7'3°Î&rß‹ ¡¥‰_—KWÀÝFдKUŠB«1 BûK)?GT,Ï» ½‘nz΄¦Èøˆ|Ñwó·ØΚ’1Bß“:ÈöúvV<è‘ð=5ÂÇqX?¹ à³¶Us(ÍÐVí‚ÕY9_1ÜQ^$uZ0[QQåÑz.†ØZİ5F÷õ2Ûµl¬ŒŠx…Æ¡P+ÑØ1;"%5Yà“]u••†|Ô¼íÕžíákn·ûȯZ}m0ù8E“Õˆ½ñ¿Ÿ=ûg«%$ïÒ6x ˜}Ö´ T4Wv»ãçH.ã~4€³×+²oƒÝœÅrÍx¶…ÑUЋÉû2³m ò §'a1‰†I{{%ˆ_¡.ÝæÇIý¯–ŒI~5“ûyæå(”ÌXÐŰÄ-T(¡Œz|{}d ¶’¶×ìÁ´ø)²QÉìùãk¬Žµá6Ô´DÛ‚9eHÝÔÈ|»0lm «M1Ç*Ú·š,®èÆQÚ…]ÉÿÉ·4üz$ÕÚ%©U ™;Á`)0¶NjM|E¤ž©AkûJN­ŒL’%«}GÚ+Ë`ÿÌ;)¾´oã“-ÒZÈŽ÷X_n&ç¦P!¿×šýd …8à†Üÿ6‡Ì>[4L9ú˜¾ÖÌ[¯ü1„2z hìts S‡† xý€^Bí_z”Y¼–æSÁÉë"ºßfÛÙ‚¿LãÖr¬:v3Nm#Ê‹þ*OpòÙ»›ažø†ªy­4Pá€}ÞŽ[ðÕ‰À^IåÐK Iül´èiBkdáÑ…)|ýK §÷ FH2yœ_»€Í/ꤸ%­›ãÇSu‚Ú»'}½2½°’ö¿·ùäû.Üç?òcš'ê£Bÿ^¿,\Ž[“-qkgˆÎ_¬¢ôûؘÏIf›`óÿ“lü:²k>pìá›dl =øâ‰ìeã(üžŠRCäÊÊ^NÁ~YDT¦h¼üãÚ¼•êXÁŸÁMÍ÷}ƒ×£Ë¿a͈ìpÚÄuvò× ,†Å{ ££Ñýl@ V#æ’ß“ï…NÔâã6á…·è¾wÅlÂo”ˆ“ Vý0ÿ)ƒœÙd¼ä¹ÌØiýð ¯ùâñŠoHù°ò®Zéõs±}/i”ª±$€J‡L8K¹òEO¼R †^ÊnÝþòY› Œ%tžêѬ&“45€Æd­yËÕqÌd:QMÃ&Âÿ±9?Ž‹åT¢ÿ°7K`ÜH:Úe¶&ß25VõH(ñÈZË%.+õÂM˜-£ù¤åÁ»iF¸¼¹ÆÀ¼%y6ïÃígY?‹†ÚC”žpÝl"|fÄ(ñÓx[°èkßW$’XN’®÷®À‘¥¬Ñí9Ø9\§ÖõÔ›^5xÆÈ Ùgkß·KáØÁ¤`‚¾u ¶_ŽTNq}õFÓ4öEÞ>;¢šëîxõÙ÷i%E‰¤éíÍW3§×ÅUJzƒC3H®ûÊv:¾zI;#ÚìКr¼n5øìs¦¢¦q¹ar†E¾UþEýÖú=!±åÊõË &>„8í`SžÉw^/M]RûìîP7–[½.@QEÖê ¶Ó @ë’j³`ËȹæÄƼØÖݵÉå\GO¶\²pÄ5ÄrE†T£ ºØ¿œ)áß•Zºå´2JÀ…„2z¾ÍÛ5±Þ’ÐK[k‚=eGHZ¯f¨EHû‘l¡&ŸZ£*¼Õ TÕFšb!@Û6gïÔh9ƒI—õ¢b‹Õ%oG6{„«êÆ$ÔW iùΆG@ :î·y7SÓT½¡7# Spð—‹¼õ×¥qö]ù“VåAù|PxÝ®ô>¿R¢òu”•?Áh‹ÏÞº)LÄ ¢ßÞ¨ÊÚ”8Å ‡šE/t)…§À¼/ünqJ¥^K»;L¤È endstream endobj 80 0 obj << /Type /FontDescriptor /FontName /YEEPJZ+CMR10 /Flags 4 /FontBBox [-40 -250 1009 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 69 /XHeight 431 /CharSet (/A/E/G/I/J/L/M/P/T/a/b/c/colon/comma/d/e/f/ffi/g/h/hyphen/i/j/k/l/m/n/o/one/p/parenleft/parenright/percent/period/r/s/semicolon/slash/t/two/u/v/w/x/y/zero) /FontFile 79 0 R >> endobj 81 0 obj << /Length1 2568 /Length2 19764 /Length3 0 /Length 21235 /Filter /FlateDecode >> stream xÚŒöT”‹Ú ÓÝÝ ÝÝÝ)Ý!ÍÐ 0tI§€„´tIHw· Ò Ò Ý ß¸÷9Û}Þÿ_ëûÖ¬ÅÌuçu×ó@G¥¡Í&eíb ”wy°q±s dTµ¸¸œœ<윜Ü(tt:öNÀÿˆQèô€`w{ð¿ dÀ@ ˆLÖÂb§ê({:¸x\üÂ\œœnNN¡ÿº€…²^öÖUv€² èŽB'ãâê ¶·µó€¤ùïO£€KHH€õ/w€”3loe¨ZxØ!­,œÚ.Vö@ßÿ Á(jçáá*ÌÁáííÍnáìÎî¶gbxÛ{Ø´€î@°Ðð»`€š…3ðïÊØQè:vöî˵]l<¼-À@Dàdo¹C<žßÐëOF®ß‚?Áù~›»x‚ÿ• b`û/‰o÷§>Hí|]퀠Y@dÿÊÏ )Éá_ÒMÇAHËþ]¤ŸÎÿ* Ò«?‘ù ® ÈÑüK©Ý刳Ëÿ¨!ŸþQC‚¹B^ ' ÍŸþòrýG þŸ¶ó@r¹Áá¿Lùÿ’Ù»ü/¤9®NžîÿÊ ‘¸ý™Þoä tÿëþÿ‰-ô[èyýOJ®ß£ûWã¹ }ü˜âät¶ÿßýâûmôúWûù AÜ!¯›B qw²p·ûW`HÒBÙv`à¿–Ò(o—9@bxþ Bfæõ/aæý¯}ƒxûü BÂûþ BFâ÷‡$’üwªÿyìYy‚!3ñøëÅy&þÿõ¿è´BYšw± w¨ ︫•"õfÛý*6C·«ŸÁÄæ¿îô|À@Leªùº¾‘JíÃZÝ–c¼–\¦|ö?jm@ŒjKÑl x2KÒšÚmGYüF04Y|$U?HŽLƦ#¹ðì âÛ Ý­L—ïæ)ˆ¡Qˆ{ç= àS?X±29¿«¹WÃÿ õ©bš-^7îuHÙ,]eÎ5‚93ΙæìõÍ NÞä ¥r JàqJ­–î¬êÉö/êNõ|Z¨B»½yõ~ˆŒøuÌQZvø©õ” ~¾(rè¼zzŒè¢]Ûá§xÂõ×ÃVkckx-Bærä­Á[¶ê¼C×t¨FW}F”fÏ•ý¦£½·™ðή¬²]†º÷&Ü­‰M¡SéCÅjÛRódQYHßÔç{Þµ’“ÄÓ¤~ÈÊoåiÔ@63©Û=BeÊ®9hôF¹‹ü±W¡[ñ"Uó)_ðv1²"⻄ûf˜¨Í O…o›Â²ë8Q›ÊÑ ¿# /õ?õ]Nt]žš±qвWØjKc¢©9½Ç5ÊUOT9)Hà#5jèÇû%\öª>à§Kèe}œ&ô™Î6þ´"uµ/{…Ö›‰y˜.°Ú'¡™AOÍ 3`40Ë”þ«˜…$ÆYs€WˆsQI¡ÐBp—AöÌ5¥gÑùXKÖ=ËIë5éÃ4¼it‰ádÛ2 ߦS©Òº)Óæ s„w×BY|ì‡ö©,aq]Êð>5h½E{«“§†Zû“¶Ã»Boj¾z:é>àûQU˜0D%%˜m(7îçn¦ å®z‡º%áÛѰAŽÙoü€'˱ƒEê7âýëÛʹqõRyL¹_3*£ŒÚ«ð²ÈucúÅžá}Oã‰ø®ñ]ߟµhåéÞ¶\àÒsv´}ÄM eHcûž]^'ˆ›:å¡ô"åÃ<^D»IµjK©K¤¬ EV)¢Õ«u¢û=øX‚Ê©4^u©jŠÛWý`…/Bg@ …è¡É{2%ˆI¢¶Di#?MÏOÀtË1;·üZY¤Ê E­ç=ó%úR¼YOiñ÷¥€ìäÙ~ŠhÝ⫉êÂŒÑN³A›)üÓvYüðÆÈÜKßò)(¾{é^em9uhÐ1é ·`8Ÿµ-TæãàˆÑwX ìW\)'ô»g„›‘×%gÂû&-‘øk…Æó4䎥K§¿pPº%A !Œ ÉàN'y®·À‹y*£C{ÉàE•|ÂÿÁ˘LÖÁ.ý0Aiž;mÇàZ5½Íâ“ê5aY'ñv[až[–\8=Ô´é]cÁL^"3}+ï¹ë"xË'þi“K‘ÿÎÔ3ÛQò\ÛlB[ih1W«ˆ,•dËI ¤ùžøRt]!ýÑ+@ô„qVaiGÒ#ÞÍ 2N|sô«á'ºZF ƒ+¯Ô±=@®!h§J©šWËÕÁДü%ØHii&)½X,Yß?;%]™ñã_2¤}ãY5wdÖAkb¬.7ÉíÇäçÓZd3îe”ût,¥LÅã. d–*ü±Z4Žoô«bDνAm*ιÁê[Å9;ûʽ8ZT_ôÌÅqÍî(úVÒ´aŸêÝ£ñV?PFwt¤£ÌÇZ7}¶¥Ôç0~·Dæ Wö['£|0…黯<ÂÜ%KçK¾ô¤ò™TÞ¢7n”§'µíòìª3þDå›"YRœ Ëäj ¯\Cµ¯,ÊéCÛ5¸ƒüôù´ÇÙ‰¢¨¾8?h\1o'kaA$aWµì:;©¨P×QDô•ØQ‚»³y~Ÿs\¢…zÆg©M ?ÝkaãúDQ™bvyËY,Ø|žþ9Úlïüò!ž——”òZíå˜$óöÕJÏn'öùÅáçJu»Ie©á̬úqÓ2!¯¼™D_fRD%g–™jak5šÓôТ÷*3¤{Z>ùýTOÖTZ¨Ðﳃ¢³™ÏóBºw„öò µ«e­qûI’-ikô·#+L=Òxíø€IëŠjÑàÅOJ%¬ê͈ü ßKˆ7'± ë)#³QÂ_"ÕÔ-ÓøX@!©ëä"éí²µ36S)76uùl w~¤2©ñ[X•\`o .¿ÇGã;‰šd{—"«ÒÀg^RÜ=üäfZVÃAÞ/ Å:°¨Ñ Ky먲þÑÖã“?+õlu4˜1Ö6YPødh½ÆÎ,œ{çom]X(¥ú aÉ*NŠ:¬ñ€K6¡i,‰r²¥~Lÿ„yfÉg;Ŭ.‡Ì—ˆþYWÇîxÍÉ«[¨ÔŒ ú~–xœÖU&;k舋eœ±E5y®cYãQïm²ºkÁذ‡•ŒyÛ\þgvÂ@]pµ _•¡ã Ãar4—r*I îû±1„œkB¦…vaìëšû L_Ìx—È»_Ô°4ZÏ‹›Z­ë½åÂá”3ò`yÆÃ%fª²¿Ô)ë?Íäñ°KIí¥ù~1ï …§û|uJRöÊ=ÂÈj¼ˆ·åiñ”®WŽM[@K=¨†âøw…Ž4ß«½%z]û7^&RúŸ7=sÈWz¨Ì¸3Öà:ÿ’'k´ämÖ”iÉ –Ŧ¤ÎX™L¿Ök¶?Ü!§Ö±nu÷«ó82Vú¹åCRÊÚ×$CŸWw¾r©H×VNâÐ(ïÔA7žõ\þê?o!w%$äÄŸàA}5ˆPÆÁNz%`¤"KmQ”ze³§Äõ‘LbÖÁ£ŸaTP˜ƒ1N)W¡ oj¬‘?vŽ8*]4Œ¥ ®|¸ûà“»èòE,º!¨¦]¨{ׯ_©‹ ®t¨ Œ TPë6Ps•ŠIãEÐu7±±M‚¦ˆgSÞ»åÀ¯Z®wŵXLCÂÞþÆås?üþbdÇ< A¯'õœ^N&/D¢É ‹cþMf%}8S@ ŽÍ|x‰®æ“ª×âòõôîq_Ѫù ¨li@Ö“QÆ)ÞØ;á! Æp륄t—YÊÛ2³ˆã÷.ÜÛ¢kíÈ0џɆÑ{1a(¢|T•ºMQ:¯>ÓZËêü0šÇºG›îwhþšb Î¾/'äm© Óæ>(è—¸9Ÿ5Ò@Õ˜Åm{S<ÿ„ÇÿëûÊ„%¢8ƒ²õb%IŸ„ #HŠzdP8~ÎÕÝÎJ yEÞ«.ÃF &U¾)&DhË'v¢oê31ÎïÒ0ð²œ+DQÛ»ì!Hˆ¨–w5¯” ;þ>9#¦»2«„²›*$‘hf>˜Ú$ºI¯{°'iIN—{ÄYË^¹´ÌcAÀ9|4HEa³•<|ß«ý^ß_tªaÅì½ãû@Y#Gz¦¾Jú.WÊ"_žo’`=)ZÛ<‚^ÛvMÙÕRYkÿEHh³©| %šé^BK0ÂÓé›4çþ7gï?$#É{‘é (c^-²c!¾f0,¼J¸2 ÍÃ'‰žØÃ¢GüÐ9ˆ±nÀÜl Öìxjf¨ðÅhâìžpÇÂt’§„«kyËŸÄw&QKü j4¾Ô°:è'ÐZ®öhpC?n¿spvB‰ŒÍâÉ£Z=#'‡‘ÄÛ#b™{RÕñÑ’Ô[Á}¼×ÕÍ|Ry¸ò³ûÎZ<ûypÀ|$Y!®OìÔo‰ÀÛÁ/Í'áÁŸ£F ùßÌ ÿêÌ‘õv¥®q8¯•‚{ø„üÕ\[ëu“!Ægöioµï„Ï2Ÿ“w}q+߬{*Ò2 bLª Ô¼078”)PmER8UmHü“åyÈ‘Sâô½A®²Ÿ9OŽ®|¯w,lŠÃ‚?~â‘»I`×ÂÊ“Æ€Þ€ß I‡·šÔ P¿øÈÒªKNÛž[ŠŠI¬&%>7ìó™§±~ßä˜=3‹ðI-žaŠk~P[P0²G «Ú¸ýd›é*æ9c†9’É9«8!Îø¥ÁS¿s¦Ä/ [g¼a[OIu»Æ†y£(œ¿qÜj¿zÙT4ýƒß„›w5ó®*æâ»èûË4®P½ÂR4û(‰ÂPei›ˆ|âœ#r­RD{ÿEš^;TÆè|RÛÁ7(‚]ló ?":'ð$ﳉžböt> è ª¦×øô9ÔüÔu6ºÀÜ/ÎÿCö‡h´˜S|–¬d”/„¢?E=’…Ô²–zÇ7œ”Éó×ÜsúÅNݘµã[ãp„7AÅ\Ê_+Ê™ãj»ËUŒ3›âÝ™­l¯%ß8;Úx}”\Æ DGÒq5’|gŠ6>[žo/àÚ\ÉÝ”ª©RY/PWìÚƒÞL`-¹Ï¤eÒûb'±lìá*AsìS”ÎÉ ç½'áâW‘Ý¼Š¤´å©&­ˆÉp ]–@8¨§_GeÀ? Ì2h¿ä t¿óÈÉ:a\ âŠ9éäìÙq_ʈ@¸õ„Ù»"ܯu.R@÷~]L(s¡ •ÏB¿Ñã¬CG ·?Þ˜õNª»÷Ûø…€«LU~‘JN‰²t+çõ öu¶Ö›û"ç~‘°„OÈ^[L¸ 5OÛ»Dt˜u6&tïÔ=B‚Þµîn9ÙtH9"nàˆÎçEl6R6IF›M6×m¿À—_êãÑïd‚§¹ÿº\›7ÿÈR@H;šÈ½go–Y.ãçwjNf"s8lbÅr2×ÞÏ6vßX½«JÊÙÚy[°ðzbä‚ËåÊeÂ¥s›J9k‰ŽqÇ%BÑÒ¼Eø)à 8a¹k©ù«K>û¡‡Yã4+CpiŸÓòå·²\0ó ö&¯~„ëm>*™®?9[\ÓÇ©PéÒK@^\$‰Ûr~f!Š…¹úx€ÛvŒu|ÁúæWžCØ™þ6ÚÍ—ÓªZÍlæq¤ßkÐÊEø÷Tóúmß\ß<+Œ?;]0ºt,½ ̆ؒd:Éa{§4·ô·³Ç¹^Y/×8ὓ5ð¤Ä+ÌU@m¥°äV…~Bßa.,ÜmØk­ø¶J¤Ë´qR_ká äû¦ËÍlb†d÷Áfö…‘:L>éqj¤”kš–®Lt¦<93ý¾ë«Æjï‹Õ&¦À^‚H¡×H¦³ï³ Ä#gãYâæî(¥Šæås8,__oÔy)­ÝîÂ4£Âhâ¬ã\æ@Ë~žýqùèxçžVh'Þ”e‘”g_®QËøÆN£:²edT¥QAß)U%dJ&3'j§ñì¾ôn-©œ¾7ÖÎóо“B :’+.4~–î!AÈêµµ#õ:ÚàVÅýóucäæ1ühO/^ê4”_Y\^: uÊN0i ÞrKX…Þ–blfòõ2qc<—ÂrÞ­¢Oì–!fÇ¡NÝÄtå(´{"[¿«vBe¯L}]¾›0J(¬Ð ÁDkÆßOæ3lT›„¯z›ö<ûËwó'sêE@òcÒGn©lñ]z²0Óºµb-¿)1ì˜Ã4¦;[©µŸ(Ki kÑšíÓéÖ*Ìþ¯¹]çETeª¤ÏÌ¢ÕŸ9´ë`Fú`ÄTÇ… ÈW´x6¤¸YÔ¬¨·¼ äù‘宓OÙ1 ¾Î©©…Ê’’o÷íSÚáÇP✽Úç›~ËÎÇøjóFœ12Œ…·ÝwNò#þ:|NÂ7鹟Ɔ”-﯑«ÈÙÌŸ°ãRcÞ'O$Q•”±”_ké©‚ù‘­i±âo+½«$ymŸâOéØÍÙo.Ð=zRP̉ÎG‚¢snÞ¸ví˜ ¿© VÎ÷`нóÞºz-̯¥H"ï>ouOfµá; G(«ØœÌ½¢Ù^¡*Å>7ÁZîÑâIlžó¯ AsÙW…aì!ÚY,#„’ô˜±I¯¦Lzr,õ7 ¨ ÕÖK\—ð-úr&Û¼ëpz·jŸA‘“GkpE< Ÿ×^’cïÎkbÁ‰í@%àmçè7’ÂúS$9Ëè.6‹4kzü"ÝÎ1®Ž5Ú¨ÀÁvÊj0„Õä¥Ù“Å7N.þ$tÙÙ}p¿œ„žT¬|ÈYS½RL?h=Ëßç:Ét8mÿÑï*x1/Fùâ†-1ÝÛ,&'‡ü+¾ÅŸû*$ІûÜÛ"ÉÄB\ÜA~´ùsÄ/”ôÜôŠg÷Žˆ¦oP-ȱÉ#ˆ]Oz‰oùR`:¿ˆ0ƒ&,i/´«½Nìž¾° úN|Iüü½é×O ±3{÷•ž8J0cú)JA/ºõÁ(F…S@0S}˜1ú}”êuEoJzh›ŠƒÞ׆nÐDæcb½|­GWʽøÇÆ.­âôNEªíæ&>ü>Ö¬Õ/bìÔÓTx• ®¿"ZXa,^õ9Ñ‘ÿIª`lØô…«.É®ã¨@­â¢²Ë<«qÀ5y€¤ÙȽ˜åΆ» i•8K;ñ“.©úÏð.±¬6k7éú (6|>F¡Sd'æ`zk¼DÚ¾½+Èpư7únþz~>è¡€…ÎQõÇX ™q'*u¿~*Ù|t«vdÁ2"=GqwH¶õ@”JÀµx<{›âf/Œxf³ô¨.pÁImº„¥ë5CÙ§üÊŸŒc—ä´a}sÝíM¿Åðxõ°£NЫӄôb_‹FˆüqZ cGS=n¯9µ—4üS¯¥Üt³ÝmÊÐTëï¹. Û¬º_o(§Õ<ß\N³ëC{RéU ڴã‚ÄÁÖXpy«âØí®ÿé-©¾2~Vöµ ³}ŽÐŒ#u×[äbÆûó¸ãÁíQbq7û ‹'cĹE&Ü@\ U=ñãA¹”5æN´T/´·4˜Š±‘…¸@Ù‚)fÉààý¹‹X(êJž÷™ ,?¿’?;”¿`‚Eë$1Ðéгd!"†^ÜÍ#;¸†KZxL1áÐF~Êm „bÿYôì¾È¡Ò˜~¹¹†íÛ®‡ý•`‹ªêXH!5(ÚyÐ^’œZ¿>dzÖÖR£\ÎÓ(ãoT’›(%öø<˜f`F7Ñ¥¦5)iRúscûýbÑÛ1åèñ‘î|U°¿jiþÓ½pƒF¨œàR¶iX¿3çB”7ϹëX‹«Ÿ¸SLäâÓç ç»ÎÕ¹U«tb˜¨µãŠ ê­á¼²)Rî‘éz®<g÷´ù#‡UE¢Ö'?7¨]¢,¡‚…ÞÂ÷Ï—¾2f†nêÖ'ýh£wÅús‡x BìéÓ…‘ ‚òWCPjðgÓ ·¢?ut¾¡€°J†ó¥PœvñƒUXCüaêž~mRZŸà$©1ØÓ­o©3ì^ÆR~ð+h¿¥: 8…Yéxÿ+œ–¨%Ú ³Ñ%73Çh€ <½âêOêÜUÖǺÏe#âKxÓ+‹MPI÷Þ¡§w*×TÊáÐP‚°)í²‡JÖ‰¯M7\ô+ɈLJ|-ŽŸëm%?öŠS$ysżøÎŠÂ­'Žu3¦Í «–‹®Œ{õÖñ®8þm°Õÿ&ÿè D«:þE…™qNUyYȆ£ÐŸñ‹órbNìx§ÿˆ²Ð¬ë·Õyå|¯3î¤é$ ðLm¾.cŒC¼¦&Œ1îÇÂçq;j<’%£sË›ÉÝ/mþ>þãÞ(«º‚ù'ô¶RE^ >¼ÈÖ?*µ°záÞÜïwºq×Êëóà ’½h½û”ÂEK?áŒ_ÉÒ—2˜ Ü)¥¦”Œ}z±k=Ø0­kÅ;'¬ALìWÙ=iH?Ïáßû̾e"uæXà‘*˜Ìd[Úv %U—³êä|€¡}iÖG¿Æ™ÅëÃÏñCØeµl1XŸêYn»x¢y&$w)X°kÂBpÅJ®°ðø¯kõëAì&=(I’±•.§Ñbº–h#æɆ#Ìt" •Áy`‡î™áE7¥Ð$]ía(6W¬©xÎ2ºb—|(æÚ‡Â`<nSyà%2È€Y~ÅÆ,bGJ*B”=u»ª)  ϼgwˆ3/µ’ž¦É@fF¬@Úà÷Z‘5ÃÛûÉnÃ.´<3x4¬UÿforÖp±uãÂr!Ò®êȸI˜9} MÝþrY™Õ°ƒ_ŽI–Þ'V“¬ßX9fÀ8YÜ*ú¦jëu>ZbWõñZÓŸ¯Ä}T: WÞµßÁ#–ú@nù(ƒcT‰½üÅØ‡É2ÃÛIXm|™Á««¨Kbúî’guû LkÝ|LÃÆ -b¤¬~ñõ0ûR¾_¥œÐ—¨‘ÄâêôiexŒ0yæ7æ¶»œp?_.p8hµŽ¸ŸÈD¢³ÍÖŸø +´-?mòtZ5]ß_õhxbAF»U×OîÎáÓ³ªÚT>5ÁFÓ”+wJ·¼ò6"t:/H7Ç£S9ús7¯¬¾-¯@ó ÿŽ 'E9ˆ$Sv3ÂÅÙÝîîDïÛÁ¯Æõ1ÒnÊßòÌC¼œ m¢í= =K•H¹ìOrTC[|; k©§¥ªÈÝØ"~úñÔ³÷Æç9„Í̽YZ:ùÛRÉX9ðщp¦ROa•/·Íà®4Ÿõ—;°?Èg ĆlwTqhù|à«çK}h¿…Bf Rax*Ç*<²¬ ‹ÑSˆDè*ê§tN„šì#ÿê•€^Äô.é'm‘ÛT”;‹¸­ec7E}Žˆ·´á(\Oñ”hIÇbßuÏNŽ{ wUi‰VÇÌ=AYá)C«5žÂ8¬íåDQE_8ô/¯n¦Œý&·œ|úœª Ý%¿n¤BË2f2#¸É›6ßl¿1Ë[à‹ìLD^ Ti9ͧOT˜sÍ*Œ@òz®:óÕI‹¼•Ú:HSgË¢Ì.Ú}Œˆ:©R–ké2Züš÷u¡ñ>‹Å‚ó­V¥É˜sJr,ÛÝW3\Øš±t€÷ZöM”/xæÍv^ô\zÍXø“ŸEzmÊÊõl³ñê^ÓÞM—K »\\Z鯵ºÏRG¢}¶? ¥Ivh~mgÓ8Ë»º‹’¹×’“9o jyîU?%dY XKÀ1)ûFšdb†Ûì7~ØsF‚>Ú18 ÓÓ Å(`UI§\°QýÇŠ³XßÂ-!þ)¤¨Áxˆu‰-·lÛ¡I7òÓ-Tj¬h”)[Àþ'î¸ÓÅcò;ê~ÚìZ@rÊ‚<§£9Gü 9Ž%aõ*‰|ÇVkêÌWÕÄ&„X-¾òÇ©mu A/šŒÒàןüù:è­ŽXN3rúöÚeEï²"Þáù¡óSØZŽ ç¯òè3ùDÍ?âíazÁK”x6íj<`ù¯Â5ÚnÁZV·4ãnqd—©|E.òò“8¢<Òõ–€£gQ [BIÐïïŽ}6Ô`÷û’p0]ãï~Ä‹… rNÓÐ=q xÏãy‡5D¶óNŒÈ·úìúÊ'Ú»Kҵ﫩o} £˜ý ÎÛÑ4©MÁàB]9Ù]iÎ¥ cºn¯ zÒàhQ³¯â»aôËQݬ¹XM—=O$ÄÛ:Èõrù=¨]¼b…Py Ë¿~“]Ï¥‰øJ9{_3¸ ÷r+gíÀ _Ø”E¢ÀªŽê p,0þ¬^;_4©“è| ·£.´"–çëÀcSi+7CÇSÛŽr€5f îÉ…×ýÑšEµ»¹1`2µz6÷6GÍQmOJò}Út‹,9š'y8íÐ>ÖÇl_ª_ ZÙn„ɱÀö.OÎeâed\¶½¶'LœÃ%Ž!)܃Ç\) /»²‘^´FðôøF&ì;±ÌÚ¢aò0“%?¶f°“E_ @2‘ä4ÒXªÅYp’¯E #~= kÈl¥¿mB‹ó§³ñ~*¯#ã`ß|É‚Z,ÓÝMã§ØËˆ7Âéqm”o{½{¥À¤1ùÍ»jþ¸W°HfΉjï‹Q½6T“9*ýNGÏlª?ÜÖ}½¨÷ô¡¬žˆ÷hy+ð½ouÁÈ4-Ò-Ò X]Ÿ2Ík¢X×NbùѳMÝ<@â9ñÃÕì®<óvãñ•/QWiúF-ú/ ’έÜ3\lx PƒA‡b,$¾4í? Úª†ß–Oâ/ Û!VíÐ Hì9³‚N'¤R€|Šœo}ñåêpXÝ4BI5/Ø¥û,‹ÅH›Ll÷µG·š—SÛ¬ýCÎ]å…˜à–z=¸5Sé±å):ENwnÔUÀBæ:ôænxI]²yb…·2¦;IźÅf1ÊûhAd½“ Üý(Ò ™»©EM»ï¸˜µNß ¹„ê»u›vEÖÖ@M–Àº,ì–hç¼ F\I@[ÌÞWPk„%¯ }0SaD7­Z„æ·)ضùX…Õl  gb73O–þ6z¨KIo¨^«;*)Ë 6—{ud‡­©¡lÑXÍ©µxº‡¤v¸ÙèdÂÌ$‹H ý¶ iC«Æcâ57=LA’E<²dm„Ir|Ê8V´ä÷ô òæp]ÏFóCz¡ ± Ë[±Ðú2˜ÎLl§ÿýŸxtsäýê@«§¨š¨uTEzxž3 R0ùSßsÅ«ÜˤL— ‘¾ÝÓ› þ×>Áß{í±MK"ÈgBŸÓÜY®ïTb‹¿Sž •„é FÊQ2{YIo·´qzMN ¿ 1^Vb«XÜØh.#£Ähڎ¹u´|Š ËŽ&ªV±ôsH¡¸ÕœÉ—}™à $—ï®u½C…Î/9!rå víT2GÒ/ìÉÓTW¦ Må$©—kµ,õæÎç~ó`+:ß “]\ÿ$S{fúäùý®½Uæ–xöq Úì~Q“›Aœ·Éá’Gã‘¿LÓ·ÍÜ&^ªz?™/y!s6<=Xž6´ù—àíDzo‘°MZ¬§[Öa°¯@ÊY‚½×£ïR£š¤;$äåÙ 6†aÓ5B“³át{‹Ó+¨]ØŒ:œæ\Ó¥…nuGÙ4±Õ­õia~¬ûÌ…bâÛ?ˆ[ÕD©È¡ÒØå•Àeâ›WP8£`¨_>™ê'%°n†‚:+5¤ÙÇsP˜Öb¯Û5ÅYM^áf²ÊééÃrªa¿WÎê‰ìt/Õ£rŸïÓCë§WZ^L Lã _û¥ ¶ÚÙ™|}ˆ¹xE-ŸºòL挎Ëñ Qk0C¸ò ©žGyêURWÞWêé•@©’º‡K9\‰Ô9Š×Tëd'Q•ŒrestDJ&†ý$Ãà©zucjQ”ËE('>„Øß‰Ç º&m`ý·õâÕ“¥W÷m=ûh'² ï†Eæ {È5ã•<¨údNÈÚ‰q//Dõq’¶ÀÀÓÂx·Rƒÿó–c8èâЬ\cÒh!lè5„A­‹®ø¼’¬ ™•fÓæo'X½«-kn»U™p^l®pšõ#¨‚p9ÑgDÚÌšJÁs…˜ûO>r™!ü/žaŒ"%•¯»+úëªcÈGºSžq°¢ÓTÛ GªßiMq²Õ-.™àÜí[9êxɸ]O4`JÈ{ÛH„Ò+O÷­OîF«fS÷K€6ïC1é¾d6®€AFÚêQ$»ÀH›ÇŒB-í¯? °_]x2*g$wgý´ŽwE0(16íHu“°)Úê}z­ š‚°ÆÌôX°G;ɉ]Ð(ïGw ™2F`aBááb”’V ä6µæ,w¥wu¥üÆÌ`\"§=ɡ˪IÛ܌ɶ=‹ë‰ŒP·qUù‡!Ž•:‚jã·>Ü<¼·夿ŒK·Üs‰ÕLÒ-8B™ˆ¥ô +¢•kÎñz4ýÅï&SÒÊŒâ÷_{K4v+apRpíojŸÇ F;%‰dǸ­]Ùû†“qaÏÒ-ÇâE4.›q«1Äl­»½›é³ö铺8rÊ(uÚïnȱgþúÕx)ÝúÔ›zÿFˆ&¯áú1ºw² t”zŸF+Ipgë˵¤—‰¥”ù†w@­ðc€”†ëÀÕ¥ƒùm’%Z¿@suXPbø»¹·†s‚E8ÑùKÔ¡ÝŠ}(U…‡OexY‚Ñ=!ù¹dë! 1$£¹³ä×µ ]ùˆúÅ]áÀžôîc·œ6,Ì/¯‘aã¶¼y„ô˜‘™W­² ¾úº.îÚŨ¼ÒÌl]·!ñõû…îªoëiMHéÅ:/–ÓGdpàe+ -ß"ßÙ¶kÐðÖ‰dM«[ |‰#AEÿKñ¥à§ÒØ9Nw~e÷u­mZTU LÆ@D^ÿÁ¤½˜–ºýë-ÙG²Y®uübF÷Ѫ–^v£rFy‹rž¡T—†ë "%¤ä/Àª'{DÁ0óAKÞôÛ·|᫤ý´ï>@'„Ðð¼i× ¿<;1$ÚâÉaE5uƒ&?àߟµ¤k•ºè‡GìY‚1.DIŠçËÏÓä´$ô¿þ¤„ÓÆ/ wc-íç#j'òÖâEôn…¹L¥f¾¬QÔ”ãY/Õä,x~ȯÑ{ImÜö7G9¸“#›Éw6€_p¡7̼߰¶Y·Îö–g¡|´ ú"|à¦P‰Æ®´dí7“g«Máõ¡ 6Rˆ—"GŽO±µ™}v~Ùš·`&çGR¯§Î ñDøÌðÎò¶†±ÞNB«I¼Nagœ!m²@i-Œ”©5ùAV(™²õ†„Ç%È;¢RŽ&6bv:Î:—Xåk±Ûþ©Ýkâ²ýJ‚[jù÷Ù“W?-fSDvý½MÞÕ!ƒñn÷lœ¹Ö Á”Ò¹d]vâýuÞ©åjv<=ɪG6ôZG°5¥'Šñ±Êçã–$0O¢9›VðS+ gÄ-Þiê°{ÎrBxKÔub )˜N٫ΫU‡È.£¸¹DFucþPI^?Ȇ@¹[Õi®±o@‚h퇌–É\`f£!R÷_óñp÷UײãŠ0êFÛ“|K…ŒIó©ó${¾AIäüüeÓ•^ ­|&…êÕ-A.ß@¾qŒ ˜ð@ ¤b›o‡›§D}o8"¿ªÂ b…^ŸÆ»ŽÈ˧­å-zOGõ‚ç^Ó>M‡áûh?G4äñeëæ2¾§Ñâáêä°Iû™ f Fkò ÚÛd:ð'~x6Òƫ֧W׫ ®PXYQqÒa»ZD£ÆRD3Ñ£ö]]f· í&Ë_z´ß’ŸY´‹hq0ôR}ß,ÕIÔÝ/Ù.¢ià,n)ôÀFÝê­³QüŽ/†Þ;.æzVyEb·ñšÓ»0‘+[ð’Û$ûé’Üà„ +ô–³(U]?•SºÑŠ;Õ™Iøn²ÁÍÚÁÛ·Š2Œà†#!ú(è'Íç¨g$ …1ʰÿrU;¿Ä¡Ûq{8´gÔJ(±h› -ÅT¥ÅvÖ–/ÆMô£¬Vš’V}_r‰*Q²qø·‘ù“+Ð)6Ñâ¹OØo•ð-e<–¨Xè+¾l[òõx¬kÂÍò~¡œ¬üq6ÿfù„uÂOc òR‡½MÆBCzû>JÝ8¯ÒHúi…Žnì[X¦`Ãæd†#CµÀþ¶/»C À,~]Å|3ÙØLñÞÿõá‘â‚rCgð¥-’0ºô¾vK¢êªÇø%µ i»¾ÈV…5ñìµ ßB×ÅþÌ·3׊fñ ^,y D&ú”ct=aúãgzШ±õ¡Le£­ª)ìÇ·DÏœl~Þ˜ô믿0 DP0ÜŸë—íºµžß2ÀFCçÂ×Õ Twx1W5u*X«6$ªj.5žäݲî´õe‰Ý1!"`žŽòj–ÄÄ;Ì*-iȶ´ŒW81OÄ;ã k¹Ä¾äRÎi/¦|=×Vøú…åû³ÓÑ·ïøràŸ_Œv‡‹[Ê;Ò稌$›=…BŠOßÚ͆y¦+)zjûpQONˆˆ¯QhFUKlÐâÓÞ÷ed@Ë0!ô:³…HíùÍçûu› ÌupñJpD:žoÏ~a¹S~øQ¹Qa…AŸ à‹ø+•·½ Æ™øÖõvyáqr½6‹§¦-æJÉùŸZÕט4/;‡Ÿø\ÓZŸYDв~hpgÓw‹•?Ï–çî×>]“j˜å7Þ# >s"þ"XQ9”?3“ÅTú©º›ŒûηÔ|.÷sÚå¼ÉùGìf·Þo'e¤á_ŒŒ‰ Ë; ì²XÛ®{@Ó_j>Dyrb—…‰cˆ§Õ`W7Жúç %fQШe[pIfjl*^•¡¦%¢\ýú5o¾®ƒ¶ ¾¿zõ#ß~’ª0Lœ‚3'enüÈcgÞЀ! +ZÑ‚ä)ÏýuÑõ¹¿îóÂÅýDß%/UéÇ©?гßPÉ îªñ5™;`véü5àà[GÕ Çšº«›O ÍþƒŽCcZ– ÚÃkÚ͹ÕÉPÛýÏ´w‘‹Uѯh ˜ú¨' Q”±iûÞ[JD7Ù{R˜¿OÚ&>UíÌâOì9he&Û•íë‰D£Ö±“øB©‹eÈ9¸½Õú€ÿ&¦NýKÀ­z;“Gª«®¥õ@ùX)])DUf œ¨ÙÈø±áZ(Ff4fC«¢±Eïñpr€IH •î'Óv‰"Óo…"Ý'Î5äôö?ÆÅw‚ç¤è»xé­zQ=öÛÉÁxB\þ"ã×\ùóú`Zß"Äù°é_ m8¶½•HÌnÂ$Ǩ;.^±8[ùöžœï®_\W¦½k´và,ÏûÄQTcîsrŠJ»Ë4–sf‘çó²VèÕ”K‡ a>¶ó‘%5;R̦¹ vúÙ•Þ°‡"n·-2Ï÷@™š3 Nj <“TBéGÓ8øBs“ðK †,$¿ÓµšÔ ܸH¼·Óô†¹8WKuš™‹öÁß}re’‹’°£ 5úNúp_e,#M%³s³Æºø¤"µÛ:$ ?—>àÄ.ÊÖ©¡—-“´˜’[‰þ% ý–ÐMå•“[r’¡’î™có(kÎwòc¤©¹ÈŒ ¶æˆM-o#%já_ºø mcM¡„›ELª õ:? ÷½ê#–v_p~­68¢:­ñ‰ÉБ„Œ8­ï˜½üàîl¹Ç'‚Ê”¹/ùjÏPŽO¿ƒ{þ² °ˆªý™òkØ/{¦,m֟Ç{LìÈ,É Mq—8´Õ{eôÕ“ÄïE€U>3!¿1Œ­z˜k»€ÕóúmM¶#= xÉ¢&‘?(PAßHò;SÀ¨x„M/Eå3SËYêÿÇZáŠIÖž Ç-®¨Ms_òM'“#Uü4x½K¨“AÍÁÜ|–c§³L½¤P˜m|t­r%å[àŠþ(…È©½¥ýwÒ“^øy=\äZ28ÖÄòù4—z3‹H×½®Ü3äÍ\Õbsé’ˋݬ‰<4ÅfÊâY&#ëг7RQ>·Ù¾Äî!eüH£-#Îf8hýô>”ÛõË ñO¼aªùèc{¸µàzõ&W¢æ›Ô…¡k`ZÃd­œ5ïCè¶]E´|ZÄÊù³’¬Ï’?pÕnX;u¡éŠ€ƒ?ýß¡§9·ÙùnlŸ½:G¢;[‘¼c?\ì³ KßFŒ"¼ïÅU )òY…÷{&zÄçúd“öÅTŽì+E˜;ý‡ÌÎTE¡G |øä¹‚€¦4ëgµÀB{™PÌÅÐF·ü)""‘š žR* ¡Š&Úó¨§ç{S6¹|ñí4…é é…Š„9C·ó°Š¥PÙH.KÛ¡¸ÆÃ•”È(+5_<{ŸfGœÕ8\³_C[¦Íä”fopÖsƒ§?¶vSdúá4ÿˆ¤ëá¢Æõd^=ZkQöÉšÆÂÆÂ]ú|¯j\E¾§ƒ&>‚Ž Õü«™Âö+‚™xÁÊŸò˜d:áGÖÀ~nHJ£WhÁ¶Kõ ô–a×Tˆ2åZ6Ñ+9K«ˆuQóƒ GÂø-‚x¼?± !â­§žDô',‘hšÉW‡`1·ÍÇ %1•ÄÑŒyèe±¸¨V­A×w„ k+6­fÑd²?ïÜ^{pú“฽0ñ7Ò1.JÌl¸~çÐú“´=wë¬pкªŒ/$• âL¶’p8]ãª"F?ŸØÎybiÂ#6)ÀàRé’¯¾D55:Únè3œK—§fX¥xÙy2U?áÏÒ‡±»ó@ò_õ_a"Ê ä£LfüCyáœl’ÚåϪ=N1mR™ßH“ƒô߃šÂ?/¸â³Æë EÓOe`Í"*pÎÆ_` 3‡ÞR$šÙÓÁ8‡éø"=ئ/w£žøâN½-³/Síð1¯ÍH Mašêb]U;¹…Nš&ZœŒ*„Á|¿*®§Š·Ñøè!à Œš±¯^mšÁ:¿+Ëç0\‡êa>Ü â r‡7Û\ä™—XÓ|Uad“Ù;öœ¡i‡‰Ë†¾œêôF%ïdr (ýõ!ÎK»?Œ6òèå#Þ§[*¹@/jU¯‹vÕuk5ßuÑ•‰ÜoðÕ•…÷¢„Í3Ê×Èf?ÆÇÏÑ s㨯ŽÏ`1È\]âÜ„Ø1ü=kɵ<ºÜÙþÚ¶»m†Î­2mJª&f¼;aÓ[6wPû–Gâ_ÔÍ›0m}3kr¾ÒP7€š \5hzCi¯|z«H¨–ÁÆŒ¾âl¿DF¡¶® ’áY“?×Fk×UE à MÂà8ãÃè›" ‡És¤p,wK©Sv^w[«*©Ú˜q›ÕNÍåkæ.öº B xGýê§„ ÛJâ=žƒÆg{%Ü™5¤«þ‰„’™&¶<å£ÍXžž’[ˆÎQ¢kÖ&¬‰*+n‘ž¦¼üçJ”ýT­ü®\ïÅb­O*¥«ÝÈó¯r6dÀVJ¤á·“q¸“ä)C¤ ±·”ý’2åKáÕ\÷Ï3B47F7˜fï]–‹w繯¥Ô™t,W[Äõ9õ3Ggƒ~$Ú‡‹¢˜<Ã…ÀG‰F9ñsû§$a0ÔâP ž`HâøÂËéNN|S-Y­¦]à¢dlp²Š”G>ˆÈp¿f6K¶)„ m”_éÙ¼^â'B!tŠ(¶]ÿ®¿•¥NƒsìJÆ|v LC‰kž¨™žì’ZªûÑöF^¦orÞ&M¬O"G=‡éVßåÍhöãq߯b0ÒæM™—ª º¢^ â"üÜ(¿=ç¥Ï°<öÃH£ìKv¤ÄôgìAžÿ'0ÏîîªjJF]…8—à…¢BŸä°7 VÜnÎT²!lgðzß„fwÐŽƒ41Üòðb±)`7ù9¸Åo©.”z=˜hÁ«$Âû/V’ñâ5«¹±—WßÙ¨ulÏÆ[ÝÍJy ÇÁûzÍyâ*W¿ëJ+¡XŠx êeS7 ¦O^NKHõ^',ú{¶qã[¦¾#NÝQGÞàç¾ mB§‡›:hYòU,ðNÓ<ë6̇Û‚» ,úÿ#|޵ؽq£r,‘=w3ãÿHwÒ¦×Y_98/¹¿÷Û|ÏàwëʃÆ:Wh!Šq8MnKù¨pAšd7óŒÎ¨­c~¡ôÂ>›×æóûÝ:®îïˆbà- n5rôP˜°¢‡´îE¬=,p‚Â\#,«õØ2 ÇÉÀA&|”ÿ`ûH+‹Î¹ú‚}(0žŒ×7pþ·|€å´Q¥¸:bÃEaö³y½ ×Aæ&á° Kzˆ[^Ÿ˜€ßT°ëë²ÛÒŸKª™°MÀ®‚­vLÊÊP˜Â¾}»— -IÇÄÙ æË·€z‘Î%ϵ£=¯W̘ÖI³éº÷?ô2 4ôÒd0vuH4wQ£µáÄöŽƒwOÃýýbAAÞáý ß]^o õ¡¨¦·Éó k½P-q›ï&®+Í»+n(ìGØœ4T”·êÖ²e¨e¼†E{ÐxHø/ÓÜ&RybuÛNÒù=¦Ð€Z‰!Ä1{_~ÍìÖ|– _s›=·Y #¾|øy©@¥jQ¤Ž]#Ù£ ã5tñÏ`°äÍ™™™ó½ ¦Wìñw±c×þt!Ńž†YUã{ø#Úš`„“š~ë ˜ÂŒödŸ2¡ì]³Ûsi“ Umqíµ‚¤ÛT3´d…jΙÒñäcÝd`zC9?UœÅë+Èq ÆŽñù]µÍ¬ìXÑ"ý ”æ§ŸöÌih‹F°Ëì šÊ¤øƒ:yg¸M5rtô#n™U;»°™»RS®Ý–vægHÌíýAºä{®sÔ0OÚjîÙ*ÞbÍ´d¹¨À3ƒB¨>mq&‰Fví¿‰Ç¦voúe® ÒI·ôý-Tû‹o–ùvÿ¢_PÁ>ªá¯lH€ì[$]ä½Ûê[‰á{ªR¿Øˆ”÷±ª•l«&Ñè™ ²u#ö5*G/ÀóLH~ß]÷ÕºÏO'Œü^Ó`ÿÈ“¤ØÔŒ!d¥±ZÑÌ‚¤ •Óª›Ót-çqf'ñ!GÅÈÕã™U¬+ ùš5.-LWÏÛñˆ¾0‚O~ÖDÈ;¹ 0ʘԮO»œ ~×ç•'òOh =¡ãJ|Dxt* ^åf3èqïœ81wÒ¯+ä™ñF&_·KŸýb™þ‹8'àD¹iI… ò €\› ŒG÷äý¢nÄä ©':6‚ ‹×ÔW~\úŠYyÈÒ—Q¡Úá~ŸÞí§/äž #¾j;yÕSÔ’,Þ+eAöeMþƒ<ý‡×ušç—zÍÀs5RW>—RÙ¼;¾`™Ã„cÁ¬®<ûµ½xÒEÐfÑs·›(]”Á⛓𛾡‹YkÉšFÙ4C>qÙÀ†}«Þ%uÊ;Œ3’•á~½ H¼c=iäœ¢Þøxq„8rßæ¶ÝÕ áÝ 1Ko<Ä ¦]`ɨÑݵ/Ê">’;ýmé`ßÎE ÓáÌö<ÓÙ9–Ýûˆ´;|ªZ‹$Ö‹Pþðo¬Ýïh2\®žüÒd¡×"EtÛÑî9H±¦ÎÇ 9ê<¼J2¶O¬»TRU»nÏ™mmꑼ½<Í!v™ypd³~‡{a¥!ò¯û¶ÅºjÅÒ»Éìßhë' ™ŒB7™¤µe#¤6YµfõpØ+ 1/º–esŽd†ªO—¾ð<[wBTJÕóå ~Ê•ÑþyLnñ+Ð%+•—ɹ—ÅAµ¢Œà³Òp»æ^hÂ_òuË3ˆúøÌHЧ¬ÐÛãVåµ@UH~Id½öš`͈©ÉœáÐ_$æ¢Ëc15(Á\‡avëî)殩0²‡5:¹Ë  )0Æ3ô,N/þvóÁq–¾ƒ¶&Qk i9êJ!';l²÷¾ÈÃòXªeò=Á^†s¾@äv÷UÆÑÁ&Lv/輤áõ™T[Hãñx+¡Y÷Ê™%K¹U2HšڬÜ_a‰Ýß„¾Y¢£á?áÇ)Þ™}ŸIÚAÄ'lüWq}´Ï>RºÃíu¥ ¤Bf6—׈q‹¦ålˆåi;˦E°Þ9`Iëd¿¬°Hâ‘ýÿ§Üg↮‚âñ‘¥m´èuÒŒíÈžu£×I Ï,8%À@·½~mÁW•±hú ΢"òP¡éòŽëdSTGB:{‰§XÑ’ÚÒIªÄìò,³žª*‹ ]vwÿ&Z†‹|ÇP àA$î*޽åç^LÙäÊÍã‹ ¥‹!Ųí¿bò9Äù#|ûZ͈&š˜¾úòAØ“u¬iw¯S©»ÐžHìy…ôÇ(ï¨ÙJÔô"ÿVÿLë"Ñ5,Áô<OËÇŠŽS¾!öÍùÙß@}ä´‡GÙJÇR©P1ïh¢êdãJ:œ×3{ùPæv ~ЉC¨KD$ãÝÜ¢•žL„¾µK÷ÑaÈí”wÆ\«;y1Ms4prê@¶´A ?:Ð^˜õgPŒ²6}9Êik÷Ij[ûÅ}Ñ}ç=?oÅ,å>ú6çæÍÝd(ªÄÕ õú½#LÛHÆ#ºó «dúgcÖ:w“ÕÕÞm!\l!Zó‚¿Ïå;Ÿð#ÞË””Àö¬¡Þsí¥­’#÷' Ð,xáofji\Œ9Åg±ä4œÔ‚=ïö¼¹?bÍ´ô¥LìZÆ“œQ¿@5{Åj÷c˜µ¦y@û+éx¿èÞ„" Ôq§Oß?B¯s–”’õ‘ÙܵлOíÙhÈ' TÑB`åÁY}§{yÛØßë¦/4ã¾U6a±#ªéa;%7ù³ÕÛ%z_ŒåV{ÌòQ¯ô%ê¬Ò’ð“~öðœ í°æóÝ1Ó †C¦£µp²ð=u%¹"¬h@‹¨ òl99ad0Æá¸•3³M›ÌáA¥oQ¸<­_”›ð3#ZÏÝW¦­wW­ – <¿•Iå¸VVDùhMÐÈŠÖ’uR>M‹OYG¹ì´ÙQZçI{æ•£Ï\+¯ÕòÁnŠŠJ%‘)‡™#ö“ÇA§Å½õw±ƒ\è]Ùr)‡Pz{ÆVwžíŽƒ…x§áPP‚ÏÓ]ƒ¦v o¾²¤d|oÉùzŽôvÔ*¯)™‘‰Í¹·.>< ]çbZ¤{+v»Â4[¬Œ~D¯æÐa׿=õ† úµR•¬ß‚%Ë›ü¾žÝÞ¬NÁC{Ôknl6F¾8;f*ÍÕµæ­* ¡ ‚RŠRW&uÀèUtþ«kd;aü\ÿþsI â›AQ¹oÓ6ÖåDïnþâþ_![cAñSHQ|)Ï^\¦›èä;`»»àl(¬·Â“R¯eñŽiëþ8¶T§ì¾ŽB΀ñÕB懻Ýÿ²~ûˆŸèꚾݖƒéÌ¡F‰Ï^zéòîP3Ì¥ñyBñ#“Mä¶ ¯:Á“°Ìâšé ~¹)‘ÿ’ w7žo#%I—Ú¢.nÕPU"3o™`¼—u\êWÔ2,‰ ˜;‚Êý2Î-<#@aÛ6nßÞ“  ìÏïX>G¹Òøƒ²ŸwÂ)ϵŽ+÷„‹*2å³f¨ÑÖÄgSä ‹wS}zü y;œ»–Ø”åœÉ8f¤>µµ9Ä‘/Ã7Í7€öá·nÄÕ/±f–ÁÃóT ÿÖ/ó d•+q¬#Vñð9çe(xvÔI‡lÎÚ¡SÊg@Š–¸î°åÚø †ËÁhu¤ù“-þ8"T3Bbj×p¶êmb?ÿØîŸ½-0zñ(CÃEéϼãûþÔrŒª»~oï Ð1 ·MZa¬òGÜti! »C%óÖü缫=†OÌIöä‘€+Ú¬ÞõA’åÞw çÒÚXÍ9÷8oàoG6”çè9»ý­¿ã #¼iÎÈ<”B5½ ÿ9}5ªËã¸ð­M¯f ó™V’ ãœêKè!é%B?ž4¹ÿr$¬m±á íG® ÃäÓV¶ò·»¿&^^ÆrwF!Ç“nåù°Õ7Yç …ëµ¼¬qóDòÄ¢õ,~Dg´ɬyHàãÒý²Ãñ·:Obê ÎŽwžË¨ ¢Ruµ$*1 { £6T»h«ß¾lT¨öòLüÙÇI[”|!¸.Ú¸ÿz-û¸héñˆÿÇG=%Œu³˜ûx1†Tœþô³ªÅÒ5•6fŽ^ÝŠc+f)%æ™wÃ^â ä³¹Í>‚îLE?5Ý"oá¶ b@7J:9±VÜÕ1\4¼.¦79½ÐXÓ‘xú°âÒ—t´óy'4® èäÔB7÷ýÉ饨ÅåÎ\lëÑy>R¯„¥q5O“5NaÏ(k!³WØÕ„6-² y òW(¨‘‡×ù”9(·€“fÿ-ƒÚ‹Ù,^“få‰eÀnc’öV£yI™¡ùW~ÐC?f²Ü­[`BTÞ6îXµ‰Ç$¿Ëî)J„zOúºNSE ´YyX½ë1‡|ŸñR½,ÀJBM z†›m·£9À,B–ǦµÖ­Ú©·ío[”‡ô—ͱ•-f|­…>~âÇý(õÄ¥üU»ÀG}Ö£õ{ °°jèÄԣšà_Òm+¡ð—Íì2ôΟ,iæÅ=| ®žÍ¢?žÝòGyì¹ÓÜì4/9Óó¡â;w«RU‚!ðAÈ»TÑöÙ]2¼ÉR×xZͽâ;¼ÊuÓñà»Ô°Æjl–z(€˜¶ÖfKŸŽóùlþ‘à`ÒyvxH[ Š‹ÁG{–>&_5õXú*Íqø¸ÅÆTÚ\cxè(Ø4:åBñS „š l f!½h 3ÚmPIãeïÓWSÝa¦Jø«ù¶ ‡\/Y™mjšŒä³ìtÛ¼aÌ’ªºbÚÐÈ­d ÏIô¶#ˆ2¾[PNr~k+»¬ î:—&i`Ó;bGVŠðbD¨ÍAI9º×¨¹ª¡ûõ}XFMu~: øÝØWº1þMßdÖ·`moF0+d:NÏ ±Ò à;“È6h2ˆ¸ÞRgÕ§2ô9ôK¯ñ ½ZŠ"Ú ®ÓÉÝivÄnÙÒí¢dÜÓìÊàBBÌ•÷póSõ8»†gžô.#¿íÙñWñ_b.«…l—Ðê$N\È“¾«R¿v3G®¥ùîz¬EBdé®~jÇ@Œ~ ŸÕ$Ùyz]ê›SPJž£ŠÙ ¦ $@ö0 )Ê"qO±arÈóhÁî> endobj 83 0 obj << /Length1 1604 /Length2 8971 /Length3 0 /Length 10013 /Filter /FlateDecode >> stream xÚ¶PØ-Š NpéàNãÜÝ=8 4Ò4îîÁ]‚÷à– Á%¸%ACpLfîÌÜûÕ{ÕUt¯­gí³ö)è^ªk±IXA-@²PŒ“(RÑääÜì@ :6æúËŒN§ rqC!Bÿ r™ÃžlÒæ°§8( èæàäpò qò . Pð?P!€´¹;Ø  ÂP„B@®ètRP'/°-ì©Í~-™œ‚‚ü¬¿ÓŽ °¥9 b³9>u´4whA-Á ˜×•`|e ƒ9 qpxxx°›;º²C]lD™X`˜-@ä rqYþ P5wýÉŒ m výÓ®µ†y˜»€O°%âú”á±¹žš´”jN ÈŸÁʰþ𠀓óïreÿQ ùlni ut2‡x!6k° &«Ìó„±Ì!Vš;¸BŸòÍÝÍÁæO¿On•И?ü‹ž«¥ Ø æÊî vøƒ"Çež¦,±’‚::‚ 0Wô?Î' vY>Ý‹ãÏ›µ‡@= >k0ÄÊúVnN:°³HAú¯'ú?6 À ùy gÈÓÒ–ãòÚ^N ßNÎ?ÌO ü|œ Në' ?°5èé ÝÇÕÜ€¹¸ü|þíøo„ÎÉ °[ 0ýŸêOfõŸøéò]Àž#à“ö8À?>ÿ2~’—âàõOøïûå0Ô–”•Pgù“ñß>II¨'À‡›ÀÆÅ òðøy~ÿ]åoþÿáþÛªnþëlÀ *@¬¡Á?)<Íî?4ÜÿRã_ÃøïªÐ')ƒŒÿ(ÿ5hùô‡óÿYÿ¿SþÿdÿG•ÿ›òÿ÷@²n¿ÝŒ¿ýÿ·¹#ØÁ므'%»Áž¶Bú´ÿ Õý¹É* +°›ãÿz`æOÛ!±qø{Œ`WY°'ÈJ ³´ýSBÿ¹…§ò`Hê þã­°qÿã{Ú7Kû§÷Äõé®~»@Oëôß-e –P«?öŽ‹—`îâbî…|’//À‡óiA­@ž¿• à`‡@aO)€'z~k¨ ú7Ê'àùÃôñó8ÿA|å?€Cåo$ø„ÌÿA‹ÐSM˿瓖9@ÿÀ§ÖÖà¹yÿ‚œ@ä_ð)Üå_ðéH°Á§¾îÿ@®§\ÏÁ§Æ^¿áÌÒÍÅåé)ù-ê§yþÿ~·@ O%úâÔR8Ô®.ôãU™ÛθÈ4ÝŽ^›Ï¢K‡Û Ê;¦ê¬à5— ‰wŸ{q–·dÏÅ—¨î}ö[P"ÚÞj´ßúÞ™&jNî´£/|!œ(Ú—¨ @#gÓßõ½wöÕ ²Gl…ïR¤ËsvÀR/À¿òè—ó¬(ÿ:>·£±[ͧ„qW>ŧû:¨d†.ß"{–˜ÆFÊŒ÷Ó{æüb/wâ‘J1‘Ýï Ž»ØÇp+þzÖ{¥R›Ëµ›„–Ęñot’ÞGò{Š"ѼOéûœö®‚{Ålãƒ(ôÅ—Œ&;}>vãJ=(ÒëÑôž ðŽ‘ÝË@?dÔŸÞ²¥Pcvõ ä<{DÚ5ȡɟqÙ-p /º|¯fÝ'K2Á˜£ÀÎÕÖèø.©èŒBº†9åoüXÝ<µŠz:ÚÈ D¹ô 4Jà`í­©O‹½“[*ÈÃyöU=¿{%³g7UÔ,Æõ×Çv¼8a,ÇàWW±s²Ú*›·ºÅ¥*ò4Ûó“^†rÉ–'±/µkô7R/ýlì³åñˆ0 Ï}ªî9$|"¯D¯Â5ï Rzé·ôf÷Îy‚¾_0{nÚN}\ã‰h¤PðHqÂNz•#-0÷Ó€[—è»{ÆÐä‡{Jö»°;è—•H:cÙ¾&Ö»µ½¡6½ÎØVíúY*‹!T³Uöamkd2¾\F«rMA8ñWLåsw…¬¡äÝZ±o/XrmÌÇ—4¨ß¾úé(˜Í@>½QMZÙk*‡‚?àY-¦xÍ.csðkªáè[æp”ºë7aDG›ÚêYƒGKž2Z éÉgÝ~´6oÄ­[U! X™›æï‰­¬½Y\К 8º&=ã´ ›~µŸòt>p |¼ÚµùFÙ¡~@uˆiñú-â]fLU…¸2ëpšøzã¾øm¢O´Ü§Ëáèkl÷E6ÑϘ‚xCwxþâ-(1–8éÆcÆŠ¤kÄ#ñ "h<èy' àŸó”ò˜%ç\„ª=æç2VÖÇ1Ñ®ÄÙ³Ò«¨ø8l>^&ï4Ú’·ɱ©=ÞÈaɬ?êøžîK*Ôm²üâ\ÖÛTÁ#oxÁ:Püvw=0 êŽîUj‚^µl‡q¸BÍÄÙÙ5îd̸«Çˉdyb<5fA•á)j„Ú|wIüØó¢LÖ%)c?«É„(É¥zRðC$—;y_ÞN89æF.¡ªå÷b;, ¬€Ø¤¾ÏG Õœn¢ÒT©Æt‘[ÕüY¡´p–ñ–I\$‘¨}A¼N½¯ÈYQ>Ô4ahÅÍÛûø%ÊB ÖfŽPn@GðèÁ3r \®÷ÂêwÒÍÜ™'â¾0ù°g¤Sä_`Æö=:â99üÖÜN¯U¤P±&d¨Œ탱ËkÙ Ç÷¥ä9ÅÉdÕD10NµŒk›¦€)#KK‚šsøÏ7Mç{bgå$:.ް° ‹?·¿+õ(Ñ3Ðî] Ù <‚½üå;3nû‰…™uò~A[ßÖ‹·"À’›®×6ãl•ߎUÍs:¢ù|9MÛ-²e©S©OCã龂N1\‚“?Q)f`ÒÜ»ž²ûÁ©6hû…Óò™Ê^{ò-¤|ypö@/"Âê£3aÃ3¶™ØÊ%¢Ml7¯Ð¡ÌÊ€‘·Ã¬”a±¥ 5GÕ½²öÂÏ/5)xç–ä+¿¿ö}sEºF¹Ü£î Üa. ÑË*H‡k§W`Ô/…Ê}9]Öž 9Nݶ¿BæŸï›aËÿÐøÐ¨f)ÉT‹¨3)e-#À^© ôYÝ’›y–ü­_²ö2z,L_“ĉƶ}k¯kSÉt-â¼KåìbÑWG:z5½b6†yìy`ñgÏ”º§cgN åÞ‹ ýam’üš¡’nÏ=®ô¹‚.ýõ†ucjm!&—¶Òà½_ =] ,*máR£ï…œ”³[ JÅøœ'5·H«Áíºçˆ#3`ÍãÆÁÿ‘ÑmÄXÁG2ä×%Íe9XKNã{•‰Š¼¼5È6Þˆüo‚lää«"'¤ƒâ§o—ÂØÙòå_­“ Ž‘`G ´K+®.Z,ÔÈÍx©Ñ·!‡}0ÜYǼ›—ØÃôBi!}Õ5‘u\Ž)< ¥ º¹¹BŽ-ɰe¿8¾Ý‘~Ï,%^á× œä¶üÕþ¸"P7Ò°ƒjOÝ{e#;—×nI€ïáÝÁÖòøî5b!sâ:œ.1œf×&÷mÞ¹!Ã7¤8mܽðG%b•ú,+t‹ÑôŽÁZø··Q®Úw¶ …딎aÆV+½¯><ç!Àïúr^~ž#òPØz‘ãÖª?.¢ =1+Aù¶šýA÷z–´ØŒŸCԻɂ1çžÁî› 2k-xúçvr«·“}iz”«ˆI\¯ªAU§b+ŒNx8út))Œ("ÃTÎ̤žºhTh#âÐÀ<§µwz=äñ1Ë ‰0ÉACoÆ‹ùÄÈ„ãßrf*#ú›(+Þ¾î€úKÙ)Ù®ø§·eM½Yw$r–U?3S|³X#T„ËrÀ(QˆuÿÜ_bÐ=Žc`B%µNllÂF¢Ö£*üiwZ‚MÖYZxE5k¹}PÔx­OÑÁÉñêªÃ³i[ÿQ*#·Eå(B_y‹º[´,m%‘C<ú© EŃ×Ô`2ع(¹ƒêÚJ´ÚfgѦ9Ù>a–—ZA=îgLü† 7)4Ú³¨[‹a‘Ë+÷˜àç<}L?d‰köÑîYà/­¹ÃƺñcÅZ©™¾•_ ~ÊÝ QZFU7¶Jkßß–ò0*÷S%ïUŤâç²—TRñsRít'"Û¦ê@ ·¬žÃ=ªü}_uÓ<`¯´$¿ › úä²¢Š]kµG’ˆljkL§šˆ}žxu­ ô3ZáÏœÎ'¨ÞxÝÚà*éwêÁ=©·¡³Á%‡40òIᕚó¹AȻŪe³0Œ+a¬É Ò¬tþb>S.="z¥Zß/ó líc‹åG¢pYšµP˜.ÚOðK;§g,ÛÍ]ìHm¯js:I5öÑ€½g‘š"} _xËZu¸¶K/Ýc9®ôS£Ã¤+¸k¼MÇc+0iüÆÞÍôñ­Èkõ¬¢Êäæ/¦ƒF"´&æç‘bF6]t_Þ~¡ŽúXòí0þµÊ[?m\èֵIJãXy'UdÀ ÝÎðQ„eýÃè6³¨ Ô&GÔÍ/ IpYÐv£LP# /çé ÿŠTkBj0ÁÏ䄢ݻfVP6æË«ã~7ŒÝÄ'®¥ÅœPÓ+ ŠqHÿpH±á*àÐ؉ðKr–¥ø¹™ @¯;ÇÛ~›.#!vÿª¡.Œ|¸L”zý€ážӃ€3cMª[8KŠÜ²ÎY‚Ž\°H·A™«—è‰çtB·š¥Ï ŽbPKþP-•¾mîíQÍÖ ³_¯Ø ×ÏE th»0ðË^/YìT)¿# qgÛZ2©VO±‘¡ 5§Š‰5è>s¨3¢Î“¦íÈ/E.‡=;`lÔ˜*ÆCOšâm _Õ®8í¶ž¸n9˰•ŽThG’D.¸4âJ¼´ÃS£}™ Åo¬îFröa}XÉq(Äðª%”þâÙ&ð’¶½»Àšk*fçÅ’¡…—ðK œ—ÂÞ2¶fKöà /NÌeˆéÅì\ç&×;ÑÑûŸKx|õÙ™Û祸>£ÁÀ°óölcúz’”dÝPÿÊñ©n«eUùäæ@4wÌ4wQƉ*º|<òäž^£®é7l;N¹¦\eŒ“è‰Oe²Ë÷ªb{CŸ,Å(L›ŒfÝ1¯-=´…ǼíÆô#›À6Ìr„TG!/š¿CbÚ#Ám¦ÙWé4ˆ6Q! á“qÚ¸Ú’ã«Ú››—+ÓgÌ2)«öE&•¶6Z$ñN“ª È‚*ýÓ»GÅVhsý|&„; ïú5¥^‚×4Yð“ߣÉê*e”@¦u%yR•€¾\¶jF¸ÉåÕx\h¶a\ŠÍ¿ëL©¯ñSêõ “ì!“Ð3ÊÛ”ñÅhÏšÐwtiŸ<ìÇ(¾Õa¿([ÃK.‰H¶DúPÕ„|†ˆ*Ñ Ú?›Š®ù¢ $Ãÿ“`GB¸”V»JwmÛù7ÁÐ%¬ïÏž)ʤ|š|E*§¦ÃcgUõ±ÞJà³4ùÎkõ pOs÷¦PªzSê'Õ|þÔK.›Šò*Í:ÞZçÒ6ªþóØãP±Ù™ù™ èÔåæªPë²c=ÚBZØ·½˜/LÅrz,ÝõYÑÆüí¢À«yTÅC¯ÞGÎá³QŒŸèø¦Ÿ‰JV…àjÉ„x¬‹|}Fk÷¸ªsÄôzÜ–~Ö—ï‡lg–oLAˆ¥ï©Ý„>Ú~ép׃ÿh( ¾ fTaƒ÷Èò‹åœ>3oð>ÄM\éÏ»÷Nù ­oÏ5÷ífŠ—ÈÚÙ§Ž„üÙ;w÷2jˆÈmQŸm6àˆ`[Çþ8ÕŸäÚüÀá,Ødß°^w"c´ò¨eÓ° ¯n 4g8Ýìy®…I³š—näˆU¾V¶œäù@5äY#7´!^îy*\ö>#àÄWW‚º m_þ”•æl6ZYsã}Iº]"ûJãqè͆S_f‚çÚ¦g…Vœ£ö¸Ýaé}ë,Žmc#4¹_Ô«¹ÁØð Œ¨ŒËºŽÓTö{Ì>DB¥­v!héNÃ7ìy€ rêç»]‰øÜfñ‘ E÷sVÀtwý­é¬gk¼–7Çà6­Ç@ªL\y4Á–ƒÜàþUAzªÿ¦muÌ·¤º.ÝJ!F³::Âçåê|œh[­…Ñ$îßÖ‡›y’Q¨:¨Ý”Q ¶>A œó | …³ã|)êO¢[W¹¢Ù)xd[cZ§å¼ ¥„ã?3½ TÙºÜË´iûš±T³3;׊£qÛm2:e5 ØTMŒ‹´¯Æ$òì¢u7rduž×šÉ*4…tþ›4?bPöÕ~J–õ’¶Åg˜ ua˜­)%—/ Ç[üÑ!”Ú”¥ƒIk ´ÎŸdžN!ß²æ0Y›O3œ“ÇÖ tBFcbÚš™??þØÚ£Aw\%¡<_¶M|fq—Þe¯µÏž¹í­÷È!’ÒnbîâÝTd†•ByÏ—WÁ—H>‘:î_ë&4íMd!¯¹Ôl¼Gq$ú˜»ŽSwšÄ=ªª´ø2í—› i— OPp½ß=t«¬À+#Ú@FôæÔ¥WTÝײ‹`^ð’BĪð âö©’O¯q•ü"å/œ²„z^V_BÐÛ¼_ûål%¨m7ü’ž›mÕcêåiz%˜@ò}e@~< \…$I§ŒÕ’ ¸É’; ýb0jíŒ$?ÃÿÅzuú¯WAà±Ï;žÒf ÎÖ¥N)²å_[®ËiãÄý¾ôŠIR¾4»;a:,ì´~ Rã€:¾w:Ŷ‹j¨ƒ}ýÈ)žv\:ªjB0åŽ ’ʬÇòÚ‰£Ô¢ÁšlF Ô2Š-ôïÉÛMèÆ Pæ3Öýº)p béÕµºcãÏhIîÉ6ÈBà¼0®‹Ìl¾2sÜ(u!3wJß¾*‘Á¨× «‚Hß´åIÒêƼñß{Fƒ®b¯*qt#K,À~µKÏi)N“Iô2zYR¹öìapsјè~>Bhø™œä¦AÚ9ysùN¥¿|Fã@Ñg<ドvætãó>;ë__@«´ç% œGÊ4c¸‚æL‡d‰ò:¶‹é¨±œì©áoÁžù·Dò¤¬Ïªz‰£™Šš÷r4ô‚J»$8êÍo¹f¤“œÌAbÌÇÝîy_™ÌÔa'¼:?W%O Ãk 8û°sgoܰ}}+Vë®o&l­ÎÄWË/// Á3ÚR¸ô‘y©eB±á%‚¡‰ûM>é[1‘µõêwSy©cî]dÜw"inÉ—lOò³úµ»´qõ›ÚÓ;(£üSox$#Oœ?•±¤yÙZ“|Zb>ôÏ©v~©ñâæ,¬ÞÞív‚q®¸â5¶Wô Àš~0Ì^vt6ï+Ÿ–ˆŽÙŸÁdɞ͇hÀðRÖ3vs‚Më´ý ömЭð-ÍøBg†?#)¤ÇAef5ÂxQþ m«Ã ³tÍV2Æ`Ž (sã#Ÿ ßXaœ4ñµ4U³“RQêfPTƒNT£A¶eT åðø‹?­ üfÚÝÏ:-LŸ ãöä1<3ÁOMgTÊâd4ì㡨æ{mY–/Kà»òËçéR= ³Ó(Nï’T¨ïµñ‰9&ëÕ¤e‰ÓL.$>†y«H”£"…çî 75{E[ÀZÎb®Xˆ{Ô>uûGlzy,4-2ØÈ—ŽFó”q&è³c‘Stwá¯4K¬_Ê‹º*NtIõ_tQu"ñ}xë–-3ãv®0I¹0·ô‚J)üý8üp<©#¼p$´·Ì‹™t¦< û:Å¡Fø¥Áî1c—Ë«T‡u `˜é<À)ôûßÊw/‘j-‚v­@ØEFè2.ßdmAÅßûk*åé÷d¥¢1ÖSÌjU©6áØ¥ºÓ–/ ÃÑDß™(¡­÷kå(¥ã½B¡T.]†”½ßT§èUéÕ‹ÑptÇùX2­wC\ ËıÓt<ž!·¥ÿ¼«"ûnôÆ ã€vfý1"(ÆÏî¡×ãÇè~ÈL†å'ö(ÇnÄ«»éo±ÑmÝk^{8[·2Ì„÷òd²©¦¼æXìõ&&ò½nµ Œ/[ 0xÖ/ñÊæ)R¤e‘–ÐÇ™œÖ ¼k93µ‚ØýŽGEo—d"j>Γ]ÈEcŽë0dBC÷Eyë»â9 ÌlŸ>”„1eß¾vƒ¿ þ±{åep|5ô‹>W©|æ$ÈE +–§?^ u¢åüÓŠˆI­:÷˜su,ÙÈRžªÈÕµ=…oÇë*k¡޵†…4c–óÊÉ9Ÿ·£Ûh*ï°YGˆHô’§»©iàÔFP/ɲuð /zCä¢'Memø·í›#ÅZàHŒ+Ï@8¥PçÆÕV’îõd,&•;®=ùÊ1ý…¦äïâž³Eq–EHË߬Ž!7®ÄÜí¹{{óçFõ ýæÙ ‘ïü}áwpfQFIP¹è­Ñ)B0wµÉiÛî´Ž‹˜ßä§É-’reGoûD'±`FW¨J®’Ñ^-1í×z#wy¸ìiû«`íba¬°Ú)_:[eáÔÓ@žõ}´ÇŸhäk~ÒdÞóÌPFX‡2 ‰"NJi¥våµÅc+ØËJHOå¿d“o°ÂO]oßàN=œ{ä”1|ƒ#ê9m%Úš?õjÒC©¯B“=¹5ð:6…g­žÙ¿ÿ‚£r‹¿¥ n*âÕ/yü®B”³Áìa³<3¦Î/EúÖ¯°¾ &‡A#ÕÕˆ¸¬âäÚ»ûq`h‚½¼¥ñ4ÞG™’g¤ˆËî·G üÁ椧Mp¹±T—¿ð–g¶ŠƒÒø˜&Í™ÞNÙ†9\: ëliÛè¥ÂÑ,g}cÀ”°{¦±Óf*/ê±á f¨¶>H™Ö:¯çzGn®“a3¥­÷vú*ìN½ÿRÈy»,£@[Žg'iÀæ8XFç‹ <÷ËPĉ:­³/y©ù$Í7ÞŽïª.ãÊŒyPdW&ÃuwìiymbdÉO”8Eñhr&ù¬™v §ò. Ÿ˜)ô®RærXÖ–ž•¢žÒyhŒî­‘ІË̆ñQD®’ÇQ­Ìóá"—Ì/Õ[%p¿¸RöIØSã¹ïilÐxŸ¡)¿€{ÃzS‹õâªÚ# ±Ã:m¨:1z‡³nÃFó"ý>ÑRÃäN¿Þ­Àš(BÍÜå`£ëxֲɖé“Û¯L»Fj’XëWÏ‹(1µ”x!»HÅ®EI¯"¯óà§aöM¨ã:Ç qÂEÎî¢Úü6pa¥µí÷Vßì J>­?†`ÌU>O%J_d£<ìNµÅM{Ì%w;ºJŒ‹æþЀ\´¿ÆW­*̾ƒ%}L£^Ä_.áÛ,6sV \âþ–F,g’æƒÔ|õú­•ú%øÃ~4ÛGÌºŽ™üÆYB™ŒSÅÛ^Šò—>DYÈ¿œºNýÑw‘ïú¥¥(âqiâ½ÄF |&ØD·%’þŸ`5çWEÑYiõ* G²G*s™ªÎä×6ú`QPTyŠ—Ë—¶éÁ+:¶UðBž®j—.Ù¦ÈÕÑ­>u?ü~ÞÞ…ô´¸t_`Ò‡œsá¼Ò¿k¸«øù‹mÞZ[{t™/(Å r¿ÇþŒ6Û‹–¬¢Ò¦ÿc Öç™Ü ƨҡvë7/𧉬ue°äñz«-Çûª¹ö£ÝNmªpx½Ê²Ã ÷Åg¡y&¢zÔ2 €½ZäÁÉÍÁof‚˜–5oaóõíϪQ_–„g<ƒ×GC_‡&­K §²Õ’ÛšéU…YÌ}Èá{$’o£æâ眃ïª2gŸ<Ó”1(ºYÁUÀ':éaÙi% )·÷ž-ú _×TþìƒÆxì=J›Sw‘ð¤¢Ï”&ßÖ‚«qáEY‚Ðîgg»;p¿¾0Ûxw‚/7\!ª5G±·UÞhܳI9¢Ç¥q ½².ô–,Ù:R$p1~LDÄs@×ÅD’þ~’0ˆÔjP@‰P$c´ÿ {¹Å÷øîòõÞ%5\«ÆHÏg¬Z»Tü®‘S‹¤â¼›mŸr®¤¾Î¨yB±<Ô>o¸Ý¶€¹ÞŽY¥!–$Ý{¥½ _ÈVM)«ˆù9ÎoβžÙ4ÒÞ%m²'²ÒËí›zqswPù@xí×Jqy'¿ÞÀ¸ÿÌ×^HŠMºRçvHž¡fŒ'M”©‡ Jn—’ Ât€²ø2m½|à£ÚñZÅÕÔµV<‰S}¸àógpGdCäOQâd™oôö¼bá]¼•U†øäÓ(mp°R}»XØÓ:!±€œ›¨Z+°«z%kLöåÞIî ”Š!E™ã¼?AÀ§5qƒŠáÊI±(âU7² ñä<Úþ5§Ë&n8ÆéQþ<ø@]²ˆÁøb ù46¯k*õ"憭í+9]zžÿ:â’y|óh¹¥õî/ÅN6,wzSxlõ›¤-ö·×»í+Ã]ÊGzµ-xZ·\4Ø«œ”ªˆþÁ-7':ñð×DUý¯…êLöe[JcJß<†9ZJíù„mVË ôŠÝÆ„O|ÏìûnîØßZø²¾0²¤U·Ì‘3g7^œy°ù{ò—%:kïU)ÝQ g5ÆÓDIïÙåz“føÚf¿ )Âr‡rªr­!rëĈؗ¹Ò@ÄÍPëGÕa;¢/<Œö·1Ìh±Ý˜Di¡÷gµÜÇþØkñެ­ôIƒ>[¥©Ë`×8DãXêl•~Ås‰àÊΆ<· õ­«›ÈØ¢cœCL,Ï Ð`jjô{Áö•ùÛ]¦÷ýR-Ý›ƒS+Jl;Æ ¥+E^`-ÁµØÒ7ñêöìç¥Y£€öb}‘«±à`Çý}7æ>0œ»kÎTC÷~…Ém2ͪ®?½²šJp Z¥ÄMºœÅ×ç)×4“ìì³¥×”0ýñŒæí€ÍI_[n”¡¾ˆö¥Õg˜@‹Š×]Ž?–ßùÔ'Ÿ`8ÀÉm†·î¾Z4€›4±ufòádÖö &á)Õý¬ß…S ŽHhÉV<“Wõb}IM­‚‡,ÞÁ~ué’£o¹¾3y8K^ÇÙ 4JtùÈщ‡LÛŠM6¹{¨Æoñõ,ÊÊñœréd{‰£ÀU6¡üÍ6®‚Drr^BÆJ1îY„[ÉH²Þp¸dœNco‡ý‘×éˆ"´fŒ¯_5x~K@uWUdGzU‚û †¤¾ æ¹¾ª ÕéZ)Üo ùÊ2Ÿrq~àÒÐgeíFY(ˆ_XÖ®äªÂŒðw‚Éôör{ŽÑ—>H-¿íà ™ìÍÒ«å’v"€>Î$é]'mYò$¼pê{®‹ØàÅ÷„yã`äù8 Û)µRDáÞÖ2Z 7 ?]ðln 5Á°ë‹4ÌѲ’E»aÊcvMÃP—=Ös2÷ÍO—oHËI<ÎóB æÖ%‰EßÓ«fÖÅ[~ßé¸õ£ µ+É$<è8%šeæ–tºHÇÛåÓ&bÑ[ø)&‹uSçÉ«-“lÇgª<¢tšÏ_>?{4 dtƒ3|@6y`ðàKòð7¡¡ÅÛ¸w|{õŽD"¤ïÏÚõ'üáM”Ký6N6ÏsÂiñå—qýÆ·3‰&¨V¥zŒöfœŸªâ¼€"m„ùub¸-ZÙJy+>|è ¬(L̯‹„¢ñßÖß ×)À¼‰©m)ëYiXî-©×M ’4·%ë ¦Î&íMÆÑVˆ•eörá¤Åqú5á›ß 蘳†wN¿B¥eosÕ^&  í5ï[× ¥$FnÁ˜¸Ó%x†Õ÷¨*DÇi9¨…ŠH#Ôœù¿3ê,àfñŒ@žÿ]Çs* endstream endobj 84 0 obj << /Type /FontDescriptor /FontName /ZTBFAP+CMR17 /Flags 4 /FontBBox [-33 -250 945 749] /Ascent 694 /CapHeight 683 /Descent -195 /ItalicAngle 0 /StemV 53 /XHeight 430 /CharSet (/E/J/L/M/a/b/c/e/ffi/i/n/r/t/v/x/y) /FontFile 83 0 R >> endobj 85 0 obj << /Length1 1395 /Length2 6090 /Length3 0 /Length 7032 /Filter /FlateDecode >> stream xÚVTì»§$F‡42 ¥·‘‚t·¤„Ôlƒ1r4J ’ ’ÒŠ(ÒÒ RJJ()ÒÜéW÷ûß{νgçlïÓÏï}~Ï{ÆÕÈTTÅ í×D£°¢1°PÍÀDKˆÁâ~~3Öþ‡ÀŽñF QrÿÍ®†C±x:‹w3@£€º>@ˆ"-‘‘ƒâ`°ì_ŽhŒPê‹pˆuÑ(¸7€_ í€A¸¸bñUþ:`‚@ˆ¬¬ŒÈïp  ŽAÀ ( ë Gâ+ @S4 Çü+…€¼+ë)ùùù‰A‘ÞbhŒ‹¢ ÐušÀ½á_¸ð\ ! ÿ L À4sExÿ¡6E;cý 8¯ð@Àà(o|€Ê ŽâkMuô·<á¨?œõÿpþy5@ˆäïtFÿJ„@ý†Â`h¤'€@¹pà-M}1¬?VE9ýr„zx£ññP_(ÂêˆwøÝ8¨©b „âñý‰Î†Axb½Å¼¿‚~¥Á_²ÊI DÂQXoÀ¯þÔ8 ë ßcuG¡ýP¸?ÎΔ“ó/N>ž sÂË®£þ§^øGçÇ¥À`°Œ,÷Âýa® _ÉÍ<á¿_j|ÿÁ8O´'ÐŒp†ã8o¨/ˆÅøÀƒqÿÝðo 0,Ðî‚@þÉŽWÃÿñ“Ç üwÀxâA€à_Ÿ¿O¶xn9¡Qÿ¸ÿ.HÓJKÃÈ\ø7à¿Mªªh NT\(*.B ââ@ü!øßYþÆÿößZ#(âÏÞÀÿdÔA9£²@ÀßÝ_0|ÿä„ÀŸë"üwC4žÇp À?´·Kaø/Èÿ›ü¿Cþ7ÎÿÊòÐþ?ûÑôñðømøeþV(áð§Ïb,~# Ðø½@ý§«ü%6€;!|ÿiÕÁBñ›¡‚rñøûÞš¸“ sýƒ@ÍŸÞ‚¡½¿ž ( þ~×`îø§Ä?©ß&8~•þ]RC;ýÚ9q)i ƒðƒÇKR@¿œNpÿß¼‚ÄPh,>ˆ‡ tFc¿æ)) á«_Êß2¾ë‡þ-ÿ«ÌƒÁ/ßo"à»øKþ½ép¸?˜š@ÃnÞu{u÷Ía• ‡Ÿèò Â(ÿ²E¦ (n ÓìsLC–&ø";bs ’Ö×A÷iIC`_yšû ·Þðš,º1Ÿé$èÔ>Ùdd¹ 09ÌüvèéºJu7§¨™òJЙWÐípwâÂV]þ‘|ã¥R/ñÕ—…Ÿ­”õý(­˜Êéô§+g"¡•žDR+«§àýÜÞPº-ÜW9Cí+žÖÓ§2j‡¯]^”Ž Óå½Ê® °=•{sÚ—[qš[k-½òjˆšÛ˜Z“ÆàuH·3y…C(q_ ‡ç*¢¬= &ŨHÕ]xJá”"¢kWQsƒDdgÈ6®¸ÊÂÂþAˆƒb·F8ÆÝµl”Èí–ßZó'¯ "Š÷k")+öJaÞŸ÷ÅÀ®ð¤ ”ŠÇ-bRsRÒÇïs3¶±rS$¸w¦¯Ä¥9l&X?¯Kíí=0e ¦LPJ«! …‘}I]¶èvA·$o%Ÿ³¿«|åØŽ¸á ÷>l©2¦Eßík”ÔÌO>bô­wð8̈êöÖr)ódR›'Â=¹ÞÁm{|ç‹C[VM»F…¹ š|ë[Å¥›ª¡óýö™¶úH£>³øIÒÆâP{¾í¯tÏ©û|Ô˜¢&%É2TÙ¬M|$©ÖrJý;æ‹æF äÏsã!“ó-ÜÓdXFu²ù9NׂGC“×g–Í]–…\æÓá¼ðšh¤Ã[-jÀ2´vÛß}¦Ã¿{CyöÍØL6£õœ®´kØöóÅiW•骹Á÷¤rt­¼IhÇ ßÆY&0¼ÅæŒ{6“°#¿› œÒ·vifôB5×Í^àL 0wXë‰ûöYëñu\'äc›²Ó zH€%¦%M½ò–uR©FŸØPÒ'…õ~»Òføí¶zÁúö'ß>t÷|˜ÛÙDn7²97²‘]bà4I³:ÌÆÖ™é#÷@„_Œõ¾ãŒ Ô›4àB¾ä(zY”½s:I!l÷µ~ÂW¥ú ­Ñ®åÏ]î˹±iY§ã¯BÔ÷ÃâuîS²ÞãqEÿiµŽòÖu©’ÈÔ½í«~ù£v_S¨Ž˜&»Š&}Sˆ÷F$ED #àßߌ6’+Lb—62”Õ«½à^íéôO*8É«EóóJÉý56·€|ûŸ2˜“ „$Ðo*3#¬Æ„Á8aC±ã³š°nÅ¡˜˜ë yáu=:º'œgÛ÷Ñj<Þž¨ˆª<ñNâXAãtÚ­rHrÌÚð8€àž^ˆ_x£Ò9áóÓµ-Þô×yQ$²åì7÷¯IT. >6  ¡”‰ þdWƒôáÐÜÊžì?ŽËO}Vå‚”î •¿m§çAÌ=xûAÀÏʧ<E7hµèóWº¿tÕuµ¨Æ¸5Ó¬¾‰ë4ÍtH²±£e¿x|"\d›Ãí¶¼n¤æ–:­E¦ÈZñ±9ž”×~NËܦ¡Íý¸Î©½âòÑù”¶SX¡œ>`û"»Üÿ>Û6Eâë9å#óàaôI¾r<Å;4ZŸmý {¥d_=® Fx–@÷ÈNòCxÞµ§º)èímsFài¸³4û˜çANvûÁäbékm–¢ìÛ˜¥Ø—ƒi‡Š_*h¹%¯‘ku+aŠl‚¤³Jiõê Âý:ŠY“?ufª cÆT“`«39y÷Ú}YóW_?“ã|ØôW: †U®Í¸ã¼$,ìT Ê®?ù,pÆÈjUDÐëŠOXt™¬=0]P"ða8"˜î¢:#ÚÈ°îæ®ªM‹y€HF½^§0Õ\?ד)¸ž‚«ñ~¡°†´‰Hkõ¡÷°Ór5ìåž$U>YŸàÌHò¦ö'i:–¾œ2Åù’ÄñØ :ü:ƒÐ7òÚëÄåÅÝÒËJ_–×Q­*y ¸ìœªGÜ"M 1¸,ƒ˜ ± ¤¡$[£ûÜŠcVƒ‡Øàˆ®œ¸5wfeÁFƒ Ž­¸X#z=Gþhßóls»ð™‚}½I«x Ä•œCí3^Ô™´µ—î¨?ªKßÂŽèÐg²jŒ6oöSÆÚ†'8w¯ÞþV9žR1ë&sjíkû±Ï#ŠãÝÝdY)á ?¾ 8[åt¼•1sç» ý–öó7dc*–DÓëM©]%?Í]råÝk¼JôÙ:«U+V&Þ ¹=m¤w¥™Ð‰¿NÅw©EyZ)&òÊà/÷ôª†8¨mœ¿.ûè®d4Óèå.ïqó•(z¯Ínî’^WY)—5ö–J—­ÑÕátš'‰ß\Zx…V{ýy#’[E\¡MõHi«ðM;I } ÝžO$¤öä§—˜F…~?”a&}¡dçø^2òó^0ö'<§íœ˜•hlú¢N²~-EßÉz xO<ÊâG½ØºdIb¤ØV“ÿ€PÑ0W5s¿úTжµRõæ]™»‰ÂçTBÔêòFK~7Û£ØyÊ@ÝÆÃ´¼Ï¤ß*r}gRgÏU2²¿ØÆ£ó~èÅ¥%éÇ]‡•Çí×qìÏR|✋λde2%Udj}?É”œHu3tpñŽ „xyºà~šÃ FY];ˆ:tåÜy#6Ö}{⳦p¿ŸãçÜŒ/‚&–´¼\õÅG²EÞ’ß-cy^ñ:.Òúëãr`Qša†Ï Üȯg½Ï3ŽKÆ6p‰s|4›F…l‰mVDï¶ös¤•Ûw_aÜaKª?wx®y –nåœrZHñˆ¹„|•0U|vu cwÀ{öÆ áÁ¥ÏQÔéiˆÌú©¯ê2 }Ìê§MG•?x—_ìÏ´¡5N ŒÀ£`Ï2Tùûû6á]S•'“\2éïì)›Œ’FštÅR±"ÔѪ³‚òòP|Ä⎗owfµXpïm×0™ìøì<¶Ûh°}-#Îõ¼5zçÀ_†i¹ÎTƒ¹Iªª0íVÎäð¶ù;9%ôs/ªj: Úów—¿/sçzų°Í¼ÃÊï_v%\ªéèX0ñ}!sŸVÑ ¢{¥ÑZŠI}_±3ë(ƒìÑN÷D6Óa!ïå&WS•ê Eñ®YÒHò[ãJ´<^³´#êßnEEïû¸ïKÚsÏôäð–Q9¶Æƒ +È"èšìÕ–ŸM©Ê/*T¸¬ëÝ¢€Ž¡ÍW7¯F¥8èö?ÿÈ&+ÝcRØ_!s#+þîÊЯþépì|4ÄVÁú|"d Ü§)N÷¥›Ÿú+Dv§WÏÎBFÿ‚P æC«»öÚ Lw(ˆ(ž¹‡Ôžü^Åב¥«ŒTÍw£ ..ÀºŽß/Õú¤SÔž,ÞvB›5ØWhðE•DGô­ÕÖÿÑÌÓ >Hb,áõ9‡®}ž'[’/ C’vs^\ ޽/jýºBólï0ÍV¦6c µvï,m¥•FN:ö`r…×á9 ÚÀ¡^gþËC-µ86X÷¼N‚I‡€3=ák*­ÒbÚWEa2+=25k¦{üå©ÞL‚ž†~Îúï\hßbQ7ùèzWÿ„(6>z†~±¬L  )òí@y¦.éqO§‡è"¿? cżÏê[}¢6³Œ¼ôhÞ€`y„­÷<ÖQa}8’È\_ KÈŽ…žV0FV^µu\ŒÎ—s'%ÌáÅ9ÆÒnÉ|è¶b¯ÖP'cC—­ôEx5¾ûFöOœÕßP £U–ÿJT*Ûî¼ûx±£þl´Õj+ƒ¥MfÜÎÝóÝÀ¡eÊRdªïMXü˜‚jÆÐ6ªôüÓ )šéN§ãDÿhkï…Mï.樛U\2WhvM×d[ÍçÅH=· Þ2˜Ô|E÷äî×ÅQQôÖ¬À[ƒVféj¶+ˆ±ÐñÛo'@=6»šâhcRh¯ÚD>.žô&áÂÓ2²»%Ñ›7ÊÕjŸûºÇŠ[iÏÓ¥&iñ­ëNuí¥dܪQÔ§æÖœù!Fɯ÷i³àâ£Å4-Íô×Y ëKTi>0Ncº‚“q“D¦â¤U³§œš§ÀÏŠÛ˜µÈƒ¬ô͸ø›šÃW´&J¾_?ká’{Õ]VètyƒÙ2z¤ófßv ´Ðß ´Ê !>môFò9z¦‡}ð¬“7wÜóö%—ik®ïU_ïùDhÅòàEï°HI~a󻈳âë7šú<Óžú½ÓJ@á²] ¤*g$²äc×'Ô­Ad²Å籨k|îÝÆYï‘„Õ”¨ÁÉ+ôžLµÐñ«6›mÜî-„ {¦&âÏ—ÑÔ>Ö3-$¾j¯ì ÎAfQèafQ ÜÝ‹ô…²Z…îö ¿±áxïî“Ñt®˜HÛpÕìggù~AIß§Rî¤ÙÖvMÒø©Œ;›;-S€y‰qß¶Ãø›‘¸ô ÖžG눱ŸS°ÙõVmw—…Ìï3  þuj´#Ž€ïš·}âÑZ5è¾ëŒÍgæm>ä5kWÃp²›dÕµ¼¯U´¤U•j¹»{@ p»«L׊‰O÷„cíË6†2h¦Tš Ûµ‹Û·ÌBiwt]šÕ»i•žÀiOFš+ ²uXhl¦$€lòaúø³‚i7¿%Àé1ú“©©Ê÷Ø…äÀô†Gÿªy) Ë×) êîW•ò¦ä”I|©›\ã@¿éÄ2³EI©Œp>d®^€j\¦êMôÏl+©©ì8Ö\¦ð·¼¿—^, •5Ö_Í¿ä5ÒtPO´! ι¼hý3ù•à³7<#ŠïDÓø}­¨àiºs­Â§@®Oˆø æ±Ï–èEœBfi FMåí2Îqpw'{Àeôpõª¬\#pZÞñÕ`”òG@àTô"‡0Ã+üœ‹À¡'c3 MÉ”¤µ­(…égè—¥ÏXvžŽÓTr9 ا$Y­·ƒ-µËø%«„ f´‰±~›¬ÀáøöûãäÁGa?º¦ß@CT ÏìüaÉ(œp).ÓqèG¸³ôq%4ê#ä‹[ñ’ 3±k…ùˆE‘6aWÙƒTýã‰Ó„|WÁµPÃÁÁÒæ¥r=EJp ¶Ø~‰ZÈáV ¹œÔÊXƒœÇKÁÉA‡ËÖ†Mæ=?ׯòÎQh¦U«JÏÑi4„¬ 9~RƒrHâùô Œ¨ž ÙìÆ˜ÍqÙ§ d»8¨QRã%=3=r„”Uü@éÔYÖ³y#IT:Î|°—Õ…è]¦Øª–SÁÍý0nvÝÕËü’ò3Ã!¥£Œöâý›©5nåMN·:[¹¿Ä-›Î áe<Ís”C HÂrÙ”8Øç>Ç {ÑJsTËiµ+.cRå¶H"Û¬ý×lFâ®E ë‚–ß}gZS¬}§Ä»SÂm)7QzÙs²õúáíŒñ•BL¢ ª0á—Äí»YÛ¬•nÝÃïg´wX`mân½ÞÕjÓtö`ÛXnYWy´ë¼ç¬•RW£ã+“nXôpIj9K«’Üå 1fr.ñÌsTŸ#øÈªSJùÀñ$ð• (ôÓie µÇ–ŸDŒÍ×G6–9K*½­Y¡’Yïm_l¦¥øF-EN‹CZPæœÝËuj–&“ÑltW[Í@&u¥œ²VXáÙZ/cÙ#½"*Ó¸|#Ì8æÚær {†Ö‚”mšù‰ß’EÁÕì7;ù,÷oÀTwë¯;㨊rQ¹ÆW^Y¾ÅP˜T?@å›4'AfÉT©W¾>b±ÎŽÿøxµcU”v”\£pßÝmehýåÎóã£T‰ÛH<>äÙ’ãýû•÷dÄð¶k¦#­fÊVC‚ Õ=Ÿg˜qšI[ó?Ö¦€ÑvcÝÊw%r³§m.…RéªAàFÎ"Y®;Yo $:ÇAó°¯’Så›Éz³§/ìªC)$·ùUÙ•ùÊ œj7øn¬{§Ü7zg+¶ºØ‘O1¼¶ëEO2ðI2s?‰/PzÛÊ·ºã­v-i‹)0‚M C)¬ô ¢Lºï‹â¢7nçZ]e™2µe =Õ—“W¼_ü´µ…Õùã}­C,n%(Ý&—è– 6¤Ô¼7ž-;LH–¸ÃCÅÓTƒA>ƒgÇd¬göã&ÇÎ%ô¹Ùe¬ºd?é©Îx³nBâ`¬wã%·ÍáÎÖtZ˜3Øu?ï%0L¾òâSþ=ê€ÈÉ·Ù˜~›7FsGêQ vÏ{ ú³÷wmîñÐU©µh:nÿð00& Lãnì_ÌßÑ™yAPu£ÞÙ—ªBtjpžˆ:§èVø¨ªÙí‡$,Úe3V,ÂmžºÁ¦€¹¾WHÏ]6‰¨Ò>«{gÐoªÏ¹$5B¦ÆVúªFöw"´-HTºŒ]œW€;-œ!ô¥‰wüßÏ?‘x.’}ó”õŠYlþï&{–}†û=íºZ”ñúø ËK.9Ò‰\B —{>ï¸g˜ŒkrÞËÓ‹Qv6Ì›w¡Éãrpâ鮉d`-}†¡\\¦Ÿd÷Æ4JJ±Å›Švš3õѱØû?&š¿px¯ÉK3·Üš„$x o>[j^ä âF¿Ôë™)pw¨ ;~Y‡ !®’;\Šw_ò˜Ã%¦. HH‹F3zTŒ)±„ïLEÚ&Qv¿þq-.ò£a@GÌÔà‘Í­døËm$%:µšýËæï¼ÔÐã2O±;_¶Ì_òº…ðÒ*¬äˆm'Æç¤øŽ?ÅòöoµCù¤a¬m…Þ¢™#gyß„ßß1‘áLÇŹ— e.¡õîSªP \¿<\s-3ž´4›¥ZÁÁÚuÐ:°>÷ÇøÞôcr¾¾a‰‡¬6ÚS²¡ ‹ó+»¤å/l5zîXˆ8@ ˆ˜™¯_ŒÃ¥|6ÝÓY$"ÕAL´*yØóo™¦RZîv}æ n-Q`»Û~¸—¼mÔ“øÖÒ—ÄÂTÈ*!4¼Ä_iã”A.É^¨Êœ ŸûÚ°À[oÂÞ j}I\T½éÄ®½éËÞʾ éÐUð¢dŠþB£­¨˜Ç‘­”Çv½/å{ò‘"’³GöÚ ÆÖ'ϧ}ƒynÌxF˜­eb| ^‚Äòk)W¦Þhu([å/&\©Þ›"–âùòƒhvà¼î£ËýØÝçþÌõpÁ6–¢&³œ®U×pûEíܹ!¥º¡„¡ò‡šòŸ~|lÿ“áÖ”m3ÃBw¢X¾¼‚„0RT®Ñ·'v¹Y1xõ»ä·‹®F@ˆÜí·LRb‘íÞºPø·,Ò±¿h CDF&||×Cg;ÿ_ #‡a endstream endobj 86 0 obj << /Type /FontDescriptor /FontName /FYGEPU+CMR7 /Flags 4 /FontBBox [-27 -250 1122 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 79 /XHeight 431 /CharSet (/one/two) /FontFile 85 0 R >> endobj 87 0 obj << /Length1 1413 /Length2 6272 /Length3 0 /Length 7226 /Filter /FlateDecode >> stream xÚtT”]×6H#]’2 ÝCJIw‡ˆ¤ÄÃ Ì Ý"Ý%’RÒHJ‡HK·tˆÒ%ßèSïóþÿZß·f­{Îî}}íÃʤkÀ+g ³)àH^ Ÿ€@AKÿ!@@@ˆO@@Ÿ•ÕŒ„€þÐâ³à0 *ñv8È ‰Ò)Z!QnZ0(@Ý  €¢@1 € €€ø_Ž0¸@ÑÊl Ðâ¨Ã  >«ÌÅ ¶w@¢ªüupØp€ââb<¿ÃrÎ 8ØÆ вB:€œQm¬ ˜ „ôúW )$ÒE‚ŸßÃÃÏÊÁƒÛ?âäx€‘}wÙ~Áh[9ƒ~ãÃg:€¨ `vH+8€R@À6 (àµÁ¨Ú5M€Ž ú‡³æ<€?¯äþîÏè_‰ÀÐßÁV660g+¨j°C@eM>¤'’`µýåhAÀPñVîV`ˆ•5ÊáwãVe9=€ ߟè6p° Á‡C~!äÿ•uÉJP[˜³3ŠDàÿêO Ù nÝ‹ÿ÷X 0¨Ïg;0ÔÖî[7þÇP°«HMñO” ÿ= @®§ÿ¯ä†^. ßÆßjTÿ~>.0€ ÈlBýáû ¬ÜA$Ü äçóŸ†Kø@ ÀlƒXƒìÁPü²£Ô »?dÔäá`O€©Šx@€À¯ßß's·laPˆ×?Ëod £®¥Èýðß&yy˜'À‡WHÀ+(" ˆ ÄP¿gùÿ_Øku­Àö&ðOF5¨ þÔÝýÃýONpü¹.œ€WІ¡x püC{3Ôø&ÿïÿçeù_hÿßý(»A ¿­¿ÌÿÕÊ ñúÓŽb±µZ0Ô^@ÿÛõ è%ÖÙ‚ÝœÿÛª†´Bm†Ôò÷%‚Ê`O­.iãðþš*= éÂà_Ï €( ð_6Ô®Ù8¡žjR¿M Ô*ý»¤ÔfûkçEDVp¸•>jð(IàD-§-Èó7¯ü|P@ÁóØÁàø¿æ),àG=V¿”¿eÔ|ø‘pÐhPØoù_¥mÜàpÔ:þ¦ª¯¿äß»y‚lðçf`6’/k^´žWÉÑyðnŽHO²n>yÅÉë3os»$ÂIá¬Ì|¾?•Kø@²øY‰ãDvžñÆçkSNXs’^Ë•ïµe‚þøf þ§1ªÞÑ‚¯rµ= xô¼†²[¾7®¾FANMèê¬9®n‰tóÈÏ=ºUÙI'ú¶œçB˜j„Öà÷#Ú§¾HÊ””’^¬®ó´ôÑð´™q$™I;} ËÞé2P$ñ›úª5ζI6Úú’ù”ÑýBâÞÇ!ŠãÎ2w„FêöJ^°ãî]Є·ç7­“‘ŒrëÏѨܸd{)Þ£Wu÷ôq $³Ñ¤ÂÌ;z´nh_š £í¦ŒÀkTÞÑÒ¶ç0@\„ÉLqbî5ËH¶Êj‘åïËk¯”«´ŸÄ)‚‰wa„PBÝ·s­ Œ±L¾žFÇÙ÷™ 3;»ŽÈ«[ÐÈ$~·ŒlÌü.vvñ Ðsÿ1ÚvW›sslÛÉ3Ç76Nu,nØú¥s!‘`¥/›IZ¦sGH^Kíµ®×OóY¤û¡oÿ।bëËAºì1ÁuîàÁ#ß¹ñN\•̤¢íéý̯«Nâó53ÁG ¯Ó¨¼‚›yœä¶&¸±XÖ¤+ZÜmÆÎß@KئH™ÊêUµk{ÅÊ;»ÐÐQ«ÿ¨u=RãÎ1Röx°¯[ª)L^wM½z࿵‘¤8òŠƒüäW¹+A«4Š&£Ò~bOE MzÔ9¿Í`}*À2Våj¨ƒn®‰mØŽO!7”q>^Ž=Ñ­5œt¢›+c|í©ÙÜ1áï6pß<¸År||þ !:…øß@©ìdÃýtº¨>~Ø9zo¶ iÞâSÕÐH²7í=jóÓç8¿æ\7—¼½×ñ¦®Çß;Ê3Z´£0À9)„ ÇøTÙ(2ùTAIÇS=ôßQÙ¹ð…'ñ@F.ýôXXÔÃúà>†¨ù—>ŸÝpº£Blò¹6%‹A2óÖ›+}h£òŸ¾g#¤²Ý㼤yôŽ_åìÖÅßµ][çÖâ‘=¼cxµ`[ãH-Ì´cÔÚüjTs4qŸ2áN„bÊà›ÜYÚÒ£R€}á~»©#÷ß9è ¯2k†ù¹âº;;*Ìl–Yku“IØg¯íwv…âué|¥l}Iš/%¾_ñÀwÜËùŒWx˜—gð{æ]»åSÏ'—D1memïb\ÆL1¢®¼q/´ˆÙÈor{âæW˜}½¢;„S^jÑ…y„WWÌo Só‡ÓB —Éw;ñi°z›-·"nŠå—ì2ŸWðnA®TçÛ8—'EXU­ä÷pÛ.&“æô”ÜìX=?ls83㢣Ëßå°†»>u¥qC7)Se°ï›ëF£.pËIÊ«¨ÖžÓ“£´EoÝž~šò=蛞‡/åØ˳ƒ|þþÁ³‡VIFý¬ì°ywæÇ‚±Lå{EN "z2qG¹¥œ[‘)ölê¹,ŒE¤Sƒ<«} Žæ”l{Ê®cC\ý»\ Æé\±qàRHØ;ídòTWz¼Jv Ù¾U[Ìs(„¡Ñç†Y£[ñ8ý¶'oF¹`ø4Žøžxú­±Ÿ°HÒi)&›LjBÿ¸»¤ÿœM3×9Z‰\§™0ƒ¤ö¤O6£ðí~î5¦ÈIùÆ{ÍÊÎ9i&#¾»íY~ptµ+ª7®Ï7 Ò0¸Øõ/¥³‰%ÚÊè–~A:F¼Ô4s$7éÊ Òß×c$¹L^·Ä¼Xî̉$QEƒÎð•bgyäXö£G¯¦.v÷‰Q£éê¡Y'þЕNŒ«(¾(Á˜S©<Ñ@ËÏúŒÇ™ª¬œ½G²e°ºŽ¢¥j=‚ /mÅç_š¬O¿¦ÂÞ³Dªg•Qºö¥uâ¨gç&;¹õË{Õ<à.­*ªîiZ}µþ¨ HÞŒHKÿ|²Ù{÷‰5c•9§^ 鬣'nÐÅ!ˆdY‘&9b¿}úPb—Ç'¼¦FúCX)XÐôÉ[ÅfűÅñÎS:võÀå쳱ͫÀãQ cªÄ8”ûK%g¶g”'…r“<‚ø)Ôºô\YíÖPu5N•>äY"Úiº{f{Ê×’MiÖI>«-/tиˆ /-ù (S››“—;³Hõ‚¢7þLÑ"»0íÀÙÊÚ =_B¶™âæþ÷“ ÍúÔ6BNl“­sê99ÂÎ#„G¦ŸÞ›&õ;øŽ˜3d’‹l¬ á‹«×÷Ç4Ýï?™ž™Ä¨ šþüÚþÇM§%>½t­Ãg§UO® ŠQTÒ¤bŸ¤¦ú2ÚG‰ð¢Šè(Ðc”uÛ°Ø*,Á†;höÙ°à)#Bª£6§qõe—v“Ì*¾Öë~‚}Âöª–õ¼é†l˜Î fî.k ç¥"õ•i–34j„¤·|nrÚƒ÷>Ä ¿GÊ^o¿qKÏÛzöteŠª¿å£ÜíZà4¿Ûu­ü}Ü[•¡ob£<åÎ5w>+í6ŠŠ?J™¼.S ¥•K¦nWø|{›#c49¨Ïã¢{j˜´ y}×Î>[RígÛJgŠLsÚ‚üä̤¢×X æžÖ#|¥%ža›Â™Nß|Z¿¢p"¬MéË/UõÞ”Ö‚×wZ#¯,6,žœa>–3{ë©ç¢|p ¤>dÇ/‚®/XDà˜±ÜGT7•½£L<•®ÆFiëÛœÂzЬ-Bšµ‹9² óN¤'é[Ÿ(¤fi"_–6§Ê]Çù±H¨—…dfãzÓý;p°fÈÉ èñUYÝq~F™b܉WD—GA7–œÖK¾3õwP¿þ¸ïç 3ùáLÖ—Y·“mnó²ð+ÓŒ£iŒŒ‰µqÁ«F×Y°R”Ð= rÏ监¸‹+ÑéB¥c±¼Z…Mn „©Ýˆ¤êµ‹%e[LmûR ®ÊHóë)F"ÚðlPqò»½…Ñåž…` ×zí½åMì2Šð¡ 6ÖþViyuö+P¹SÏ.ˆ¹ÚÓ•"n–òmWöCkÆÆ;ó›=áôõÑéôJ ˜cµ7¬ÕvêÞCŸ-îßͨcO©­Á½sØ@¨¨Ž µzÑJÕœwð”Œh&Ô¤1÷øÆ„>xrÜ>Ķ ï±ø$ÿgßÜãI£Ñ6CK2ª%6ZËŒrªi`Ú•7ùˆÊ¬Êšgß6ÿæšúÂJå³Vq­WBLå½O§ÄsfŸ~‡ÍJ¬X±Å;*,QõWö¼qÛ§>Ñh{VZ5èö!k~€Ášévéa¥„ŒÉn<€0ú=?Š/»»v“Ý„}âø),43œªˆ ¤ï°ÉKÃwߢX2Æ[ë ¬÷S¹Meñèiç%ã!ø=u¤ÇÝFÊ í¡F·õ”O„§÷ Np㥋ћE-Fi¯~°Ô`GšÒ'ÚÅoŒìÏì½¼”5EÌ8¡œ ;©·Êò¿5Ð)…>U7cvî§Ý<ðöæÖbÑÅ$¿û‰•¹É…®~­q0—è‹ÉÑžm÷P Ÿiô °Ýq´loS)']æ«|[qmmzؤ¾õ°(…úPŒ‹™ -pd$«œì<†å»ÊÅAaœÌ3HÉë®RÎàhI6_÷P-"êfœó÷]Ùf§ÙD¸JùDš°C§m¾›ðîqílº6Ùgè$éÑâ' üÁ“º—ß«BûÇG£¨RëSl23–ÀmÙwû Ç‘èíèímÌ \'?‹1¼)8´9²Gº®J1Òž¤sb·”N8¾|¤™ äRH/^Q#ËŠÇ¥°F^ÁÃïØ¤>qm?Cʘª¥\m×&óŸzœ’¤×Õ-R{ƒ¹eK7‚ŸùN@¹º›ðö&52Ǹ¯ÍnŽ+t¥Š”~ w¨VÒ¾ë&;¬,nˆÏ§W?‘k‚U±‚†g¤¶ýñîÙœnog]¡#v²²ÄPíR¼-&ž©Ó7ŸgÁO¯g›7 éD­ØF£îQíØ!º3+Sé>üæK‘Èáí¯Ô¾À--¡EEzæawŒsöHäjígX´(ÃJY€Ü|ºšz{œ¯¤†ÅAò›óƒ ½Æû"Œ¶¶´nBÜ¥Œ3 6A¥'&“DãQS¾ÀùnsÉ-âúµBÃðûUÍã~íQKA­»G>\Çñ¯ë™pt,Dv% ß‹®ôNu« &D§9óözÊÝ™\ø‡˜0íDkÀ‹Ö¦S˜³~ùŠ;¼Ð’‘Ç=}^6%uó[Ízýö0úÀÒJ‘œ¬øNzÀ#×/b®i‘ )$³.^2™8¬L’2ðzgfýxÀc¬ÛÞkò^WÔ;¶Á gBõKÐ68j¥­@àØó­o¼ái7Í䃑þ…è9½ô•2–7õÂÏ ? EŸýAŽƒâ.ÉÍâè˜ê;ªÎZ·âéßRÒè@ÊÃÃ7»­ Ôtú+ÉÇ–8?9äÄh!ßHÄ|øg^Ü£OIÂf.êJÍtuBò*Ž£˜ ¶O-c4<Âܧ.ä$Õ–'æ¤ë_tÑÞ©ûÍv/àÏíYMh¾e#“IäEhmÜdòaW¼ÊtBì| ÷×ÓÖäY²Ð8ͱ2É0·;*Lk+Ú¶¥Em˜}|SÚ.ŸwK±"(<ÀüMùAÁ²Ff…æ­—üŽs ý¢Çݼ%ž*ž×RìZyw ñ`aÿáJv¥ä{Ó•¥ yqQû‘Pb6¿ý!eÍ 8ÐÏx;«EFrTµ¯r…AW‡KI˜Õrr3HÏ+‚œÄ lC>üè·t"9«‘âQIDyTlseèÄV“×>S¸¤U‘ã3¾Ɔ”]Ž ñšÅõk[<¦¢dɸ¸—ü¦èÝQG¸ÂÖmcͳt½Ç–öæå,»-«·e8/´ñ…âjN×à}ÿ¬§¤:‘aæa§»%šx‘8HÑ´öýÛÈf¼ÛÕgÑÇ% Âžë€•·òíІ¸ZCY×: WÑé ãë%¬ìÀÉ „¯]F20}¯2Kiî9Ý&?eÙë¸ß;{½Ù½/á’=AÙs¸ƒëÚòø™×0¾à*nîO6Ùá:m¤dptÎÏsiŒ‘ª»‡qó'°¯O¹K5z2‚â"•»z!ÞÝü ÞúNæÞ<Ù.q¡luw-b Ê(bn½®ºÙËÍðsÃêܹóÝwÉ›¿º)^b¨½Í!ÚÃö}Lkœ–ˆ>gæpÙÔk-:ÍaÖ×{¿Sdà ôŒ*äù²´7UyÞnîÉÆ8œBàôúU³ˆÒu1;Áµw¬²sêešyEÄᢳa—Ïès‡4`@·IdÂ+ŽÞû•d7î™H÷´÷%rÆò¨i2„`4‡º·þSyeÛÕ¯!’ëQgKµK?ýÏj½ÔdÓ#c™ì4C‹”DógI¥‚G¸—>{dæ¤ó[½á6Ö> 5ÑÜyo¨&ó´+“ÆÍI”±¾j_Ül•†G…t•¾ ù¢%]ùSæÒí‹°¿ƒ˜•£Êm‰úÌËЂÁüé´ª뇟|Åvº¶w-ÉSȺÑå~ô½D<’݇rŠecnN„ÑA+æ:ž]QD¶Új(jÛ…ä0Vnˆ ô ?haM:©_y;4ùódx•ì³±Ê[Ç·•FÁâ%ÙìélÊÑ®ÉE·uÂ1/@ÚœËÈ¢ôÆ¥ÃC$ÇÙh> Ök1'[ÐZ†¬ÉÞÕ䡆F_š5vë‹Qõ#r–Ò†›u‰pÁ(R?‚*Ÿ¾:º¹»Iõ¦[h7(¼9‹í[tfmšû^m7Ea8~Q°ÈheÓZÙÃbžå78ÍgÈW‰€êúÊ'm©2̇CD5 Ø@4ÏÉõVh•š,šèir1&X5ðüÑ{pH¾m±û¥Tªî;à±o6émNAYèµþIÕ/­alÿg¦ŸjPýõÔàZ-÷H°|™vËVõr~—i®ªnu؉w‹%ôå׆”ÇÛ±UHF1ç©‹šïä_nk#ûZŸk‚L]ƒg²w5ì0VóŸ£×®Jl.¯ú:{³d;¶7ïÙãÃéŠ7ÙÂî:ÐøñU}º±É x½ßÃñôyT.º¯¼‚ÇN’u@!× )µá3nYšJiRW„~lõV²84ô#`$ýc˜Åæ»y8­û“½†>Ë„Æ) Ü´Qƒ £JhíoÜ´ûX=/ê‹8âç½ö;Sk½Õ&Í|×f#s±’:½oÙ¼EÞx"YŸy—¼ä‹# ^ê´û×Õä+Ûcµ¨/&ÚÀ{‚XõÛÔOµÝõ‡Ra– #½ªýARÆ<7,bš±“k=¬3{¡é^×Ã;"]õQ©N’¸™JÅt{zUÀ¹‡¾®«îWaûHZ‹…zæ…gIüì.àC’&6q³ÂóDßhç_Ãf§pç:À¦%d`ÃM"Nô(޳úE2ñtÜxx¦PI–êüÔAíjºš—íª¡7‚íÖ8DEàÇ2Û%Á2‘FÕa´`ˆt],–Ö>ÏLÏÎx59àr–d®3Å4ùÝŽ!&äû½ïê‰RJo¼vÂëÿ몼 endstream endobj 88 0 obj << /Type /FontDescriptor /FontName /VSOJMD+CMR8 /Flags 4 /FontBBox [-36 -250 1070 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 76 /XHeight 431 /CharSet (/one/three/two) /FontFile 87 0 R >> endobj 89 0 obj << /Length1 1504 /Length2 6604 /Length3 0 /Length 7616 /Filter /FlateDecode >> stream xÚxT“[Ó.Ò¥#Ò‹é5€ôÞ{/‚ÔB‚$t*Mz“&Òé½)Uz¤#Mº  Rþèñ|ç?ß½kÝ»²Vòî™gfö³ç™¬°1ëñ)Ø#ì ª8ŠO( PÒ12€@a~ Pˆ€ÍŠ‚Aþ¶°™BÜ‘P\ò!”Ü! Ú¦ B¡:8@ÓŠJ ŠI! Pâo Â]  ò„Útøš8IÀ¦„póq‡::¡Ðuþ~p‚¹‚b¼¿Ã ®w(è€PNWtE00B€¡”Ï¿RpJ;¡Pn’^^^ü W$?ÂÝQ–‹àE9 !Hˆ»'Äð‹2@ä ùCŸ€ `ìEþå0B8 ¼@îÚƒ‚!p$:Änq «Œ4´znø_`í¿¼€?‡äüOº?Ñ¿AῃA`0ÂÕ ÷ÂP §ªÍòFñ@pû_@ ‰@ǃö€h(ÿÁ MÿØ!(€PBTTDy €xƒ~0öqƒüvþ6£9ø¹!Üh¨ýAà‡yB(wH€ßÿvü{E (°‡‚Q;ˆ#NðOv´âð×Ýw¨7Àˆ–Ÿ øëõŸ'+´Âìp˜Ï?ðß-ÐSÖ5QÖäùCù?NEE„7ÀOHÀ'!  ŠÄÄDÿÎóŸø›ýo«>úgwÿ+£Üø‹úôþ&âùGœƆ ðï º´ž!Îäo ‚Ño‚ÿßCð;äÿ¦ý_YþŸòÿï©zÀ`¿ýœþ?È óùƒ@ëÙ…ž zBàÿ }ùk u öP×ÿöj @èQ€;¢uÎ'ø€øà/;© õ†ØëCQ`§¿´ôw3Ð5`P8D„þºwÐQ@àùУvAß-HtË~» èÉúw]8aÿk…DD wwZè•ÀO=«öïßðÃ(tÍ1à€p'øÕXaa€: áõW»Ð¾ßfA (@ÀäþA½FŸ%äŒ Cï òØݽ¿­h£+îü½-8ô—tþÀþEìáñßJC³û{ýûB@¼!`‚¹X*̹&¬í¢JÞ‹osweµ#*Á¼7RÅþñ¥Ÿ“6^¦ÚäcE[û š¡çú³¥á3þôÜ_.F½-ße/§©ç¢0Tz×øò¾Ÿ¼s„0Ù#èÇÄžG­“&0’ÚZ`[p$?œ¹|*Ö%¼õæsÁUrë‘ÄÀPtFÆœFŠUÈéØÃ|fÎ̺Š4·$‹»ãn‘îa¬a2v…ù w®ØCûÝgÝ".cpié}v_ïsáã|­îJÑŠp Ú»¾šÌ9CIý´”‰ÙšH vE‘3¥ÒÔÚB×pöe,[±åŸSù}­‰ýÂõŽºJÁ„zO†Mû•ë–†`:±!¿—íå0š?®êP…ll¾6ßíí•fZnËMóaÛ¡ò`ÉéNd¢‰7z‘ž]6Ÿ†;õ Fk,ýf·óÛïèÏ›ÝEÏÛÞIÖ>JÛîìÛðœe’p!ò!£ªWOòq“¢Sø¸Hv¦=Ì—<2 ³z½”e竦$ÇÂâY*ôbÞ®N*4ÔßfýÜØ,yÓþk =Nåþìv¡=ÇëîÍNz¾æ¢÷Bô½¶¯qsô1³‹ÔD®CO+]Òõäk“ˆ½=‹Ô!îÎa¾ŽÎÒV/üТµxzÒÕþ ïqÏǰ¹OjïHkanÖ- á˜+[>ùZ<àSÜ+zŽÓì±êñ³R”QÉ@©½ÜRµ%6g¨yèÓžs݇õæoTg¥·jÓv\jºñV 8ç§Ç¬…fÙÈ€˜ —Wû®a­1£¤;0×PÄÔûýÒ´›-”ay>/(ü“ãç=ïÝ9äy’PËÔ“¢RŽûP3‡•¤Ó·÷Q âŒ‘j5ûëR’>§¯T·ã©ûe‹EM4€¨hŸø ^nŽU½`žuÂÛ˜ÿ­*ÎfÓé¯+Ñj%¯ab!Zôïú.»çÚÈüTcñã({0n¦(âì¤éN­?¤õX¬m˜óÔî~æß¥|‹©ïé÷U Ê[C4Ý#£M' ý«¯ñ#k߯ÒÎ6)l¤4¿kGÁ:ªGÕ¯ò,0Œƒ½‘£:ùŒOõ£¸ë^B ¥ñEE^.ó4Lê‚\bø%ñP–ØñîÃV ãìup]y·©´óÎ(ß“-ñ¾^ÿÎBYûgãÌØàîzS×þÏÏWi;* Ò&ž$ξmɼ%á‹Óºi©´(ЃzÒ’Ø›ŽSŒ`ä>x.Óç>6­ñ,á\ir uFáíœ×›wä‚ÇN°j¦æ+Q·FLYûÐà–pðyƒ>qÚvÜÎ!=nÞ¾‚ áÛ¸ ‰É ŽáV¹ÿÜ>âk".ÍÏJ©L–õKõ¶¯#óx$÷+D ÆŽsô>ÝŸÁ#…#ˆcñø^-/Ç¥X·lnAk ’þ™èÈ£]{ÕDÚ¦QONßß\^¸ß…F‰­Øîîó³Ù&´–Ú¼1h„2Òm¸½=ëcÄÃC&aŠøð›…Æc1L޼áúú™!ß8ï£èÌ^P+7ߥ¼|8Úy)°<Ÿô¥.S{øzïqTcü¨ô¡Á›oØfMó¬Y]~—0JÃØÓñŠ{ê~T¯EòýÆPåû*B’ÜÜ*U¹ËK¾U/§{ºëMÙÂÅà„ä“X¡Ü•ôûf’ß:¶dûÛ2%¹G–µ0Gb)»%’ØAIÎR<Œ~”­ÀˆÛ\ãó IŽÝUZÜ»ÁfZ]˜ ¦ ¾sN†ç¹nÿœÖN·¥wg$,h®hîïX+CK®,ŠŽ$‘Ò/›„º˜¿Þ]6‰øáŸ…‘v÷»ˆi؞ÄIôîcýà€óËI™›˜Lôï™.=ýnÜmd¦Ä×b¦¸€ÍdnFG7… Þ*Þw2þÎåB"äJ!bYߦ‰’Ó*ëŸÏ2ò猪ÐÓ4óÓP†Ù«-јü, ^"':ÚNý —W·ã/šˆ:ùªêµ´à›£]…É@áâ5ÊNE&ÓÓ'¬G*ù-T Î2ϬäåÛ/ü¼p*mHE„Ï U¿8NuÖ>x¡˜±½‘µ¯PR~gµýqÍØÑ齕·Ëêñ¢™" Æ¿¾Ñw ùpûõ ïŒQo®èézÃK÷‚b‹Ä¥wž¶ŸˆÚê«ÆRŸvzŸ«±ÞäÒ‡îŽñä5§4–P/Žu¨Žd¤€«ª3Cdh*Þ90SߺÇ=Ô^Æ+°å…Ûe(ÞÂ)?7÷,Ó—ÜÔ.ß­Ë®áú;4åý¨$kUÂ~˜&çz¥-Û¼_=Y1s›S¶¹âÝ|ê°¥XÎózÚýÙ¡ÊÊ¡jbÞQO‹!ÖàëÖ™»tŸB>fËíÚË ƒ¹È¬„ËèÒHv§¦1ظuÔºé2v s¤”ì_­¦ã ¸»µÓV Þu¾ÊU%§#ëŒ?E2¢RÔ8Î×”,ÓZܸ°+¸Îp¯³mîe’çsUOs6ÿÈ*¬'ÔÑi!¨¯ #~ÜçÉÞP9x®´²)¬‹Ñ ýYëe¬ïá—H…lk«ºÐÏyÆÃ÷¢¢4ÏäÙójÕo&ú,­Z£áá<åm“æ1 9`9gê>Ôžž>S»NÊÑOâÝNs ¾„˜í›o_¤l§)·>+Œã«KÖ½y¹j®Îh'˜\¿ÖªÞï×äÚohm>‘IKÂKð’UµäCšºòܱ)œÛ1žÏÄóæ»úËlª2­!]ý}ЏgsgyjZ³úNµOtë,š°5mv#ƒ”ðŒ©|—'noÝ–žJK‰¹ ¾eûý­¬"8£ÉÑvµºÄj`x—4o>в$ˆ|MWÈÅ!t‚ðÐ~H¶[w칺Ûy¨µðÐ/[gjYXîc|l©Î±Õwɇ´RwÉ=ï%<%KÇ1[“ S¼—t;ªØŒ"ž_UCJ.—Ù¸ ÀO؈¤ÚÇ:3±Úxš$3a}Mx•$R÷6:È=H%ë#Sνl§„ÕñÄš¸ÕK¯à^ãh¸è-J½<¹eyz>›;À Œ¹š§ŸÌ.†B‘bžy¨ùJi9>˜?™ˆe’jôàbÙ©•ú±h”šÖåÙ>ttùMéI­\§fh«@’*‹¨ Pv ó”gQË`* HË28U>!³ü¹³|êдZýXÆ<ìu)ª·Äð,'µ7(B~”oº6TZËóš¼°ñuÅÛKF±èZdHæ›™Ò>Ÿ­ÍÁžd<ãÜ%‘K5wÇ5Ü2‘aÖøˆç1ìþUñõÑøOR—ÔÊ6fÅsžïçUâêxn®p:S£ŠC×WÄ_Çòá_²¬F­z 0‡Ò<Õ›M¤‹t%áyWqtÛТƒz<¡+í|ÿ3þ5GÈVO›`Å,É[©€{¤GO-u_€g8%g!ñÕrgOÃ×)e<`ÒŠtŒÀ.íÝ.è*Ý"¥É6~˜æ±°õiùÛh|Ê¿~졞EpÂtÕ#.Á5SܺeGç©æ Téä‘#)Šd‡Iœš5ëËŽÃOok¨nIÊu¡RfpLôFÁ}$ÎBJ®…ŸÊõÄdƒ]þp)Ì/mÇ2«ä­ùÂXD•MJÙ%mR\óQwA\aï¼€üH"L!K”qŸžîkÚŠÃ,ÕžR‚GE¬úHw?Ã>Fܯ×ê8Ƶù…@-aßW²œÖq”…ötž´ÏÌ1ÃqÍÓήïy!Ü(Nw2˜3Tzô_ˆ©Ê!hÆzœõI%ÖŽ+X²Þ9&+F¿ˆíÓÿw*¥hm¯Wš,ü½“[‘P¸6ÔÞŠÅÚ¸¢ÑG²{“k£‡ ¹¶ý@p/õíŠmHŸ¥@Oá¦N-$(Gnö]ÿÀîdUý-&²}§ ,«è"»£ÎÛW;­»å6»BÒ#i}<Ødû(†®²*‹±ìêHZͼëR=ù6DåbTQý¬'nhø´%]³€ÝúD÷±Ž©*å Päf”ÇEcSè¡„¬CZ@i#€lü¢§áTÑP~Ó’ç\^ÔíÏR\÷ùôK Anÿ€å”v´S.fœùÊZ®Y„ˆ˜ åÊuò}¶@<õ$K Þ×Þ£þ§ÈJ¤÷A¡zŽ´ªùúFÄ,ÎÈS1aó#Ñqš§®¼ËNF|݉'ÁÕ¤áh¬:”)ÙXôÒÝ|Q ‚•IF±^艬èo„yuÛŒG©£™µ–…£Æ‡X¬7'¾;>¾–V;¨ôqJ¹±È\:€?òg¹¨!¦•†ö‚×£oë}ÿºg{g¿Ø-)ݯi¥DC”Z)MëJ KÀ«ê…ë]¼òÅA£¬o ~2M(iŸæŸ$6Qy§{ÝþÔQÄøTµi9 ‡ø K؆J²ìH¸ƒ”-6i/‘çO¶‹{ó•Æà\«Ãf4‹Ús:çØ•rÜ0Ÿè#”§÷´¤‡½A"•Ç#›»5Æö,Ée¯ìx¶Þé…[ÍÂ*½?qˆz¯‹šÕ(‘u*k1éáѾ‹pÈât”÷²r(2Íê²Ø |²#¨ú}‡ÉšTAØóõíþ5½,ÏÉJ†¡[žD¾?6›– ç–îÚÝ?˺e‘åë3–4ÍŠ |½à2-òÜÞPaß–³÷©¼_‚ ŽÏCÙÎ£È Ù‰•[>òŸ{ošMVàÿþK¡[]ªì—v$í£h'V cf÷Žo9‘/øp˜ŠÏgŸ‡½Ðî±±k‰Ñ5‚ù™%=ðœÃãË ?%³ì‚ðO`],uwÛ+ëé7)4\Ó|~zñÍUz3?„È KºêH½ßoïáß‹4èÅ?õRtO\k»2ºjÍÉbùX˲;:ó•j®N×ð™¶Tùˆónh7ÊͽÄE‡¨QW¾ Âþö¥pj:¬{0 etþ¹‡1ø€k[ÀͰÿbyîm P½Aº $Iä‚§g® Yü蘃ÿnusñ·ôO[v‘5t§GUF°;¹Î½g€Z:_eXÛ"bž¤$â?àóøän)!*/¼îÌ~°†e4^¢7¹Ì)ÕHµ¡¬6¯:PíWÊYÏ(tí+åªãÕ3Þé\K×S³”»z®bõm߯?k|eÂsßÑOž€¹ž/ƒÌÙŸµ›”‡ªÖN·Zõ¦•»¥ vjÛ¤ÐÖø¦ç`ü¨tÆaEr –+À§¼E5pN¸ç·ÎÆ–üÎ5þ¢Æ³áœqò6òY?HaºiÑcøªñþZ‚æô4ÑHÖû;i<¹Þƒd¦ëÒ7ro=Õ C£G<÷~N°0ôº‡¥Zî*ñ“°&~&(-Âþ ú|l»M:îX8>‚}Þ“üÄÓãq˜˜“q,ä½B/[ –K‰ú‚™ÑŽ$Ómpûþ†üâjpí±Ü!,n+âæË´3ºÒa“Þç·g™ØÝ÷}³‰¯[DxZÈÿ†½±VVyl ÍMiåx_Tz™Öm"cÚ.UK ›¢QeT%#"âŸ~w Ãþõ°Tû‡<ÆAŒxQSW¡¨:аԣѥ~O—¸Yq8A㎦ã&-öÍâm¼.œ«*ª|NÏåÜ-±76ï†o©™ât9v”6d/¿?ZŸÇqms“—È…“t†c­^×R0nbš{™Ìý³K髜ÜŒÔ ëO7=kž®ß¸¥é¿o}œ–®"ı•¯ÜືŒr'broV?çðutzžÊkïÊ:•ŽªûÎjDdœ%™âœÓ8&TK›?öðq8åJ¤1&ƒ:.X2ÑŸJSkO㻟÷B Xi±¨ƒÒ´©H™E~’ìÒ7¢™Î?ÙËO´ª” õiw³„Fw5‘*g%­u(+q lo“ŠKгq…÷ý`ºcgùġʱ€Z¦BáÜSY#®Òè 1É[¤,-é3QþÁOéÅPé¢ðˆÉ èÂq6'2nÉ®b7%‘P4cci3ÄLßü‰íÜ ½æÕùgHíµ×|ïDІu&oo$¼F¼xd SQó£?õÆÏô endstream endobj 90 0 obj << /Type /FontDescriptor /FontName /ODNUDJ+CMSY10 /Flags 4 /FontBBox [-29 -960 1116 775] /Ascent 750 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 40 /XHeight 431 /CharSet (/arrowright/bar/bullet/lessequal/minus/universal) /FontFile 89 0 R >> endobj 91 0 obj << /Length1 1393 /Length2 5903 /Length3 0 /Length 6851 /Filter /FlateDecode >> stream xÚuTÓýû6-N etctJwHƒ0@ç6`ÄÛèî‘QB@$DJZi DAB¤;ýÏx~Ïÿù½ï9ï{vÎöýÜù¹îûº¾ãá02V£ï#4Ñ(œ°(,T30µ’‚Áâ 0X ÀÃc†Ä¹ þ˜< ‰FÉý¯5 ŠÃÛÔ¡8|œÔõpŠŠE¥äD¥åÀ` ,ûw #T‡z"á@PB`"¿7ëŒB{¡üþì‘(¸ýOp7sÒÝ¡£þ'oücs@à€’`Y)) Y ˆð†9Šü,oæã†øåýiÆ#ðsC»íñ H{þà‡…z"€8Œ"Àï;þ}ˆŠáHxá€Dþ©Ž7#ìŸñËÇ ½0ž{¢@ðÏÏžlñô‚£Q.>ÿ„ÿÚ¯ˆ™šºªÁÍ߈ÿãSUE{ý„ÅÁ@aYII ¨¨Œ$PZZðï2ÿÀßàY È?—ÿSQeÊþÆ€Þß8<ÿЂÿd€ÿîpç2ÈÿõmÀ’`þKôÿ[¿Rþo¼ÿYåÿEýÿ¾¦‡‹Ë/7ÿ/ÿÿᆺ"]|þà©ìÃËÂê¿C-¿¥l€€#=\ÿÛ«ƒƒâå¡‚rÀS\XT–ømGb5‘Þ¸süM¤¿Wïá‚D!ŒÐXäÏ7> þ/^u0gü[‹_Ø//ª÷Õ@ÁÐðŸê“”B1¨Œ'™ž~¢x™ÂÞ¿ø ¡Ð8| 1hÆ~® qE¢<°?­€U†y`0xÝý"¾íßç_"G ¼0Àô&îô"¼ù¨Z…ÕKøë;²OŸ[c’­º£%q¼“Oüõ/ekº«ÞƒW\ëÏ0šz92áÏ*¸q4èmÓž2—®ýG Ñ½ º%œßw¼ÛG³8 IgÄ,Ðl>0¾NuBá{h9q!Ý!¾\¹TtÞŠ]¶–]º‹¨9ÒYq *y­kDqVÜŸqo­l¨i1L3ó¡s¢8dâ¡js<ó±Ï$1ëíìì›Üžî ñ½Î*©ŠH:fz_]޼þ”^f†¹º X^UɵgiÉœÌO]#y爡ÝÓÙÆ×«8(sÍ{š š$ʬ֩Q]axÀý­î³†—ChE›×£óa)'³›º«üõd_•­R‰þ}E‰Í»óöl{Õ¨È)óYä? 4z7µ;™´¨8À£•…¹‚Êäž÷U|L̉aóUé<ôô®Ù'£ª¦‹ŒS2¹ƒ0‹¬* áemzÌ(Ÿnsª`&»ê#¿o º½ç]ÿœ&Ý"J_ÁÍÝ•mæ¿Ò‰0&ñáüÓyÒ'¾6ÃN°”Hb ‰â2 ¶éeLÜzæ¢îÔÏ"vPRÞžÒ³ÒÂûä뻞›[ñž³N9O¶áΓýýWÒoõˆ|ã´®(H“¼È`¼ñ¡™8 “ÉîÝ|špÒ7ßáΩ+áw0¾Uk›î„wED`3 ”“G7çžÆS½»ë ½P¶Š›ÿ &´jþ*˜´³Æ'È¡C…¶¤5Š_•,÷6Î7èŃ’ƒ¢ðÐ÷Kxv‡ã;IvÞížò XÒPÇd±nE™ ¢ ±ýÑ·i?ÙUë¯ùÔw—½öp•µ6òkÉè­yßM’ATÉXWŽ&qúx!‰HcöÄc õ4µc1ì¨K$+‘KpI”Eì–›¢ÅÿÝ5vI:wšêÊaw+5^q V à ½ÅyåÃ{·žàÊ©eígçJ% ]`r\Ú]HsKMV˜ºoN»' §Åtݜݶ.Ec!ÄGoíˇm;¦u‹ÛÊ79Özí_$±ÃWZŽ]³%c|K¢©YŠ$ä>§2ÑHEJíƒÈC7U¥ZŒÇ£™ϦIBNÝ?³µSÇò%Ò}v zì"ívà®ý"¯mþtìÒG#È“–½™# áSõ²"’q§°µ»7N1˜Aü–…ÜM[‰Û'¬vߨ(¸KœÝá ŽÉ ÿžltCN*ÛàGvÛ%Ùˆ÷j]ìAjŸ¬ƒÁ GÌ5'I:´‹jðãô7 ¤~@ªƒÐ‡]®ãÙ‹þLåÑÒ«oÜ¡~>pÄØ°ã¡ä!J «ã2+y zÈ\ì¿ aN7šÝ [n²ÐZè!¤ -Ðý@S£àµ²’Ít2Æ’@®^»Öek‹[Åç{û=Ò ({H˜O[>ýˆ£tÙíùr¸A™¤ù;!Åd'!Ä!Ä\Ùq@²iœ<Ð;&0.1‘Â\±þËuÖÛ¿æÛsbֹǡ%èÃh«:•ÿÒû´\zçF3±;·uë»#ö<ØùLIi]QÒçgž—µƒ³E“ˆÚ“1_Ï£æÂùB?ÛµHM Yö¶¥Ñ®SÚX¹n[™(=õiÊæÐJÂyòSh¾ëÍìߟøQ²_ÿB¬M$7¨ÅR´=ë" n "¨Ðgξ²WË»=V¿LiRä;L! 9”—X q³[©¿½évZ殪¤¥â›Š9šaàKˆš{—Ds'å¸+Á¹Î¿hI‹€Ä8­Ç¨.xõÃyu—«Dt›]UËJãHfÜü­þ<³Öc÷ba1Eþ™º+-w]¼¢¸!ì_7ó-˜ÑTI]¶§¼ê¾õññ#’3â…Á¤/_)nú@—‰Rè¢{ª'®ex+!õ Æôêa¶Ù.WXÓ$mùq x1m€åÜ¡¨ÎÀö+ßuºÖÒL«ÇÌï#Ë â_ˆsè,s_õ÷~ÚQòlRˆ÷…#GÏtس˜ø©a–u÷vÀRk½Þ)¥ÊÂSÒ@i‹þññîtÕ4ïCòÐÑ>u1©¶ÓÅ"ŸjtÖ+¹¼ˆAލxNõ <+×ÎnvAS–¥€ÉÆË{}Øy Àº,HEkw!Ž©ÑéãqÈâ÷ÅùÈ “ƒöªÊ­W®[¼I/^ôØ®E£,ÃB¯õ ŸJò6_•â<ÿ1ù`õ@}²òà\|85Rcµý˜–»gªo¦2oGQÑkÚä,¤7Ø: úWýW™®…v#l錜ÀQ<ç ©wR\¯¼:Jšò¸f¤Ît°¬¥”®Ý2f¯õ»¸ÉRæG;Âø/®Xm‘z)élw„t™§ö4¶\æŠlÛ ? H¾Ëj´r€æ¯7±¬¼±Œh¸÷9– 6HÖ—¡2×ÊMìU¢tm£:†Q… PÈ}ò¬<‘¦Â°ƒ¬^y¦8š¬!vufB'Çö¥ÉboÛÍ7Éú™ör— D±—Y [%‘–@ýÙ>âsz{kªÔ“lÍTD®v$3ß1õ5'Y›/÷ÉÇgi,¸#¼R"Ø– Y›ñª iÚ œ&Ü¢¯ó$>Ç<®ŒxZ™!×qÇã|tñyõÒëW¾õšœl3MœŒOùF,Ä…¿¹!MÛ„…²†/„¶kmÃCYÓ£ßñ/(ŠzÝàs)b‹ÝqcÓa¼®wž¯Ê7ã¥ÖÃu¯“ª“¶´GŸ4 9Ý(ÛÕwzÏ¿²áCDvŸQ™nÔ1âÚÿù¢)CÑüÈ'“»ÄaεÝE«1úŸ†aH#•œ$[]ņd =†ëáÏ]=kîfl—2͉ö¼¬…jd½ ¿?y¥+ôâ&é3eÄB7u˜œ½3ßjœnø˜ÿF\ÿU¾÷Aœs»;œÕXúæ¹ (}À´GnÛì÷*¥BaiˆÒÿºÃ óšÞáèR·ˆõÉØÂê q˜oδm§%Dîi¨I GšnÁ¸‡È &Z{¤Úe¡GlÁ‘CnVѱäÖaõ²˜Z‡ˆæ4.Úåå7Á±Ëc/GtC>""áÍkRjÃsü)•Ö‡'ŸõeÇî*Ó0[¹+> böî"¹.’—¶RaøQ&·ªì§bö—“½àò2S{á†Á|t×x ˜¬rLÎÞÂ-Ï*k÷9Xó¾+ˆlÐrDö¸r•ÞénõÐzÔ˜0Šûôx¹M"ÔŽä%@ß©“ݾ UÄÚˆGãó“ÇnÏ®“èŠD¤µë¿árÞÌKi»G¿¬ I:¯º÷#·¢š Â×H¿Ð~?!éÖ ¡©b™ÛT¨ÆBQì ‰”ãÍw¹!ò¾,oi¿“š=s¨8+6;)º°8²å3â2φŽ{š’¬ð%®¡…@g¾pæV–1zp0ê™?¼Tã¤ã;_ü‚`J¹­Ã½þå'F`Ò¤à2³°Ki¥2ÉçDrÀýÄáÅú‰Âê³ÒÇ£ïˆj¦õø®r|›¸·Üvle³ÜP(ƒ^ O`i¿h¶×Úwœ\hN®É3ÎO¤¤M"a¸øè[¤xÖÿr0\»-%»è‚ %{ØDlYÛK2SQˆUf)W›Ÿ4×8Ó ¼¿ùÄa÷SÔSí’ƒ1A½Êz&ÊæS©oµšh¨ArDÁ¼õ ÓHň J»süÞy?r·‚ROë¸>õ­_F4ç*dXc?'ÕΑHhýLQÏKËbâ9ßµP´õÚj½dÇY±ÀÛY î[;åR6q·qwñ!z>‡”Cµ|¬Tn¹G?»Cž'­g­ôYÀnú¹¿á!ÿ¢„û$ꎳ¬Û¶Æ‹[†Èy‘zÉ›2˹Rz–vÑRže[*Ø/K,Ãé"Ï;ß”dÖ±šx÷E9+o¨Ë¾×#e» ”ÊÓGLÇŒ'QSæ«úöqëG?sÐ2ÍpX@½9|n8]Ùÿ¤a¶®°ÙïyzKõ1jjSÀ Š\2R ÿk.ëóa®‡Rølß®€ÃmÿJñýœW•-¨ÏÑ_™®?MÝ'dý4ÙÝ]¶Çh¦ê6ö ‚Æú˜HK2«ÓŒìëÊœTò¬ØÜï™[iþÐÝ*”Ýp„X¹Âááù›îWF‡=dO«œ¶ºÓÓþì¦ÖR0A¡£zÆ O}­Š&AÊC1Î÷7Á×ëés¯´‡+fM‘›,/*Py6?öçôì%097[\üÈ s½hºÄ¤y)ãqã»Æ*mÖ³‰ÃœÚZuõµÝJ¯2Kêžxr³7-w1íCJ¦?iZ ³Øøýˆ!ÂRøÒNC'C›³¥ékîtÿòIüÇ©xM~‚ ­Ùôj•O†œ=ÚÇü¦×[ùª¤¥â+‘í˜H³PÈIS–Ã!Û]&.äɹ§•êõ;òßo;åyv;SÈE˜-Ìô]ýÁ+glóƆr!úƒy˜xÕ@1’П2r^7º`AC§·J4çÐH1h£¡åYÙ]úª~õ©RÀ5éåºÅîtü»¡ÍR¯„./46˜»u÷³×€>”D¸ʸ¾¸“•;…nøÕ”íy mZiçWÏGÔ¥„Î¥ç'‹sI6釣é͹,‡`t© -¡Ê†¸‰0É>Ö<ªjëærÛìø^™¡[F¤]Öà ¯=½9õCÂ*óß°„á¬}zü*å¡9׃Ô&/¿´gFCt–èzßÜü0âGÞ}å¡BJÎŽƒó jÚ!Ì:€þF£×ô•9µg[\ätðA)„w¡E\”I̫ѓ^Ýh}l ¹ò½±f] *5î-r«žó,?%e*xÀ_VFÂâ¯Îýç 1EÉîTìǧ ûwÅL.Îúï!›fäó§`å‡#~°`×p4Kñj[ÁÓ“Øð󬥄]˜ù[¹É«IÂôY*A°ØÈÎêôµÏy*,Tz$)·IMƒ†«0úG¡AåÌÕ°rù€:O;¿ìk$€Â¼G ÷ #ÞËTŠ„UÄZn$¥_;¡…ÆáBdòŠÛ¾š%ݯØzu‹:€”ä9ƒÝ®{+›ÅËss6zmïåÄÞ7¦Ãý„˜×äßLѕđ’ÙºÝ{„édzGÒqI²:Â=õ‚.g]ÜfÏâ/ µCL8g®í=jž]IWU8ýàtÚI’l¹Œ/ÃbU^øGÅxoÚ±0’QÁ®cù>µ¡vouèKrá+HïéR©õ—è5e”s¼ð©æŽR׫AkÚdžœÃ6ùQ²b ÍÆ­ê‹ìï®óì…ý)}AÂRÏ¥™ás5§¼ zÐÜ.H·!äJ¤ã`dÛÄ€ÉúM]9åŒíaRœ \£l>:ôM]Š8H®šÃK’’3î¨üÁlJÜ&ÙW\ûÞÃæÜR¯>ZoÆ©¶ÈZ!Ç'wE¯è^ÅòNŒ½n8o]”òoËÆüÚŠ=’ï²ôþaÚמn†—Œ96PŸç×{mWªV dÈkÆœ3«.T·þu×ò}l„÷Úܵgœ5ë9ªÍª&c0J¦LfXèò´–{þ¡gaÓ%ÛñÀÚ®‡Ú‚²€ô6Û^2µ˜î‰áŒ7ÆŸ™ :AÞ_sqd(çHá$]O9"vc¥ˆ?ß‹y´ÕgÁC¸Cóp<Ùz×Pœlq¬-¨þ€üKÉÞ[•/ÖIpx†ƒÿÍh@E|p3—vó©gbè®o@b)íXaµö£4‹w{ÁËǤ¸îëoG„@7]¦rMFÞ|‚Ð"f2Á«QÆ?N÷2dœÍÔŠS‚¿Û>u5׿|?,Á€ªaQÜ+i1 :ù·N-o•Ï{0ÿøzBv£`’æx€Ëa9w†‰·Íã¶ÔJÔ” ‰á7Ýà™Ý S[¨˜yÉ>Ôwk_¦°Úðnt†•wؘ'“d*w Å^&ÀC%ZälUq ´»ŠA2Bíôç¬ nïéP×+–Øõ”¯fÞŒ¦¾ ¬¡Ø"õ/z®(@¾Ô>xߢ㯺o:ú]Zßå:R|@Š7tÝïrR |ë7šõ·n]Çnx¥RÍn®^º¯Ò¼[_BFuE9ìN 'Ú¯¦îÅëÓqS#Ëù©}Y §ŽYjȼÆ[f-UeTæµÕIçÄ‘+Å×dèI‚t¶ý:N®õˆçߘ7;ç”ü£žÚRùFgÕ²¾ëÖȧ ¥¤ýþ,Ípᘪƒ[ŠÞ (TNgyÄÖ8¾Rž/ì+v”³«ºÒyËû¹ÂË'õ3“†w?¼œõ| ¯[_z»ñ®·h5äKïF ³ ·(Xšøv€Æ½cUen© ˃±Wá/¿,mc4å­¿Ê™hÐTÜð„‹>/ÐyeIîíÿ¦Àáçú¢cµ±»×Äü£ùëúמ }òâªC†ñ|IkÕ‡×ì‰öw([ú¢¦Ðßê)¹¹ôfá—U‰Üâ‹kë„àèZg¯†c/®æ¹MÂ(‘”—˜ç2 T]å%'QÒ ÔwŽýYbÒÑ]³ YÎ'{°bujcÂëû-üa;ÁõCA|R„‡kŽhë3œب°Py<ßJ&W·‰ØÎ9ó€WDûŽV“WhÑ x{È{oébð‰ ¯d僴œ.ºv÷7ÎT×øºc¤åw¿mì-ö:¥wÖê@íúQÁòÅÎ-)3ׯn÷Ç2 ´Có½#ªýwt+œÆVvÛò*—I)W UÇå»ÏÙíF‹8–©’>ÉQÞï]8YSo‰\sl9iã†å'V\¥¦‡Ì ˜Vj6kATR ÛŠ%vxs[Æ 5#¾”)QwN^ÚˆmL÷*3b§ä+n"r5êÛ‘×–ôÎÑ=s÷’+'àkÛ1VéIp0kÝúÔ$9\ÅÆPé©uTôC»ÕÍÌ€^}ÃnËÕ8VÜÚ Žã%O!E ‚æ8ÿíh3*„?òóZĈu–p?}O/]Äi|„±+a°hb15ËK ˲¨Pô«âÈ]6ˆ•T÷§µêu¦yiïÒ5ueCpgUŒÆªÙ»«s…¹} >i­o{ ó; ØÌÑeéÝ>|¼ÐÃ(ô‰»™6{ O»¬µÑLݶ?ã3¤ÈoªËáQ~Kᙘü¢hÈ" j­=£Îhš ~ðºàÛ­ÿô¸J endstream endobj 92 0 obj << /Type /FontDescriptor /FontName /TMCDBM+CMSY8 /Flags 4 /FontBBox [-30 -955 1185 779] /Ascent 750 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 46 /XHeight 431 /CharSet (/minus) /FontFile 91 0 R >> endobj 93 0 obj << /Length1 2367 /Length2 9436 /Length3 0 /Length 10811 /Filter /FlateDecode >> stream xÚµTÔÝ5,%R’:tÇÐ)]ÒÝÈ0 0Ä3Cƒ’’J—€„„(---]’Ò’ÒH#Ê;ú>ÿï[ë}kûÄ>÷ì{Îý±0èèóÈÙºÚ@”]aH /¿@AÓÀ(àçäåçÀca1€"!ÿØñXŒ pÔ&ñG„B¢lŠ $*PÓxèá €"@Q ~~€?¿ø?®p €"Èj Ðäp¨½UçŸì`P\\”ûw:@·‚A0€&éqAUƒœú®`(éó v)$ÒM‚ÏËË‹ä‚àu…Û?ààxA‘=÷„Ø~µ й@þn`àEüåÐwµCzàÊà C`TŠÌ ªôÕ4ÚnØ_ÁpþäþK÷wö/"(ìw2 vuqÁ| 0{€ÔÐVÖàEz#¹ ˜í¯@3•òAA6¨€ßG”åt T‡÷‡Ã¡nH/êü«G¾_4(™•`¶ ®..÷ë|ŠP8ŒÒ݇ïïËu‚¹zÁüþAvP˜­Ý¯6l=Üø aPwˆšâß1(ÞÍ‚óóó‹  îˆ7ØïW7Èo'ð—ÕC€Ÿ›«ÀÕ$jAýÁóC€·¨1#¾Éï&Ò+½HïþÒýù 7t9vk‹ÐMý8sëAÚf‡ºõàËj‡Õ÷8öàã¦Ð vÄ N\Á·ºímÆÐ xýnÕªêÇ·%+c2Çz;¢¡œöæñk¼ÄŸ5äqÊ¿ÀjqâtØ›¤Ly”"FËÛ— È0™"dsÔüLZÙî ONްsƒÈ„võ&À÷# ¯÷ò*°"b–¿]Nû_æºÉf=TyW»ÒO|„úX};ùÆÔÖ¿œó}}Ìû –i¿ÝþýX“³¼¼¹\>3ΊB“j‹OaRw¢¼©”‡évXm“³&ƒÝጜiÚ^Ò1¤¢ÊõÈøª^KòÉiºÌõGóœß]>ª¼!‹l{‘å%?{8ðö>ðh¾þ©UÉ'–úRÂß¹äcŒwȶþèM\ØóSÝÇÜÒm]F Ç­¼Ÿi*n“´Dìc0hÜ©½ÌúR‘aRNþ‘j×=<ÅÁ×Ý̱€,Ûâ‚GºöhÞÊó¯äÝKw\ùùz/Ž%í9-*mdÓØÖ÷R'Ž>¨`’cVê ! áGa¡v/BÝñ§Àyú â›Äf§l EŸˆFÁ‹ä¸-šßÖk~ÁOæÖŒCsÒ×¶«¥{ù|„LÖ¢a=-–¼1™|Yºå¥«ñšƒo&XhÅã;Q<”{)í±àhþžø½ÞÌþÞfKZX棕jx»ê›O3 V5ìÎG?¿{aÑù¼ƒxÕN¾ë˸½w úÚÇ„“A}È%9éTœØÞ¶-Ç Ts¦‡›Ð(J{RÊTÓ&ŇUé ,×wmU…kj²ãÆ\Ê|ûŸÓ‹:Ž‘ù0ñ9´Î2¼å¥Û›à×ê%û??BRÛG”Åð‡€®bšp?šË·Þùú–ãéÈ, “ªÈo§-±é”ù]€(UP#Ñ`Ý1 ł˅ÏÃcâÊKw=Õ³÷T$«\Ôú;8añªÞmLìÍü¡Ó\LU;<ï6Ô«7Ú—‚ä«Ì(è12LL܉áBãyâ\`ë[òºS?„€Eéãõ3¯Ý&Uðˆ;èì.ÿÈœL|zL¾)îþ-z’ùOŒ‰|Ûà*Œ.=ŸZ/E)ù9žø+cí]M'¶Õ1~µ…˜a8õ¦3ÊÉôh¬ßJi…{'*ïüˆÏÃäÓŽy.BjD­QmrÂ×qPÍï;’ÚNéÒ¥Vè¿wÏüZE/p +àÌXo>{€Uþº|GÕ[Ó&V Ñ;°¾G01,¬òªßoãŠLÂh¤ßx‡wXµv <–="3l†)#¿Rý²{°Ñ¤>þ£K‹¹Ž.˜é%þª‡-Î*Þ’‚ƒwæøžl”ûÞÎÏþ]Ø NT_­õk6%Á/ ì'Ÿžñê Os ÷ÜÁ¾(«?tû@*ÒŽo¤hb„Ÿü™ªÃØI:K† Mnô%Õ67)Õã½\æçû}ôUæSzèç¢%: ,ÄÍèä™û¾è³KÕ[EÅ}Â.è ™ë"€ƒY ýnŸ‘>Â6¯xª(ŠMýlž :0¶/ ÊN£V0ùKLF§'Ë •¹o×&J娮¦î©Ð0㾂…}x!«Ë¢'¥ ¯uw ÈÂ.³L©îÁ<ù„À2u5=„ïæS÷ü°Lö0-ûÎJe3"Xê_’cé—YZ{‡IcKE†²1p;ë¼}¸Ï®H#oQb|}æ§ÑJØ‚ƒk ?öçsì%íÇ£¶ šÿ¡ Z1€Þ&ï¥òQØ#»²oÔ¡‘?tW”á¢,ntVMBLù—aw"OßœDÌÚ}`ø¡WÛ#b?»òÓà{ÙpC2´%ùƒ¦[ÁÕCS£õèn­¤ˆ‰¿Žk¦X\yõ€Y{A ¯Í$ê´é¯¼_¹yL·mÎîm‰ÒŸŽ¾g,>¹$ýÂSÄÓ£«=`“±Åè~͵#‡#Þ¤Õ-x‹øäšÞwà^v·l%yKO65~CWÝpsA:Y”ŽWæ'W UþÞ+¢N‰ VÃ]lî@nkVXßvÐØÉ÷™¢\‡#Ïã"̲„¹d‰|'œ•Ç­ØèêF<’iÑ_0±ÃùJnÛ<ĻӖ>œ˜Í‘â|a¼qÕ*{ÿ¥¹¸zÆô©Å.‹ù+7"Ž{d…ë OYYE6ñ¹ºz±õƒwg!1‰ñ ßηy¶Ÿ=JhiÞÍb1µÓµ~ô:þ&¾DæÕ—êeU”3ÙN{²*ïÈsOMkèѺ•Ïþwg‹n¤ã'ºóÅÖ¶V¦û;ÉÆð7ý™L¹µ¡nzFÄ_ýž§ç†êèÎ+Ü-yê[5O¨³(&™Ÿ¹#ÖÙ•¾Z¹W—IR“ôómv±æêÐCzW_JƒÃžÅ иÚÄÌëÏýÎü;e›7¿`gҳ̔ùI{¹Ž7Rgןìø½Î¿þêÑ“¦/‚‡Å òv¶À‡2YÛè­‘?à-öC×NeȬHm–¦îÈ,©ßûì4;»2ßÉ7κ¤tÛ©–OGfJ‘LV@òK`½n‰Úéw¢¨×=2$Çž°ýÞ%1K‘„ЫÃÙœ\ú…fð´^Þ¶ˆÀ´´Ñ5=ôr JñX›îb Z’Il4lRoyn‘0¤ö ¾Ë¸` ±ÔšÑ> Þ…¡Qñ—iß7pYæ|ª‹ÙIºÔÞ }š`ñ¹6é™HîD~#AÉš“Eƒô|Møs{MþYfR„êb–òí´^铊z¿C"Kªª˜þŽÄ~‚Úå>R´iÿÜd;˜úúÝƒÇø;Hmä“û§•DUNvZ‰g©wx Mëé³Ç̤ü­>ß“ñòÿ£ñ¾åO«Ö=¥KœüO…WŸAqEâŽò¯n? âµî“º+ÎJùˆqÖÍf{zþ¤P‹ÚRšþ³µ‰QÞ0™–pi¹ƒcHÑÜ‹KM.áƒõTMÊ;IbÅñÑ6OÞwˆaºC'’òS.•* ²BS Rv®2cj™Üvï§eÖÆ“ž4íî¡Û¯Î(Œ÷I­º«„ßsaM:¾ìð“…?sk’ª„æŒ=ûhb{ç,zæ+,L.ɽñd;Õä@áö…ÅÝ€s©øËvA‚é®—7×â•Ï»û-3"/•È>°ó\f{,\ûJMù&ݩ݌¡úH21ך¼\yNmJý(‹”£û˜Ó˜?”ž¡ØŒsWò­‘säRóež_ã˜{§ÍJž¨‰Ç=FœËÞ{à¼[éîÑo™ò3ˆü²pW;#®cü«º:Úu¥4 Ÿ§e6¡ Z¥Ê¢ž(™7Ûði_¯´ú‹]ú˜Y˜xÆìô!ZB6uÇžqĽÍ6ù…fã„?ô§Ÿ¼¼—‰}gEÒ{ò™Û£ˆÌsñH0:‹ÿ5w²÷ýù²Û=ç·€"±>6ç/Ù¾›mŒx¶¢S>¤6 ²Âé Ñs,s /m(_jë&îzPTc=ýÔG>ŠQù2‰ÿ!Ú5m@Ezª$ñÖÃj¼½TƒuÝå¨á¿7¾t,±ËxQÊÓÎ_|[r¥D8:K“ ­XsÖÖæm‰1;<ÞÊŠÝ)¬·¤=ÙÕß)ÉBÓ]¬ná݉øB¨“\bªÕðxº XIé 4ºœÓ3³%tþæÐ.óŠ`#ØoQ™ ñqùn+ªjÊ2öè­Ä ¾d"¹WxÇLýPP¬ÿZäTÄ.Ñh9{¿g>¯pµ<Ë䢚h”­Øïƒïû£Uti Ë‚‹GWäy ±ë3â^@óXñ×áØÞš`(m*_ ;åàåjÑ$ Ñv˜GœûKµ–vU@Çã¨öG‹êËXmÄÈïÄ 2†Š7¶)9ëÏS,¸›y¡5ƒØ½`SvÀ¹Cî®C—U…¼„’$}i·òãmP‹N]²Ìksð Kežv;ö2êìWåZÒom4ukª™»„Šñ ¶5hUCž7n4Áf‰pÏ<¸ ß:/±ï5âüØ ¹œ¿ º"5C—wª¶+£,ËBãœÃÑI0ó:´Óäëì¼¶Rîy R›»\æ&É€%ýh• ‘3:•[zfPjåëúl"öÛ[¥lú©XFÿLû™ŽQÃuÜU‹Z—>©ýŠíŸ³Ö±ÕéeÓÎ%ªÆ<$8²Ó¢àZ€C,‚¾c|7&CCm1WÇœãˆÌ‹M%»!±ÿZžÌKz×ÏÝqÎÓã¨+k-¥+7ÀrSiñ¡ç}ÎùŸ¥­Éê?(_¤8´%š‰M@ï0½ËÇS:tê\0ñ,ÄíךøfIñ0÷ {F÷qãVªßŠ¥°“«"S'÷k°?¨%1"Ë:§yæA¬Ø£AH ‡ÁÛÈÁ“œ'ýRà9Ü,ž¢BªCz©‚pZÍ^›`S”…ª ‰û­¬¢6O&„M^MÌ~Wp¶¥œgϸ†œGFÚ´Po¿pþa0Šd‚ÅYë [;ÈøcÆÌÛ‡}[Hš>‹½›åþŸ=•‹„>7?ç±ã^cí1ña˜¶ÅÊ6ÅÃc©©§ ›Z/Ûm›hˆŸ'†|%þÒ!rÛ?"ÈNÿã†ÖE«GWX³¾¸oú6™Ãì(ÁÕ s>Ý=G·ÎÒ|·Ê§ó·²‚NbJ´è*ÜÖ\Ǻmæ~{ý!^Io´mæLº€­—––† ²h.芶pzîY!i Ö/®PüûzÊαÙfÔݳ¶*ù7Àº5)ðØ–S¦ 92’c äõ¾¹Š×ÊþÑDERda£<'lb6cë9³…g˜zqœŽZ¬‰SÅ0SçWôȧé :|17­-yÙ²Ô6…äXâIߨ÷éÀíS1Z^8X¯¿÷hFpô›,ΠŸõ6ÈÆÜzK=ú¬ ŠôMZQh$Ø,¸¼Fœ´®òù ¼ šêY“qÛr`¿ÅS õ!¾VÅÂ,áÍ3šÜûµ~)Ð}gˆ”ŽÐIÐúBîÊØB¦AšâY†SgiO÷èäh}ºsÙѭkMïRxa¦¡ÜYø Rõªt¾*9%“¯‘YxÛݳì¬L,Uj?~"ÐqVdÔ¶ß§ttF¼|mÒvI¢óþS³3GtŸ@ÆÀÂÌãÒŽb«›jËØƒôÃI ™_B¶7±_`ð*Ÿ’ÝŸ5t¤QôyÜö:Žkây Tö¤BzºJˆ©*E¿Ma²N#\+ÅVæ£\ÒNÚ[«Å;<ö ŽÊ "f¥6$XĆÖÓÓÁäÌ#ÊË8+Üv‚‘f {˜Yš ‹µymäx,CÕt_q h$ˆ¶(?‡ésDìsÅV6öšÒ*î.çß\hPæˆXKxV+Z‡¼Iis°ìsa¶zŠwq-¨ª4±dÇÒÇLÔ ÀÍÍ®3•Áÿ’ ÚCê0¤Ñ’Ç%"RöUº.&´÷ñ‡Ú=ÃògþGÕ\Þ ÅÔ‡zË¡=»¦tÖ8r1|]̘s&Á”~Ú¯S?SÀìÛ áûìNKãòkîÇ‚¢é[Ê+ ÷NBû¦Ë’hÒqÁý©&éü¢ž÷r‰ÆnZâ,Û§d+J-¼„·¾Œ“·+‘~1‹³QÐÝ1w4"7d=tFZ2çHnùù?~/]\4‰—ÖÑK8Tï~²œ]„–†ìÌÐkч2™'çñ–)ä¼mÚä¥ï¼ÆWö\^zZÄL¬kñ8Nìó‰ Ë Ô¬´+ží'8·Õ1†|}dìÍ7Âqã(y?§Äº8‘’¾™‹˜þRh ‡T)ºnã=| áYúT²¼URÈÔy|•wy°ÐþvIõPîêH*&˜){s3ðÑ:ˆäHŽBQ=ÁãÁ'ªJ1u[¹^YÈK¡~^¶Y'h™ÃĘñÐ4zym‹ÆPxecÁžžÀoiÖì²;ñjðm•5Òů÷äö†a9ƒ®óY2äשîž&x[=g®íù¦BÈò Üe;É ï«õCÌ7'ãïè^`˜kEÕlØÄFJì¦Ò]| ï–Ýi•PJ° ª`ÝÊÃ.+ÍIq°áÌwÕJGHñ™Óg}OƒFo]C% ûóÄ£#~dÞÛçÃ'…ÇÂóÁ_ÇZÒw·iq˧B;;Õà^îÖÜ)» ÌòS^' La%k2xI/?àÆAjÍs„ÎKèb¸çÓÝymÿ½âàöšh¤éL“yµ ‡JÁŒŸ-IÄ{PÓ¨½Ú.×nÙ­Z§ÖؘÑèÀ»&Èê–w*ÒmaãÖ¾Ÿé„­ëúËÜÎ÷ލƒ¥Ö-‹Õ½]¡pà(ß9T{È”(y'FH#î‘!$›7»j=šêF[—¾À?[Ý{Íú\£¦Ñ.w¾;ß·W‘ïWábX›¨º~ÔàT6qH¹¿„sá(èoÉiÍŽ¸ „ñVK¼|›>~ëó·$Æ®Ÿ´¼ 8«#ÑÛ²y•92²üßâ"'9BKÀ‡þÅfëgCe3-v³ÅíÞó5 “©Nˆæ¯s{é Þõ€—kÊIæn°CWD<5:å'“‚ðz|²ãàÏAîÖÙÚKŠžQVB˜£ºÚ°Ý-a¾µbÿ}ÌsÉßJ¬ƒ³(Æ@e9>B¨”om›¸Ð†8ý“»YË_w(Lxcï“:|_ƒxÝz€á`ýZ¢.ÆWBRõSÚà ”Ò6øÃ¡Vû“g¶s!™Ø®Ý7‘*ff¹v¼'¦ž÷?Ú×dSe3k4Ô pɪqÅ{Y—QU!¿ Åú} MZúöªFòêÕÀÀl¯²Q£µ/á‡âú9 Ø#Áã´MFB •K·¤<¨3>£‡Sjï—Ë1°¾J8ŽÊ1íåΰÿ˜rxf£ÇFÃ@e´ÏG çó{Ń¥…š~§\¡ýH«˜`ð{´Rã O~ªøÍ!猵Fu…a‡áû´N2:V¢ßSe;7YÔ xÓrgF]µí‹•[1ÝëNÚr²¦Þˆ8¤¥¯y“jm’ æñ²CíÁåµ ».LLBݵåܤ¸DS¿²³ãA9+X¿—ü<(`U–•(ñsYŧA^AÕh,—VôeÖcdÝ¢ùþ¥ÊÃKѲ®~K#†ù™!í‚ÚD‘ŠeÉ]‡o*ŸMÊ4K5Œí¯þLÒ`í¶ åNÇFóW:ö¾rç— W™ñP…–ì’äñ‘Á»>ÞÀXþ¤Ã§u¯.&Éäµð‚§ÂÔê¨j†ÞèÛø='wgÍØM3x@#í8ÖêߌÑç„‘¿ <¨)ô° ýn‹§X’¤"êÊÈádw4^Jöî)¶ê."ÊëJzf¸^ 馬tÅ:ú±œs¾³±/*O×î7ŠvWõÜ›#¥ƒÚÑ=ºŽ_æ :S|OgÕÝ„#Œˆ ý1õÚÞ)6çAÕ«5™•¼Ò˜Øˆnï°{S_š7•ûë#ª’¨Ï€•tŽã²QX˜ÙuõϺ™ "õBåÿ߅¹ŠJœøÔ¦ðÐù(~Tß aœåÒ6>{ WÍØEÈ~k¾pÐàkñðÎ|»=hÔ_’ñ„}(Œì´«¾í,ØU q»[uÄRÅÜ&0 x¡'Õ¹n2š±ú­šfŽ™VçM¿_b4zSD_ìΤ3ûDêq¯Ã]‹=ó‰Ò1”q¼p6ùjm@×r;@›„ »yìó×Äþª·Ä¢Röo#ŽÕ‡Dë#OƒpW/9(š¬+‰Yošy‹äÌ03ÃߘºIã½|ÄZ¯+Ÿ)5éǼYÿ®¤Æ†÷£öH·±Î!ÁHÉÛÔk–>³@0 kéïV·ÏÆÛÉh:˜Í·©WÜ âuxƒX–p F+á"Ü+¦'zªûÞÏê¨õˈý%péû9Ô"G¬-~dÎy*Wö¦â`Æÿ9C yFªÿ“†Ÿr²½f<ÀÝ-·…y~V»¨ýç Òêû·>õtq¿tÛŠ •è]¼ŠÖæx¯ôùò1ÞÄô:uÈKò÷p±ÔVýº˜7¸&’”‡)Ižµ§òžÕ庚m°4£šˆÒ÷4r–aÊbêè1nÓb2Ó'LX¦»À¯!9î.ÎLw/œ x®PÏ_'yK¶0SØ(«8ð³8L^æÝ>çaãàJs¥ÅâêÙÝ£êL|×¼øÈÄû]˜›íñì­[÷äʱ>Ðcñaz±Iú9©×›¶l›MÙ(*õ^g39cÑlÈ]åÝ"~©D²QR± JŽiQ(©‰jqLÇìsè~n›RqÝå˜zQ?É}ÒMŒM£4A(áË¿?ƒÕõtˆ_mh6Ø4ùÍŠ#ærªÑVȲ·É}äâ“Cp*‹^àj±ïúÊÄ­¼'÷¾S¬8ž%öå„'„ â•_`¬gÒ$V ^=Ù*;Š_œ=vþ(hZ¨+Ãfviw=VüWÝ}-¹ùY0unmìÄœžËÌ:0d+—‰÷òÌÙ}Ÿß.ÖÉöv”tˆ<áîh »ð©¿¢eˆ:O³‘àòRéÍY!*õ0ø£• Ó35$ÿ¸|gê¤kâ-´F&Æ_=Ë_´Ìù1óð^Å,¶(vkâÿƒ=z endstream endobj 94 0 obj << /Type /FontDescriptor /FontName /MEXQWI+CMTT12 /Flags 4 /FontBBox [-1 -234 524 695] /Ascent 611 /CapHeight 611 /Descent -222 /ItalicAngle 0 /StemV 65 /XHeight 431 /CharSet (/A/B/C/D/E/F/H/I/K/M/O/P/R/S/T/V/X/Z/a/asciicircum/b/braceleft/braceright/c/comma/d/e/equal/exclam/f/four/h/hyphen/i/k/l/m/n/o/one/p/parenleft/parenright/period/plus/q/quotedbl/quoteright/r/s/semicolon/six/slash/t/u/underscore/v/w/x/y/z) /FontFile 93 0 R >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /BaseFont /QZKRDM+CMBX10 /FontDescriptor 70 0 R /FirstChar 65 /LastChar 116 /Widths 65 0 R >> endobj 6 0 obj << /Type /Font /Subtype /Type1 /BaseFont /BKAUHP+CMBX12 /FontDescriptor 72 0 R /FirstChar 46 /LastChar 121 /Widths 66 0 R >> endobj 39 0 obj << /Type /Font /Subtype /Type1 /BaseFont /XTWYRV+CMEX10 /FontDescriptor 74 0 R /FirstChar 80 /LastChar 113 /Widths 56 0 R >> endobj 17 0 obj << /Type /Font /Subtype /Type1 /BaseFont /SUCHGR+CMMI12 /FontDescriptor 76 0 R /FirstChar 11 /LastChar 118 /Widths 62 0 R >> endobj 37 0 obj << /Type /Font /Subtype /Type1 /BaseFont /SFJPTC+CMMI8 /FontDescriptor 78 0 R /FirstChar 84 /LastChar 106 /Widths 58 0 R >> endobj 8 0 obj << /Type /Font /Subtype /Type1 /BaseFont /YEEPJZ+CMR10 /FontDescriptor 80 0 R /FirstChar 14 /LastChar 121 /Widths 64 0 R >> endobj 5 0 obj << /Type /Font /Subtype /Type1 /BaseFont /YJFIJV+CMR12 /FontDescriptor 82 0 R /FirstChar 11 /LastChar 122 /Widths 67 0 R >> endobj 4 0 obj << /Type /Font /Subtype /Type1 /BaseFont /ZTBFAP+CMR17 /FontDescriptor 84 0 R /FirstChar 14 /LastChar 121 /Widths 68 0 R >> endobj 29 0 obj << /Type /Font /Subtype /Type1 /BaseFont /FYGEPU+CMR7 /FontDescriptor 86 0 R /FirstChar 49 /LastChar 50 /Widths 59 0 R >> endobj 18 0 obj << /Type /Font /Subtype /Type1 /BaseFont /VSOJMD+CMR8 /FontDescriptor 88 0 R /FirstChar 49 /LastChar 51 /Widths 61 0 R >> endobj 13 0 obj << /Type /Font /Subtype /Type1 /BaseFont /ODNUDJ+CMSY10 /FontDescriptor 90 0 R /FirstChar 0 /LastChar 106 /Widths 63 0 R >> endobj 38 0 obj << /Type /Font /Subtype /Type1 /BaseFont /TMCDBM+CMSY8 /FontDescriptor 92 0 R /FirstChar 0 /LastChar 0 /Widths 57 0 R >> endobj 22 0 obj << /Type /Font /Subtype /Type1 /BaseFont /MEXQWI+CMTT12 /FontDescriptor 94 0 R /FirstChar 33 /LastChar 125 /Widths 60 0 R >> endobj 9 0 obj << /Type /Pages /Count 6 /Parent 95 0 R /Kids [2 0 R 11 0 R 15 0 R 20 0 R 24 0 R 27 0 R] >> endobj 33 0 obj << /Type /Pages /Count 6 /Parent 95 0 R /Kids [31 0 R 35 0 R 41 0 R 44 0 R 47 0 R 50 0 R] >> endobj 55 0 obj << /Type /Pages /Count 1 /Parent 95 0 R /Kids [53 0 R] >> endobj 95 0 obj << /Type /Pages /Count 13 /Kids [9 0 R 33 0 R 55 0 R] >> endobj 96 0 obj << /Type /Catalog /Pages 95 0 R >> endobj 97 0 obj << /Producer (pdfTeX-1.40.10) /Creator (TeX) /CreationDate (D:20100626114130-04'00') /ModDate (D:20100626114130-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-1.40.10-2.2 (TeX Live 2009/Debian) kpathsea version 5.0.0) >> endobj xref 0 98 0000000000 65535 f 0000001283 00000 n 0000001179 00000 n 0000000015 00000 n 0000168267 00000 n 0000168128 00000 n 0000167427 00000 n 0000167287 00000 n 0000167989 00000 n 0000169100 00000 n 0000003071 00000 n 0000002964 00000 n 0000001395 00000 n 0000168682 00000 n 0000005515 00000 n 0000005408 00000 n 0000003163 00000 n 0000167708 00000 n 0000168544 00000 n 0000007169 00000 n 0000007062 00000 n 0000005631 00000 n 0000168959 00000 n 0000009229 00000 n 0000009122 00000 n 0000007261 00000 n 0000011731 00000 n 0000011624 00000 n 0000009309 00000 n 0000168406 00000 n 0000012255 00000 n 0000012147 00000 n 0000011845 00000 n 0000169207 00000 n 0000014404 00000 n 0000014296 00000 n 0000012324 00000 n 0000167849 00000 n 0000168822 00000 n 0000167567 00000 n 0000015812 00000 n 0000015704 00000 n 0000014545 00000 n 0000016631 00000 n 0000016523 00000 n 0000015941 00000 n 0000017402 00000 n 0000017294 00000 n 0000016712 00000 n 0000018008 00000 n 0000017900 00000 n 0000017483 00000 n 0000018836 00000 n 0000018728 00000 n 0000018089 00000 n 0000169316 00000 n 0000018917 00000 n 0000019146 00000 n 0000019170 00000 n 0000019325 00000 n 0000019355 00000 n 0000019931 00000 n 0000019967 00000 n 0000020609 00000 n 0000021228 00000 n 0000021826 00000 n 0000022144 00000 n 0000022592 00000 n 0000023203 00000 n 0000023865 00000 n 0000033488 00000 n 0000033719 00000 n 0000048546 00000 n 0000048873 00000 n 0000056001 00000 n 0000056240 00000 n 0000067288 00000 n 0000067551 00000 n 0000075169 00000 n 0000075392 00000 n 0000093186 00000 n 0000093555 00000 n 0000114910 00000 n 0000115387 00000 n 0000125519 00000 n 0000125767 00000 n 0000132918 00000 n 0000133140 00000 n 0000140485 00000 n 0000140713 00000 n 0000148448 00000 n 0000148714 00000 n 0000155684 00000 n 0000155907 00000 n 0000166837 00000 n 0000169390 00000 n 0000169463 00000 n 0000169514 00000 n trailer << /Size 98 /Root 96 0 R /Info 97 0 R /ID [<3252090F765E550184307D6A533CF36F> <3252090F765E550184307D6A533CF36F>] >> startxref 169780 %%EOF ejml-0.28/docs/bottom.txt000066400000000000000000000007211256171534400153770ustar00rootroot00000000000000
Copyright © 2009-2015 Peter Abeles ejml-0.28/docs/header.txt000066400000000000000000000005421256171534400153240ustar00rootroot00000000000000 ejml-0.28/docs/latex/000077500000000000000000000000001256171534400144475ustar00rootroot00000000000000ejml-0.28/docs/latex/ManualEJML.tex000066400000000000000000000414131256171534400170610ustar00rootroot00000000000000\documentclass[12pt]{article}%book report \usepackage{bm} \usepackage{amssymb} \usepackage{amsmath} \usepackage[pdftex]{graphicx} \title{Efficient Java Matrix Library} \author{Peter Abeles} \date{\today} \begin{document} \maketitle \tableofcontents \begin{abstract} Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating dense matrices. Its design goals are; 1) to be as computationally efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime and by designing a clean API. EJML is free, written in 100\% Java and has been released under an LGPL license. http://code.google.com/p/efficient-java-matrix-library/ \end{abstract} \section{IMPORANT} This document is horribly out of date but for some reason its a top result on google. To get the latest documentation go to: http://code.google.com/p/efficient-java-matrix-library/ \section{Introduction} Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating dense matrices. Its design goals are; 1) to be as computationally efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime and by designing a clean API. EJML is free, written in 100\% Java and has been released under an LGPL license. EJML has three distinct ways to interact with it. This allows a programmer to choose between simplicity and efficiency. 1) A simplified interface that allows a more object oriented way of programming. 2) Letting EJML select the best algorithm to use. 3) Directly calling specialized algorithms. In general EJML is one the fastest single threaded pure Java library. See Java Matrix Benchmark for a detailed comparison of different libraries. The following is provided: \begin{itemize} \item Basic operators (addition, multiplication, ... ). \item Linear Solvers (batch and incremental). \item Decompositions (LU, QR, Cholesky, SVD, Eigenvalue). \item Matrix Features (rank, symmetric, definitiveness, ... ). \item Random Matrices (covariance, orthogonal, symmetric, .. \end{itemize} In addition there are many specialized algorithms for specific matrix sizes and types. \section{Data Structures and Algorithms} \label{sec:structures} DenseMatrix64F is the most basic data structure in EJML. It is a dense matrix composed of doubles. Internally the matrix is stored as a single array using a row-major format, see Figure \ref{fig:rowmajor}. SimpleMatrix is a wrapper on top of DenseMatrix64F that provides a simplified interface. \begin{figure}[h] \begin{displaymath} \begin{array}{|c|c|c|} \hline a_{11} & a_{12} & a_{13} \\ \hline a_{21} & a_{22} & a_{23} \\ \hline \end{array} \rightarrow \begin{array}{|c|c|c|c|c|c|} \hline a_{11} & a_{12} & a_{13} & a_{21} & a_{22} & a_{23} \\ \hline \end{array} \end{displaymath} \caption{\label{fig:rowmajor}A matrix encoded in row-major format.} \end{figure} An operation, in this context, is just a mathematical function that takes at least one matrix in as an input. For example addition and subtraction are both operators. CommonOps and SpecializedOps are two classes which have several static functions that are operators for DenseMatrix64F. SimpleMatrix has all of its operators as part of its class for convenience. For a comparision of using operators with DenseMatrix64F and SimpleMatrix see Figure \ref{fig:ops_vs_simple}. There are many operators in EJML. Figure \ref{fig:operators} contains a list of some of the operators in this libraries. Figure \ref{fig:simplefuncs} contains a list of operators that can be directly performed by SimpleMatrix. To make SimpleMatrix easier to program with, only a subset of the most essential operators are provided. However, by directly accessing the internal DenseMatrix64 in a SimpleMatrix, all the operators can be called on it. \begin{figure}[h] \begin{center} \begin{tabular}{c} Matrix multiplcation using operations. \\ \hline \\ \begin{minipage}[c]{10cm} \begin{verbatim} DenseMatrix64F c = new DenseMatrix64F(a.numRows,b.numCols); CommonOps.mult(a,b,c); \end{verbatim} \end{minipage} \\ \vspace{1cm}\\ Matrix multiplcation using SimpleMatrix \\ \hline \\ \begin{minipage}[c]{10cm} \begin{verbatim} SimpleMatrix c = a.times(b); \end{verbatim} \end{minipage} \end{tabular} \end{center} \caption{\label{fig:ops_vs_simple}Comparision operations and SimpleMatrix.} \end{figure} Some of the operators do not specify which specific algorithm is used and some do. For example, many of the operators in CommonOps can call different algorithms depending on the structure of the matrix passed in. This allows the most efficient algorithm to be called. However, many the functions in MatrixMatrixMult are designed to be optimal for matrices of different sizes. Unless there is a very good reason not to, all calls should be made to the more generic operators. One good reason not to use the generic operators is if you, the programmer, knows something they do not. For example, if a matrix is positive definite, then the generic inverse function is suboptimal. In that situation you should use CholeskyDecomposition directly because it is much faster. \begin{figure}[h] \begin{tabular}{cll} Class & function & description \\ \hline CommonOps & mult & $C = AB$ and $C = \alpha AB$ and $C = A^TB$ \\ CommonOps & multTranA & $C = A^TB$ and $C = \alpha A^TB$\\ CommonOps & multTranAB & $C = A^TB^T$ and $C = \alpha A^TB^T$\\ CommonOps & multTranB & $C = AB^T$ and $C = \alpha AB^T$\\ CommonOps & multAdd & $C = C+AB$ and $C = C+\alpha AB$\\ CommonOps & multAddTranA & $C = C+A^TB$ and $C = C+\alpha A^TB$\\ CommonOps & multAddTranAB & $C = C+A^TB^T$ and $C = C+\alpha A^TB^T$\\ CommonOps & multAddTranB & $C = C+AB^T$ and $C = C+\alpha AB^T$\\ CommonOps & multElement & $c_{ij} = a_{ij} b_{ij}$ \\ CommonOps & add & $C = A+B$, $C = \alpha A+\beta B$\\ CommonOps & addEquals & $A = A+B$, $A = A + \beta B$\\ CommonOps & sub & $C = A-B$ \\ CommonOps & subEquals & $A = A-B$\\ CommonOps & invert & Matrix inverse $A^{-1}$\\ CommonOps & solve & Solves for $X = A^{-1} B$\\ CommonOps & normF & Matrix norm \\ CommonOps & scale & $a_{ij} = \alpha a_{ij}$ \\ CommonOps & transpose & $a_{ij} = a_{ji}$ \\ CommonOps & trace & $\sum_i a_{ii}$ \\ SpecializedOps & identity & Creates an identity matrix \\ SpecializedOps & diag & Creates a diagonal matrix \\ SpecializedOps & submatrix & Creates a submatrix of the original \\ SpecializedOps & diffNormF & $\sqrt{\sum_{ij}(a_{ij}-b_{ij})^2 }$ \\ SpecializedOps & diffNormP1 & $\sum_{ij}|a_{ij}-b_{ij}|$ \\ SpecializedOps & copyChangeRow & Swaps the rows of the original matrix \\ MatrixFeatures & hasNaN & Does the matrix contain a NaN \\ MatrixFeatures & hasUncountable & Does the matrix contain a NaN or Infinity\\ MatrixFeatures & isVector & Is the matrix a vector? \\ MatrixFeatures & isPositiveDefinite & Is the matrix positive definite? \\ MatrixFeatures & isPositiveSemidefinite & Is the matrix positive semidefinite? \\ MatrixFeatures & isSquare & Is the matrix square? \\ MatrixFeatures & isSymmetric & Is the matrix symmetric? \\ MatrixFeatures & isSimilar & $|a_{ij}-b_{ij}|\le \sigma \; \forall \; i,j$ \\ CovarianceOps & isValidFast & Quick covariance validity check. \\ CovarianceOps & isValid & Rigerous covariance validity check. \\ CovarianceOps & invert & Faster covariance matrix inversion. \\ CovarianceOps & randomVector & Draws a random vector from the covariance. \\ \end{tabular} \caption{\label{fig:operators}Some of the matrix operators included in EJML} \end{figure} \begin{figure}[h] \begin{tabular}{ll} function & description \\ \hline wrap & Allows a DenseMatrix64F to be manipulated as a SimpleMatrix. \\ identity & Creates an identity matrix.\\ random & Creates a matrix with random elements.\\ diag & Creates a diagonal matrix. \\ getMatrix & Returns the internal DenseMatrix64F.\\ transpose & Returns the transpose of this matrix.\\ mult(B) & Returns $AB$\\ plus(B) & Returns $A+B$\\ minus(B) & Returns $A-B$\\ plus($\beta$,B) & Returns $A+\beta B$\\ scale($\alpha$) & Returns $\alpha A$\\ invert() & Returns $A^{-1}$\\ solve(B) & Returns $X=A^{-1}B$\\ set(val) & $a_{ij} = val$\\ zero & $a_{ij} = 0$ \\ norm & Returns the matrix norm. \\ determinant & Returns the determinant. \\ trace & Returns the matrix's trace. \\ reshape & Changes the matrix's shape with out declaring new data. \\ computeSVD & Singular Value Decomposition \\ set(i,j,val) & $a_{ij} = val$ \\ get(i,j) & Returns $a_{ij}$ \\ numRows() & Returns number of rows.\\ numCols() & Returns number of columns.\\ \end{tabular} \caption{\label{fig:simplefuncs}Functions provided by SimpleMatrix.} \end{figure} \section{Examples} In the examples directory three different implementations of a Kalman filter are provided along with a Levenberg-Marquardt optimization algorithm. These two algorithms are popular in various engineering disciplines. The three different implementations of the Kalman filter are provided. Each one demonstrates different ways that EJML can be used. to show off the interfaces that one can use in EJML. In the following subsections the update function is shown and discussed. \subsection{KalmanFilterSimple.java} Figure \ref{fig:update_simple} shows several concepts related to the simple interface. The wrap() function on the top demonstrates how a regular DenseMatrix64F can be changed into a SimpleMatrix with ease. Memory management is at a minimal since new matrices of the correct size are automatically created by each operation. The code is also noticeably easier to read. \begin{figure}[h] \begin{verbatim} public void update(DenseMatrix64F _z, DenseMatrix64F _R) { // a fast way to make the matrices usable by SimpleMatrix SimpleMatrix z = SimpleMatrix.wrap(_z); SimpleMatrix R = SimpleMatrix.wrap(_R); // y = z - H x SimpleMatrix y = z.minus(H.mult(x)); // S = H P H' + R SimpleMatrix S = H.mult(P).mult(H.transpose()).plus(R); // K = PH'S^(-1) SimpleMatrix K = P.mult(H.transpose().mult(S.invert())); // x = x + Ky x = x.plus(K.mult(y)); // P = (I-kH)P = P - KHP P = P.minus(K.mult(H).mult(P)); } \end{verbatim} \caption{\label{fig:update_simple}Code from KalmanFilterSimple.java} \end{figure} \subsection{KalmanFilterOps.java} The operation interface, shown in Figure \ref{fig:update_ops}, is noticeably more complex. It requires matrices to be predeclared. For this to work the programmer needs to figure out the exact shape of these intermediate matrices. What was on one line now takes up multiple lines. Memory management is more complicated in this example. In Figure \ref{fig:predeclare} matrices that store the intermediate results are declared in the constructor. This requires more though from the programmer, but greatly reduces the amount of memory created and destroyed each processing cycle. \begin{figure}[h] \begin{verbatim} public void update(DenseMatrix64F z, DenseMatrix64F R) { // y = z - H x mult(H,x,y); sub(z,y,y); // S = H P H' + R mult(H,P,c); multTransB(c,H,S); addEquals(S,R); // K = PH'S^(-1) if( !invert(S,S_inv) ) throw new RuntimeException("Invert failed"); multTransA(H,S_inv,d); mult(P,d,K); // x = x + Ky mult(K,y,a); addEquals(x,a); // P = (I-kH)P = P - (KH)P = P-K(HP) mult(H,P,c); mult(K,c,b); subEquals(P,b); } \end{verbatim} \caption{\label{fig:update_ops}Code from KalmanFilterOps.java} \end{figure} \begin{figure} \begin{verbatim} a = new DenseMatrix64F(dimenX,1); b = new DenseMatrix64F(dimenX,dimenX); y = new DenseMatrix64F(dimenZ,1); S = new DenseMatrix64F(dimenZ,dimenZ); S_inv = new DenseMatrix64F(dimenZ,dimenZ); c = new DenseMatrix64F(dimenZ,dimenX); d = new DenseMatrix64F(dimenX,dimenZ); K = new DenseMatrix64F(dimenX,dimenZ); \end{verbatim} \caption{\label{fig:predeclare}When directly working with the operation functions, matrices that contain the intermediate results need to be declared.} \end{figure} \subsection{KalmanFilterAlg.java} Finally there is the algorithm interface, Figure \ref{fig:update_alg}. Here specific algorithms are called. The most important is the use of the Cholesky decomposition, which speeds up the matrix inverse. In other cases it takes advantage of it knowing before hand the size and shape of the matrix, which results in a slight performance gain. \subsection{Notes} What is the benefit of the added complexity of using the operator and algorithm interfaces over the simplistic interface? The operator interface runs about 23\% faster than the simplistic interface and the algorithm interface runs about 28\% faster than the simplistic interface. The exact performance differences will vary greatly depending on the application. \begin{figure}[h] \begin{verbatim} public void update(DenseMatrix64F z, DenseMatrix64F R) { // y = z - H x MatrixVectorMult.mult(H,x,y); sub(z,y,y); // S = H P H' + R MatrixMatrixMult.mult_small(H,P,c); MatrixMatrixMult.multTransB(c,H,S); addEquals(S,R); // K = PH'S^(-1) if( !chol.decompose(S) ) throw new RuntimeException("Invert failed"); chol.setToInverse(S_inv); MatrixMatrixMult.multTransA_small(H,S_inv,d); MatrixMatrixMult.mult_small(P,d,K); // x = x + Ky MatrixVectorMult.mult(K,y,a); addEquals(x,a); // P = (I-kH)P = P - (KH)P = P-K(HP) MatrixMatrixMult.mult_small(H,P,c); MatrixMatrixMult.mult_small(K,c,b); subEquals(P,b); } \end{verbatim} \caption{\label{fig:update_alg}Code from KalmanFilterAlg.java} \end{figure} \appendix \section{Design Philosophy} This library was written in response to perceived weaknesses in other Java matrix libraries. The three biggest are, 1) unnecessarily slow performance in small matrices, 2) lack of flexibility in memory management, and 3) needing to choose between ease of use and performance. One of the areas EJML performs very well is when dealing with small matrices. This is accomplished by having very low overhead and by using specialized algorithms for small matrices. The overhead is reduce by not having abstraction that allow native code or java code to be run, or generic algorithms that can work on a wide variety of matrix types. Specialized algorithms vary from switching the order the matrix is traversed depending on its size to having hand coded algorithms for specific matrix sizes. EJML also performs well with large matrices, where it still most often performs significantly better than other related libraries. One way to write efficient Java algorithms is to minimize the amount of memory that is created and destroyed. This smooths out the processing time by not having the garbage collector needing to run as often and reduces the number of cycles spent reinitializing the data. All of the algorithms in EJML have been coded such that they predeclared all the data they use. The reshape function is also provided. While extremely easy to implement, it is often neglected in other libraries forcing you to declare a new matrix when the data changes. Jama\footnote{http://math.nist.gov/javanumerics/jama/} is still a popular library despite no longer being actively developed. The primary reason for this is that it is easy to use. Matrix Toolkit Java (MTJ)\footnote{http://code.google.com/p/matrix-toolkits-java/} gives the developer more control, but is harder to use. EJML uses ideas from both libraries to create a simple yet robust interface. A user can program in EJML using the following interfaces; simple, operator, and algorithm. Simple is a wrapper on top of the operator interface. It hides much of the memory management from the user and allows more readable code. The operator interface simplifies the selection of which algorithm to use from the user by automatically selecting what it thinks is the best one. The algorithm interface gives complete control to the programmer, but requires more skill and knowledge to user effectively. \subsection{Why multiple implementations?} Optimizing an algorithm for processing small and large matrices requires different strategies. An optimal small matrix algorithm typically minimizes the number of operations. Large matrix algorithms need to minimize the number of operations and cache misses. On a modern desktop computer missing a CPU cache entails a large performance hit. A cache miss is when a computer needs to access memory that is not available on one of its high speed memory caches. This forces it to access the much slower main memory. Small matrices can often be stored entirely in the CPU's cache, making it much less likely to have a cache miss. Large matrix algorithms are designed to avoid cache misses, often by processing the data in a less straight forward way that takes more operations. Typically running a small matrix algorithm on a large matrix will result in a very large peformance hit, but the inverse only results in a relatively small performance hit. \end{document} ejml-0.28/docs/logo/000077500000000000000000000000001256171534400142725ustar00rootroot00000000000000ejml-0.28/docs/logo/EJML_logo.pdf000066400000000000000000001546321256171534400165470ustar00rootroot00000000000000%PDF-1.5 %µµµµ 1 0 obj <>>> endobj 2 0 obj <> endobj 3 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 720 540] /Contents 4 0 R/Group<>/Tabs/S/StructParents 0>> endobj 4 0 obj <> stream xœWËj\1 ÝÌ?x™ª±eËYäÑÐ@]”.JHRJh6ýýJ¶ïí‰îe ÌD’}Ž­#yl³ùhNO7w.=;3ç—æÏzek­C´É$´†‚5¯ëÕ×ó²^9ó4ޱ6:v=ž¬WŸÖ+suwaÌ„Àu‚óízµyïŒó,ší£ 2œW CâÌö·ÐT®ëõêÛÑÕÍÝíñw³½Y¯®¶ v D‰?“ü™‹yeŒ»ÇÞ¸,ÃbÑüeH¡/ã—™þE¡õ#mJ•x;P5ÞTæxçbIè$5÷¡¤yL=¦aRÇ$G³p31 .pÞÏÃé1 .u¸A •Íê1 .¤’J¢Ç4’²X]•CiÎNKaÐG‰© nO<O©x¸«æ<«Þ~LÅ𬋡ãé1/ŒJyïG½²§©T:‹SYh±èº>*ËLLe‰KU×EÓIô˜J’v ®\²óªîÅTм§ªŠ§ÇT¼CúO'Ñc ÚÅÒ„ÓXfb*‹;DT•D©$¨‰J8/ê^LÝoUO©x‡µªÊ¢ÇT–ÃZUc™‰©,q¹vºt*‹SY†^­—'âãºðŠsáŠá+U %q…±Ã›gq ÈŽˆâ Ë\ž§°#‹ã§TGN¢ogHe ᜙Й@|»BÀ¶"Äf$sß”š8˜‡‰¼ºj5\ëÛØ (‹ÏàB#"ðX_š#6Ñ1asdù1%#ûH¡†cæµ€ŒÉU|v$¦ç +ÈT/“ÜלËÜæöÇË“9zx~wýùxçñÉM`å°™¾=wAíî$í¸÷ö<µ˜.ÏÞžçØ|ŠVž»ÈÇSð_Gýì|g endstream endobj 5 0 obj <> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj [ 9 0 R] endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 18 0 obj <> stream xœÝ•KkQ …÷ü-ÛÕ\=îc ºéÆLìé"m†HãàÚüûžÙ®!©¶{ä¹sôéZǾâB‰$‘fâž*>31!.B¢xØHŒ$oÒI!5H*iI#SHz²fxNY™ðʵ‘ •1I©TAUA©Z€(ÔXI+µ‚úú4©G!KÄ)16“ °›ÔgÂæpc†ØP»€°–¦d•X±¤°ÖJÖäF«Ø¸e28— n‡Á)c °Þ'\Àï+Ö+¾~ººêæ£(Ñm·è/wÏÝütºŸQº¾¾¼pI¿—̻يøe$ÊrxÝ~_¿ŽBôkgÕ_v›¡ûò´ýôyJ ©5¤¶:‡Ô%¤®!u ©ûšSL~Þûwò˜ó“c†rÌQŽYÊ1O9f*Ç\•˜«sUb®JÌU‰¹*1W%æªÄ\•˜«sUÿêjN§g³þóáŒÙñÁáŒéqJ<ïö)Q?<îõ0bžïÿw+ûÁ2ç)ˆõ`²OÀpžBóàéš<8E¢NQ§¨SÔ)êuŠ:ÅœbN1§˜SÌ)æsŠ9ÅœbNq;ö=|ß‹åÛËÐ-¶›Ýír3 ·ëõ¶›ßm†çévÐÓì]í<ŽOoÐêÙðF¼gÝì~þZAÅÕ¥ãò±³>{ÿ«ÎzúáWvyñ…8– endstream endobj 54 0 obj [ 565 0 0 0 0 337 0 547 819] endobj 55 0 obj <> stream xœí\ \”ÕÚÎ;+3, »È # ² È.(03À2``R 0À0È ¨¹!å†Kv³=S3µÅr0-êËÔ²=˵Ì6KÍ,m¹¶˜)ó=ï™Ñ[÷Òw?îïþøu^ΞsÎsž÷ž³¾/0@À¬Z§ÍýÁçéû*.ÈS Juy#×0M‚tÒR¤‹oŽYùÊa­)SÔ“Ê[FÏ|@¸uNÔ4é[¢O%¬H…:%5í¶æpñ€ìs˜¾½®¥¾éÐüMX?mê·ÕëÍ-àNx?,Y}ãìºÝz÷Zu –Oo¨mšu㱌KÎ+¢îk0èkßÚd¨C[Q¨ŸÔ€²ÂÇ1u`TC“e–¿ž0˜ä¥7šjôÏ[{lÚ1ïx“~V ï~ÁÔ_Š l³¾ÉðóÞvô¸x¶˜Ì–^ ·Šw¸ò–VCK¬æ¾n€ ßcý߀óƈ'ܧßì–þø‹ ÖÅõ'¸Ïî··¿f›ß[é´Yd@='JìuD†ÞJ§±<Ói3µ40Äs9¤npÔa@±P‚yoÚì6xw0/‚Ä‚c1jÿä­‡YŒ‡˜a\1 †'äš>ÐtN¶–‚aå𪨜ld¡ Ã~C{`2  þ‹úäºÀl··_5•0í?Ïê¯ðWài$„€d0šÜÄcˆ ë@¸‹ à Å6ƒØÖ‹ë¬QBQ RDgŠ.àb»®à†èFQFÑdˆàn» žà‰(9¢EoðBôoÛoàKÑ|ýÁ1ñŒ€Ä@Š#!1ˆ" #m¿âJ„,¢‚GAb((l! F!†C(âhŠŽ8ñˆ„Ä(ŠÑ01"c!Êö3(!1bã)Ž…XĈ³ý‰˜c“)¦@b*$Ú~„4HFG1R3(އ4Û˜ã3!1‹b6d ª`¼íï †LD ÅÈBÌ…lÄ C\wÙ>ƒõ°qÜø܃¸‘â£pŸíSØDq3<€¸…âcð âãðíxÖ"> #n…uˆOQ|6Ø>†mð¢6"vãˆÛ)>›mÁŠ;á1Äg)>#öÀ¶ãð<<‰ølEüx ñEŠ»`›íCx‰ânèFÜCq/lG|ž±ƒW`â>xñUНÁs¶àuèA|žG|^@| þñmÄ÷áØ…¸Ÿâ»°ñ=Š`í(„½ˆ‡àeÄÃð â؇xñ¼¯!~@ñ¼ø!Åãð¦í0|o#~LñØø)ÅÏà]Û!8ï!~¿€ƒˆ'áâ)ăpŽ ~ GÏÀûˆ_Q< ØÀ×p ñ8ŽxŽâyøñ[Ä÷à;øñ{ø ñЇ¶wáÅá ÄŸà$âÏp ñÄýpN#þJñ|…øÅËpÖö\¡Ø _#Úàœ;sqÏNbžG™¹à3<ˆ‡vßæA‚þæ]ûÐð{¸ÀG†¿üýo©“ðÏù[è4ÄŒ†wp– Öß"ø ̉þ¯ðGÁE*Boó¡Ùçoé3ÞÁU"B'ÆßtÝæƒø¯ñýï7©øOúû¯ñýï™Ë`ýM÷I8¹ 1£áÜÝœ¸CÞ 4é:"'·!f4¼ƒú[ðgü-ùËßÿNð”Iéoºn£¿eCKh˜9õ·pšKeCKh˜/wé ýí̤îCÌhxo)zûOøÛù¯ßý;ÁÇÓyþ¦ç@¸x1£á|圿EƒÐtåý-bFÃ;x»¢󎕞ÀÍ{ˆ ïèë6HË8€Ìwh óÀúËÐÛƒy§M÷I)xø1£á‚ÜéoºO¢¿†˜Ñð¡#=¹?J„¦. 9ÄŒ†wâ…ƒÖyštÝvŸ!f4¼CL˜z{0ïXéºí~aCÌhx‡ø?ô¶ë 4GpàCÌhx‡¤¨îϡČŒbFÃ;¤)ÑÛ²Ahs V9¤|†{P%‡à"1˜w"tÝöÐä!f4¼C~FzÛkšc8ðƒˆŒ!f4¼ƒN=½í3ÍXF@´zˆ ï0-?½=˜gô‚ >ˆ ïP[‹ÄˆAh¦rÉ%CÌhØÆñÿrràÑÿÔÃÁN„ýÿDgÿ¼þ–¹ÌÁüÑÊh¢!VùÿCõ?øÜQ1ýƒí`ÐÀD˜d³8ä›ÍvÒ~]û?™i“‹‹ 'äOÔæåæhÔªì¬Ì ã3ÒÇ¥¥¦$'%ÆÆDG ¥ ò•»ËÜ\¤'±H(àóQENk «²òÃyyÑ\Z¡Ç ý€Œ*+‹Y9×êXÙ*ªÆ^«™‰šu×ifÚ53û5‰ŒM‡ôè(V£`­ûÕ ¶‡L\ŽòJµ¢‚µž§ò$*óÃhÂÁÁXƒÕø6¨Y+©b5Öœö†.M•íuK%*…Ê ‰Ž‚n‰E)JÖÑŠ–n2z<¡3Z“Ö̀؅»­•ªÑ×Z‹'—kÔÁÁ4TÔ–U¨²Š¨-ÖÈq†ålwÔž®=2¨®Št®UÔê§•[yz¬ÔÅÓtu-±ºGZ#jkÄ­§|±Ék”B­±F*ÐX~Iÿ ˆU*S°]?’Wœ?wmŽÞ‘# •ýœÈ5±ßMXÞ'rC†Ø¾à`ŽËòžL¨Æ„µcr¹=ÍBuÀvÈŒ¬°2U\Éž¾¯2®¤£¯¤¿z•"˜ë*M•ã§½Á×ÚQÍFG¡÷éO(þ`9kå…UU×4pŸzC—B­¶û­´Üš©F!Sïh«¦[‹úú*l„‘sÃärk¬¢Å*WdÛ0ƒåúÀ¨+§UÕ¬r•ªjµ¬±5Ç‹ÕtU©í9[ŠÉåÏÃXÛ‰î6à™±¸Vp<¬Þ*ì”0MWym5¨* Çg[lͬ@÷U(Ê \/)dÖˆx»`zGZ ÛvvŸ2×rQ¨˜-gx\oa›ƒ ÈNÇvMr=šÎ–“èSû848é;˜à…ªò¸"WU•\lÿ„R€ƒ“ Ô*`K†ýœì÷ùCjvmŽP«1¨¼Æ¨ÀAÐaí÷y2œ/7Æb®;óúŠx¡8s1A34‹ëE_Ö Ål¹Â ¨PàÊ,.çÚÆùšöo¾N‘?yj9ímÇ()½&e/Oé/sH}Û%Väëº8…£Ø.­pðeâ4KñH°çæà:ÕÕ•£`sºªºô=¶Žj+Stugfvµhª8’åèðÛ Ë¬9+*¬²ª’ÆÙWhk»ºòttC4·îÚ6'ÁØ„±øÆä Y1Þ‚±c!ÆÏxNÙSõ\KµGP¼Ü¼u÷V§$s —ä‘`ÒFRÉ\Ò†¬BðÁ² Ìm$ðê™HÒÁûÉd9™夌 f²šŒ‡3ø`*ò‹„`ÒB|á\‚ˆ'\B=>¦¹WÔn"‘Ä—¬†'àøŠd“©Ä¤p’ 9ó/­†3gÈDæqâÌÇýï#Zz™<€w¿Á!û‹ <ç)`”âcÅ#‰—˱P$ô’ûØÛ“œ”Œè•Àe)”áa‘ÄQêBËùÓÜ=\½œ¼´½ë&õ(ösæ‰ 0‘DLÔ’0m‚Xà%ºõþ|$ÑY wWJÒ<ç/”F…È}=ÄSSßž!"w³&ñ`‚7IŽ4ÏóõäI˜À²·¥•$¯sõ‹Ã}Îúyo?ç,µ·'{ïãõtq±\"” R ¼ÃDžè1žÍ•™ˆ30 b3ýÛ…$RH„®Þ£Aí[èÂøºWfAlå¾Ê DväË+ïÊ>ÞWY9Ð5Ü•˜Àµ'd¼ýê%g˜œˆ‰z:K¥Š‰‘¥RéDy¸×ˆQ ËÎcG¶ ä3A—–]èrw‰(Uà,v’dùÆæê?e x…þ]WŽ"ËÛwü‰‚[!¢2}##”~…Áj·B§"çM±r&¼xÔN(aOžºrj×…§®|‰]§päB…;ì7æ*/7"”9öO<íE/ÚÞ…)];¢zF—Š\GŽœÜìFˆ3F¸¿©¤~j€Ÿ@&pçóqÒ þMä™& yÏâ-yº¼Ø»¤÷bÇ8g_ž§Ï“sý ÷\:ÍvN+X‰,ó™; HUq+ þãȬT"I$Þ DêJæ8“‘äF’êO‚üI)Å¥rÒ"'Œœ,p%G$D&!íÉW'©dŽ„‘¸JÄ®yÉòää M!æåŠÄ 2îÈ`ÆdŒmÉÑ…¡…£s‚ŠFÄûËýGÈ''Ç£f<OZâ;âÄóÂâIü6erqrUòúdþ¨d"K&ÉÉùÅD’ìÏ Éˆe䮼tjú¾ô ûöyøØ'´_leeå¹ÊÊK\c|#Åódûˆ¯ì(:þK?ÙåÊJ_N<…e´P—T:Bœ’K^MW†ÊÁö.ä ¦pœ+^\qØÀ‡çC¼¹Ùå™4`„¡®06°÷á@7'霼<‰›@‘ I*¿)–‰$#z·Ë¼$DLHdòÇÉR9ä%exÍ]Ø6Ò¯Þo¤»GPÂ@ÖaïÁíÝ>|"o>ôi@è$¯îU­p‘5‘ØÍtºËEc®,ÈÊ?D¶„ %¾í½‘íM½ö 'ØqÍúÿ¹ˆ{ÿU‹×^fç_×_×þ¢c[ÃËî§Ä}G”]&à‰g"»Ìš2P‹8ÞZùB«C€3t9d!ž˜îqÈ"è„'¹·}|Úq%e™I$šÊÜ—HÈr‡Ì‡xRCe!æ É.‡Ì‡r7•E˜/&ß8d>(É+TæÞ93™ 䕹?Øzš wȘ£íð&8d$ñÜ2Úäù8døòr²Æðnvȸåò–9d1ævÈNà+øÅ!K˜¹ü•Y ñ"'‡ì 9YÂùD4Ó!£ODET–b¾‡è)‡Ì‡4Ñ"*;sœEg2òí¦²+÷Mgâ`‡Ì‡ѯT–Q;g2gÇ®ïÉùV\áÑ·â8*Ë9>â%ùˆííõÂ|9sÅ!ó!ÝáCoª¿Ë!súö>òãôÅ2ê‹ß¦r××N±ûÚIDå@Ú×ß8d®¯í}Dõõ™ÓO¥ò(®¯îrÈØ×N·P9šê¿î9ýuœ,àgñ?‹ðàï<@ßy€¾óÿ;;ü¯2µÌn5Ö7XØÑ5l\jj2[Ú``sLÍ6»­Õ o‹bµÍ51lVc#KÍl«Álhm7ÔÆ°jƒÙXßl¨e«g³j}»±–Í6´6šfÆädSÉØÌêôÍf“jC“‘Í65ÖþQþC«Ùhjfãb”J»§’“Í)Ds ×SMIŒâ0™b ÅÔ?CþêMX£™Õ³–V}­¡Ißz kªû}; \2Áˆ :Ðã§¥,aA¥MXÆB!Jõ¨i ê ¶–Úˆ –t:”j­CùX«Ï[ÊÛÅÛÇÛØ *0A ÌÆzFlYZaa4>ÐEàg> ¦â£ ‹… X›³dB›œN6´Q?èñ3 ÓZ̯ÁÃ2 YÈ ?¯Z4Ó”?9~í´m1FfªÕLóX¨F&\¾µŒ4§¯M&˜ ƒï§bî+P³ -)çÙÁZÈÆZÈ` Õ7;¬p>‰%^íôYálôYˆî·ð¯<œ‰Ôƒv9y€œ2@N²^ø½–°˜âPOGo+~ÖÒvéQ¾óL8Bÿ Ÿ?òºý.Õ˜6;F€ÝËzšËqo¤µôûzLµp_ì…¥šS‡Z&dÆñ´³iÄR •,8f ´¦‘¶;j€VæqýÊÙ0÷ó±PÛ\^¶ Æqç>5ÓÒVÊÓ@=ØŠRíu£8ж‹óU=m¯žÞ¿Þ•³VK9éŒmÄÜhôh3ßÍŽž3S{fÚŠ«³bµdç?Óák ÕáüTƒV¢þÉÜáÏBßÙØíöùÂLyÖS6œgúzÓH?MŽþ0;îd ž²N·zóôÕ‘åè«ÆktjhOµÐûØ{h&õCJÊŽ»ƒ…jÚ=­GÉâð³™Ö²Ûæl´9x4SKµŽ6T;ú¯¯1”‘k¤A,^3éÓ_^=`ÄÆ8Æ^×§Ü8ù³;„ñOíˆ ´çL´fÛ kæR/™Þázkð»ÆYÔº~Æ»r_x7ØzSè«GÇA;ÝÑ_k Ý"~<_ÅOâ§ð3ùü|~ê ïXú§÷è|®e$K_ƒi-èóÁ÷RêÖÒu¨ï+Žz/sßaü»GS/b³Qmúšög'¹¸¿o A ì”ûÆ,Î[ü‹ 1ë;åbÌâ3„Ĺ*…b{ #€²J(‰>éLf}‰²X5 gÄ##;F@:½Šp2™é¦gŸÞã¹KÉ^k/k Ì ü²{qµÇ{G#ÔßÞvãúN· ÊNfÆFî¹lÇÁ®¯¶ìÛ•øúƒ+—¾ô–nÊJ—~®Ü³˜ráÃqAÊ@!¯Œ/ñôÆã¥Q‡‡U¶´µÍla –™¦Ö[â|”^œ‚ÔÓµOÁ~Ô‹‹Rޱ(®Ö46XEßÔbl®guxŒ4ÖØ“É— Œ·kG±Ú¬lm¶´‚ÍR©4Å¥uwdÅ£õµ÷PŽôqIMV&ÆÅ+“•¦b25.~lœ#ùß߀…ëúœ€·p%ú}³p!Ža¿o˜³pD·pûésî.7×k;ùæØ1ÛüìtcÂ…³«{œ|0õùýg~^Ú½vÏ’Ðoæ•ËÌÓg½=ÃëÊkå?GÈðpP_7$xÈ+Íý¡E‚ñ‡Îvü6çèã?n}YpùÇ#G¶ÂÓ°¬7j ¹cêÕo¹oéøñ¹—äÏœrÿ-âjÍkl:ž¸@òik4±`Ë\'ï»äªïñžô¾hÕƒ²Æò^Iâ½o-[÷¿å¡1óô«ö~%ñÀc¯×Uggܽ&$þ¾e]—jÅ£~:t Çï~ŒIŒìrà¸ê|ðo9å·/{+géêÐoåUÃoo W†Ú üç4úZ*ýÖþŸ(öùGòþqWºq"O±¶Ùbhm6X” ×þÃ^޽°„ÒOêÏïxjåêÜÕïp¿Éø±dAõjaÜþwmKïÌù@›¶æìᄵO=2kê¹_/×hŠz¤ÍÊïIz2Úé³LáOºL®$-x·´èÀsQÙǤVöÜd{¶ãÀÉ{v,ÑfËßg%S6¾ò^̺´£¥”Ýø|#X¯\¸”KþÂåüÙœ{NT]i¸ïBÊ;Íãþ.íÜPó˜Hfž •Á>!6¾R®äN~WOvÞ1u,v£wȬvfL2µ5[ôÈjŠÑ03 »MMP&Œ•”鲨kÞŸÆ¥¦&]gŽ¥¯IKì¯IKú_“ª4%¥YÚBÉ Y%%Y…¥ZŽUkuª‚,í$šÍ*T؇ ´“´¸ ÇH8íBman[š§aËt¶(E­ŽšÓæhUY¥“ºÒ­ª´ ‚Õ•eOÔ¨JÙÒ"®ŠdЦD«ÓæÐײÅ%YªR­JƒõÐÀ$Ma)Òæn¡ÕéÊð~lVYi^Q r‘ô‘Ôõµ€ÕN*.Ð:8kÊ‹K4:{µUè„BUA™š³r5W‚¼'iJTy˜ìkeQ ›£--äªç œÅg!GUYAV [\VR\¤ÓDћܠ-(` ‹J%Ùê¤ ­ **Ôi&—!ymVAV)Ô–j§8êô‘-ÂV•°ê¬IY¹] «Óh$\;¹ý‚³¡Ö V=­2áÜoÆ.3Õ]?ëf\ µl³©™VuFC­Î>²,83ªÛpI ³°>ÜíúÆ6knÐã8h6YØj[c¢ZjDofõ55m­öXgjm¢sFÒnßnì¿àh³b$“:3ÍûòMõ¦˜zcrá6n%aù ·(;”BiÕâ<²ø¢†ˆÁŒÑB1®*® Þ#þÐ>:IYݯÉ(§(½¼¯[•xX!þ}™áfêYãÕ¸Maúê¶Ñ‚sáÚÓ¥ý)Yé=`¥ à‹•B\íðçºswR»»à‘ÙeÇ-Ó–‡¾¼™ý¾±ç™99s^wë 3„y^†w*#.N·lF÷ò”YÇïxZÚ‘´º2ïÞW!E¢Û™lëò o‚Ü„_ò bZÿþÚáùWÔ¦;þmÝÉ5çÏØàÍ—¿mñáC¼æg÷Ö̉Ÿ¥÷ð¢®ßn_œ<:æÌæ”äñ/\¾Ð©ˆëäçá¬Æ¦+ÛþûÇï¯yÈ_¿ðÒ¯ßKN¼¸ ÏWSÒ¸ë¶eÐÕŠü8¾lò%sùçßÞóNrœSÄ­)Û¨;Ç5(ëÖ§w¤ýéûý¯­7„uŒâFœcÀ5õ|舳Ìn1Õ·ê[f_ðáwЧýòí¾±_EF¦Ÿv=¼s꘯7äÜ«ÏÏu»ý`ç… b˪„Ïo˶ãFSî¾ê÷>ªnþÄgÝrI´ù坸H÷½ú?'.×,½µF|wþÚêïï(x»µ«-C±ú±uëîK7oM6¤.>R6sÂ.ó‘};ÚTÏ|]}ªÐükËf룟 GÆ¿3ý‘K¶ŒßpYúüÆÍîùß~ðà‰ […AcÜpY8}ù„àŠ{Wzîì}«>9\zoÆc¿ò÷݉7NÝš‘§ž¥˜žV_Úp§E|›gVt®ïÛs.Û¼žºkâ¾…s…⓱ r¥¿jÛúRþ˜‡_4?4ezìšÃ%ûá“C æµë"ã|L«žÙÐIàÙï«=&Œë$»0ëyn(.ìù¯Êý£‡õk‡s…Òwàh–^}uFp0÷—âÜèJr\B¼2!).qê? æÝÙG×\8Óxþ«E{Åû¶]ÿš…3~¹†ÝêgüxÇã“wy]z¶ìⱪWVn\å².üöGÞ~;P ^.Ù›ü‰Èû•SãŒäØçoü0ýÈüíeQOç¯9ñâÏçZ·>¿/|o‰¦úæ ¤[.¶omEŽ?´ô½•>Ë–/z3{Ïüª‘Ófï]ëùÒv¯êÎ/÷,ünTøÕÓÈ*9¤ˆ¿.ÕÁÿ6íàÌ endstream endobj 56 0 obj <> stream xœ]ÏjÃ0 Æï~ »CqÚ¶Cl-…ö‡e{ÇV2C#Å9äí'{¡ƒ l¿ï'>KŸÚsK>~ç`;L0xrŒsXØ"ô8zR‡ œ·iëÊm'•¸[ç„SKCPu úCÄ9ñ »'z¼Sú²§v_§Nún‰ñŠR‚J5 8dЋ‰¯fBÐÛ·NtŸÖ½0ŽÏ5"Kø cƒÃ9‹lhDUWR Ô©F!¹úFõƒý6,îãÃYÜÕýócqoï™Ëß»…² ³ä);(ArOx[S 1Sùü#oL endstream endobj 57 0 obj <> stream xœìœ \”åÚÿï癘˜aPáÁÑ@q ‰M\PÆ@M`€Q–i÷…v™YvZ\—´Òr˜¬¨ãéXÙj™•u:¥2Ûµ”Ê•y÷s ˆdçíÿß÷ÿþßÏësó{¾÷rÝÛu_Ïæ01†›’eæM¿ô½œƒLˆ<ÏXTInVNqÍpÕwŒÍÈ•97kröÝÁ#1VìdL8<>'7%(«`í1ã §½¼©ÿØ?ÄØî°ñE¦¬öíL÷1ÖGšZ”œZ¯ó{ô}öeuf›þŒ°“±µŒ‰) œR™äÙŒ]õ3cªªlÕu[¾ÎÚÍX¯ýŒizU›6Ö‡0%úW×.®ºðVý8ÆFœ„ýœ‹¹òxéžÏ0þd´§× B·_›‚òÍ(¨©s.Šø^œƒ¹1TSÛPa¿¡·ž±«a¯>Pg^d þ>üØcýLª7×YîØ·ú.Æò‚Ó³58œÞBö æçþlv‹-äùŸ±ßè#Œ…÷gÜ—*ÆŽ:O~:7h쬯šñë/ß,{ó¹¬/µçƒ:š¯ý›a«a"£ ýüXh—¢Ý¬ùZ©Û¥(â5J3»–KdÁ,™•1yee<¼¬bjÕª4 CTfψLÍÄ Q¡T*De ¿ËdÒÒα Š$‰!SÒü›Å‰±Íò ûUz¾SŒ®gW®+וëÊuåºr]¹®\W®ÿ¢Ky–™þ»×À/ålV¨¼ß\¹®\W®?t‰Øç¿Ûfeoþ¿\Ë•ëä¥ð)Ú÷S€”¹¬dƒÿQe‘Å)Ú¼^”e*;^ìú©ŸpR晞?GûÑODö¯/_OÅÄÿð~®\ÿ…WfÞÜ9×Íž5³´ÄT\4}ZáÔ)“'Mœ?>/7';ëšÌqW3zÔÈéÓC‡ Jˆ`èÛ',$8H Õ¨ýýTJ…(°!¹†¼2ÉPæV&òó‡ò²ÁŒ s·Š2·„ª¼KmÜR™l&]j™ ˪–™d™Ùe)KcÙØ¡C¤\ƒä~#Ç µ 3§• GŽ¡TrŸ’ór^™ t(ÄÅ¡‡”Û§&Gr eR®;oAMSnYÆk Ðf²-Ú¡CX«6Ùä܃ ¶VaP† gÄA¹£[E¦ÖñiÝŠø\s¥»pZInNT\\©\Dzå±Ü~Ùny,ÉÊ×Ìn—Z‡ìoZÝÌÊË’+ •æÙ%n…š¹MM·¹C’܉†wâ’}°e‹{ˆ!'×dÀ`“¦wM ¸UñÁ©éG†ÅN¼´Æì«ñ‹þ‘ñ,ßb—›ÐÞ™gXVˆýÅÅñµÜÞ–ÉÊQp7N+¡²ÄÊ£<,39©Ô-–ñ–ý-á&ÞÒØÙÒÕ½ÌÇ*·Ì÷± ¦»±\:Þ—?âñvÉ­H(+¯¨á4[š 99ä·âwf2™fß^s[S’ao.Ã&¬Ü ÓJÜÉ›;ÌE¨øX‹Jä.¾nî°l7+«ðõr'çæðuI¹Me9´@>–aZÉÓ,Íûqë0)êñ46Œ•òu¸#²q( ¹M%•UîØ²¨JÄg•TçÎ,…ûJ %–R~J†`wâǘ.NžQî…½õ°î4æ;÷WK%b”¢”Ÿ*¤<Ü Ycь㒋üD³ÆJ%Bë4Ã,> ž»dñÙù¼IÁ»fçGÅ•ÆÑõ/–å[“*Þ­î6V0*ºÖDóüîÒÈš/(Qʵät[à%ƒª| ôvùuŠÜ¾‰ÑCÍ3¿³I'u"†‘«ø)ö‘ܬP*1X ¥ÄPfa ß÷µ|¾“Š “¦Í,‘OÛ%Å—”¨}$•Ü,Í11˜—Õy¬ry¼\î*æ÷hžÐÙ,5© “Ššøà߀L„Mû%L0ß>2tÍ<¼Ý yfƒ,å5™Û¼åM­™™M¶Ü²šÑ| ÄÊ&CQÉØ(y­ÓK–G-áS…²I¤⬡CðîÉj5«¦µf «Šf–<̘´ª¸Ä# bvYVië´•<-áÝ.׊¼–Wò‚Ä |¤é(¨eû¨§3k”[•r…\®h˜\§î¬XE›HuÁu"ê”T—)×ñ ‡Ô§.Æë6Wªädz¬´¦©¬”?\,G‰Á-2˜[4d´ ¢_ [k°d¹ Y¼~¯Gõ~¼Þ!Dp'5•ðžB@•°(BQÁ‡”ðULqIÜQ§Jãj³¡™%nMÞýªø‰°ÏU†êñîÆ 3_3•ð¾þñ*J¶Âd‚[ƒ4¾`‘'÷ááˆN8 Ü¿wc©»4‰OZb-•Ã9ØÍò £qì4¦*O”\ÚjH•ŸM< ÚøÛ84X+*¡š(1Y)9É?+¯0 ©¢L‚·•¬¢¡NïRmÕXðJT&Xdi£|ŒoK Óº5F ˆž0òGRï_ZJ‹—K·ù 0w°;+JèæJ_xMøZðq–ÊMŸãÃLkcÓ ‹ðfá‹–GòG³[?ÁŒ—?õ@adgg5GøÆ8@µþ|çð»"¾¸Í»Ó°8®Û5tˆràÉ¢žF`³Ò¦žîYIC‡¨{Öêäê¦&µîòÈ_j]QÉZ5Š6ñOL¿Ø6ñgOLð“'fp–ð#ájûžJí„3„Ó„ïß’å)ÂIªü†ð5á+—„/Ÿ>#œðÄh€O©tœð‰§_(ð±§__àŸž~ÉÀG„c„£„Éä*ýƒð>áï„÷ïŽÞ!¼Mx‹p˜ð&á-â Â넃„×hÚWÉòÂË„—/^ aÁJ¨!TªB%¡‚PN0Ês s×fffJ=}G%„k 3&B1¡ˆ00PH˜J˜B( L&L"L$L äÆò¹„B6!‹p !“0ŽA¸š0–0†0š0ÊÓg0’0‚NNFH#¤®"¤’ FÂPÂBa0!‘0ˆ0@ˆ÷ô <½y$÷÷ô ÄQ¥Dˆ%Äú¢ Q„HB_BBoB!œf£zQe(!„L"è :B !€ %hhL5ÁŸ*ý*‚’  ˆÀd^Báá<ááWÂ/„Ÿ ?ÉÓ gå ?Rå„ï í„3„Ó„ïßNN¾!|MøŠð%á šïsO„øŒpÂÈ>%÷DŒ>!|ì‰Èþé‰È>"#õDäz"ò€ÿ ¼OCÿð ö. v„ðámì-êw˜ð&áá Â넃Ôï5úUÂ+´ø— /Ñ|/z"²€ÔášèyZõs4Ø~ÂßÏþJØGø áúiº†~І~’ða/Mô8ÁCh¥iÝ„=„ÇhèG » »ö„ã…+<ä ¿ØIØá /ô„O¶{§Û<áÓ­žðL` ™´Éf2i&“MÔ¶‘,7Pi=Y>@¸Ÿ:ÜG¸×^ü™ºßCXG¸›–tY®%Ë; k<áÓ€;Èr5ávB“'¬ø“'¬Xå › Üæ »¸Õ6¸Å6 ¸™Ún"ËÉä†Ì=àé ÜØïôù±N‰}zÚý-`F¬j…ÜÐè1èQh7´ zzzÚ í€„¶CÛ ­Ð¨Ú 5kkb×C@÷C÷A÷B†îÖAwCwAk55±wBk ; ÕP›°ÒÓ‹?}+<¡<’œ‡'„G’p=ÁFh Ô굄ù„y„±„1ž`ŽÑ„Q„‘„„tÂpÂ0B!ÕÄÃò*B !”B&ôgÐ&Z‚† &ø{tüdý2gßB§ “Ð7Ð×ÐW8½BAÇ £Ð‡ÐÐ?p ïC‡ž…þ íƒþ=m‚ç7j¹§ÉÓKd¸ƒ.'oq:L’~çr®¹.ôEaŽÃÁGu%ñŸáï%üw/àíÕgîþ›cÿfÆ:ÖuûUò HÙ.ö{†=Ç^cï°ï-+c·°¿±OÙ׬ÃÃè/„ ÑBâÞo°;nRÕ1b?óc½óþêýªãaïWxæõÝjÖ¡Ô[™p±Æê=Õ³®c]G[Ç!¿,÷ ¢ö´pÊû«8Ž—½é¼,ÞÆórÓþÍ{:6_²³3[ij%l)[ÎV°•ì&v+»­b‚/V";[Íî`kØl-»‹ÝÍÖ±{؟ٽì>v?{€­gàÇM¬™möµñr3Ò½r+oÙÊv°‡ÙnpÛÎd;ÙC(?ïïf¡Žj¨ü(jZØÔî@-·âu{ܬ•yØãl/Όʥ6¶Ÿ=ÉžŸÆiþ…íceÏâ÷ãdŸ—ëxMgù÷-éþ;À^d/±—Ù+ìUDÆAö:{ƒboþ_µ¼ØUÃK‡Ù[ìmÄÚö.{ýýƒ}È>bÿd³ãˆº“¿iÀæ˜ÏêX}ƾ‚å)X’Ù•[¿”G8‚¾³‚šý(ˆìó"ÇOï^ù„Ï‘Ÿ?í²ŸùyìA™ŸÐή³y>~çÉK<¿ÞwÁ¶ìôßå½vÈw:äï}°á¾à-oø|ñ²ï$ø8Ïvõ=(·yä~ÏwzÑ£´Ãw»yçh7~Æ>—=CÞ£Ö‹Þã'`ýÌǸԷÇÑ—¼Ïûòúî}xÛ(…·ÃIxšóù$¾a_tå¿ðµŸbß²ïØòý4;ƒ÷É÷ì”Ï¢æ4J¿­íYóÒÏìö+Nð<»Ð­t¡GËÖ3ÆW ‚((XÇÅÜÅZYJA%øá¦4‚Vt‚^Â× þ=ZºZB~Óx™6\*ôÂð¾ì-ô"…(¼7û 1B¬'ôïÖÖ·«EB‹A ÄûÚ"äž}»úÆÂ¢w7ÛD!EXˆ{’`’‘¿J& F£P3åT”G£-Efÿ¿cŇx;*˜?Å ØV¼é„Mx…ŽîÍÉQõE‘IÂA¦†«6eöRŠº¨¨q†á~«ÓB&Œó_-³q>:öno„ŽJ~CH>vê½SÁ^ •|êÈ©«R„¸YazÑßßÏÏÐß(˜ž––š!–`è¯åºaé#2i©1¢"¬³&CäeAñáù©ŠÜ ÄÅqcŠ®R Iñ½c{©ÕŠØ]|š4©À>(R¥Tû)TjÿéYÓ‰ýiû Œî7°ì ^x^¥ÿµ]¥?w­2çÜ>ñËQ%üëD•F½iPLø€«¢¯ž¤ Ò©ôQ½#£ýÕ!zíà|ó…"ã{kµ½ã#£ãùXñÆÀc&ï×ÊåXÖ‹ dW³Q­i1ü×EÚAaü×EL;ªMÐ?n4ªúò‹U€V••;5î|tJH>rá%¸Îé±UÕ0£È#rÿ äíqq°P¶L¸ã­Ûn:¸jüÄ5‡oi|õö‰íý²æL—}uòÔÚì˜Z¥F¯îøV£Ó(•¸ ¡j½F)J·¾s×ä±7¿µî†Ãk 2nzc}a㬔ô9ËrM7ÏJNŸ»rRÔ€p­6|@TT|„VÏÿåa¡÷+e jöÃYzkL,ÿ6,xŠic>‹å›Œò€ïô[UÝ6yì‹ÁðMŠüذ‹Ðôô´ÔˆˆP•QÁ÷é£àû¡ ÌYñÄõ ö¸F_³ü —}Ï‚«;Î)ú¦M9bêˆ~ ±oZá¨Q…éQ qß ß>V8áAAwà9!ä±Â‰;:~¬®z zXŠeüÇë¶Õ>[=ÿ7J¬}Ö®g3ØÜ},MœË"™VÌðdg°6Ñ‘©+*ˆÌ.(ÈŽT ä?íØk4†eµ 1³‚|U›áÉ?Šï*Œv5.íT*íì@ïQÉÉÉ!iÁ§RƒOó §íðcSEˆ¾ .¦Ÿï|•ü|ûÖ¨è<óÞrC˜ŸA<§íŸ:n`ìÐh]Ü„EBrÔÒ¿6ÖÜk6ú…‡üý4~J…JÓ7çªa×^Ý?,1cÐÕ×W­ywõøxÓUå÷Öå…kƒ´ªˆ^Šg3fgĆDzFć½v ãè æôš •+£ãÃ5jUhÿ˜Þý{÷ 6äVç,˹nLäøµÿX'¦•.Ê}}Éð1¶íV žš‘FîÇϽgD¦ªaሀØ},Blc ×< Š*ÎcãÆ;$øv½‚ow Â··ð^=ŸåOmߤXip_­;|Рa±:•..=1q„¤ÓI#ÓãtÂCÚà?¿€`­bµ.Lçç¯ë¥;75qdÿ  þ#2Fñµ½éýJx_Y/¯MâkÛ*¯më“Áƒ±:?SžüLyò3åÉÏ”'?SžüLyò3åÉÏ”'?SžüLyò3åÉÏ”'?SžüLyòóÃør;•¥ ¥#WÀ¬¬‚ÙYs@ỦºläìÌ&ßͨ±"WÏŒh¹†Õ"Il:êªY ÚrÉZ`½÷JXf£_-lÊQg……U¶3Cu«R¶­Gɺz¹ú[± 2ÃΊ£´9'æâ6.ŒèD½%¾fzW¢½«á£4øFu¢Î7'·°ÇyN>‹CÞËy¯U¨á{t¡Þ"÷°Ë5µòª¾}T eˆtF½½ë³J¥ü^­—߯æßÝ)ùÙ|‰O-¾èïù p¯òÈsÉ=+åwߥknY+¿çþÕ ýg=Ÿ‰dy5ü ÏNFù¬llÑÃRjJJºT`­°78ªœRvƒÝÖ`7;­ õFéšÚZiºµºÆé¦[ûK¥1Û\k-·[%«C2Ku •{½ä0×;$´[«¤*sµv±´Ðꬑ®rg­E²7¸ê+­õÕ©¦NKzÖWJ öz‹Ýa”&8¥*‹Ùé²[’Ýb®•¬NÌQá"9êÌXA…Ù†<ïRçªuZm²ÞUg±ÃÒaqÊ8$›½ëæËÆèµµ ¥,\²ÖÙÌNÉZ/9ù>°2t‘j­õ˜«¡J*·VËÓDNË"':[ç[Œ’o›R¹~±TáÂæiÝÎÌoY(ÙÍØ‹ÝŠm££¹NrÙø4±5ë˜;°¡|Kfi¡Ù^Gsq7WÔ˜íX˜ÅnìrýèÎ9¥¬†ÚÊÑü`†Ï€ƒ°%i¸1%Å×:”·v; < ͘©ÚÊWdÁíæJKÙ>_jà-ÝŠU—?jÙAØ—©ÞêDÿ"§ÙI»MÆ ò8E§Ýjq'»*™‰R¥Eoo@«Óiœ¼páBc]çàÆŠ†ºdçb[CµÝl«Yœ\á¬j¨w:|¦<_eÆæs»Òœ¼Xr9,X¶Ä›%3ÎÔb¯³:ù‚ÊËËË5M¾­v¹€¯tÑÙ.¬±VÔtë Zë+j]•Ü R¥Õa«ÅÜû6»°²Ô;RçÜ õAÖDÉRWÎ;]ª¾Óø²+’ÍypÃý¸§‚"°kvÙ¯¾±ÆÈ dÅ,x¸ëíüQ©lXX_Û`î>)Öl¦•Âñ]'ÐàrÚ\N¸}µÂÂmj,µ¶ú#g!ŸDr¥¥ÊŒÇÉhvØù¾WdÞþ·1/s °Àw,ˆù{½¸‹¾ï°˜ÀÿžE4c¿ù;—\â,Å´À@6Bε×édû²?j$Û/û£öÁÁ²ýýÔ>$D¶ßûGí{õÅDù¯o¨å¿÷Áä¿Ã$øþ‡®G[H·6}¶ØnmA=ÚŒÝÚ‚{´etk éÑ6µ[[(?Oµ(¨•ûùÅöï׈‚† ¼¤­jW1@:‹¼(Š~û»UèDQw±‚×0ŸÇ´l‘ eŠŠÅöZVm·Ìg©µfg=ËD‹P4=KbaˆB¯_~¾œ€ï„å¿`%—øŸB fâô©‹,ž>Ib|-C¾Ï–ïåò½f>>±zùî”ïKä{£|¿U¾¯î:õï.ü;w{ÓûJÁòŽœ£€U«ðuK¡¼%»‘ÿE]±­·‹g-ŠMŠMìÚȽ!.Rþz¹äŸâŸ¢½;°åbÒí Ä[z&ýªÐô®télèÙ^³{Íî}7O‘ûz&ÿ”(OÌ+±wSŠ»ùbêßÌÓÀ>—Mk’¶w¦ä×Rgw¦g)^ýÛ4fǘcï¹zÞÅ”1€oé™2^w²3eNùT’ùZæk×üÀÓ¥-Ù —Kcvd™š»—Ržçbïæ)ÿ±Ë¦&|Û™&´µ3MÞM©`ÉåÒ”}Söê§5vKñºžiººP_¨Ÿ®æ}Šîæ©øãÎD#ÍȘ‘?cæŒ{fºV}mÖŒŒk'óÔs¾’—K| …ú’“¥"¥™ùŸkÖz~Ÿ®æš}zî”ÎdÞ]¾£3Y””ª>¨ú :Ê@ZT½µú(ò[‘:jòkî–Ó‘šöšvkŠu&R™u…u/´ÂúŒõçyéÔüåæÁ›+7ïh‘Z²Zj[nm¹¿åù–#-[ò·Ü¸åè–Ž­ÒÖÔ­c·ÎÙZ³µiëë[;¶n›·íæmÏn;¼]ܽ½j{Ëöãy°êÁû|ïÁ“;úïÈܱfÇë;Cw–ílÞyä¡ìêý’õ‚ p(ê ô~ÁA‰Ð`( ÏÒc IÞl2TM¦B…Ð4h:TÍ€J¡Jo³@UP÷³Bó ùP-TÕC º²Cï}Ìéu3´Z-‚–xKÙRh´ZÝå}ŸÝ ­ƒîþ Ý í€vBAC@Oãû×g ×?½½‚Þ„CoAoCï@G w¡÷¡O½KØ è3è øãKè+èkèè$t úú: Ú½[Ø÷Þ§ÙÐÐYè'èïmìWètºà½MXï}NØm„š¡ÍP ´Ú mƒ¶CB; ÐCÐÃÐ#Ð.h7ô(ô´rC­zÚ í÷^ö¾ ¼½ ½ô¾ (ðîV˜X_E ¾*šé¥˜åݪ˜ÎíÞ/ÏÂwï3%v¥‚ü H i -B:H…z#ÂŽ#ÂŽ#ÂŽ#ÂŽ#ÂŽ#ÂŽ#ÂŽ#ÂŽ#ÂŽ#ÂŽ#²Ž!²Ž!²Ž!²Ž!²Ž!²Ž!²Ž!²Ž!²Ž!²Ž!²Ž±9Þ“l.T™¡r¨Zé=Ë¡ ¡»¼íˆŽvDG;¢£ÑÑŽèhGt´#:Ú툎vDG;¢â ¢â ¢â ¢â ¢â ¢â ¢â ¢â ¢â ¢â ¢â ¢â ¢â ;æ=Ç>‚þ } }‡>EÛ è3¨ëýûûú: ýýŒ¶_À_¡sÐyè‚÷¸ z?RA~?¤†þ¹ûº°ó<>Ù¹î=ÖÝ·Ûî¹´w¶]w»jkXÛZµm±­?ˆÐÕVa¥v…>–õV»Ð«Ý¥bÅÊ"5}Ô¨¡"@Lƒ 2ͬa’@CfI2$“!“a†Äo€`³:÷šÛóºÐGíþs¼ =3óy>ï×çóM&{¿GgÑïӻ鿖rHDï¡÷ÒÓ£³éOh*½Ï×=§4Tñú }ˆþ”Î¥?£?§Ó_Ðy¥ŽŠóéú}”.¤ÑÇéôIºˆ>EÓ§é3ôYº„>G—Òet9}ž¾@WÐ4º’®¢/Ò—h:]M_¦¯ÐW麖®£ëiUÒj¹‰¾Nß ›éïû{ôôO´Œ¾O÷Òrº~@÷Ó zÐóczœjèIzŠji-ý„ž¦uô ­§gé9ª£ ´‘6Ñó´™^ zú)5Ðz‘v”vW¼\ê¯ø9½B­´“Úüûvê ]´»´[ÊúC÷JX a„HX a„HX a„ÇØ8ÆÆq3‰›iÜLãf7Ó¸™--uag;#ØÁÎvF¤%–@Zi B÷JÁrº~@÷Ó z€~HÒJ¡  ‚¯Ô$£ãT¤×鄲ÔgºûLwŸéî3Ý}¦+0]é LW`ºÓ˜®Àt¦+0]é LW`ºÓ˜®Àt¦+0]é LW`ºÓ˜®Àt¦+0]é LW`ºÓ˜®Àt¦+0]é LW`ºÓ˜®Àt¦"0©LE`*S˜ŠÀT¦"0©LE`*S˜ŠÀT¦"0©LE`*S˜ŠÀT¦"0©*b’ÙæÏvê ]´»„oÄÚ[èV½24Å3Ü_pô<:Ÿ. Ð¥þ—ËèZ¿Ž®§TI7ÐLšE_£›èfºÝ3Ñ<šO›–5TEУô~sžcsžƒ‘IŒLbd#“™ÄÈ$F&12‰‘IŒLbd#“™´-‹¶eѶ,Ú–EÛ²h[mË¢mY´-‹¶eѶ,šš¢êO†o±f‡¾¾ÕŸs=w_"Ý2Ñ-Ý2Ñ-Ý2Ñ-Ý2Ñ-Ý2Ñ-Ý¡)Þñ¥î˜ËèöÒˆ|ŒÈLj|¤å#@>ùä#Nùèùèùèœ|ää#'9ùØ/ûåc¿|ì—ýò±_>öËÇ~ùØ/ûCÛJ‡B:Q:z«ôºGç×+BTQz]uñð7è–ÒQž¥ÇGUxVè5®TáJ®TáJ®TáJ®TáJ®TáJ®TaµÝš·[óvkÞnÍÛ­y»5úY)=ÂGÞѬÜZ:`ǰcرìØvìnå8SàL3Î8SË™ZÎÔr¦–3µœ©åL-gj9SË™ÚÐêS;¹ÛÜu›»ns×mîºÍ]w¨Úÿö#zœjè z’ž¢ZZK?¡§i=CëK¯šÕWÍê«fõU³újh£¿‰6Ó TO?¥ÚB/R#5ÑVz‰¶•6ëØæÐÏü½™¢´Zhýœ^¡VÚI1j£vê ]¥¹è‘‹¹è‘‹¹è‘‹¹è‘‹¹è‘‹¹è õúoú¨ßßþÜG4HIS3D)ÚOÔ¦“𡔣ƒ4Jcô4N‡è0¡<LþQI8FÇ©H¯Ó žŸÔç7h‚þ•Þ¤·üûR©ÛÄv›Øn÷H»{¤Ý=Òîiw´»GÚÝ#íî‘v÷H»{¤Ý=Òþî‘À=’v¤Ý#i÷HÚ=’v¤Ý#i÷HÚ=’v¤íûÀ¾ìûÀ¾ìû â›¡s+n ÝXñ-þu輊ÛCçTü-Ýãk$×säÜ9w@ÎsäÜ9w@Îs«ýù0­¡*z„¥Ç¨…o,͔ع§Ò*©á;á| <Ž-El)bK[ŠØr[N`Ë l9-'p%+i\IãJWÒ:yL'éä1Ý9¤;Guç¨îÕ£ºsTg^×™×uæuy]g^·3¸$Æ\c.‰1—ĘKbÌ ì‘´=’¶GÒöHÚI‡~—OSøtŸ¦ðé,Ô)"N14mâhG›8ÚÄÑ&Ž6q´‰£MmâhG›¸Z“R_¾F¥|TÊG¥|TÊG¥|TÊG¥|TÊG¥|”cÇòïÆ¨FŒjĨFŒjĨFŒjĨzŒªÇ¨zŒªÇ¨zlZMë±i=6­Ç¦õØ´›ÖcÓzlZMë±i=6å±)MylÊcS›òž2³ž2³ž2³ž2³ž2³ž2³ž2³ž2³ž2³ž2³ž2³º5ª[£º5ª[£º5ŠM1lŠaS ›bØæδâL+δâL+δډïµß+û1ÙÉ~Löc²“ý˜ìÇd?&û1ÙÉ~Löc2“ñQ•ñQ•ñQ5¯˜ŒWLÆ+2—ñ¸ŒÇe<.ãqËx\Æã2—ñ¸ŒÇMQ›)j3Em¦¨Íµ™¢¶ÉgŒ6“Ôf’ÚLR›Ij“é¬Lge:+ÓY™ÎÊtV¦³2•é¬Lge:+Ó}2Ý'Ó}2Ý'Ó}2Ý'Ó}2Ý'Ó}2Ý'Ó2= Ó2= Ó2= Ó2= Ó2= Ó®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“®À¤+0é Lº“˜3€9˜3€9˜3Pqkè}òt¡<Í•§ËÓ…¸sQÅ| ü[ ZìÏ¿§ %´”¾Cߥ{J)\JáR —R¸”Â¥.¥p)…K)\JáR —Røoôš+ýùÏ´Š¢ÕRõ0­¡*z„¥Ç¨š~\êt½vº^;]¯®×N×k§ëµÓõÚézít½vº^;]¯®×N×k§ëµÓõÚézít½vº^;]¯®×N×k§ëµÓõÚézít½vV4z/M´•^¢m¡ŸQ3Ei;µÐŽÒ³¨µµ6¢ÖFÔÚˆZk3bmF¬Íˆµ±6ŸzþÙ妽9rÈ‘CŽrä#‡9äèGŽ~äèGŽ~äpë…>äþ‚ "È ‚ "È ‚ "È ‚ "È ‚ "È ‚ b÷ì^€Ý P£ 5ºP£ 5ºP£ 5ºP£ 5ºP£ 5ºP£ 翉«cr¬BŽUȱ ç¯Ãùëpþ:œ¿ç¯ó$7%´œî£Ðý´‚ Òƒä–C8êÄQ'Ž:qÔ‰£Nuâ¨G8êÄQ'Ž:W Î¨Ó‡:}¨Ó‡:}¨Ó‡:}¨Ó‡:}¨Ó‡:}¨Ó‡:}¨Ó‡.O ËèòºŒ ËºŒ ËºŒ ËºŒ ËºŒ ËºŒ ËèÒ‚.-èÒ‚.-èÒ‚,se²ÌA–9È2G²3’‘ìŒdg$;#ÙÉÎHvF²3’‘ìŒdg$;#ÙÉÎHvF²3’‘ìŒdg$;#ÙÉÎHvF²3’‘ìŒdg$;#ÙÉÎHvF²3’‘ìŒdg$;#ÙÉÎHvFB’„„$$$!! IHHBB’„„$$$!! IHHBB’„„$$$!! IHHBB’0õ ¦~›©ßfê·™úm¦~›©ÞÔ?oêŸ7õÏ›úçÃ7†Î±™¯ Ï.Ýa;_žëÏï–^ßSz*¼=ô©ðHim8º0| tQ8çÿíh©?<zWèó¶xÆÏØâ[Uß§ê7Tý†ªß8u¯-UýwÜZÿ‹¾K÷Ð÷è¹õO´Œ¾O÷–V«pµ W«pµ W«pµ W«pµ W«pµ [UØj»m÷¢í^´Ý‹¶{Ñv/†FBÿ9¤O¡ôžŠmë~ۺ߶ûmë~ۺ߶ûmë~ۺ߶÷ÙÖûlë}¶õ>ÛzŸm½Ï¶Þg[ï³­÷ÙÖûlëœm²­S¶uʶNÙÖ)Û:e[§lë”m²­Sç¹]¼ÐGè£t!}Œ>NŸ OÒEô)º˜>MŸ¡ÏÒ%ô9º”.£Ëéóôº‚¦Ñ•t}‘¾DÓéjú2}…¾J×еt]O3¨’nTËMôuúÝLïtã>è¿Ym[=Lk¨Š¡Gé1ª¦{­Ç©†ž¤§¨–ÖÒOèiZGÏÐzz–ž£:Ú@i=O›éª§ŸRm¡©Ú©ƒlÊݦÿÆÒ¤'B ÷ús®?ï(m´5ã6æ”ЧÿmÞn+ΣùôË|çå;/ßyùÎËw>´4ôŸLÿNÓ¿Óôï4ý;MÿN[kª­5ÕÖšjkMµµ¦ÚZSm­©¶ÖT[kª­5Õ&:Ï&:/tÂßߢRhjEˆ*è†Ð%3i}þ’þ&TY vsÃ7….WŨàÂw„þ.ü¨¶,tnøÞÐ9¡ïþšïl±ûØýGìþ#vÿ;?°ó;?°ó;?°ó;?°ó;?°ó;?8ãO n§y4Ÿ"ßéÜúNi§öqj§öqj߯ùÚ½=doÙÛCöö·ÎâÖYövÊÞNÙÛ){;eo§ì픽²·SövÊÞNÙÛ){;eo§°â$VœÄŠ“Xq+NbÅI¬8‰'±â$VœÄŠ“võÁÓ~?ö¤ÚÞ  úWzó<ßS”¥AY”¥AY”¥AY”¥AY”¥AY”¥A»ïÐiŸSÛ¨:hí.…¿Á“«ßÑÏ”ÊOÞ—z²¾Œþßνvú9/ë^B÷º—н„î%P}Õ'P}Õ'P}Õ'P}Õ'P}ÕË?Ëéw5õ»šú¹çn?wû¹ÛÏÝ~îöÛiIG8áp„ÃG81ʉqNŒsbœãœçÄ'F81‰NŒØs °ç@ Õ'*ÎáÌ\ÎÌåÌ\ÎÌåÌ\ÎÌåÌ\ÎȽ›þ M)Ý$;qÙ‰ËN\vâ²—¸ì´ËN»ì´ËN»ì´sq+·ÊP‡ uÈP‡ uÈP‡ uÈP‡ uÈP‡ uÈPG¨ü݃¹ôMº¾EM·#À<šO÷–¦qvg§qvg§qvg§qvg§qvZhui— Ý-CwËÐÝ2t· Ý-Cw‡ªýo?¢Ç©†ž 'é)ª¥µôzšÖÑ3´Þ-ÿ,=Gu´6ú÷›h3½@õôSj -ô"5Rm¥—h[©Ú¯ýÌß›)JÛ©…vÐÏéj¥£6j§ÚUºKÆï’ñ»dü.¿KÆï’ñ»dü.¿KÆï’ñ»dü®P¯ÿ¦úý=áÏ}4@ƒ”tO QŠöÓ0¥)WjÀ„LhÀ„LhÀ„LhÀ„LhÀ„Lh˜œÚSÛcj{Lm©í1µ¯žŽ ®³œë,ç:˹Îrîyîyîyîyîyîyîyîyîyîyîyîîîîîîîîîîî;ð§*ñ§*ñ§*ñ§*ñ§*+n(ýÏŠ™4‹¾FI7úïo¢¯Ó7èfº5t®'ôk=¡ßú-žÐçzB¿Ázµ'ô¯xB¯ö„^í ½Úzµ'ôjOè՞Ы1®ã*1®ã*1®ã*1®ã*1®ã*1®ã*=¡W»îð„^í ½Úzµ'ôj7Ä7Ä7Ä7Ä7Ä7Ä7Ä7ÄOÎÕžœ«=9W{r®öä\íɹړsµ'çjOÎÕžœ«=9W£ÇôhEVôhEVôhu-7"ÈÙ ;d‚ìpA?ê‚~Ôý¨ úQ7ÃUá›Ü_/mp;Üèv˜jëþ¹ÛaªÍûçn‡(³(¼½ôãðˆg‹¡³ÂÙRKx4tmè Oòt Oòt Oòt Oòt Oòt OÇäO\ö£É~éÏINúsÒŸ“þœôç¤?'ý9éÏIîmÏÅS?ñúFù{Q^µÊ«VyÕ*¯ZåU«¼j•W­òªU^µÊ«VyÕ*¯z'Þ¥ð.…w)¼Ká] ïRx—Ä»$Þ%ñ.‰wIï°Þ;,§±ïúñ®ïúñ®ïúñ®ïúñ®ïúñ®ïŽàݼ;‚wGðîÞ - ýžJªt¡Jªt¡Jªt¡Jªt¡JªtáäO=ÖâÜZœ[‹skqn-έý-êQ‹sµ8W‹sµ8Wû[þÔ£Qÿ?õ¨Ã¹:œ«Ã¹:œ«Ã¹:œ«Ã¹:œ«Ã¹:œ«Ã¹º·ýÔ£î4?õˆá\ çb8ùÎÅp.…s)œKá\ çR8—¹Î¥p.…s)œKÚÂo™¨’Û&Dô;¥‡°ë!ìz»®‡°ë!ìz»®‡°ë!ìz»ª°« »ª°« »ª°« »ª°« »ª°« »ÖaW5vUcW5vUcW5vUcW5vUcW5vUcW vÕ`W vÕ`W v­Ã®uص»Öa×:ìºümìš‹] ±ëFìŠaוØîvŰ+†]1ìŠaW »Öb×ZìZ‹]k±k-v­Å®µØµ»Öb×ZìZ‹]k±+†]ë°+†]1ìŠaW »6`×ìÚ€]°kvmÀ® ص»bØîvŰ+†]1ìŠaW »bØîØé.|jÀ§|jÀ§©ÿÖ$ŸZ¥ÿóØôg¸ôg¸T‹K'YtCÅï¡B-*Ô¢B-*Ô¢B-*Ô¢B-*Ô¢B-*Ô¢‚ç±Ò½¨E…,*dQ!‹ YTÈžþ“m¥¨°r¨C…*äP!‡ 9TÈ¡Br¨C…ܯ ¥îÍ{K+Pa*¬@…¨°V Â TX +PaÅ$"¨A…*DP!‚ ‘ß’ Tˆ B"¨ù-©P õÿ*DP!‚ Tˆ B"¨A…*DP!‚ Tˆ¼ ‘ÓP! iTH£BÒ¨~‡?ÿ,žá*ýgøùç¯^?MÒ„ MÒ„ MÒ„ MÒ„ MÒ„ MÒ€ Ò€ Ò€ Ò€ Ò€ ÒŒ [d+‚lE­²A¶"ÈVÙŠ [d+‚´!H‚´!H‚´!H3‚4#H3‚4#H3‚œ… ŸE¿CËäòÉŸO´#Èg¤AÚ¤AÚ¤AÚ¤Aê¤Aê¤Aê¤Aê¤Aê¤Aê¤AÚ¤AÚ¤AÚ¤Aš¤Aš¤Aš¤Aš¤AÚ¤AÚ¤AÚ¤AÚ¤AÚ¤AÚ]?åOÇ ¢È Š ¢È Š ¢Æ×Pãaĸ1ÞïF‹–Ð:©H}Dê#R‘úˆÔG¤¾Q꥾Q꥾QÚ#Ò‘öˆ´G¤="íiH{DÚ#Ò‘öÈ¿oð°W]CUô=JÑzz–ž£:Ú@ÿ÷§…-ÒÑ"-ÒÑ"-ÒÑ"-ÒÑ"-ÒÑ"-ÒÑ"-RHA RHAàÉ´Å“i‹'Ó‰Ø%»$b—Dì’ˆ]±K"vIÄ.‰Ø%»$b—D¼,Ñ!Ñ!ÒÐ( ÒÐ( ÒÐ( oJÛÒð¦4¼ir{LnÂä&LnÂä&LnÂä&LnÂä&LnÂä&LîI“{Òäž4¹'MîI“Ûcr{LnÉí1¹=¦/aú¦/aú¦/aú¦/aú¦/aú¦/aú&¯§âÇô8ÕГôÕÒZú =MëèZOÏÒsTGh#m¢çi3½@õôSj -ô"5–’&q«;¼ÅÞâoq‡·¸Ã[Lg‹él1-¦³Åt¶œz‚ÿåÓ{KÅ|{k¦½5ÓÞšioÍ´·fÚ[3í­™öÖL{k¦½5ÓÞšio}É×›àz\o‚ëMp½ ®?íÏË/-ý³½õÏ&y‹IÞb’·˜ä-&y‹IÞb’·˜ä-&y‹IÞb’·˜ä´IN›ä´IN›ä´INÿ»ÏÍÞ[šn‡M·Ã¦ÛaÓí°évØt;lº6Ý›n‡M·Ã¢R0_ æKÁ|)˜/ó¥`¾µÃ¢vXÔ‹ÚaQ;,j‡Eí°¨µÃ¢vXÔ‹ÚaÑ3<ÁGí°¨µÃ¢vXÔ‹ÚaQ;,j‡Eí°¨µÃ¢vXÔû¾ö};,j‡Eí°¨µÃ¢vXÔ‹ÚaQ;,j‡Eí°¨µÃ¢vXTJHé)] ¥ ¤t”.ÒRº@JHé)] ¥ ì°¨•ÖvXÔ‹ÚaQ;,*½k¤wô®‘Þ5Ò»Fz×Ho—ôvIo—ô¶Jo«ô¶Jo«ô¶Jo«ô¶Jo«ô¶Jo«ô¶JoDz_Þ¤÷é}Az_°Ïž–à~ î—à~ î—à~ Þ"Á[$x‹o±ÏÙg‹ì³EöÙ"ûl‘}¶È>[dŸ-²ÏÙg‹ì³EöÙ,ûl–}6Ë>›eŸÍ²ÏfÙg³ì³YöÙ,ûl*܉ sPa*ÌA…9¨0æ ÂT˜ƒ sP¡ü–Šóéú}”.¤ÑÇéôIºˆ>EÓ§é3ôYº„>G—Òet9}ž¾@WÐ4º’®¢/Ò—h:]M_¦¯ÐW麖®£ëiUÒ ¥o£Ö·QëÛ¨õmÔú6j݉Zw¢Ö¨u'jÝYñW¥a;÷¼Š¹¥ˆ½{¹½û7öîµöî-öîÕönMÅß ÈßúßûûßÓ?ÐZJß¡ïÒ=¥Ùè7ýf£ßlô›~³Ño6úÍF¿Ùè7ýf£ßl»·ï´{kìÞ»·Æî­±{—Ù½ËìÞevï2»w™Ý»Ìî]f÷.«øQ©5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5»P³ 5kìù{¾Æž¯±çkìù{¾Æž¯±çkìù{¾]†®;Ðuºî@×躣"扣Í{n§ÚE»é¥Õž"V{ŠXí)bµ{àÜK=E,t¼ÏMPþÉÈ{=E,Eá5át)ïI¢5|°ÔïiâÜð˜ïd. s™ È\@æ2¹€Ìd. s™ ¨<„ÊC¨<„ÊC¨<„ÊCgø-†4§Ñ8Æi4N£qÓhœFã4§Ñ¸üYÔc¡Åô÷ô´„N÷óÈwöù€_þTf—¿ï¦_P'uÑ«ÔM{¨‡âô/´—úéí¿µðÎ~Çåô¿ápúßn(¢O}ŠèSDŸ"úѧˆ>Eô)¢O}Šè“GŸ<úäÑ'>yôÉ£O}òè“GŸ<úäÑg}†Ñg}†Ñg}†Ñg}†Ñg}†%9/ÉyIÎW”?£v3Ýz÷Û>Ùs¡_4ù‰Âó¤3+YéÌJgV:³Ò™•άtf¥3+YéÌJgV2ó&z¯‰N˜è„‰N˜è„‰N˜æ¤iNšæ¤iNšæ¤iý iý`¸ü{OWëôNéôNéôNétJ§S:Òé”N§túB¾P§Ó¡ò§ý~AÔE¯R7í¡ŠÓ¿Ð^ê§3ÿÞÊ*°Ê¬2{LÀ°Çì1{LÀ°Çì1{LÀ°Çl6›MÀf°Ùl6›ËßÛ3KLÁS°Ä,1KÂ×—žßúýÉß4šëjÚžSšþ«RcøVÿ<×?Ó?ßæŸïºì7þ”Áô†ªèz”£õæôYzŽêhí* sn˜sÜæÜ0ç†97̹aÎ sn˜sÜæÜ0çrœËq.ǹçrœ+g w†§ÌòÏÞŠ(r È"Š¿ú ˆð_!Ömtw)ú´jÕª T¨6Pm Ú@µjÕ*˜PÁ„ &T0¡‚ L¨`B*˜PÁ„ &T0¡‚ ¼¥‚·Tð– ÞRÁ[*xKï»õ¾[ï»UÓ§šaÕ «fX5êVÍ^ÕìTÍNÕìTÍNÕìüÕïºarV_èiùó¦GÂåï“|,´ÊóÏ™_ïß÷g[èMø«2§Êœ*sªÌ©2§Êœ*sªÌ©2§Êœ*sªÌ©215:@…ÒÞù°w~Ô;?êõÎzçG½Ó7&ÛàËá9¡³ôáÓ¿uðåð7ýóm¡£é½Ò¹œî£Ðý´‚ Òƒ´’VéÞ¶ÒA·çA~îáç~–ó1ÈÏQ~Žòs”Ÿ£üõ®v{W»½«ÝÞÕnïj·wµ›Ÿi~¦ù™ægúm¿5Pö4?éi>ì~—ï÷¯þÆŸÀ_UÚ¦#z0¢#z0¢#z0¢zèA j:TÓ¡õà ÔƒƒzpPêÁA=8¨õà ÔƒƒzpðŒÏ­¿ÌJÀ€7n“?EàÆ7&¸1Á‰ÓL×JnÜ£oï×·óõí½“}{¿¾¯oå,}˜;·qç6—@øÕП†þDõåï¹M¨~BõªŸPý„êËì;®_Çõëøä§² ÞaÁ;,x‡ï°àôx‡¼ÃÞáïð€WW|Oèwüíl;;ôßu¤WGzu¤WGzu¤WGzu¤WGzu¤WGz½§¡3òø4Ÿ•R}§ê÷{¥)^iŠ*„Ë¿—qW<äyÅC^ñW<äyÅC^ñW<äqàE¼È9ð"^äÀ‹úߨÿúߨÿúß(ƒSdpŠþ7é“þ7é“þ7é“þ7é“þ7é“þ7é“þ7©êª©êª©êªÙ,›%c³dl–ŒÍ’±Y26KÆfÉØ,›%c³dtb\'r:‘Ó‰œNät"7¹YFubT'FubT'F'³|®™8‡CÓ&³|®™8‡[Óðµ3TþdæÙ¡åtý€î§ôý¤•´*t ·z¹ÕË­^nõr«—[½ÜêåV/·z¹ÕË­Þ·íäwþ)‘Ò“æïIó÷$‡z9ÔË¡^õr¨—C½êåP/‡z9ÔË¡^Õp¨–CµªåP-‡j¹³˜;‹¹³˜;‹¹³ØÎý] ™aß.Ñ«ìÛû±d†}» O®²oï×n¾§ô£pwèCá=¡? ÇCSCŸ0[)³•2[)³•2[)³•2[)³•2[)³•2ÍåŸì½†¯ýš+c·Jw«t·w?t†þ¾ünš2‡'?%ø.U%'?)ø.%¥#—¿WwÍoü)¾U¥ô<¯çy=Ïëy^Ïózž×óÃz~XÏëùa=?¬ÚݪݭçE=/êyQÏ‹z^Ôó¢žõ¼¨çE=/êyQÏËßï.û8‡Žsè8‡Žsè8‡ŽÿÊoX8t‚C'8t‚C'8tbræÐaæÐaæÐàÐàÐç8ôEÉ8›C—IÅû¥âl]&ïçÐ5º%—”Ë»¼íìéåtý€î§ôý¤•´Ê¤o ½ÏÄ¿Ï;òއ¼ã¡ÉçãÞñqïø¸w|Ü;>:#'mÈ7h‚þ•Þ,%Lå•á›Bçéá¸þ•?3®wAø[¡†ÿšîÝ>ù ±„ËïíŠßø>z¸4¦cú8¦cú8¦cú8¦cú8¦cú8¦£ú7ª£ú7ª£åÿŸôoTÿFõoTÿFõoTÿFõoTÿëßaý;¬‡õï°þæÆ87ƹ1Îì>‘õôî„ÞлzwB߯õì}§î¨¹þ,ßQå곪Ϫ>«ú¬ê³ªÏª>«ú¬ê³ªÏšä²ãçÀ8Æ90ÎqãÀ1ãÀ13É&y‚Ç8qŒÇ8qŒÇ8qŒÇ8qŒÇ8qŒÇ8qŒÇ~MÖß>å½?Ɖ1NŒqbŒc&y€{¹±—{¹±—{ÍC©&ÌC¡&Lgpªúåª_®úåª_®úåª_®úåª_®úåª_®ú5ªYõ/«þeÕ¿¬ú—Uÿò韧´KõåOï´©¾MõmªoS}›êÛTߦú6Õ·©¾MõmªoS}Û™>ñ+{+Â7•†Â_/=®—+dðCúyýävª”Ãéëõ“Û©RÅdÑsOi½«å¢p¿»ßÃ{C׆þPõqÕÇUW}\õqÕÇUW}\õqÕÇUß÷>aá]$½z¿¯žôÕ“¡/ø*u¾J¯Rç«Ôù*u¾J¯Rç«Ôù*u¾J¯ò½_ó݇=<ÜÃÃ=<ÜÃÃ=^±Ù+6ÿVÿ6’21D)ÚOÃTþÞÍ¥¥ ò•¨|ŸÊ÷©|ŸÊ÷©|ß¿}öû·Ùügú¼ø‰SÏ'÷¨>­ú”êLVñdõó'«¿x²úùªBõOœúLð'U[TmQµEÕU[TmQµEÕU[Tmù&Þ¦Òm*ݦÒm*ݦÒm*ݪҭ*ݪҭ*Ýú¶O²6«´Y¥Í*mVi³J›UÚ¬Òf•6«´Y¥Í*mVi³J_Sék*}M¥¯©ô5•¾¦¢¨hŠŠnQÍTS¾moQņÐUªXªŠ¥ªXªŠ¥ªXªŠ¥ªXªŠ¥ªXªŠ¥z6[%Q•DUUIT%Q•”²ð’J^RÉK*yI%/éÙ=Û¡’í*Ù®’í*Ù®’í*Ù®’í*Ù®’í*Ù®’í*Ù®’ígü>À[ØZ*#ø8‚ëßõú×¥å;åªÉûtšjÏUíâÉûtšŠÏUñbý[®ËMïJÕ¯5½ç™ÞVÓûÑЧÞÁÞ;ÓÍzºï¾K?ßÅ…½\ØË…½\ØË…½\ØË…½\ØË…½\ØË…½\ØË…½h~Í£ùa4?Œæ‡‘| ÉÇ| ÉÇ|LŨöb•^ Ê‹O‘ü†ŠóJÇ+Χ è#ôQº>F§OÐ'é"ú]LŸ¦ÏÐgéú]J—Ñåôyú]AÓèJºŠ¾H_¢ét5}™¾B_¥kèZºŽ®§TI?ÖÃÇ©†ž¤§¨–ÖÒOèiZGÏÐzz–ž£:Ú@i=O›éª§ŸRm¡iGi¤âåÒ‘ŠŸÓ+ÔJ;)vê“ÂíÔA»hwiÀ^L‡Ë?ÉûKæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒyæ9˜ç`žƒåßG,p°ÀÁ ,p°ÀÁ ,p°ÀÁ ,p°ÀÁ ,p°ÀÁ ,p°ÀÁ ,p°ÀÁ"‹,r°ÈÁ"Ë¿W´Ÿƒãçà8Ç98^ñ OÔE¯Ú·œúžJ>4çÿû™\­ª‡i UÑ#ô(=Fÿ›·{²<ó?þdF‰ÐTQ»»ÚZ±­'ÐjEk­[+¶¢ÅV»ëº»ê.žX<‚»žЍ Z­®Åji«®§ŠHP˜8 0Æ $™d’ÉH2ž}Ï0ZÖîþÜ×ïÕ?>Ì0yîÓu}¯ë¾îdæ™™ø•ÊñQ<†ÇñkÌÂø žÄSø-fãwø=þ€§ñ žÅâ9<ð"^Âñ2>ßâX¼ŸÅûY¼ŸÅûY¼ŸÅÛY¼ÅÛYüO÷7Ù¿$ö•D±öD)ʰ {cn6Â-¸·ávL„}®Ä>WbŸ+±Ï•ØçJòû\yIEpdÉ…¸Wa,þãp ®ÃÝÁ‘Á?šG³y4›G³y4›G³y4›G³y4›G³y4›GsÉ—ÃDÉ>Ø_A%öÃ`ìp v~&zcÉÁø¾ŽCP…!ø¾‰CqN/…sq~ŠÝ}ùæ°… ZØ … ZØ … ZØ … ZØ … ZØ … Z Ÿ#žNç÷ãü3ð ÂÌüÝh‚Ê’EAYÉ›XŒ%XŠ·X°õx1|6vF‡ÙÙ°³UÉóÚѪäùüÞÝX8µÍÂ|9ZU)Éà´èf»Þ– 2ÚîÿSÁ‰ÑN¯u9}žÇižHóDš'Ò<‘æ‰4O¤y"ÍižHóDš'¶ðÄžØÂ[xb Olá‰-<±…'¶ðÄžHñD;O´óD;O´óD;O´óD;O´óD;O´³zŠÕS¬žbõ«§X=ÍêiVO³zšÕÓ¬žfõ4«§Y=ÍêiVO³zšÕSb±C,vˆÅ±Ø!;Äb‡Xì‹b±C,vˆÅ±Ø!;Äb‡Xì‹b±C,vˆÅ±Ø!;Äb‡Xì‹b±C,v°ü@–?ŽåóŸ¨:ŽåX|ptAp`ð3ÖL°f‚5¬™`Ík&X3Áš ÖL°f‚5_à/nykv²f'kv²f'kv²f'kv²f'kv²fgÉ9Á>%£p.ÎÃOñÿÏÂYβp–…³,œeá, gY8ËÂYβp–…³,œeá, gY8ËÂYβp–…³,œeá, gY8ËÂYÎîü„n°/+ŸÆÊû²òiÑ+ƒƒˆWòï¥?0Ø£è…sŠ^8'ø’ÜS!÷TÈ=rO…ÜS!÷TÈ=rO…ÜS!÷Thyœ–£µ­µÓZ;­µÓZ;­µÓZ;­µÓZ;­µÓZ;­µÓZ#­5ÒZ#­5ÒZ#­5ÒZ#­5ÒZ#­5ßqVGku´VGku´VGku´VGku´VGkuŸóî²Zºª¥«Zºª¥«Zºª¥«Zºª¥«Zºª¥«Zºª-¼»lz˜‘/3òeF¾ÌÈ—ù2#_fäË Ýåè.Gw9ºËÑ]Žîrt—£»Ýåè.Gw9ºËÑ]Žîrt—£»Ýåè.Gw9ºËÑ]Žîrt—£»Ýåè.W2Ç.yMX#bÞwØo?´ß~h¿ýÐ~û¡ýöCûíZûmŸý¶Ï~Ûg¿í³ßöÉÒ]²t—,Ý%KwÉÒ­Ážbq€X ˆÅbq@0Š×y­‘×y­‘×y­‘×y­‘×y­‘×y-ÉkI^KòZ’×’¼–äµ$¯%y-ÉkÉâç‹S¼–ⵯ¥x-Åk)^KñZŠ×R¼–²óuØù:ì|v¾;_Çç|¦÷‹Þݧý»»o_;ß@;ß@;ß@;ß@;ß@;ß;ß;ß;ß;ß6¼ÜN7²ø9š³ŠŸ£9«p׊|-žQ9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•cFå˜Q9fTŽ•c^³)šMÑlŠfS4›¢Ùͦh6E³)šMÑlŠfS4›¢Ùͦh6E³)šMÑlŠfS4›¢Ùͦh6E³)šMQêæÏ© óŸm¡ÔJm¡ÔJm¡Ô,¥f)5K©ÙÂç óï¸Í¢IM²h’E“,šdÑ$‹&Y4É¢IM²h’E“,šdÑ$‹&Y4É¢IM²h’E“,šdÑ$‹&Y4É¢IM²h’E“,šdÑ$‹&Y4É¢IM²h’E“,šdÑ$‹&Y4ùg»ƒäœp+«¶²j‚U¬š`Õ«&Xµ•U×°êV]êkXuÍnN8¬ÚÌí­¢½U´·ŠöVÑÞ*Ú[E{«hoí­¢½U´·~Áûyu‹önÑÞ-Ú»E{·hïíÝ¢½[´w‹öî’¡öšÃð-|ßÁá8Gâ(aŽcp,¾‹ãp<¾‡0'â$|'ãÈïg?Ä©økü§átœ3ñ78 #q6~ŒŸà…sq~ŠÝ݃ìfk¹·â6ÜŽ‰¨Æ$Ü;1waç½ÆvÈF;d£²ÑÙh‡l´C6Ú!í(ù•úúQ<†ÇñkÌÂø žÄSø-fãwø=þ€§ñ žÅâ9<ð"^Âñ2Þ°—/›XŒ%Xºû;PR%õPR%õÈ‚“eÁ±Å,xb1 ž( ®-¨«“º:©«“º:©«“º:©«“º:©«“º:©«“ºº©«›ºº©«›ºº©«›ºº©«›ºº©«»øþ®^êꥮ^êꥮ^êꥮ^êꥮ^êꥮ2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®2ê*£®^êꥮ^êꥮÞݾ'ífûÜŠÛp;&¢“pîÄdÜ…üûΦË÷ãü3ð ÂLü*(¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Rê*¥®Ò¢ºv·§îN]}ÔÕG]}ÔÕWÜc§ìF]­Á÷©kum¢®MÔµ‰º6Q×&êÚD]›¨kum¢®MÔµ’ºVR×JêZI]+©k%u­¤®•Ôµ’ºVR×:êZN]Ë©k9u-§®åÔµœº–S×rêZN]ËyjO­ã©u<µŽ§ÖñÔJžZÉS+yj%O­ä©•<µ’§VòÔJžZÉS+yj%O­û_ïã5'/€Â9ºªðÙ–|\µXy‹•·Xy‹•·Xy‹•·Xy‹•·Xy‹•·Xy›•·Yy›•·Yy›•·Yy›•·Yy›•·Oqÿo5ÚPYã0| ߯wp8ŽÀ‘8 Gc†ã‹ïâ8ïáŒÀ‰8 ßÇÉøNÁq*þ?Âi8gàLü ÎÂHœã'ùï•]Gá\œ‡Ÿb÷§ÌNÞêä­NÞêä­NÞêä­NÞêä­NÞêä­NÞê,œ2ÿ÷¸úsfíÝÅÕî~KóÙ¸š$®ª‹quJ1®N)¼ïôú/x?À Ôµº6P×êÚ@]¨kum ® ÔµºÖS×zêZO]ë©k=u­§®õÔµžºÖS×zêZ¯ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/§ÒË©ôr*½œJ/G]ýÔÕO]ýÔÕO]ýÔµžºÖS×zêZO]ë©+A] êJPW‚ºÔ• ®u%¨+A] êJPW‚ºÖSWuõPWuõPWuõPWuõÈ9Õ_Võ—QýeTÕ_Fõ—QùeU~Y•_Vå—Uùe?ýÄ È áªÈ©8#­â®hqEË.ïŠ^Zc½+×c­+×›QÜŒę̂.RXO8¿øîÈþ»ÿ/òø÷Ae°—¾ŸÑï3f1ß,æ›Å|cÔ£>ÿ[²`_}ß ïôݦïô½CßY}gõ½ÞÕ­®nŽþx›1*vsÿ¥ …ó_¾§‹õt±1—ëébã.œ|Uèá³<"z~øDñ½Ã‹‘xd1,þ½úâàËzºBOW˜SVoóõv…Þò3­§Ñz:LO·èéf=íWøëiþ¯¦WªÊ® ”iõ¢/j±B‹…û§ý=òO­` kd"cÂG#—‡“"WàJ\f>£»èãEö¼‹>^Ôú=~ÅRNäZ7i½Të¥Z/\®.¼Óàm”ÞMTæú>#®3â:#¬3—½Íeï‚Õùé:½mÔ[\oµz«Õ[­Þæïâ×¾¢_û ~Í÷¼Ñ:F…Oi»EÛÚæ´Íi›Óv½¶Gi{"+—k;”•ówïÊFS úË·ž`^ËÌkYdL0ØÜ–iu)˦Y6©õT­ÿ²ð·Ë‹<æÿvye8Më ó¾ÂØY=¼¦‡×´~Mëãµ^¥õËÅ;¡ÕZUçßÍ”ººÞÕõ®®÷Óýüt??yžR¯·†XêÆ0™$ §êûA1ôpØy$ì "~º=’ÿ[~‰·ñÃá¶Èx¯M(¼¾óšo´>#l4BÆY#d5B~žû›ç<£¤’ލÊYºÛ¼Ÿ3R·‘ºÔm¤n#õi«õ4­Ãh7i•Ö*o—v³n7ëv³n/ŒóÉŒï3«é¬|?À/ñ0»>"¢ó¾ÌPy ;~b•V²S§iפ ¾ëÞe~i+èc‡üÌsÖš“n°‚Iæs§qïñü^š¹/8Ь÷¥Ûk(áZä#âfÜâªI§°÷ݸWS ÞËjuXAÅjg3xÏ Þ+h03Èhû4v²A´c“¿ãW…±ÖkͧWßöûéF3ÛÛxÆë(Øö>³žÁRRÖÔýH˜*ôµÍÕ]úz?8&òœµÎ±Š×©gɉošÛâðºÈ’ð‘ÈR¼>‰É´ všU®Yíq 2¬Ü‹­vœþðîH.œÙ†íáÊÈGáãÑ@ÞÙÃ.Tæq/ òÜ)9ê”uJŽÅa8<ìŠþ>ztøŸÑaŽcÂMÑãæèˆð™èÉ®ùä[~ξý™=açgpòw}¼x÷ÑÇ §­¿Šèáƒ#V±ZTçµÝÃ=|‘aû4›÷ˆÂüo Î4›3ÙrQAy=žÆÃóîǼû1KŸj¯Ê Ë»KÌuiA'ƒvÍ·…\{½ÕÜa%5VRm%ÕT·ŠêVéûÈ•÷R¼%ÇœõVy}g®½îsríäb®m”kW&×Þnå/í’k¯Û%×VSoõ.¹v¼\Û¸K®ó™\Ûô9¹¶º˜kŸgÝ늹öVJß$×Îkgȵ3äÚ, Ë_Èò²ü…rí³rí,¹v†\;ƒ ÿN®!×Îà•³yål^¹E®!×ÎàŸóÎÏåÚrí ^:W®½NÔ,cå§YùiV~šçΑkkäÚrí ôG¹v†\;C$=%×ÎkgȵÓxøB¹v/ßÆË—Éµ-rmþe7ɵɵÉµË ç•潿å½á½?òÞ¥¼w)ï-ã½e¼Wo—læ¹×)~Ï-ã¹ mäÓ|.5JÂ(«Œ²Š?_uÍFZÁoFZa¤ü•-D×`¾Ûàà`Ûogóul¾®¸—¬`çùì<Ÿç³ór¶])êØ²I½Þa÷Éï“Ç8U°Z ]ÌB²Ðƒ,ô–y>Å ÛÌkö§5ø–øH^ ÔÏeØ+|&¨åŸÚö-9FÁýáóŸ¶Ú¹#viÑ¥E—;Q/¶ê¯?|Ü•¯¸ò뎻z¶«eÝ=ZüJ‹_9 ¶²Z¸Î•Í®l6“6W½Íí®zÛUoÛ![ít;÷ãu®Zçª|]³Õ•ù,•uec4ÿí>_áçÇøù1þ}l/,7ƒåZeµê/X¾Ô8åácüùª[Kukùõ? ï]¿¨ð[¤X°rzÈé!W£ñ7ê-ßÓ–‚böØE1;?åu¸óF•}µÅ¾ÚR°J»^ÚõÒ¬—ÍŸTñziÖK®XµR±JÆÉ±[åšþðý¼ý\õž«6¹ê½hþNÖÚÁ2=®Þîêí®~¯x&ùd–ik^¡e‹–Û­¹[ë­[‚ˆ•~×J¿ë,7§´í»cyØm‡údo5BºàË&½®×ëúb5rO¶hû=ÖDó÷±Î·œ£å<-»´¬Ñ²÷Óõî`÷]ô¢EMñoa‚’Hþóc´ï*ÆåÎ5ì(h¬ÕH[´kÕ®µ°òߥÆówñrƒ×hÑSðpyá·k¿,zwc!û_#Fò­ÿCë¹Z×jÔ:©õ»ùjYˤ±òv¨-Ìí|ö3äßsMXì«u\ëÅVØ Ï·é¥ÎŒšqçDZ/³Q>£äõþ²™¿¬×:½>¡·š‚—W{…±ëõ1þZåg¿B‹-z¨'΂­jþþðc=eõ”-œAwÖé)=½§§EzZ¤§CõthÁ-æÿ®ÖµÞ¨uþw-ŸQ÷&ëØ–¯ôYl°ïð'?l4NÜ8Í›tè¯C…Ù銣åãaêN .Q1^ŠËpmøûà¦pzðoøwÜŒ[ lƼçšíá}Á|€ñQx_Éа±ä0| ߯wp8ŽÀ‘8 Gc†ã‹ïâ8ïáŒÀ‰8 ßÇÉøNÁq*þ?Âi8gàLü ÎÂHœã'#‚ßëw{gî·P‡z¼X¸$ìkßú *±cŠ¡8 ß·qFâlü?Á9…sqÎǸ$|–ÅŸeñgYüîàºðùàzÜ€17…ÏñÂs¼ð/<Ç ÏßüBw”ú¿ÝIj?Ïáç9Å»Ï7N[A?r؆íáB¾_È÷ ù~!ß/ Æ{{¢eØ P޽1ƒð%œŒÀ%á£ìð(;<ʲÃ,v˜Å³Øa;Ì &û²Å$¶˜Ä“Øb[Lúßv2,¨A2|Èʲ²‡¬ì+[`e ¬l•-°²ÁûÁ>V7Íê¦YÝ4«›fuÓþ\ïŒ9:8¹<œ¹W†e¿«£¿ï’¯Žþ½ÇëT׋þj½•Ae´«ÅüY?.Œnöÿ-ÁÐh[áUÑN]A…<¼Ü³$kåŸå?éqPÐÏ£HÚO6c Þ ¶Ê•}Èç̶a{°°àC|TøÄd­óC­óC­óC­óC­óC­óC­óC­óC­óC­óCmÉ—ÃgJöÁ¾ø *±c€ñÕð…’ƒp0¾†¯ãTa¾oâPœ.(…sq~ŠÑ^??ÃÏq. .,¹ÿŒ/ùÇàJþ)8§ä’à’’›)ýÜŠÛp;&¢“pîÄdÜ…{ô5]ßðKÌÀƒx3: ÿ.r Npò<Ùã©Ï~93øfä,Œ ÿY”4Š’ÆÈ˜àÄÈåÁ×"WàJ\åµ)á’ÈÝáõù*êQÑçïá%ÑV§å¤]msá.¢OD;Ô»){_§ý±+Ì•ä¿IyH$‰„A"aH$‰„A"aH$ìrçï&ºÐ·Ð·Ð·Ð·Ð·P„ÔˆR#BjDH™&B¦}¡»•ïúML7•"¡R$TŠ„J‘P)‹„Á"a°H,‹„Á"a°H,‹„ÁÁ´;‚éáæÿáš6ãQ<†ÿÀãø5fá üOâ)ü³Ã±"h¬+‚ÆŠ ±Á3^Ïáy¼€ñþˆ—1¯`.^żðaQ÷p0ßó×ð:`!ÞÀ›XŒ%XŠZ¼…:Ôãípœh'ZljÖq¢uœh'ZljÖq¢uœh'ZljÖqÁmÖ"îù:뱑ЂÖüÝ«äÉøâ£`O‘;QäN¹EîD‘;QäN¹EîD‘;QäN¹EîX‘;V䎹cEîX‘;V䎹cEîX‘;VäN¹ãEîx‘;^䎹ãEîx‘;^䎹ãEîx‘[-r«EnµÈ­¹Õ"w‚È r'ˆÜ "wBÉß™ëEÁIÅï8Gôž"zO)Þ×8Q2†ò¯÷xnÄxLÀMøwÜl^·àV܆Û1Õ˜„;p'&ã.L)¼rBɽ§bîÃôpª¨Ÿ*ê§Šú©¢~ª¨Ÿ*ê§Šú©…»³¿‚¹xóPƒùx ¯cîâž¶§íÃiûpÚ>œ¶§KjeÝ|{zÉ;Ú,C–‡ æTæÔb†9µ˜a”YÊ,Se–©2K¹l2U6#›Œ‘MN’MN—M¦G_ ߎ¾Žayô ‹ÂdôMYdqøkYæ æƒè–B–ù‰,óX4ÿ{’ÎpN´«ðíŽÕáHQ;RÔŽµ#EíHQ;RÔŽµ#EíHQ;R´.­KDëѺD´.­KDÞ<‘7OäÍyóDÞÁ«wñê~¼ú ¯ž¯V\ȳ·ðluЫZ©’窜ôªœôªœôªœôªœuªœôªœôªœôªThUÎzÇÙ Óv´0m'LÛ Óv´0m'LÛ Óv´0í´7Ôio躿ö%<|).ÿÐç\Ž+p%®ÂÕ‹Å8äw­ë¯ ';íMvÚ›ì´7Ùior0Á¬o ‡;ñ wâîÄ7܉o¸ß'¾!N|Cœø†8ñ qââÄ7ĉoˆß'¾!…ûå}þýØz©³—:{©³—:{úŽwê;þÿvÿÛðV ¸•nuêërêërêërêërêërêërêërêërêërêërê뢖qÔrµÜA-wPËÔrGð~pµŒ –Ô2‚ZFPˈ’H°wI{`O”¢ {aʱ7ÔBNaÂ:… t è6Ð),á–p K8…%œÂNa §°„SXÂ),á–p K8…%œÂNa §°„SXÂ),á–p K8…%œÂNa §°„SXÂ),á–Ïþ³dÿY²ÿ,Ù–ì?KöŸ%óÏ”ùgÊü3eþ™2ÿÌÝœÂq ûŽSØ!²»SØ!²»Sا°‘Na##gçßQTÙ ÚíùwGßë$v©“Ø¥Nb—ÚÚ#Wëëéàë‘炲ȫÁÁ‘yX^YΉ,Å[á‘XxZäÝ`D¤ßé-§&݆›£•ÁÑ#EãÑá«ÑaŽãEåkNg ‚£ì&u¢´&ºÂ®±ªðû𧏠‘ùÝe““Ü]Å“\yñ÷6åv™l4e‡)Üy#Ì8KíÎVËÎVËÎVËÎVËÎVËÎVËÎVËÎVËÎVËÎVËÎvª{F}Ú >m°;M±;M±;M±;M±;M±;M±;M±;M±;M±;MqºzCþ|Yþ|Y-Ô jP 5¨…ÔB j¡µPƒZ¨A-Ô jP 5¨…ÔB j¡µPƒZ¨A-Ô jP 5¨…ÔB ê uPƒ:¨AÔ jP5¨ƒÔA ê uPƒ:¨QÔ¨jT5ªƒÕ,j–F5K£š¥QÍÒ¨fiT³4ªYÕ,j–F5K£š¥QmR¯6©W›Ô«MêÕ&õj“zµI½Ú¤^½0E½0E­0Eð„š AMÐ`ÿ?—GÒöûœ½þ^Hï¼ÿ‰ÿÿußWÕÑô½åЛT¥ ˆˆ½ *vb,D)‚ H±`‰c7»˜(ö‚±÷Ž QÄ;bDÁ‚Ñ{¿ÿÙ{5¦½&yžç}¾×û;³÷ìÎÎÌÎÎÌÎáP¡<Ê_©,øke¯T^äo”x•ò*«ÜËß© ¸ý*e©¤¥<*i«,$e¤«¼(é)7HúÊ«’r¯d¨2ŒÐo¬,%¢õDêþjù¯luBËFËFËFËFˆgçÁ³óàÙyðìÚ:¨zN? NFàðòĻكYåw³‡¡M—|ÕMäM¥È™ÞŠ}½L´0KŸhc†Œ-¿·Ñ˜ÖÀ,F94ROE|Àé]!ÿ¶ŠàˆZ ¹X)vH ^}ô^³Ë1£L¦)GzÐ샵+ZÌC¯Œ-? 6ù͘Šk¡‚¶üF®|ôŸ½ ÐãEìâO8Q.A×@C÷°M EfÜÁŒRÌ(à mÍSC-cŒ]ì ñ6fù-ÌIbjA".¿@Í«3 À« ³åê  6W„¼ð.®{¸*‰+*hWTЮ¨ ]QA»‚r¨¨¨¦ƒIŠ6 í0d§I aö'öGàŠ}î'öƒTûW÷þ]ýÊÿÍz‡ÿ‰¾ÅÈê™KDW²ÕD_²Áe‹9v˜oïȤ¤šsÆw\µ1抱:ˆÇ’d¶uD[[Öd;K¬·:plÄh™ å€þšøî„ï.»L¦C´v Áµ\`8 .åÄ ria´T²BOu\5ˆä3f)h:@>ÐÅU÷ŽwÂåŒ~àÔFŸ+¾×cP)¬ò µ$kp·!\CEž]ùåjIµ0æ‚1õl-R 2ècöc±Ò k,[hÏýjþú ðXhÀã.è«qWô˼± зĨ•ê™T]^+,NÈ€½´_{ô9§&úã$ë8Bว"¼O&B¯5ˆ…fŸª ‡ä0†&B·Î¸WïSd°€ Æò®íiif½ü•ôòºÕ3^~ÚäŸÚ¼ö¾ýÆ.àí5‰Ñßµ ̪/ýûÀ(#æÿ.5KôüC;ÁlCbú¯Ú ¨XÉ+ú÷Ø vb•ØÇd3bEF×nÀó52 åyÄBwD QÍuô!D5[ÔÑÇ}š¡Ž®BT«†:úÍé·ø´ Kññ¥ëéÚ’¡çhk¦`ž´óbÞ4€5gÍi_ÖŠµ¦ýX{æG?gX:€ub]é@Öu§¡¬ ¤a¬/ ¢ƒÙ6€aƒØ ͳHư!4–ŰxÇ’ØšÄF±Ét$›ÊfÒÉl[@g°El1ÇV±­tÛÎ~ «ØIv™îfWY=Éî³Gô"{ÊžÑ+ì9{E¯±JVE ™Šz‡3Îé]®Ãh17áfô1·à´Œ[qúœ×ä5é+îÄékîÂkÓ7¼¯Kßòܪx#ÞˆQîÁ=ã^¼)“xsÞ‚éð–¼ÓãmxfÀÛñvÌûq?fÄ»ó̘÷æA 5.`Èwø0æÈ“øHæÌÇò±ÌçãY]¾€/dõø&¾‰5à;øæÎwóݬ!ß˱F<_aÍùþˆùñ ®bþ’–dÌ‚$ É…K-¥–l$¡°}Ú\;—ðˆÑI¨›‡$EÆ’ø¸°”x’‰ó’´sDµCT*bŠ \›Ø'Ôêõ`W^°§ö¤éÉF†hðŒP¿ÛgbNêÃòšÄô„RXÝ@û“0GkŒ:ßžÔBUÜ|šÂ:?#½`« vL"H ªУ»#ñíÐÕ‘ óÌÅÏ„9Ä…XÂâ½IKÒ™~ "œÔ!ÝH*5®(蓚ðÚÄŠ4$‰iÏè¿ø’¸‘îdj…X eSb@‰ êÇê¨Þ›Á“Ú‘N¤7éS¦.ñ'¡ð¡82,Â39‚Í0SÀUnp€G#ÂâRØ/ xSÀ»– ø2",9’½•!gê h, …€6ù£€®6ÐS@[ Ž‹Âýì"`ÏÁñ Ãx_ .`´€ñ¦D%…Eð4' øµ€‹\!àF ã»< àѸøÔaü”€y^𺀷,ŽKˆˆã¥>ð %‚Á$I[@Cͬ! ƒ€. h¤z*l* ¯€íì”48^ò°·€ýåþP£Œ0IÀQŽO†Î¥‰NpŽ€‹\*àšä˜ø(i£€ÛÜ#à! ˜›<,"QÊð–€¥¾‘¡–®€VÉ©áÉZ.ÖP!`S}l—œš˜¬ÕI@{ Ø_ÀP£R ¹Vœ€IŽp¼€œwâðËêðˆòÁ³uþFKá Ÿ†Ò_€v¿ƒŸ„1C>ýO¾QD°ßÂj2±zJò¨û É_€6¿ƒÆ𠹏héGP–÷ã>ÃOB-Ä> DSµEükwVš»¿Â—"2}:#úû㌠AtŽ'#Èx2 yÍd2kãìB~s‚ä!³¹EŠÉRA”T›#Kq ®´!mJ[ÑÔ_½¯´š¦µÑ´Žš¶)¬_n}Õ÷ÌQ}ÏfkîóÕ-·Q÷s >ï©éOÓ´ 4mžºENªn5ãÒM{]Ýjy©[UbW©ÞMõ½~SMÛFÍG¿‹æ~š¦}«n ÝÔ¾fxSÝšh«ûM¢5m®¦½¤i5|M*ÀOW/< œÎÔÅJ—È>@ËqgL$þïÈ;ñβ03fã³`Vbp¹±Œ+ÿî Ú\f߱Ǹ!}FŸá¶´(}CßFUTE8ÓbZDbÌ€h±j¬Ñf–Ì’è0fCt™3s&z̹}Þœ @«:V—!‹MMÈÔ†Ú“ Ôº‘‰ÈS’¯›#ShM ÓèpšB¦Óit™…\u1™|´'™ÃRX*ÙÎF"3ÚÉÒXÙÅÆ±ñd7›È&’½l2›Lö±ylÙϲ…ä²É+ä 7ÂËÛy‘ÈäüÈKHÓ€˜³e¼ïÁ£ø>”ÇòdžÊGòÑ|ŸÂ§òi|:ŸÁgòïd-°¥l)‚TWÞšòçþ„ñÁ<’pÍcˆ2¿$¢ÃSx Ñå#øT£ø(¬¹ 1@.ø%1äKøh–‹Øñ‹Žä]`-˜¼7:̃y`oš2Ø kÆšaÄ—ùB×~̺îº@×=¡m`×€~¬ óÁìö¬3ëÁZ²®è×ûëTXË×¹l.쀹"sjJŽ’“ä,Õ’\¤Ú’+j0†5ïCMC„ô5>’¾¦°œ8C’k^5†ÝGŽ1ù”€M$¹V¤’›ä&ìBæk!YJVRu©†d-ÙH¶’dÿ_FäÚÚL2G†¬-éHº’ž¤/H†’‘d,™HÕ$SàHÐôAžÃ?·"†R[©-<€!o­Á×ðu|#ßÌóø ~’Ÿâ§y.ÿ‘Ÿágy)ÌŸð§ü/ãÏù þ’˾£ÍWóÕ ¸–¯…,Ù<ûŽlëyHrîþúj`ectßÏðƒü?Ìð~”^¿Ëïñb^Âïóü!æÉÔ×ð5 ¾Ž¯õ|#¨oæ›Aý8? ꥼ\Po(ÿoÙPýƒuÝÁ<¢™÷œÿd­²®ÏŠyÎĘö¡ýèç4ˆö¥ÑôKeãÙ6Ÿgòõ|›shOÚ<„!Z4ŸæÃ–RX liï—ýPOø¡>_ÄÁd ò­|+NF+Èkò%™H¾Â0™L!SÉ425ïLœ³Èlò ™Cæ’yd>·…¨{£ÖYB¾Eí»”,#Yd9YAV’Ud5ÎŽµdYO6lTËßã$ÙL¶­¨Œ·“d'ΕÝdÙ‹úy?9@â”9Œ:‡E}œü€3ç$9EN“\ò#9CÎâ:GòÉyr\$—ÈO8® Ò¾F®“ä&)ÀéTHn“ŸÉRDî¢/&%ä>y@’G¤”<ÆÉõ”<#eä9y(SŽsìÖZIÞ*ò–¼#J¢’3ªåÈz³>¨˜û± ö9ëªy f!¨›CY gríÌ¢P;G£rÊbYÆâYKdÃQ_c×Ù v“°[¬Ýf?³;¬ˆÝe÷X1+A½ü€=dX)×gÙn ×ά µó ö’•³ öнF ý†U±·ìSÊ•4§r%Í%®ÅµQMër=Þ‹ð@T»y0åa|Î'ò¯ø$>™Ïå‹ù·| öuߎ w*Û<~Žçóóü¿È/ñŸøe~Ej!ùÂj,Õñ_Dò/DdÎâ]Q/¡¢ö'—QK WyD®‹8q“'òDR¯N'·ø>‡ÜÖT$bé]á›÷„eÃ.דá¡÷…‡>à»ønòPøi©ÔLjŽ`ôöð?cw¿¶ºÿ”Íü[¬î÷v÷ÞòþØö~±>Ùþ~±À,aƒÿ;V¸X¶ʨ%¢Ž r j‰ÌÁ†ÐHR_D£Æòs.âEc‘K4A.‘F|èXdG~t1ýŽ„Ðô‰`IˆOãÙT¶˜Ì'ûjnÈÍÈù™ùž[ñzdoÀ‘cÜÙÂIau7pž5ÇÉk†и"ð‚L«ñ‘!Îñ}“¸;¨¹;ˆ»|ëi}Z²7¤ ±>ÔÖØ‘vÄR»Ò®DB޳™¹:›Û„²L£4=»>êùmá$2ˆl¨È X<¬뇳¿?ë‘`Œ³?’Eâìe±8û‡³á"ƒp–ßÄú« ¢¬âsÐŒýN”sÇ¿‘KÈœug]ÁYOpÖœ gCÁñÖ‘^¤—èOô2½B¯Òkô:½AoÒz‹ÒÛôgz‡Ñ»ô-¦%ô>}@ÒG´Tâ’Ä+ø+þšWò7¼Š¿å︒«þ•> Ê—äºÑÖÅDvZM®,P[pÔ–sT-ØV {ëOt°ÁDWXš²Ö8œ‡rÖj@SédÌãè8œ SéTbB§Ó¤Mg3ùy+1‡î„õ¡9°çô$©NÏÐ3ÄZä.6â ¶'¸Bd0~"ƒéùšC 3ßüWË©'r†þðšOU€g¯"âÝEl{†8ö²ë¢´€ÜލPOxO+êG»ÐzX‡Vå.Úþð)¹ ¦ÍDB›‹vm!ÚPT…rF[Š6œ¶mm-ÚÁÚ¶¢¢~¢¡D?•ÛZžhof¸k@ä§ì …o6 ¡ ÀAÔ0”z†ÑÆ€áѼšFÊh$õŒ¢ích{ÀXú`¢—N€‰uj¡.€I´`&j`F—Ðî€ß¢¢RÒ†t"=I %Ñ$‘Œ"p²} Ëĉµ§Ó6œF‡pòäÒ XA&¤Îm0Ý(Úú½hÑM¢ ¥[EF7‹6œnmÝ&ÚÁt»h#éÑFÑ¥BË„²„– -¬ZX-´°Rha•С…µB ë„ÖËk1ÎM´þÈŒ‰ñ$¾âÙ1,ËJ躺ÐQ ¾D­?|‹–5)ž€ÒBWÊ•­Û'Ôç6΄årŒ9»ŒVÐ*mfÈL™³eµX]Q/ÿ;ë_DrQ£ýRñéÊUЇê¨ƒ>TP2÷!æË'€üŒÆJŒâN %ïŸÜÍó¯OÃlýÐZ¨»m}¶>Úzõ&ušôʈ갬 ÛºèªÍ(õ0PèikÕ7æÌF‹(´õëkS‰fx3*e*z)|Ôc·Âa‚6Iþô á$™$8IRpµ’? §ˆIoŠí‹nJ;ÞgÆëÖÖÊ“S3×vËʰ,Tdðã¸Ü³8‚«Öñ°õü™Ú¿º1¬“‘Ç*…ÑQ©„JŸ.„ä}$msÖ¿­‡¥Â\¾Ñ57왜™ïØ>,1ÒÃBa&wë˜ø¥&…‡Åˆ‰‹‹ô05ôê›k÷Ž™éa¯°•; Ì-ÔŽí#“Rb¢b"ÂRbâ=j*ìåann¥î3 \†%ÆÄqlßVáPÝHÑØÃSá¥ÿúW7òo{6nÒ¬I³þŠÀ„íèQ]a©æoÜ72)&0fH|ÇÎñ =ê+êª9¿¬ßó ŒL™,3Í Îk…jžAMúõY¥d}î¶UgÎ:nÖ7uãäÔg;üË sL ;¸r°Ýõý•¹³'*¦Ÿq#¶ éR“ÃçKG=¹f|‚ïá¹›öE¿Œ›—{0À=»SËò]?²eËÞ4ŠuXõjeæ›Sìç/º‡–¶±¿×èVë“; '”6Ô£!_œn¾®£cžG²Q?÷³£¼Ï7[l¶÷Vt£ ÅEG§Í¨wlºÓ䨃_õKH=ì»Áurpn5KßeöÎÑ?®ü¡KÁ^Ó…Îco´ªsÞaTé2ÓeÅÎÖ7ŽoïØ>ÓfP–Ãì»!åOƖ˧³Ê»ÜÊwî»nþÙMSFlz²ÏèÅÝîײª¢³6Y´Ø>9g?ã0ü•é7éW^Úº°X-- ‡S¸*\Þß+è¤Ñ))‰Í5JˆHNl8zO†ÞF$ ¶coN©JÒUh£a”(ÚÊ}5¥æ EÓ,¯,ÏI Íôˆ¤¸_Ín¤¶•M¥}Û†À–j_[2Tè¿—‚ë*ŒåN™—І„¸7•`™«¬ÕßÛ777ìØ†æãîáÞ¤ño¼‚§§“.±•ƒŽúÙyL½¸þ‚Ãée»ng·L Š/Ô­»2äTî\ó)ÀèiÇ:ˆÏ–»§çúg^r·|ÕÚÛ©G¢Ç„²é>“·ß¿¿(ÏõYàïra}ÿ´M»ÃÚ¾¨—WrúZHÁþú_µÚùÝÎk?÷SÚñÃøòs†KŸ-TÖ¿Ø"ÀÖ֧ΫÖ]àÃ*E+Ñø±ÑƒúÏ.]­;¥†§–^Hæˆ)¿õãÿˆgüÞ>»c¿¿È´‘Â]ÍÔõSLå±È¤Oºä¶žn .F§M¬á•<þøže®ª–í¿kêS­vŸäk©ubÞùïuxQ¿2˶Þã>}®:ܸ{ qìɧ+½#¿¶k¸+ÐaàØ¨&ƒ´¦}¦á_8aEºãw›¦ \¡ûꞢò‰³w·vúy…'j¿ÜçAzë+l iÏWl˜ÙD¹¬8x¨Ö²–±E‡Qž ­lS¢“å÷(½WüêzÏwM«æöxÖMí¬I=3ÇtÑ5RØçV[ûêAÐ&i}›ÅÛÜîϲÚè[˜Ðõb“ïv& ¶ß¾ Áþ–%£ K«´*vý~óÓÅ»Û4˜¿gô奀ìº)ãÛ•6sX1Ôªøóý.ÑWÉ„öÕ&OˆÕ¸d®"ýä?tIÃ.ÉDÑXíŒ õnY®Y.“œÿÌS’“Ý#„ûY ÷“Iü¨}ä/y ×o=PÞåÉ£¯ûPÇ·GŸÎP·×zÁÁoȱƒgÏžxi|UUÙýHãp…éå)¶—æÜô­£ùÖ±ŸêyöË’ Õ¿\[gîóU¹{µåg–ô 5ý‹u /l{Úº4|33ÎùÕþ\«ù SŽD¼öhqøäœäÙ¯§¦¤ÕÊ^¹hÌ­¯fÕÞ½aªm§¶×Ÿí4rì}ydÖÂŒˆ˜wzç¦=Kݯ·äZ¥i×Ì0ÏCil˘I‡V›îÜ`Ôù&#ÌIX¹·¸›¥~­3w/\òjع¥¯IhšË‰ÕQOœK|Ôªä¥Ñø›çÇ®1<&çÛMœ¶®Ølî[ÿÚ×ê錹ZcûÀ1w¾[ ôú½"C2Cx£&$‡L÷õbz¾UEDia›5&!$¾÷msçö ‰£“b†D§8ºEÔuôhÖÌÛ±{LDRBrBTŠcû„¤Ä† ;5²å¯G’Ôgµ“¢¦z›jü2âØ65%:!)&e´šy+<< oMxðTxx6öÐÜþ$úäQÎæ$·xîoë¶lá¨ÅÃëgÖôZ9¿ÛÊÝÊïV8¶ÛkÅ’³B=cÏ·<úÉÆ§{_þèÛIv³–MŒÚþClZx­Ëö¾·Lèœû ŽvÊÌŒv]œß¼ÁaÃA®9Jô[ù,h°Þ­ÙºÒÎ_¶+šh²?3®OØÆŒ±ËCÝGv{°xÇà™=íŸmŸ:ápóÒÞóü7½[›6,Ås3 ôÜœH¿Ù¡1Þû»šéøöU ¨Z¥¯»æBzß~Owµ±J)]¯8´iÂ|å–³_\^k“4Ð7÷À3ݕΊíÚ_Þî8Òü«BMÜX§H_­H_!û%•Ò3é 'TŸø4&ii­^ã-¶uÿZõãò¤ÿýýËø„‹¨0ÿ¾Á‘™/Öhòxu¹:ÒôÅÀPÏeK ~l¥õÍ”Y§›;=ÖonƒYO…?}{åL‹ý×7í£tÖúô™ ·´ÆxÌl¹¬ZâÐýJ³5b޼Ío_dÚß±ÇÃð1›7XŸªï]ÛýPär³iµM"V¾êmWétú²å‹€ñí=uÞeT}oHœQ¯Šƒe'–W¼uôЛb?¿®M÷ŸìÙê² ·ùŽ/·œê÷$²óÉ€Þ»vp73ÕìËÏtgß³ð‡lïwÓî®Y4"‹äms¡é´ÛmÍÖ5j;ôF“Ÿ/ÙIw×}&êߨ'¾»Qøný3.þÔ»u‡³v}Ö$Þ0k>ynê²µ²Ž!9جI †,îq„Øg›^?ΖGÕÙ÷¾H°ÿo…ESä ^Þ^^^rïÙô}HH_óë”Á\aª.7ôû…%G#HŸjâA±¡9xXBüà÷’éÿ™d¶LO0ýÝ2k)œÔ˰ùxdp¤H>äl¤§( IŒäH¢+"ɱ3Ž3ªZõ|’vô’KíŠyNª³õúúç~»;c[“Ñîäø:ÝŸ"Nï^]ñ 'çòÖ Vè¼1Ù•ù(ãÄÁj?¬;ò$vâ×¶û{¾L§æX]ʈ&mFù•›ùøWEôºý¦åÞ{Þ[ #tjµÞÆ«ãËØMÊë$;8ÿØÎÚ¡×®€Ì‹+óÍOX·®=ìù|'¿Aí9½x°ãž¯·+üŠÇl³o´gÍ­—Ë —8™(ƒ<Úöñ¿9¨änéç£kg¿ª×È´µÏ¨Ví¾X}w¼stõâ.sŽò 踼ÇÄ©s—2æ¡^Õ$>®bñpßúk£)t¿SŸÙ˜xuŠ,÷5Û\6ÙÎÞ5 á l¯Ì õ ×?ÊÃùÿðb¦­§)À-_çD%ª½±d%YÔ~]¿kð©¤Þß߫ȪWݪ*§20]aýaŠ“ ôI IE¹Þž´UˆÄGÔ&,-Gó‘_Š0Qtû…Öž- ¼Îgx´šþÙOºk+Ã"O5äo|:µ=·óy//ýÐ7pÝNë¼3ÅeY•}wuš×ÑåÞúš7Ó.UX¥™Ýx1Û¶T7xûW³÷ÎÚowfþÅùó¿üæ–jÊ’®{6smîhÛÛûí¸–sÝ´ûúYX€ï=ÇQOG—ÎÊë9¿F笴ÂÈÝ…®›”§ÌvXqæÄ é‰/rodgÄëÜŒ´Þ»®bÒQ½v‹Ê\7ƤmÍ©¿vKTÍÕ›'ëÆ.4ß³¥éb­•æ>+lT´ÚçtE±&7ÜÌns¿™÷ÊÒL÷…øz—ÍÍ™3Å_ê¯5ðä¹Ëë¯ý<î›Quªvįž¥Ý8hkH=SE†Vc„2[uÓë°ôGñ¸%òwO(þ¯„Œ_b_3¯Æ^Måjɹn›È·Š”ÿÈ:4ãüOÆ?™M_à³iàŠç9…·ò³çϼìû]ÍéÇ‚'5 ~¶5©<{㔡;¯oucpêÔê®ß„8›?¨,¯õÝΗñ#6=}²Ê÷äñ#Ÿl½=¹±ëšðô°ÑËÃ_ÆO™Ÿ_prÙ…U½LG„íKœ¹|ÕÔµÁéù~Q÷nô]Ú&÷íÍ. ýäÞåqcæ›þd¿ò~ƒÓSn®¸¸8.7"wñÐÌ9!ݺ›ÞotqÀ€A+“ÝWïŸø™Ñ kË?ê^Ï\“hy¿{iÌ»àm±³×íåí3ýD‡Î–óz.Úò2zÕ•[zǤ,9Ãþ«Ø…K}vævñp£ódîE_ì0?¸=ÿIY¡Ó“õ¡aO¼Û·<¦N‰2èhäëßÕ.¿ƒ'×b×§žíñÄÖßZÛaå·Ùçæ½û“È·^î­%¥/W¤/ð‡QdyʪÿFüû}²ÐU]øù)Ú)ÚdµÊòÔü£ÂoØ{:¢òKŒ‘{%&% NHIn$;€lÿ°}OQöø¨m¯h«hý¡e“kèŽ9òèF&ýž`ÊÕ„>מÎ÷Y2p‘Epïø˜Bvªd{Õţݿo”ýEo£ëž»^-6ªr²ÙjutÚŽùã§ |Þþø—K"ÇMéÙkl†Eù—ÉWV˜Ëó\㪰X=õÈî»ËÏ,Oýî›á-mô%}w¾žèz=¤qÕåÚi!™××T½|ÞÖfcŸßwºùy^粓k¾`ÉôÊ_n8mñÁk9ëòu-k;íÜÕoªÝù“š¬Î}·arézïÖ»ÛÇ9–}v`ü¦e}¶-ït òP ×µÓ÷µ#$íQñ=UþßvÏ~åÕ~{-WÃ×È£:OžÖG{=5ª|§Ô:‰Gws@ô±C«/}¬ðì›Üù敆M,§Åæq&FFƒÆ­C¦pD)àÃØ _ˆÀ+T FCvfVðÂSP5 zNfCä‘s ÓdYQe„FC`¾ÝZZxdWö¥¦Õñ“9¶þx¹Ã I aŠAÒ‹3_†L†d†"†|ðà{C ƒƒ•f…1¤åŠj@" ¦ z   ÕTp¦í’Ê‚üô¢Ä‚ŒJôÖ$K#ƒ÷±ìÙ“¾ïþ¬ñâÍݲ‚CŒÁ«[³å—¾Í© ›¸.òl•g芃Ïl/¥yKLx0ÍlÞ9ÝÌhM±êÏfLxýaË?Õæˆ)æ¬Û§žÿ}Yp‘àúw¶7ï:¯\·Ì?YíG5ç-·ûÉ9›Ïíþr‘ýÕ¼oÁ_8'(ozóÂ-xmŒ§á]ÍkUé_ùUmøøüùÊE )ºç_˜)tЍý‰åú¶µKJù’À…óAÚòQ«ÖÞ¿µMéÎÁí§½ÌÐ\ÊgÉrù¥Ô¯[74†V®¨âÝR¡y¨ñŸN]ĦxÖžzÕuË^/{²|&ûƈ%[uãyWzý;ãb¿òýÓ×ηšvš¬8ÙÕfý’m ›€Í¢&Æßˆc3lb|zJÞé4ÔÄ2”ÊÃÆq°”Yi œö¸S;ŒÀ¤—a5äÕ÷À Þ4äa¬àå‘“ž‹À™O¤‚¦æ™VG¹–M+¼‰% 4~Kn+b ú•½ 1m2ëóþóʼ,Z]ƒ^=_Ç¿0òâ\7qñÈa®’ÿtž„[Ÿb‰x1iãÌi,vîшß-Óø@æÒ Á;–¿1”}žÁ9{ÛMûn§llä–ϵJ8¶.ë­Ò'™N…g¾—ü±H¾öÎ0Wò²™¾hÔÅSRO ôùÌ/Šš5WìÃþ™7%²änߺ¯òðô„í;s'/™¸Ýº\ÙGÃiúÚøÈçòÿþqY'n:q8l³Òãƒ,sLÝùÏ6.ÜÓ!ß×™Õú(hÁ–VÓ× .ömÒø:ëÙŠT·’ˆ]S¯0Ö•µí‘šn}N“ÇïÓCÖBãë/ˆOùÆÛV endstream endobj 58 0 obj [ 637[ 545] 842[ 326] ] endobj 59 0 obj <<70452F3F444AE34BB501302D0F056FBC>] /Filter/FlateDecode/Length 154>> stream xœ5Ð;Q €áÜaÞ3Œ7ã­g ¶¢¶Çf” ±Úqå'E¾ä$M"b£,ͩȗÜsQÜ«âÿo%Èà¡„/Ç–™¬` KøÍ6v3ÿ*P<ð!€"ˆ¡ Ô¡MH!ƒ´!‡t¡}ÀF0† 0ƒ),`noOÎú¬ä¦lse·Wž‘Èi¦Š endstream endobj xref 0 60 0000000013 65535 f 0000000017 00000 n 0000000125 00000 n 0000000181 00000 n 0000000420 00000 n 0000001452 00000 n 0000001637 00000 n 0000001903 00000 n 0000002038 00000 n 0000002066 00000 n 0000002230 00000 n 0000002304 00000 n 0000002549 00000 n 0000000014 65535 f 0000000015 65535 f 0000000016 65535 f 0000000017 65535 f 0000000018 65535 f 0000000019 65535 f 0000000020 65535 f 0000000021 65535 f 0000000022 65535 f 0000000023 65535 f 0000000024 65535 f 0000000025 65535 f 0000000026 65535 f 0000000027 65535 f 0000000028 65535 f 0000000029 65535 f 0000000030 65535 f 0000000031 65535 f 0000000032 65535 f 0000000033 65535 f 0000000034 65535 f 0000000035 65535 f 0000000036 65535 f 0000000037 65535 f 0000000038 65535 f 0000000039 65535 f 0000000040 65535 f 0000000041 65535 f 0000000042 65535 f 0000000043 65535 f 0000000044 65535 f 0000000045 65535 f 0000000046 65535 f 0000000047 65535 f 0000000048 65535 f 0000000049 65535 f 0000000050 65535 f 0000000051 65535 f 0000000052 65535 f 0000000053 65535 f 0000000000 65535 f 0000003455 00000 n 0000003504 00000 n 0000012821 00000 n 0000013124 00000 n 0000053770 00000 n 0000053815 00000 n trailer <<70452F3F444AE34BB501302D0F056FBC>] >> startxref 54170 %%EOF xref 0 0 trailer <<70452F3F444AE34BB501302D0F056FBC>] /Prev 54170/XRefStm 53815>> startxref 55527 %%EOFejml-0.28/docs/logo/EJML_logo.pptx000077500000000000000000001527041256171534400167720ustar00rootroot00000000000000PK!Úe=õJ [Content_Types].xml ¢( Ì—ßoÚ0Çß'õˆüZC»1:ú°uO݆4ú¸ÉÞÛ² ÿý.  €(@Ä^@&øîãûáï¥ÿ¸HU0ç¥Ñë„m€ŽM"õ$b/£ï­ < e4Dl ž=n>ôGK > ÝÚGlŠh¿pîã)¤Â‡Æ‚¦'cãR´tnEüWL€ßµÛ] ±…™ 6èÿ"'†ÂáO‘’n-r¯èÇg±43ôåÅ笳àka&#‰˜°VÉX ƒÏu²ÃÐ2㱌!1ñ,%Ï¡uàé;ÿ{ªÂ’£ÛÌ4?©wm¦Â#屈S±è4ÂTØ>*N+šûF8ª²±þÒÞ7†«JeµU¿/MTrT—éÓÈÔ½6Ó*kÍôÑQ™ZÜ5‰*¤ëxþy~r3UK…¼Õ1Íœ¿–ºLÍÜjÛLß`,f ƒ§ f¡Ñ,Lv´O¦™´æH¹öìq üΞ ½\éuH;s‘ôSiý:R{<ä M-«ñ¥ }Ëv*¤^âÔ¡ãü(£?tÐÌ’«§ŒÈê(¤eIÁ¡„MRß‹ŠW¿q©àâBZ2];+×JË¡ù´Ó>;Qõj%ƒšKxkdìÙ®›«‡+EeÓA±qp:Ãú*Ìvïéž¿ þÿÿPK!høt¡â _rels/.rels ¢( ¬’ÛJ1†ïß!Ì}7Û*"ÒloDèÈúc2»ÝH¦Ò¾½¡àaa-‚½œÓ?_òÏz³w£x§”mð –U ‚¼Æú^Ásû°¸‘½Á1xRp  ›æòbýD#rʃYŸ ÌñNʬr˜«É—J’C.aêeDý†=ÉU]ßÈôSš‰¦Øik®@´‡X6ÿG[:b4È(uH´ˆ©%¶å-¢ÅÔ+0A?–t>vT…ä<Ðê¼@<ìÜ‹G;Π|Õª×Hýo@Ë¿…®³šîƒÞ9ò'홼!sÚ4Œñ“HN.³ùÿÿPK!c\#´Á7 ppt/slides/_rels/slide1.xml.rels„ÁjÃ0Dï…üƒØ{$;‡RŠe_B Sq>`‘Ö¶ˆ- ­꿯Ž6zœæÍNÓý.³xQb¼†ZV È›`5ÜûËñ gôçàIÃJ ]{øh~hÆ\B<¹È¢P¨¦V_s›ÿÿPK!EÌF"Úppt/_rels/presentation.xml.rels ¢( ¬ÔQOƒ0àwÿ默NcVöbLö`b@4–¶éÕ)ÿÞ†édËR_úBsGz÷•kX­¿™ìÀ¢ÐŠ‘<ÍHªÖP#oÕãÕIÐqÕp©02’uyy±zÉß„½0˜ø* é3÷”bÝÃÀ1Õ”Ój;pçCÛQÃëwÞ-²lIí¼)j&›†»i|ÿj4¾óÿµuÛŠtý1€rgZPÇ·^Ý(ý)’ŠÛ#³d굄ž‡,bBPŠþSˆtZŠâ6&Âù)ÍSH§g21 DäÑOØ“™ì“?“ÙAÖ2&k'àóÙj3»«‡Th@71Æž ©â:&"pK¿zôG*¿ÿÿPK!Kõ=ì¿7 ppt/slides/_rels/slide2.xml.rels„Á Â0Dï‚ÿönR=ˆHS/"žD?`I¶m°MB6Šý{s¬ xœæÍN}xƒxQb¼†µ¬@7Á:ßi¸ßN«Îè-Á“†‰ÍrQ_iÀ\BܻȢP¨¦V_s›ÿÿPK!FŸÎYÚ ppt/presentation.xmlì–án›0Ç¿OÚ; R!@QH¥mŠT©“¢%}€+\TcídIŸ~gã–jR€o˜»ûßùw‡ñâá\sï„RUÈYp7eŠ¢)+±ÏÙóv5I™§4ˆx#0gTìaùõË¢ÍZ‰ …M¡É•AÎZ·™ï«â€5¨»¦EA¶]#kд”{¿”ð‡äkî‡Óiì×P æâågâ›Ý®*ðgSkJ߉Hä¶u¨ZuUk?£6ÜÅ¿%)8áæø¢P¯¡ÑaKÚ¶âå/Påcù¤ôͯ*sQ¥³8"v23oÈ7`þráÿ'|(õXv"óxšhünNæÙGó0wÔçfÚ¼yÅ9g÷AM§Ôøâ’³8§v¡/-µ[QDg—@4• {÷4aW [e‰;8r½Å³Þè Çå2z·^K÷ô{-=fÂPLž7¶º¡ ?ñ %ŸäSΨ2à{šNÎ<’ÙÂËæíš‘hn]žÄwùjºDÚºnIÑJE·>ŠBw]´ÉLŠ”Ú0ó^Qš€F’º ™jxU®*Îí 3þàÒ;eÓç®™7^6«g¸í  vßj1áÚl2„Bg(Ô¡P=ªf2ÇÃÑcØ£‰æ‰)xäc¡8>³žO7–#Ÿ7PŸ¨çÌ’ È|U†Š4JÃÔã d¨8@q( S ñ¢ 2T d(‰fãm\†Š”ö€ ºŒ‡ô‰*ÐýPkêF³ MížìF :ÅY‰­NÇå|¾Bïïó…å53¬nU (Åy¯LPR+9“dÏjjnHˆë>AwèöÐïN3 ¾ë:CÛÂÉzžK†CÞ‹š¬¬®â|náÃØfqTÙÈ)úð±¬ÑM,ÎòË$MÅ £*F8þÉ#~ûþÄ~0 òRþ}OYl[¬JÏó_V)‹w÷©i‹øEZV·Õcó÷ܤ# øôRŠÀ‰³Wßn8ÿ«üïu’°Š¿E«œWçiLm¢”à̪‹xJ#¥÷1K¡à–f¥uùÞúÏÛ*’*š]Òy’?.Í(+cà—˜9tŽc¨Î.þüôYQq†ðÂ8›|¡ŒÞl2>>¿Ã ©éV¼ù@&… rÉ|c~_ åËï „” _t-1É?n 62 €Ä£¼o8–€çºïà»C‰”ø+W ôCb¤ø@¢¦ÑR6\¦¢äzcpÂJ,›|³4¶€7’ˆ¿Fü”k‡/×Ïðé LògèC ½ÁÛ†,ó4™ *Qʸ®ˆÏSf=PÀ\µð8êÒûù§|"Ê€Ÿ’£PŒ+¯ cÅ0E…«ÓAšñnžèóû»ÒgŸl@:Fê\ˆ…R(qAààÉnâ)hX&Å„ÔÅàiâý–3:‰E1ö*±¬Zð9¥H)OqŠvMõmÃCI[¼¤º>6§SÕ¸^ßžj¬Zðžó¬i¸hš®˜©%ÆXMOÑX ¼U]Ôn‰]Q2p¹ÙcPÂ]8°?7[šßÒ¾%Þ^WÇg†}µ0ºÄè’Õ%àO]ÞørÀ”ßÝâjoü_%:ÏšÙøsžñ¬¯í—{Ö8÷YX°ÀÚÿc˜q]€!¶Ð™ýë¦n[>ƒîÑ-×fíC²Ÿœ u|/ 0ãY«É̬ 'ëöž5u’ÜBIsš¼“g­í30(1>8È>uŸ&Î 8`œA2nbœž3ÎÀè£KZAZ»êM°@pÀ`ƒ£KN_—͉pÀÿ—F‰Î³¦‚Ó ˆ©³¦ü&fí©°3³¶UÌÑ èøf×cÐv°À1̸®gíÙk‡(Èl gÜ pgA]0wðòÆ©ÜM š@Î>(‘ÈÀp7ùlPÂïž”œf ÑÄröBI+ÎàÅQ¢s7cÍ솞o7¤‰3Ðí°–»á(¦¶=ÝÝÂÙ ™ÝÐávCš¸£¾ÀZ˜BR` w``‡˜&º.ºÁ¯ÍE³‘2)XºNòvÑD7ÃE7”`r)s»îÄ#åBMt g/c­ínxi]¢s7(«¬k¬)ÎkÆX;˜±j¢t{¬ín8F€™èXBLÊ«ç¹7j¢t{¬ín8F€ fvP‡¹Làˆ×Ŗ̲žÖ7aE2K Û•H Ë?¶ïéÕ劺Èó¹”96 œp0¬“Y:$à!á&äÁõÜ!¨™^ÕbÖ,^C%³ †Dä»Ät—ËÕëuvÙuT@¢Ä€$/êD¹‹ì2Ì{ŽuéµLŸªSíÛŠÑänVYïËXçy–A¾ÂœY"M,¿‡_“XaP‹tÉ»ƒ±XéQÝ+T˜ø4MŠ? €g.¬î}¸Cž{ý¾Ï]¶µs€†ƒÀs9_Õ|áng7)mYODÍ@ô·&EmšY?ÆvÐ!3.¾­NÞ°¥ìŠÕB›]¬¢Iz‘MxÙ±M‘}8Žqž MðD¿ßÜ ‰¤^o@ò¹#yþh\. —‘Fõ°N*Õ)òz©l•w’JÂ÷Km¡äâù׊x‚`ȼ]n²&׈”¹V\' yú;LÐBB[QÁˆ§.=éËÞ=œxª3ØõâÙÉn)ž¸ɵ±¥|'ÑZ¾¶JqÉ€ûè°è­ÏªsI™>ìžJîžž8A?áái×ú.é‡\ÓÅz¡ßãë&d‰¯œ´–T0Û4/<î3Qà›Dñ¢k[E¦þÕùâÓWW7"_<š+¶õ5Áš¤ñÜ@©Îþûw‹,ïZªÂLØú=¼ŸÚ†U²Ð=@ÛK‚ÓÄ¢=æ¸Øg]{ÌÈHIëžC¤M_[“â'1Рª%#JÙ'Z|~`ˆ%øñ*fÔŠ ø¹”1¨ÚTApÁ¯küÿÿPK!™Xh; gppt/slides/slide3.xmlì]Ûr›H}ߪýŠ÷ÄÜ/ªØ©Ä¹lmåVqò„,U!`ìÈûeûûM{zd!Y²[Þš[BÐ3ÓôéMÏ‹—‹yf\§¼šù©i?·L#Í“b<Ë/OÍïßÞ=‹L£ªY>fY‘§§æMZ™/Ï~ÿíE9ª²±«ójÄNÍi]—£““*™¦sV=/Ê4Ço“‚ÏY¯üòdÌÙOPg'Že's6ËÍæz¾ÍõÅd2KÒ7Er5OóZáiÆj̼šÎʪ¥VnC­äi2âê¥)aeÉE6¦ÿUù§)}ʯßóò¢üÂÅÏŸ®¿pc6¿L#gs°Å-æ}85yšÔ&qŠ]¨jbtw ΋w³,“7@ΪÑüÇ7ôëüÇ‚~ry©þºb<5 ^gçEF·€N©ÊWW5ˆ4´åôCVÕõM–Šûn²ä@/cœ4öýÀù¬r# ÷u<㵸‹F5¯Ï³”mr’àܨoÊtˆÒë”g8pÁòÊx÷Úx“Îg¦QÎêdúŽÍgˆ¸¸4e¼JÁ!-X9§9ÔgoÿüøXQ †ˆƒi>þÂ8ûºÍüÄú3¥nXyoÚ;™”‚($sÆ ‚ ÈÞóâª4°z!|ɧ“âëÎ`óà r=WH¤ãD…Û$nh <; \+ ¥DÚ‘çYžš!Ò‘I&غnä:QC£ä:*J®—Áy'70©r$7l¬à0ìæKÔ ¬È o³C@íæ‹`˜b‡Å>ø(Y깑ײ´ÇŽ5TÖ°c½® Ɉ¯Ð@]–aÇ RG+rq‡ŽZ;ýV"¤˜´*ŠD†x¯¦Þ©Ÿ-5TUd³1))0éyÆkT/¡„²«ùÇb,Ÿ-Gq˜ 8•D·‰¢"æµ4@–‹a6ŒùãÒ^3ô· uii#+ÒB—ä_Ó Œ%¬†\š¡œË“i¯(©9‘²8dYv 3¢Nêôí’’s€™ÂíYѾ¦ôn`î½À\Ûñàü­ê‡c&70Xð5¨&À«Ý¿3À”·Ýز¿ ¾RðÐ…wX0×õá‚ ÀÈšHÁÐ(Ñ(iDaw”(‡·‡’€¨!Nÿt}/3äG6¹¦äµ;}7õ1ÌFIãðjgrRaéV¢¡p?”D¶p{4JDF é Ò<õéÅ”D{¡d)g¡Š´-Ñÿhòä0WQï…’¥Àÿ±Q2”YÓ¿HáéÌrm¿<³©Ç†]H#Ü?¤éþÇ0ºÖ#lQ2û×ÌYµ`ÝÁr 03Ð9ƒ^Á=sž[ߎ†"g?”ôs%:g€ÙO*èéê´HPt+êñTZ!ÄÕ ñáª4JtºZ¾<õtÃ@u³-i‘!û+ÉÞfK†Ò Ê+[vÖ”§5í¬ÎY¨nˆWÝÐ‚í¨¦« BtË«‡yo(¨nˆWÝp”ÓLì  ó¶Ÿ¥hгÈ/]êauNo÷Ï¥Ö™²^ï¢ælv9­Wœ?ó"ÏÑ¡¯àFÐ¥û¡ì7ÅꑮIJû¬Á ôGõ…/&;ü5mv½Øq|GöÿñÜÐõ,ñ.Ca[~8zÑ^dËÆ’”¶aï­V´U3{5mÙŽpMcÚ,7~bbè±Ù4ìW¼ªbXÙ±^ 6ѪÙ,{›EÛØS“ÏÈÑ¢,úIF¨»±!²ã½‡-Î}ºÜ§ãÏ@¯ˆbÒJ ú°NUáÍzQìêpvEJ5Âç‡!š7Âgïï ŸcÇðzš>«¾,þÑ¢7Ôaóq[Fm-zëë•Ñc·ÑŸÑÉÕö+añC?t#DáÐZd,–Ñw'ZžÚsÒjò£Tk”Zše語 ƯÑdKµúÛi.©üœ“”».ݤ£îÔ]:qz|‰Ó»Tk¨êP”jU†Òm¦Åóò•ª´ïv BDiqýƒzÓ÷´­„2ˆ<ús[±ß´ðnÛ3Ù´-õ’&PÄŽ£GýFT 7ûFH4òMn‡TY»wmÃÑݹò¾ ß HU%F»s„N8ŠMÈûï\àÃQ‹B¨MÒšaä£9:Qî´ª;è—Þ¨UËÂ.›%ˆo»oTˆý VTdÛÏùWïg={ÿUîg@h3bï‹áM sê³ÿ!wtË]©Jî\4g½1ªJº‚bûËBà†±@[,@mDˆ"´,<²,@C4»&Öh¶l!µÑìâ’dü#+?_s-6§©SŽ.û8Tb;’1œÚB4°ûËÿÿPK!¡u=z‰½}ppt/slides/slide1.xmlì]ËrÛFÝOÕü‹{ÇèÆ[9+‰g1‰]Q2{˜„$V€ei¾l¾b¾iîí ±!Sjˆ•»‘ oÞs_}úô÷?Üm³ÅmZV›"?_²ïœå"ÍWÅz“_Ÿ/ÿüã—7ÑrQÕI¾N²"OÏ—÷iµüáÝßÿöýî¬ÊÖ 8:¯Î’óåM]ïÎÞ¾­V7é6©¾+viÿ»*ÊmRßåõÛu™|…³n³·Üq‚·Ûd“/›ãËCŽ/®®6«ô§bõe›æµ`âç¿§W€EŠ| u‡òæ“Õ `.¯[Ý$ëT~ŒW¦³÷Lâ„xæ+xqêÜÍ úï°=·|óÍþxhzu_:ØO=pcò`u„¸r‘wo7yQšNÁS5W–ûË$_Ì{_¬ïñtŸá7ø«²Î. øæÁÀ’|uS€Ó]Õ¥„OVÕ—x œ¬Lü€#’ìb‚Ú)Íן’2ùþ“ΗiþæÏËæà øzÚ‹Šo á1 /^ž ¼ïo·Ï—˸‘eß7Ì^ps&xEíÇ{¦HðÐmŒ\ÂmSEâžà%ðÒ@§ÉL‚}xùvðr}¦:xa$‘fA!Œ<7…û ì0âG SÒ½ôtŠDiR]JÓ,Ò4(ÿe-ØUA¡F"&ÂHÓM Rfyâ¥L¼‘È #½NA„ªn 8BåþÙÕ)–û ²¢‡¤ë+Z×ûSƒÄÔN£z_ôí  †E;µÓ^´ÆÔPD—¨æ¬jzÅ?G€Q¿šv´~5ãû @g0½]05À¨]@íûQæPÂíP¢7 %4ö c˜'Þ0`n Ç&–ôZ KÎ×ÑHŽI. XB±d„Xb rlPÒãJ(–¼‚Xbég#õOSgM1Ò€ÿ¥ÕT?€˜4DT¨Æ 46"O`Ž£Ö5uÖŽ×Y3p tVyžÞ3˜#ÀT¨êG0Ø(‚Q/‚ l<†B[TQ»û-4!ÆzO‘¡À 6EP‚ÓAhÚΉ·®¹gȱJÖ4žÁä(1µ(Y£jèhÕ7ð tVÓx³˜*{úÕÂUCT V qE@g0­Ý0K€)$õ¦pG#€0»@g0Ýà6é"œØ Ôn×uší»Çn ”P»u^N½Ý``7ðñØ “£ÄÔnPYY?YS9%k”¬—¬Ø |ÔätUûá².“ÍõM½ø±,‹¯‹‹"ÏA–¯(n×hN!šº–£vj©9(åe‹¾ÈÅ`¼ø*Ûìþ!d@që_¸…]‰FΓE~àÁ2JDɸÚ5-bîÆ.”¨wéyaµŠ„­,h+æØè=VÍó¨‘WPÌòÅWEŒüЗòªAõ´ðú?%ÕÔL¬î+ü9ÉYl²Ÿóõ¢¾ßüi‚/ÿ!ìþ›J¨)šÃÓRoÇ–a¬ïÚWghC€Ý®ZsUù­f\ vØ(¶¹*¶Û.1kNq¨ÝjVÉ8ˆ¹´J)É*@3Køoüh– ùÀÉo–Ìr kzÕf©h1ƒf Æ$ìlù‰f)Ý) DF®ûSÍ^YºN öæÈÂÀõ}á½;{e`Å1ê‹ Áq:â~Àh°žç.2ÞVOqð¨kç z{‘³TªÃc9K•UZ¥t[BNö‰V©8ËÐs F£ñAØ}Ñ|ÒŒ³¬·­ö#A«$Ó3 O«Ã×AóqúÉbÕ²ÿÂØ ß®[ÏH½Æ¯ù,‚LM¦V­È—燘<ŠìPl>…Ó 2Ð*/~ #ìù¤Ã<—uyXBHÒݨ˜}*ÒÝÊT;­¡ KMój¢?Øvê*º×eÜ Ý&Eõ rŠE ªy];¥Rðÿñõ[Jùyñ ÈK¾°/öreA$PýöýIŒP‰å3°û0°H¨Æ©äšPs·)ñ¹Ü‡øSï04ŸãIÅٱѥ¬M ÁB¨ÀdþE“’^:fµfFhð ðjÚWq°gÐ}A3}kz±¦á:5.×®S=P½Šµ¢AÒ Ã´j†Xe¿p’õ‡@t6‡SÐPÕ=]èÐÙ¬%,Î`4\'òÒÑÝþ—]–&„¬ó¡N-€Î `Úü–Þ¢Um¡GÒL´x“39• FªöQÒuŸ“ç¹Ú$B ‘_yÑÆ9ÆûüEδ™&„BÉk@‰aÂ# Ç&ãÒ§‹p’ŒU­å†õGËeâòš'–qf-F–³õ3§F‰©³F…?þXócsðÅ ÿHÑ»ÎZÔñŸUÒè…ÿF­kØñ¦ØÀì(½žÁÔ#Ñs=·=Ô@²†’n0ùYaHïJ¨:ýiÁ‘gÈ­g0µd,ÅŠ%#ÄYcƒ’Y€PB±äÄÈ¿¤ñ?”F/ü§F‰©³¦Èi}Κêg­ÏQvêÂI0d‡9k±,H˜#À¨uMµ£uÖpräCž€Î*ÏÓ{s˜ Uý¦E0Š`£‰$ÅŠ€Î`:E¡-ªà|ÝÌ"…)ô´( ±¢È±AI‹ œ›ÐnJÐMÐ23'ªûx€+”hí†ÉQbj7P²FÕÐñª!Ï@g0mnÂ,¦Êž~5¤pGÕUCãUCŠB<Ea–SHêLáŽF`vC<»arÉXb7»ÁžÝØ R'èùã¶ÚŒB Í®{³ëb»cU éí†f{²¦œ©Ý ²²~²¦r8JÖ(Y-Yc(þ¹7ú:½aò8dBѨ¡w´†s ü„UÓ³„1‚ب{ÊÌQ£TƒúÚÌéF­ž(°}ˆì;,œÃJRy;"W^®#Hìû_o †Rì2ÙzÄ.»Áž'Ú%¬7«žÇ]@…aÐþáʽ"‡‘ð;jhÀ(<('ƒœ†9å•0†ÌÌQCBùÍÐ&ùð<' ¼Æ·¡9° Pϸæ(ý®4²E\–Ô¤fñ¥F¹œX)¸þ‘ayÝY}÷¾Xß#\>Ão±,ë좀É3àa’|uS”çËU]J+Ȫú•…IŒ©~ñ-k+§4îUÊX3§kYéXs–:hÖÑp#Î@µºoñRÅÞF'éÞ챺ùxuµ¸Ã¥¬b²bá’{Úg«›ŸïêÅ v: |-r-˜6 ’‹†=‚xtý«z|=6°|€)„@Me½êõgª×HRÖÛô"£ñûñÆLe½¸e§ç#æ1꜉ôĬ±¶i1k˪ìG1ÀMk»e³Ð‹'*…¢1B‘aê‚Ç 'itòPD8!œŒÕîÔ©ëúÀÖòTžAÒ/ i&Í„;­™p04aÊ»º¾ôspÒëŒIôcª¯®Ç»æz;@Ô'SãÄÔe£µ°úÇÑ€#´ “ wV¥Æ|}Ĩ‘M;"Ä 3³ZÔ»SG1êP÷`Œî]Ö³½n„ù9U‘«ñ8'E„ÂÉ8á&î‘{0µ á„p2NLUi£Mm;np¾ŽvLÝhêFŸX7š›X|DÀÔñÄÔP¤µ>—MuˆËF“@Ç›ÊMÀU(Ò[s„5²©Ëv¼.7qwVÓ»s„˜ Wý(¦‚E1Šb#F1mpg±¶ˆ" _š,ÕΛ8ñM7Ñøx´…–Â@ì¼Ôõ¬'>2‰Ž›¸›x¢O?˜'¦Æ¥lT±*2qwVÓ³„˜*úU‘BUETX™h |<ÚÂ,!¦°Ô‡˜BAŒ 6Ä@ bž*ñÐ&TPQA6ÎkÆ*-T®‰ñ ¥TF‘L œèõ+½f®‰ñà±ªŠ´I“ãÄÔxP¹Y?eS™¥l”²˜²™€;+ˆé‡9*Ë㜈Yv”-1µTò`‹[Œ#Éj•æµð»˜sI¥HÁ¦¼ºJWõSd#Óö<¼ÉÞ¤æäv“¥éê§>ÌäšîxŒŠbki¦¡ïHщÇB¤°|’½ìÇЀX+ùøRûÕ]~ ónwgùm# ,>ý픸6kÐ!Ö¦1¬/ °lƒÜõ…ѽæA츮ԆõPÀ–§Ž€Nº×ætÊÒÃß¶KÅ8xÄ.;ÂíCj£{Ícæ¾Y1žÐ‘´ÍüH÷ú¯£{íª|©{ ~©u}Ï™¬ \°8ŠßŠÀ®Oº×bºÒ^Þavq”cƒÊן’'–±ßÔ½ŽÔ(z£{u#èVº×¾ËX¼BhVÇùX¸\Mê^G  ï‰ô"9Sº×>ã Ü†¥\7ry¤”±•îõÀYÀ®Lº×ß~jȳy^WuؽÎYÐê€Nä„ÄÞ†¼µ÷¡3J{Š/¡Ž+ìé€[®v<øs)V-Ã~'Q5÷ÜUUd›õ/PÞc&‘åø³÷у¶Îÿ{~ÙþZP ¦÷Hþ‚mX´Õ1»L£õµ³)65ë©“(ú)¤®òåEÀLk%3ÛÅ’µñ°^ž"Š‘¢)JŒ (aZ-™Ù.—¬ jNˆ_ñ ø¼˜R6;¾^OÉ‹tÀIßøôõ¹iåbeµ[”! '¯'¾‚Ç'½ÀÔ8¡ÀÁ‚:Ž£Îaùì½.w,ùzz `Ž£F6uÙ°Á†ƒ /Þe㎯‡¸³Šbz÷`jˆQ—ºlö]6Žã¿ÇTé忽|ÎLÜN4îA‹ý)¦˜”²QUtĪÈÄ=ÜYALk<ÌbªüéWE yTQU4bUd¢-°ñh ³„˜ÂRb y1‚؈31ØxŒ‡v´j²D‘ÄxñÀLŒ6ãpBóT_Ã’û$ðXAnXo9êøD½e©LÊV7êË^̹p©OÏ ]O²s;’sü8`‡ìx E‹¼±ÔùÎbYÕÒb»ÀóeU—Éæú¦¾(òV\(J©¼˜Üþ³ª!DÃíb=_|=_ú ËÙ¨i뺎Dë»v]‡žÔcl²Ÿóõ¢¾ß¥°DY_1ñ¢áP~*‹RóC’š«u ¸5OÕâß±¢ã #l›q=Ññ{oÌÏCÎZño>c´šù½¼ø7\ú$ìgh‚và4,tžP γÀX¬Ø-Rṵ̈5±çÌðC?t[ño°²XªèvÆåù!$5³ÉMé6[še›]• ÙoÖóK‡y¯L8@ÁÍŠ3çªÚ쿸8èÁ¥Ú/VÝ$ëT.:âÚ#´àÕ£$YLÌ®ñ•d×¹FòzŽø·2õ¡5?bÅNQîUEË¢ µú':ÖCVûðbù -Ø^‘ëÄ~£þݲXXwÂà>ü˜»±\a8àg›üQP4ŽÉ‡4Ö§†xŠäW2‘ùË¡ÎTñ3þ€¯ö}q–Õgg,îxkÐH{ËaMô;¸V º[9ñw¹^¶!fF!¸NÌÃÈw!A„C;ÏÊcZëku&©¼Ã6TB¦(ŒcÀ±*¯ˆÉ^H}°o{$ίe²ƒ¼ôß_’2]j”Náw?~©Áå6©©¤}â?öÙâE”à"29ž’½ùðûrQýH´èWŸñM.Ö›²†·WÛú"Kð&ÍË©ßý￘–ÖÂçŠÓ ¸—á³ÊÀðäiB B_£€ÐYCŸHð|kÜ0ö07´pÔd [CW|ÂVµû£Lጮã2[#²WYùk²ûx+Ìp›TuZ^ˆv›üZºm<÷ÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout9.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!i¢_!Ç,ppt/slideMasters/_rels/slideMaster1.xml.relsÄÕÝjà ðûÁÞAÎýb’¶é5½ƒÂ®F÷O>X¢¢v,o?) (ŽBÀ›€Šçüø+æxúzòÆvJ2È’ÊJ‰N6 >/o/; Öq)x¯$2Ñ©|~:~`ÏßdÛN[â«HË uN(µU‹·‰Ò(ýJ­ÌÀš†j^}ñiž¦5ÓPÎj’³``ÎÂ÷¿ŒÚwþ¿¶ªë®ÂWU]”îN jûNà;ÕÕù²Ü4è$ÉtÞN»ÄóÞ—­bÊV!Ù6¦l’eù’4ç¯Îò6Coß,äX”ñè­ÊC²lÉ€•3+bÊŠ`fqC ¦¶‰™Ú&˜šëã=­Y²­cÒÖ!Ù>¦lÿ'£³ßoù ÿÿPK!ÕÑ’ñ¾7-ppt/slideLayouts/_rels/slideLayout11.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7-ppt/slideLayouts/_rels/slideLayout10.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout2.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout3.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout7.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout6.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout5.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout4.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout1.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!ÕÑ’ñ¾7,ppt/slideLayouts/_rels/slideLayout8.xml.rels„Á Â0Dï‚ÿönÒz‘¦^DðàEô–dÛÛ$d£èß›cÁãì0ovšýkÅ“»à5Ô²AÞë|¯áv=®¶ 8£·8OÞİo—‹æB#æâÁE…âYÃsÜ)Åf  Y†H¾8]Hæ"S¯"š;ö¤ÖUµQi΀ö‹)NVC:ÙÄõKóvè:gèÌc"ŸT(¥3r¦T°˜zʤœßy.jYÞÕ6êknûÿÿPK!–¤•Íc( "ppt/slideLayouts/slideLayout10.xml¬V]oÚ0}Ÿ´ÿ`eÏi P•{étïnâ¨NœÙ&ƒM“ú·¶ŸÓ_²k'¦££´¼„à\ß{îñ±û댢’p‘²|`¹g ‘?d>‹ã4$c®2’Ë „Š%ä/’´­8­àDŒž½›’ÜP-#k é8^ˆk ¡ôpN#”ã ©¤Aè+§!¦hAÖR‡‰bÁ Qòò3/æÅŒëÙ7匣4Rh5ŠåÔê0ý7‡0xq^L_$ì¯cž ûØVÐz`Aó6ê “°I ° ŸGÃävOl˜LöD;fÈ`»(ô½¨*ú¿œ¦)§"ÅÝVU…b˜zÅÂruªò«ò›Ҁ©š|‘ ªRñ[ÇU5&^§š,¹±h£ ¿‡_=ˆ}*ä\n(Ñ„@ÚØpxý+…“ܾ›ƒÂ3P‚aÔäÉa@ÓðI†H”Jt…$éd`?dؑМ’äÑ sü岪û°2$m2„׊Â׉l"w4…f‡$a4‚Tš§ WQe!ÆSØ•Ú-Ð%ˆÆtæÆ• Á*i•Ý>þ¡]ˆ–tKô;û¡D®Û!vúQq®‰‡‡YRu„æ$d°¯)) =^wäøE’òÃÑ[£ó5e+.“ƒ“÷Ž…Oã½èà;'Ý žÙ c,ÉÎЄ€ïx“»D6ÿ8*0ôµh“QVô.·‰á˜P>ÿÓ ‚^wÚhÚ—­qÏöÜ e_zí¦íO:^¯ëõƽà—U[^¥Ê4#Ót¹âäv¥“CL«²BeK®ÓráltÝgÙB* å´Ýi›îLSþø¯AiE½·?±äUƒ¾­0‡LÞâO¯8ÒiéFæ4ºYe÷/xiŸÂ¸áîÐ{©Ñ6tbùNÎ;£±×™Úm·=ù6{vwÔœÚS·w“V»;:ßÊW¨ÊsÈîXÕ>=þþôôøçšÕGlu÷‚Wu[Ó×+ʯqq[j…û)è)ÐCÜHÕI ¡Ï! ÃÜp‡ÿÿPK!WQ瑈´!ppt/slideLayouts/slideLayout3.xmlÌXÛnã6}/Ð Ôg¯-YÖ ±'n²IPg?€‘èXXêRŠví- ìoµŸ³_Ò3”h;iŠu“ È‹-ó2sæÌrä“÷›B²µPM^•cÇ}7p˜(Ó*ËË»±óéfÖ‹Öh^f\V¥;[Ñ8ï'?þpR'Ì.ø¶Zie“ð±³ÔºNúý&]Š‚7ïªZ”˜[Tªà?Õ]?SüwØ.dß ‚~ÁóÒéö«cöW‹EžŠ³*]¢Ô­%$×Àß,óº±Öêc¬ÕJ40cv߇¤·5¢mDú‹à™ÃÌBµÆëL{:—+y¹HÉ9£…B™Ù¦¾QBкrý³ªçõµ2›.×׊åé6;ýn¢[f~–X†‡þƒíwÖO6 ULNx6Øfì i[úÄ&žˆfi;˜îGÓåÕ#kÓåù#«ûÖìœ"ßuÑ¿Ãñl87¹–‚¹»¨Ú¥[/ªôsÃÊ qRømxéåÚ£˜É|½d-õšLuëÚIÇ]ßN-Сç Ý¡¡Ã÷A̧å¹ùYhÕ&è·Wð`sô¦Ìx>2G/ËH`™£›ìrUÜ>àÅôþÏåïÁ0ý(5¦ÿEù’ò=ƒÓ3?˜õFîèòõâ^têÍz37þ0žGÑi¸“oC‘—@÷Uûíë_?}ûú÷ hÖ4Ðíû0éÅÙHQª¼¾Z›Ó ÿ@Oèp1TãßH†–î— ûoÃäÿÿPK!6ÈÞlLñ !ppt/slideLayouts/slideLayout2.xml¬VínÚ0ý?iï`e¿Ó" *ögmÑ à&ÉêØ™m2Ø4©¯µ=NŸd×NBWÊ$üɇs}|ï¹'Çî_­3Š "dÊÙÀr/",äQÊ–ë~1µ»’ ³SÎÈÀÚi] ß¿ë群Ñ'¼á+…ƒI¬D©Üw&$Ãò‚ç„Á·˜‹ +xK'ø`gÔi6'Ã)³ªùâù<ŽÓŒy¸ÊS%ˆ +È_&i.k´ü´\ 0föë”Ô&‡jùà ™ QÀ«k ¡îpN#Äp‹TQ‚€p¦ÉÈ|!Ñ¡¬ø(òy>fÞm1(4N5ßrªU˜yeÎÎôe„ýu,²aû@Z,èÙF_aöÉZ¡° _FÃänOl˜LöD;õÁvQhw^Vô¶œf]NI‡»­ª Å0õ%bêÔå—å…·E ¦kÖðy‚Jæ•f¶Š+?>êx œ²ÔzÄ£.üîfûTª¹ÚPb´±àpú)ÖÂ&̾Ÿƒ°3P‚AøyjÐ4|DŠ#¥ Ý`©ˆ@&ø ²ì(hNIX4ÃÞAÖõaV†¤ë ᱤðßD¶j"+5¡Å!I8 ‰æi´¦ˆ¢fþ ŒB-è–ºÖ²5ËW —,*áR/iÊ8¢©srøG))=Þ0}ü"IÅáè-ÝÇ#Ч|%TrpòÞ±ði¼œä¬Úöjm±"¯„m[­Ýà¿ü"Rð;ÏÇ4¶ÀdµØÍOmlC›ËIþƒåkçþáA¯;m4íëÖ¸g{nв¯½vÓö.'¯×õzã^ðÓªL,‚RUš‘iº\ r·ÒÛt~Ç,ÞÚPinÚh\§åÂ&çº/²…T4Êy»Ó®»3å\;Þ߯cujb%Ê}]a+Ô=:£#—‘NÍÈœ¦A·«ìa‡—öi†\îspˆè½Ô:³|'—ÑØëLí¶Û|›=»;jNí©Û»‚I«Ý]nå+uå ²;VµÏO¿>ƒfͦYž¦àQŸ¼Ì‰Šœßfσ&è)0C9-õÞ ¡/!£>ªÿÿÿPK!ÛüžJ8`!ppt/slideLayouts/slideLayout1.xmlÌX]nÛ8~_ w Ôg×Ö¿,Ä.b;Þ—4 êôŒDÛB©Ÿ’´kïb^k÷8=É΢å¤^4»0~q(j8úf¾ÎL®ÞïJN¶LÈ¢®FŽûnàVeu^T«‘óéqÞK"­rÊ늜=“Îûñ›_®šTòü–îë" £’)9k¥š´ß—Ùš•T¾«VÁ»e-JªàQ¬ú¹ _AwÉûÞ`õKZTN{^¼æ|½\›ÕÙ¦d•2JãT~¹.iµ5¯ÑÖ&A>ý’Ú7`­*gÑbb ®3˳ÏIEKØxD ²àEÎô+Ù< ÆP¨Úþ*šEó ô‰»íƒ EŽÚ“N¿}ÑŠéÇ Ä`Ñq|e5Ñt·åøŠ¦à²9À×áMÙN‘ÌlfÝn¶¾?!›­oNH÷íÁá£@uc,úÑÏšcá¬2¢ŽÞÖÙgIªìDóyÙÝÖ*C›Q}³&Æë™Z[+jÞk—Ø#R»Õb=8#JÂd`<â¹þ ðÂç~‰ãØ P½ãñ``$Ž­6ª›Tí&u¾G¯>Á_Í M¹T µçL{|BS@?À-§˜1¬ê}Z@Æ”jÊ…Œj™Qã)/²ÏDÕ„å…"¨TL¥£G¢Ê+¡€ùV%«ò*èÇšÑy4…/ƒ;,BX~þ™%ß²´Ø<™ozç Jnž QÙv–Û׿ú±µŒùIÁðœ±èÒ”jÆâÐCiã“Úx?Ö'Cšø–»8¤¤âVgNQåýzIù ؂ȃ,›;¸í4Ë9[ ¸)kÈòyÁ¹~À+ŽM¹ [Êá¢ØáÍ •2;q88@Õ÷! köŽô—V?,[|¨–^5cô ¹<¼²Åëwx‡n Óìòð"ÈoÐá=„áåF”-àðpâ%:-.0¢lG`ÏK s/2„e 8>þ…æ¢l'`D{¡I‡([ÀÃ#ÀQë»ÿòbQê«ÚÖ{D†rõòÿªø­ø3ªyà4cëšçÐsøç¨ü¹‚&ç7h±)_B]ÒÕßfì\µ÷p±ÐŽÄþD7P]Ïr²Fw]Õúkl–¦Óa2x½k6ìîÔï]¡× â›(&Áp6œþá´}c¦ª¢dóbµì~£äíçÍ™‡í—Û÷]˜)\·ëÆ j9o?Zvæu}à1?Á9øYB#£ ú²¡¾`9úI‹ ¼š£óz$²Ñ£¹Û”O/ü¢{y˜½ìàðŸF ˜YAõI×èŽXOç ß›8šÌ‚hÞ Ýpáë {ÉÄ›÷æîðz:½ñÃdÂWâYºµß¿ýùöû·¿Î³º›6,,qÌÕ3*hs¿Õ—8ÌõOÐËÂV“<6ã Ú‰ ûŸñßÿÿPK!ÃN—2/!ppt/slideMasters/slideMaster1.xmlìZ]nÛF~/Ð;ìc¡Hü)Ár`ËQÀIŒØ9ÀŠ\I¬W$K®T9EÜ¡7è-Ú¾õ(9Igf—iKŽ Ë€m0¤åîìpw¾ù·^¯æÂXò¼ˆÓd`Z¯:¦Á“0âd:0?]ŒZi’%iÂæ/Ìׇßwõ ½c…ä¹<’¢ÏæLʬßnáŒÏYñ*Íxk“4Ÿ3 ù´åì7à=m»Óé¶ç,NL½?ße:™Ä!?IÃÅœ'R1ɹ`Î_Ìâ¬(¹e»pËr^ÚÝ8Ò!Ü/<~§êó#Ÿq´)u:–yxÀútO>¹±db`ާ–Ù>_I#T“áz6œ}Ø@ÎÞl n—/€«U/Å[©ݼŽ]^ç"–‚g‚…|–Št…DD7TÛ@ŠÙi^F’ÂQêª œ’1Þ_•Í y•”$²ÕtjN–TôÉ·‘z%¾\ò\^ Njà±>ˆ>à@‚¡Áó¤õé ~.‡‚3pZ…äáPÄá¥!SƒG±4´Ý à€%JI’¬ˆ%O¢3–³×8k‘lJ™rJ‘¶«“S©êr]›lè¾Ú„2µißG©,ÐT0oiu ­r=ÛëuǯU¨wR$°8C,I#éú÷T,”éUÑP,P2R[õQ¾’<Ætùœ‡i‚/¹Ø=騨_Ìâ|wî¤ wà>J¹œí|xWiãÎpŒâÉFîFöjÒniÒ'L6 ä¾&IðbŸÁÃ21ѦM0R˜À`rÇxÑu<ø»fÚ¶å8UÀpºže{ß²ñ‚LµŒ !–ÂBSfb Þ_˜8ñ úq§…î çŠTÄÑ(‚0Ý[§Ar¥²#'R%F¾·¥UÎDÁ¢Æl[½‰À—àAÔX‡-|YþDD”5ý`Ô±[GÎI¯åZC§u>¶åúoºn/p{'½áT)iˆ@Ód<ç£xºÈù‡… Ýß~p ’“<´ÚŽ)§e­½µ_ãðJã¥)æ×õˆG}_ó˜@®@€þº`9¼A›ˆ L˜Iíj"Že»eNµÙF‚ž÷¬m¤L»Ÿ•ìW'»¥Nžƒåsãýb>¾¦™äüî«™PTëMÊIŠ'ÿÝõ<çvå|î\UO5+þÆïŸ¸ÝQ˳¼cpàv¯Û£ÖÈê ‡o/8ö+^ æ% èqïâ·¿~ùû‡¯_þكצbEÕò0,;¡È߱̀úb¦„ZBàÀŒ.a4žÚ8±\Á(º„ Ch:…”3°®f*§œ H-¹å $PjÆ+g j¨™n96;qr y~™Æ$?«‰r„ µrNÙUºo#(d¯ÍP¨µ-×w¢*”¥}lYäo#]˃͖»´/­iu¥¶•dUñÕ)àVZOE«ãáVZ\E«=ÔVZiEÛ½!™æÝ@Ú­ÿ ZÀ¡¢¥¦CCâM¾~¶÷ ¾Ð›«øZ”œÞ¸\Ùd©‰B/WÔ"(P ¨¾§G´8’éÜãžžå‚Ï!3¤öâ-UW‚³Óä8Í\±;—èG ™A«Z€g‹$„ˆî¤eá1v̰ž…:o¤+A^szu¼xmHJÇj^ :'À÷’çØÂÜ5E&ȺžÈÒA)[œ@Ãj`þ8ÿ¥%$‚»¶À™Z‹k a ÛÒÙ¦T¡U͇"ž³üt`:®ÝËŠ¸=U«œ(³ó‡–?ˆRµ3®a0J!³Ç¤Z‰é(™0,–álÄæ±€þ™¶ÎX^p8¸®›Æ‹!ÌÐôÀüúå/%¿Ž*Z?ŽÉ6“Ö“Ö­8’9ØX*)¬|À ý]…•xPö€KÖ•ÔÓÆêÏXÙÁCÙܱB€´ërÖX•½ÝXv@EÊóë¦aÙæ ÷"¤Árk`é¦êskƒe¡Ó}h¶G°! –·Ëîx>©ÚÚ >#Ëúïß›^ð)`…i¬º5¬<Ë%§÷,±Ú”^`:óè Ò`ù5°z¾E÷¬ÛÚÎ;åô{ô‚ˆ+Xƒ¥ÒôF2øŒ¼à“µ,DHƒÕ«]j¾XÖc²,DŠèF}œõS9ãyU-Cåx¦ Õ5dýG U ®IÊî…*פ0«U²ÊY?ÉJ¶ü•Ìþk¡§&ŸÍÕcÙéz‘Ï–‚Íññ‡0Ñùxj ´¹H²; \îEƒ¶T&”-½h„¬-Õ€ïªVé‹mÉÀ!££>Ä‹€¶d½]ÏqÒÔį2Ízr ‰çúaøOßò·î‡ÿÿÿPK!dB!Ã!ppt/slideLayouts/slideLayout4.xmlìXÝrÚ8¾ß™¾ƒÆ½¦Æ`Œñ:ÁÄ{Ó&™…>€bËÁ[YòJ‚@;ékí>NŸdd‹BØp™›ÄÈŸ>é|çGǺø¸*)Z! ΆŽ÷¡í ÂRžì~è|™%­ÐARa–aÊ:k"£w¿]T‘¤Ù'¼æ …€ƒÉ¹RUäº2“˼" Þå\”XÁOqïf?wIÝN»¸%.˜ÓÌÇÌçy^¤dÂÓEI˜ªI¡XÁþ弨¤e«Ža«‘@cf?Ý’ZW`­zà7w:ÈàÄF ‘£Œ¤V¤›¤R5¿•|Î|Iîm©A¼Æ³˜ª°!ŽŽîóèvëêãkk –O{:ùÐÑ5–<ŒÒçžþyp¤E—öô™Y·Ý.‚Khñg,…ÿ¦oy’vãBŒÄ2†Àñ"&2´²éoehk§ÁÛ:œ¤]0> Y1Å>`iëóú ƒ˜Qè“*Ô¢?ˆ£à‹&¸ÆÂHhŸh!X® … ¸v©¬(Y>Ñœ‚Ì Ú…;ƒ‹Ê8,~8ìæ*ì˜ó§˜lÆã,0ΑŒ§å µ¤v ­­’´l\Ö%±M›MZW§Õ±:ÄqÁuLßu¤Í†’Hº_–„ŠˆÊ°FÓ`ÆA-&%e={U²µ„æ÷²/¢4„ÇC¼ûdþ*& )kA+þì醅–N”›µÚ‡TOE¨¼jÄÚÙeE*´Ì4׬>±¤MX‰·ËŠT«µf%¦K7¢•ÈÍ WEk×h=Ó6œJ‹\­³¦5 Lx‡µÈUѺ5Z×2ežj-rU´Þš9›§lOl‘«¢õk´Ží¾+eÈ%µ¤ÞRÑð&Pu+é’w?]áPp¤À wŠŠYJÅ<ЫB&UµêAq䣻{Fãi%c¥ÄàcU† êÏLÈa3ˆky®ý3}›@s ¢‰ŽIª'jçIµV§’²€C%&u%ÃZa°J"jX©$+¬Võ}‹U¹Â*`U3Ä*`U‡Ä*`UÛÄ*`U/Ä*`ËQ“€Œ¯É•o?FÉa>TÓÊçïcɈ< µ˜-X¼§A·ée_A?žEysöêÉßXq†|ž‹Ycã­²#›ÓGÓ½ì0›œu:³•®·§3iñé¢VÎÇåt†÷Çœæ0vV'£-GåÆçXvÇsa;4«”ï2«õôˬóòeVëéæÿqVs”¦í›Õähtº¬íJ™ÔÉ“¥ìм¶–²Ë¼†1ßœ.óÚ=ï®x¶ªË¼†[håjp;6?ê¼æ*m»¥‚m,Bœ0O¶r^ l n.GI¹¦:¸•wÝÞý‚“ë KùC®ï§°;ËYƒï ;FëÚ¼õ[˜­kË6Z–{çX¾gù·þào½Úd ÁU%l=Ïsö8:²¿½- ykÑ'm“À.åÎM$ùØsû½ÞÈ-HÎq“/ß’/Ò4éRÄû‚r]ƒHʈ†úU–—ªE+ß‚VJªÆfÿ^’®J`«sÍèš³ #*0éá9°·,Aœ0qm¢ 3+ª¼–”š?|”å¶ÜH›puØH”' IÄn³Ð„ÙOa0p_¤ïZ$SY̧$-Ðq†¡e•ù…$УFq=?ÍÆÙú•Ø8[½í¶@›V5£?éô[:µÞ#«:”@ê…ˆïâxú5½øêЂÎ¾ÌÐ3ᛸzÑêÑÆ+ÐÔŠ¥ ‘T†ø-üÛI0¥·ºbÔ e“ÀáägÄøšrçf ¾.tÈ(ß7âéyÈòøih’ktI”¦YÀ)È)¨£¡9 $åɆHòé²áGØŠn+„a-áß…´B.‰¦hÃHL3Á¨ ß…¦‰Ê_áX–b0"¸Ä³Ä­´¦ÿ¥q çÁ¸û›†“qÔë;çƒåÄñ½pàœûþ㟮FþdìO–“ð;nU4Êw{I×{ßÖªÚ¦ž;ðàð¼§Þ@)¥Ûîømw"!Œ+ž÷gÐER-ë}Þ ;´=jÏKç [E†­"[–']í‹Ûºø]èï @¿*=Ûwu:Z,ýQä ½áìÛŸ8ãE?r"or†«Áp¼8}´¯2Ì9T÷¯®}¸ÿñááþgžµKýâÀÐ#vÅ]¿×º”‚êåkêë+_wHírYMÇ¡d7¡èÔÞübDl§IÚÓ§hZ\½›‹²ÝnìàqSêeô'¿£3ÍÈ’CÊŠšgLï‘`[ˆrQ§wŠˆ)%Z¦éå¶Ã5ôÍNMAZé3ƒ÷MžSÔÉy–¬UÈ$ÛEW¯Pn«£ÞÍêlo4¹Å„ˆ+½Ò{άVÈ¢4¦| â8%=ß9ïÏC'ðâ¾s |'8] ƒp„ó0þF»¦ª.+–”ëdWã‘Dƒq ðÀ0áܬ°ïJÇœ¨ƒ=msé©çö=œZÏ£àIØV¬…"[‚„ÏÀŒRaÏH·ã†ËÖ—¿»ÓïÜIêZ£'¿úãß\ËÖ O¸CçQçmkèyÄŽªHÐ)²âeÆÈ妺}¦Kÿºà­ˆÐ/Jcu·Šo|§ÃÙ<&ÎÀÌp|ýÐÍüÄI¼ð<ŽýÁhvú8¾Ê0ØÝ¿NíÃý÷w÷?Ž0³vtÛ‹—æ"µw!— ¹Ú⩆¿8O± 5ø­8ÜO)£ûöLÿÿPK!ëì¡î!ppt/slideLayouts/slideLayout8.xmlÌXÛrâ6¾ïLßAã^³ Ÿí ì$NèM6Éö„-bwåCeÁB;Ù×jgŸ¤¿d Ë.&ÉEoÀ˜OŸþã÷˾z¿ÉZS^ge16ð»‘h—IV<óéÀ7P-H‘Vtllim¼ŸüüÓUÖ,¹'Ûr%puHÆF*D‡uœÒœÔïÊŠðß²ä9ð“?N>wΆæhäs’F»ž÷Y_.—YLoËx•ÓB4$œ2"Àþ:ͪZ³U}Ø*Nk Q«MÛ ¼-¿Ï7R0¾†ؘ€çñŒ%¨ 9܈ÊBúœ‰E¤’v(L]Í9¥]¬åÕ¬zâjéÃú‰£,‘T-…1lÿhaêg0¸-ÖL$Ü,y>¹"!DmÆ$n+?a éF ¸¹ïïÆéã lœÞ@õ`ÁnSÈyÕxô­;¦vgž FÞyÕ@ ,½/ãO5*JðSºß¸?¬5™ôYÒW)jÂ/$U‹kþTñÐøZÅTº‹„íxP[*¦gœ£˜X£‘oaË@22»f‹èzÜ0W¡ØÜ”ÉVFtß8RÄi …ºhâÌj1[i&![3 !ž¡“ ºü nÕŽ 0 lZhÇwxÈ1\wx Â$„8À,eD6"-gЈ¹ˆ%@ßú$&ËâOH”ˆ&™@H-(G*nж`™djEI‹ä‰p"ê2ËTv†øjŸá²Éö÷sA<ì‚'Fbš–,#Ì×U@–@ýê"éŸ|Ëñ™PÙ §²ï`ŒÑdßñ C)4î7 ¥ÜnêPGBg_µV7UmÊ2mÉêk(;¸4ÛzíV…ßÅj`­X»‹ÕÀÚ'°²Úv6h`sX ¬{«€õÎa5°þ9¬68‡m§zV"`Ø5Ë+{Jjªj©ú §š¾QÍzKU¸´ñŒÆe‘ F×”õ W½uý<ÍxvÕ°Oˇé××x[æ%ôÙò$;Œ¹7U3[«Ù\¦º+e* 0öõ¨zÑ0“$FAJØÒ€3œJ¤jRrÔÅLU¼_yëGÓ Û–ƒ›>ßüƒñf»¹¯8”~¯ŽY‘ÀiG^JÓ«8ªlv4 蔜‰ (å­¥Ò3ºßžidË`[îŠzñh㑎¶|Øò°Û—0øÖj>ßô¥Ô÷2ð€ïH[>ÓôÁ¼—ði¶æól5¶.·ïH×[>IÖ;!þi¿æsïeùøÌèl}šP yÌýþ¹ÊÑJtK=P"¥¯U¢D|£C¸9-ȧ“B=¾÷àäyH©€:».ááH>àüeGQàOGæàÚº 6ެÁµí˜Û»síÀ·ƒÛ úÛhÏú ¸*²œN³ç§+¡æü4Em-&xhax Äx?@Á©=o;'\iYÊÓvwR8r¶½6?KÁ›ý±"vhg>s¾$GoOGdƲ„¢‡U¾8Š‹ûq@}24gæè%¡Ù•ïçÞÜÚîtà`çÊ× þ9LqpEw–ãßx»ò­¥çX'ëí’ªýúåŸ_¾~ù÷ jV KóÒ.å; UŠŒ ÕãZ ax)õ©[¼†¸Hè"9ôkÉÿÿPK!øœ¬Œ!ppt/slideLayouts/slideLayout9.xml¬XÛrÚH}ߪý‡)í3Ñ]*CÊ`³/ŽMòƒ4 Ut[i ­­Êoí~N¾$Ý# ¯1Ñ Ñsfºûôé–nÞïÒ„lyYÅy6Ôè»Fxäaœ­‡Ú§Å´çj¤, Y’g|¨íy¥½ýþÛMáWIøÀöùFÀÈ*Ÿ µHˆÂï÷« â)«ÞåÏà¿U^¦LÀÏrÝKö°Ó¤¯v?eq¦5ëËKÖç«Uð»<ؤ<5HÉ&àüU•B+.A+J^Œ\Ý>’Øàm‹F¤Y¹…TçÁ< IÆR¸1‹±)9ù‹ˆLXç6U±(9GëlûgYÌ‹Y)—>ng%‰C„j ´~óGc&f`ýgË× ‰ù»U™Žn˜!»¡‰Ûã',b>ß Ô7ƒãÝ z:cD÷g¬ûj8ÁaSÈyQ{ô³;ºrg‹„zðª6e°ô!>W$ËÁOt¿v/xÜ*0ôወÔáÕØÕÊx(ûJÆTô êxºîoÁsÓ– žEÅ2]Û„›ccÙ¶c¸r…›ÔÐ…/vã<ÜcH—ð ™cYåÀÔ%®`~R‰¹Ø'g¸Þ&NDX²†RJ€Ìùê#ܪ¾5à;l¹Tžì!Ém1ó!ðK†•ȳާ9Tb*& g߸$F“$>‘Æ‚|`•à%‘ƒº…“!º{HHž…3V2<Ô)2æ‚ù°3ø®|–aÀ|¼œtC%]•Á,aò$„Cè"(•à«(¨A¹—a®#‚MuDZꤩêhñÀ¤Ér)^Ì~ÊÊYq‚´à%¦r¹yý”«N8a)šö -\êH¤Ê´´"—àéGÏ8âyÔ”ä¿-kn‚4xæÅ»ì€X@Di­@ª÷:@Dií# ¨ðª"Jèœ:¦ÌÜ.#Jèíò¤´bˆ(  wh[ΕIA”óšÔ­v˜J;X§Âa C~U8P¯A0Ax#–¬ ‘’${ˆô›ë\º«_µ€³ÍÄ2 UÔ½âØb["â µÔ›(¤ÿi&R Îu7imÕ(v †Wjmi‚4xWjmѵ ñ:–^ ÒÂë@@ZxèG ¯ùhὬ@$Mä0ºHZ]?á hȧjM8×L1–R¢;&xK‰Ì.”(?é­› êÏY!’ú§æ05{¶äBþ“â žEðyâos2ñÜé@ïÝw^Ϥ£wkZzÏtîmÓsMïΛü£5£u®Š8åÓx /O¡a•¿žÈ¢ÜZŒhß ðüEé1þpDé¶OØ*;Ó<ÇÙö´SÈîW;ÅJ”u‚þÚ°vPóæ+ç[rÔmD‘y‡œM‰ZM”ÖÃA\T \+QçÕšš¬·4TÛøwÅq„½–¦`ÆýáS®‚^40ëš±hùQ™M,lÒB7©ÚLx±ÕLßÁ/ª‹f䬓oa©Tsµ¥Äè¬áR‚S¬0÷ã­V%±ÓN3Z埑∕Bï±TD C´%@^€8 j£ƒ$¬¸ÅØCÖ¬âv†¸m¼&Íì¯uì?×QWÓ-Å9)9- ”@g`ûO’jâö…¶€šµõp¼²a4€Ábêÿ°qÏO†zýÿê Ñ5Ý)øB¡5ÝFgùDèVL£(<ì–†­jkNrcŠ’5¡GÀ©O€_”•8½ß¶ÊÑ|ÍøJ¨òèàÃSá«åAt˜§gm±Ð¶Ø+ò¤³ !/í¬BÁTùŽBL—N×Sf¶˜)©'«yy<.M?Û!a‡š™\ÏÇØŽ?}~ýfY2œõ÷²?MÜÐÏúîen8¸ŠÃd&Ó$ûât¼€TUU“Yu¿äf¥Éc¦!º‰C}¯ïÃÙïûe ¡h”óªYufœëÁûxò™Šz©>K%ZþZa;X~3øNÑ輌Ė‘9­ ‚®WõÝ/æ |)/p·èƒÔ˜1tæò½Ä“iÏ\8é'P¾Aâ'ÁÌùÉe–]õ£ád°+_©3gÝ©Uûãë·×?¾~?CÍš³»½S«¾…šC˜Š÷¸¹Y› ÷o¨§Ì|jàÆ %£ML4†½ÁÿÿPK!ùÏ 9ƒ\ppt/theme/theme1.xmlìYOoÛ6¿Øw toc'vuŠØ±›­MÄn‡i‰–XS¢@ÒI}Úã€úa—»í0l+лtŸ&[‡­úöHJ²ËHÒ۰ŇD"|ÿßã#uýÆ£˜¡C"$åIÛ«_­yˆ$>h¶½{Ãþ• I…“3ž¶7#Ò»±õþ{×ñ¦ŠHL¬Oä&n{‘RéæÊŠôaË«<% ̹ˆ±‚W®ݘ­¬Öjë+1¦‰‡Ù»ã1õ j’ÞVN¼Çà5QRøL 4iâ¬0Ø`R×9“]&Ð!fmøühH)1,L´½šùy+[×Wðf¶ˆ©%kKëúæ—­Ë“UÃS„£‚i½ßh]Û)èS‹¸^¯×íÕ z€}4µ²”i6úõNN³²‹´»µf­áâKô×dnu:f+“Å5 ûØXÀoÔÖÛ«Þ€,¾¹€ot¶»Ýuo@¿¾€ï_k­7\¼EŒ&“´vh¿ŸQ/ cÎv+áߨeð9 ¢¡ˆ.Íb̵,Öbü‹>4aE¤f)c¢¸‹ ªàM‚K3vÈ— Cš’¾ ©j{¦2bNïÍËïß¼|ŽÞ¼|vüøÅñ㟎Ÿ<9~ü£¥å,ÜÅIX^øúÛÏþüúcôÇóo^?ý¢/Ëø_øä—Ÿ?¯BÍ%zõå³ß^<{õÕ§¿÷´¾-ð¨ Ò˜Ht‡¡ƒnÆ0®äd$ηbaZ^±„'Xs© ßS‘ƒ¾3à Wà:ĵà}¤ xsúÐx‰©Ê\îhv+Šàç¬ÃE¥ni^%3§IXÍ\L˸Œ«xwqâø·7M¡tÒ*’݈8bî3œ(’„(¤çø„ {= Ô±ëõ—|¬ÐŠ:˜VšdHGN4ÍíÒü2«üíØfï>êpV¥õ9t‘˜U?$Ì1ãM½Ü£¡#Ò<@ôÌTh_BµvŠpL“ËŠ|押-heJ잨ÃËp'«o—‹€þû‹ïž&ûâ}qº¬½—µ×ûÏ×Þeù|ÖŠ;/²PuŸcdÓ.ÇK»å1el fŒÜ–¦a–°a}ÔëÌI‘§§4‚ǬÀ;¸P`³ ®>¢*D8…f»îi"¡ÌH‡¥\Â!Ï WÒÖxhØ•="6õáÁÖ‰ÕìðšÎÏ³í„æ š3ZÓÎÊlíZFÔ~fu-Ô™¹Õh¦Ô9Ü •Á‡‹ªÁ`aMèDô/`åu8«kÖpHÁŒÚîvÎÝb¼p‘.’Hæ#­÷¢êÆIy¬˜[ˆ éß)V+qki²ïÀí,N*³k,a—{ï]¼”GðÜK:oO¤#KÊÉÉtÔöZÍÕ¦‡|œ¶½1œoá1NÁëR7˜…pIä+aÃþÔd6Y>÷f+WÌM‚:\YX»/(ìÔTHµƒedCÃLe!ÀÍÉʿڳ^”6ÒßBе †L °£ëZ2_•]Ѷ³¯Y)åSEÄ ŽÐˆMÅ÷ëP}*ášÂTýwjÚÚfÊ-ÎYÒ•o² ÎŽc–F8+·:EóL¶p“Ç… æ­$èV)»Qîüª˜”¿ UÊaü?SEï'pe°høp¥+0ÒùÚö¸P‡*”FÔï hLí€h{Y˜† ‚‹eó_Cýßæœ¥aÒN~ꀆHPØT$Ù‡²d¢ïbõlï²$YFÈDTI\™Z±Gä°¡®ëzo÷P¡nªIV îdü¹ïYBÝä”óÍ©!ÅÞksàïî|l2ƒRn6 MnÿBÄŠ]Õ®7Ëó½·¬ˆž˜·Y<+€Yi+heiÿ–"œs«µkAãÕf.xqQc,¢.~þû>³_)ô†:äP[|tÐÄ l ª¯ØÆéiGÐ8ÙALš”5mÖ:i«å›õwºßÆÖ’Åßç4vÑœ¹ìœ\¼HcgvlmÇ–š<{2EahœdŒcÌç­ò(>zŽÞ»þ)SÒ|_ZÏÉH~ËÑ,Ýú ÿÿPK !Š=@@docProps/thumbnail.jpegÿØÿàJFIF``ÿÛCÿÛCÿÀÀ"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?þþ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢¾ý©j_ü ñžáÏhÕìõ E­Í6·ª÷1\¶«©Ø4Q5†§e‘åYDàרÑö´hóû5+Ôýåz”©G–•*“÷êFü¼±¼œbøñøü&Y„«ŽÇUöZžÖ¯³©S—ÚT…{”aR¤¹ªT„}Ø;^îÑM¯ºh¯ÎþÖ_üo .¹ý™ðÿLÝwshm°¼G{ÿå?yçÂei÷÷ýÏ+åÇÞlñôÇü%?¿áVÿÂÌþÝðßø@?á:þÃÿ„Ä[¶ÿÂ;ÿ öWö§ü,ÌgèoþÎÆÒ>Åÿ,*³§0Êj{,ÃõzžÛC—ÚЫûÜ%Ocˆ…èÔ©ÝÔ÷y¯Ë=àåEƒÌ0y„=¦·¶ƒ¥BµýZ»ÄÓö´ej°ƒ÷áïZÜÑÚj/Cæoø*íEûR~Éß³½ñö@ý˜åý§þ4]ÞàøwÃ3êw1h^¸¿Ûø¯^ðÖ€'ñÇtí6Ÿ\Ôô ǤZAáÍÄ׉|màÝ'K7÷vø^¼ñOüâ}BÊ]6ÿÄ~ðî½}§Oo-¤öš¾‘g¨\ÙMk93[Kk5ÃÁ%¼ÄË Æc—RkóæÞ?ˆŸkÝÆú¡øE®x öqÕüGð£àŸÄ-$ñ 7¿ümàŸIûDj×Þ ðÿÆ `x{[øGá¯èÿtwñ5Öã mKâ?Ç-:ëCƒCMÿ_ûÏÃ:¯Š?á(ñ†|K} j¥è×lïô- Qðú•ñ£ã >{K›MCľ&2µ¹ðÄSEsÕ¸aw$Oo˜–GóŽÓ¾¢Š(¢Šøöîñ¯ü§ü4oxÄÞŸP¼ñZê?ðßßÙIw ´·ûZغ™Rž_(Ȧ!cîËp3L~/¥[ ‡©Šª©B¶.¤©a©¶›æ­R0©(CK6¡'v´91ØÈ`0•ñ•)W­ <=¤©a ªWšº\´¡)AJZìå/©÷õø³ðŸâŸÄMVÇWüMñÜWÝÛ­€Ô¼sâMÚ…ÌÞRG«Xùê$ ¹Êɰ.âÜ¿ uï†Z§‚4ËßüY½‹Är_xŽ;ÄÔ>2‚•u­Š£M*‰5£R§ï#̹£{'}Yö ñ¿ˆ~·ÃjS|WÔŒ/¿áUÂM|sñb_Gý«¯xZý¯H6X´ß'Kº×Qòì­±!K‹˜¾ÀÖI,±áMOÂñIÓü ãyüQ§ÏàŸ^k–‹ñ'[ñõµ½å–»à4K‰¢Õ¼G¯Ç¦OäjÜVòB-^ê7ºV3,Eâž¡îÔQEQEQEQEQEQEQEQEQEòwÅ_ÙûÀ¿~)ßÂi?ˆ ÿ„[áÿƒ?³N…¨ZØ—þÜñÄO¶ ¿µiÚ€—oö=¯‘åˆJn›y“zyX×€x§þoü--wþgü áðöü'_ðŽã?ð‘|LþÓþÊÿ„ƒŒãû;íÿdçbûGü°®Œ.+‚¯ V ˆÂbis{Jt1T(âhTåç£^”+RŸ,£8óÓ©B\³ŒgÅÚQŒ•šLø«Xøg¥|4ñGм á]c^·Ð´RÁlÖîMöîFÔü3áýjæK›‰´c½þÕ©Mb(á-ã… m ’Y~øåût|vøoð¯Xð_‡¼Sá95=zÞßàŸÂO ø›E³·ÒüMãÄþ ø{áKTÑô SÄ6úuýüö‘ëúå­¼Óh~·ÖÇÿ }—öÛáû7öOü >ó¿²<ÿÝgnÿmy¿bÿFþÖþÔßþ™öºþ¿n¿ ÿÁB¢ý¾¾xËú¿‰#ø¨|Mo|/¬üY<ãíø¯ZMcHÒ4ÝSÁ>¿ñ—<©ü@ð?4YU[4Xì=XÑÅRÃ*0tœê{ZTjª±å¯)8%U+ªrâýäî—»G8U³ X…« UÃOêÉTQ‡$êAÓ|ÔckÓ¾³NÍZ-4ßïýðü#ŸðTßú,Ÿ°þ#WíÿÑa^Kûøþ ¹áïÚoöŽÖÿkÏ‹|Kû*ë¢Ëð{ÁÞðV­iñßÄâ×M]WWðEä^<ñGü ÿïfkÙ´Ï üIñWÄÏ\ê1Jml>ho¥Ü|áí«5å,Ôït¯‰ ¹±ðö±âYŸÀÿ k } ¸¢}{ády#ø\Ð, ´oBëì—f[ˆLv²B·Aêõå,Ÿ_ƒâG‚_ÚfªßŸüHYmµ½r÷@´KC¯|,2O퇼K4—)2ÛÆ–­aRE,Ó5äoCpóÇÄíÇ>=ø“ws¢ü<ñ3iÞ𜖆­à.áŠ}{ÇrZ^oƒÆ—V2[Þ:]à Åz÷qËcpním¡’Ê[¿ÆO^:ðW„þ+xëÞ+ñ%¯‡üE¤k÷6š¾‹u¦ø‚þãN»UÚÞ[ÍGÕ´‹‡Ttc%†¥y ˜°`?  ÿ‰#âO‹<'àv¾oü>[›føƒ¯%¤V‰¯|M6SÁz><×=üwV²X[Egµœ±^_=ôÐéÿÈçüƒö&Ñ~5üdø¥ñãþÍÅÿ>xóWñ"|8>±×¡ñ߆tÃ5Ÿ>Yx“QÕ4Yµ+gKþÓÔ~]j:.“Ä4 î—NÓ.õÃqúÿ…•³L^W>"ÅÕÃCNORus|ªU¡9Ã&Ï_$hÏ^)à¡ÏV•* IÔJ›ø…O†­BžU±Y¶yc&•Bv=R”!,Ï)NR« 4¥lTœ)Ô©WØÔP¼?¦Ih é?¼¦_xwÆ'„í~^êZ’ÛørK -¼¯xGVÔ¥³XüLÚŒ¿k¶ÑîMItø$’i­–í,‘¦’FøUû@øã¯ÅKøBíüAü"ßügý¥ý»§ÚXïþÜñÿ±ý—ìºÿ›·û"ëÏó<­™‡o™½¶.Þð¯üãn…¢èŸ?d¿‡WPø³ÃÒÞøÇø'Ã˧^Ùiú<úËê±Â÷qj½íž8ŽÎòÖÖöÞêak¨Åg4w Þ°¯ü§öñgÄŸX뿲÷ÂYÛø{¸íµŸib+{•×´8RxP]]†Å4ѳ,ª¶ýçošðCÊ2fcŽÂæX\]<QŽÂF´ê}^®2Ŭ?¶”VP©ÊœÒ¨¨¹cðöœ}׈kÙËÓÀqRÌsl. ˆÀ×ÃϘá1.œaí©×Àáý³¥ó'8Ôƒ”U%uꨫÎ?ÒUyŽñ§á6­ñWÄ,>"xFŒžðî‘âÿ|0:Õ”>9°ð޼Ï“â±á»‰bÕ/<3yq¶K¯ØÛ]i1j1K¦Ow¡–Ëòwü:¯þ ÇÿFaðÿ-/ÿ‰®Oá§ü'öøIûPi_µ×¾ø_Fø¹á/§‡~ K[M?Á¿ ḵ¼´×µxGI´Ó´Æñg‰Òñÿµ|_â¡âØÅ6Õ²•’g¸ÝËu ™ax ƒóSþ àoøNá?ÿ…Ïâ¿íŸøJÿá1û7ü"Ú?ögöŸöÇöבäÿhý«ìjýß•öß´}ŸäûW™ûÚýÃü燲•Ä‘â fe„†?&©…ÁG.Ãa±+‰—´^DZ8lJ†JKšPör³~ùñ|a–g9Œ²9døl"X<ÎŒT±•ëÐt(EÓ~×èW åY8»)óÇEîÜþz~ ~Ï÷Z—„¾*øƒöŠ›Eø}ñàò\~ϼeðïU×<9ñKÀÞ2oxÆŠ<¯xJoiŸ>-è6¾ø…á›kkOB×¼/â{_ øÇLÔàƒÅºE¿ìüËã'ÅÏ„žøÙâvðηûXüÒ5„z¿ˆ~ øZáhݣеÛ_x“Çÿ õ‘á ⥤ñÛx‹XÔ>Ùé~,˜ëãIðÀa4»«ˆÏø(WìLÿ$ÓÿkK¯ˆÃðÚÆ×Â_lø<+áÓïÏìë§øžãXÐ>94~$×-u=Gö[ñVµ©x¿[ó-`~x¯ãd–óÞë:g…ôÇýAýŽ¿d¿ ~Êñf•áOj;Ò|w¨hÞ!ŽûP°°µ0›[ í£{K6ê{kÛ+ÛiíæÖ4(QäOè°û/Æå˜<  V6tðñ©<ÁJã&ë(IÁMS\÷—™‘ðÆ?#Ïp+‚ÁRÈ)e˜•9ÏZ¶3 Äâ±§‡ÂÆuå`í*N6¦ä”œ\ß*QôÿþÔ³—Ä?Yx3ÀŸþx¿Å·þ%ø‰àËo ø{Æ:.«­Âcð’[x¾%xJãN³»–æÏÄþ [¨.õ½ò85km5Ϊ-LI.ÓÞ+àÿðN_¿i¯ƒ_µŠ|Sñ—Ã>x¿Dñç€m>øý<àïøKtm:ë@—[ñW‡´­Âmw¯xFúûÀ¾!>*½Õ“Qð-õï„Umô;»›9~þ¯ÈOѼ£Åšeî«ñ#Á6Ö>!Ö<52xâDí¢A Ow,I¯|,¬äOèzý€¶‘åI¢²ŽìKoŽê8Zâý^¹Áú‰n´ûíLk^évú…¥î‰â_øfî+]RM>mBÖKŸ júL÷6×3iZt¯ËÍ–ÎÔ’åÖ×›âO‹-‡Äß$Ñxáôò_­‡Ãcwsƽñ68¬çGø|ö+oböÓMjÖÖV÷o.¡x/n¯!K¬›ÏÚ×ãW‰¼ ûJ|f𥾕áÍz-Ǥ?Û:õ¶­ý±©I?•w5Þ 4-kBÑÖâY®$%tí#OµUÚ±Û ÿNkð§ÂIu5ò\xá/®mí­./â—Äõ»žÖÊK¹¬íf¸0Koi5ýô¶°Hí¼—·rD¨×3ò={ö*ý–¼S¬j!ñ?ÁÏx_Õ®ïU×5ë½{XÖ5;·^çPÔõ ^âööá•UZk™ä…P[÷ÞqNQÂ9Þ+2βÌ^k…¯•VÀÓÃ౓ÁU†"¦3ˆiU§V”¥N4ðÕ`é¹5)T„œ}Ô×Èq¦A˜ñW‡Áe˜ì6_ˆ¥˜RÅN¶+ U9Q†FT•9¢S”ëÓšŸ*j0”SJM?ækSøEàØóã/Œ¯Æ„ñø7ö†ðç~/üÖ.µ Q<=à¿Ú¼;ªø—ãoÀûÍ>Öî DÒ>(h—:ÿÆÏ‡P«[N5/úL7V1i^ µ“ôŸþ -ñ/Vø‰ñSâ—ö¦•¡iØÿ켢ǫF'þÐñšn¿µ5}XŸ+ì1ùg6ày³y¢lÅå}ïûNÁ?>~Ò|gð‚êÃT𮥩éöú‡ÃïÛx‡Å:ÅçÃ?ˆþž-cáçô}'V×®t«ëŸøšËMÔßF¿·—I×´Èo¼7¬ÛÝhš¾£g?-ÿð²øG¬|=ÕüK£|ð§ÁOÚ+ÀzÆ­ð#ö¥ð…®5WµðÅÿ>›uâ-7O:Ô©øÅ–—ZÅ„~"¹·[¯|)ñσü@>ÌúÕå¢vTã|#„3žÆas\fa‹¥“a²Œv'3ÄVÃå˜<³GS°Õ1ƒÃIG-ÓöxgZôᜟ48WG‰2Ìã _/Ã`ðÕ3:ùŽŽ*ØüN; S K­ 1’¬›¢ñùëªVœ¤šŠý¢Š+óSîŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š(  zާêú}ö“«XÙêšV©gu§jzf£mé÷°=µåõÊKmwgwm,–÷V×ÉðHñJ²ŸÍŸÙ+Åvß²·Ž<]ÿÿø¡âDÓ´/†Úv—ã_ØÏÅþ/Ö#ŒxóöXñGŠôøoájkZ¥À:—Žÿfˆþ%ð÷ÀItÙî.5_À%ýµÙ§Õ|Kã½V+_Ó*üÖý¹¿àš>ý¸>$~Ì¿5Ï‹ÿ¾ø×ö^øÍð£â×…ôï ø’]Gᯌ-þ|EÒ¼uá/ü8ÕÝôŸ'Å-§›GÄž»ð¿ˆn®l¼!{âk¿éÞð¶ƒ`úSEPEPEP_†ŸðSÿÚ³À¿ðI߈úüR±×õOüTðV«ðwöøi¢è^"ûï¼ ¦_j³¯Äm7ÅÖzÿ‚ü-ñ?Ã>8ñü"¿¶ñN«¦ê¾<øGñU×ìl¼Moû;ØiÚgî]bøÃ~ñެøSÅڋ⟠ø‹M¼Ñ¼Aá¿év:æ®é„m¥k:>§Ö©é·ÖÒIoyc{m=­ÌñMÆÌ¤î›}§§XjP£Ç¡ek}rmó;¸#M¥—z¬[k2Qà VñEGFà (±Å Q¨HâŠ4 ‘Ç(DDP¨ *€%QEQEQEQEQEQEQEQEQEQEQEQEQEQEQE—>¹¢Ûk:w‡nu}.ßľŸ«jÚN…>¡i³ªiZ úM®¹©éÚd“-í\ëú¾­{m¶ÚtúÖ“ äÉ©Y¬Ú•ùcûfügøeâ_xKâÏÁ¯‰¿hÙwÆñ|eøYá='Eñ"ë?-tÍ3SðÿÅÏp4h`š_ uxÃñêw ¢hßnþxëPGŸÁVC­*멺4jÖT¢çQÒ§:Šœï9¸EòEYÞR²ÑêgRµ*N ­ZtÜä£Rqƒœ’Œ9šæ“m$•Þ«Cõ:Šùçá§íQðCã„ü%ão†ž'Ö¼eá¿xKHñ×…¯ô/|CÔ­áMvÇOÔtÝjÞ o Ë9²–×UÓšIŒa ’òÞŠK,hÝúüVð“ÝMb–þ7{Ûx-®®,—áoÄö»·µ¼’ê;©í—Áæxm®æ±¾ŠÖy#X®%²¼Žwµc‰FP|³Œ£+'i'f“NÎÎÍ4×tÓZ2ÓRW‹RZêškGgªÓFš}š±èôWœ[|Vð•äm5¿îáIî­^[_…¿î"K«©¬o­ZH|è·6W¶÷W3 mníç¶#ž#^çKÔìu­3NÖtË…»Óuk MOOºT’5¹±¿·ŽêÒác™#™kyc$±¤Šk¢°*$eê(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ +ó›ö„ý²<{ð‡â®¿à=Ã>Ô´Í*×DžÞïU‹Ykç:žc¨Ì³5ž¯knÂ9®dHŠA¹Ã;[Ñj¯Šz¿„-üVtÿ[‰´»HéÿØ>"”¯Ù–f0 ¿øL£Ï™ä%û/É»ý[íù¾ð¶}2xö,u•ðµþµƒýí*Vö’öXöÐåæ^íJp“¿º™ã¬ÿ)–3€X»âðµ!J½/a‰ýÝJ—ä´t}œ¯g¬'(®­¡ÔWk7ŸôGÂzyñG€.ŠuûL>øŠ° x—Äßk1ÿÂÒ—íaLJMÙÄ–ÛMèºóØ[}šà¹¼ø§oâÃ?ð”xί x—]ßð®üD¢ÜxwQðžžm ¯ü-&3Óâ‘0¸ûL_fûȸûX’ÛçÏ`õú+‰ðf¯®êx»LñÆ‘yáâ-ö‹¥ÞhÖ—¶×>ð·‰c•´ëík_š âËhäjsG*ÛG2¤&F{j(¢Š(¢Š+ñ†ÛöSñ¿…tãtúÿ…nô+™|5â;}")õxõc‹ïôØ4Ûi‹é-g°I­Úý¹’âd#­þÒËIû=_ Ýh>7Ö>xMŸÅ‹BÖ,> iÖöÑx'WþÖ²ƒSñ‚-4Æ›U5ìº|³ÚÍ|É¢Ù&©½Äñé uö~ÆQæ<±PÁb^ŽcGêy‚TpõlÛUi§^•WM¸Jv' ‰½$šVós¯™}^xª µ\_¬àÛ«Zš¥‰œ&Õ*”ÔÒ”cxÔSƒ¶±i³ò3özøÑqû þпþ xƒÂƒUð7Œ´ï|`ýœ¬ìµÃeikáˆ/Ñ5¿_ ìon´fó_áOÅUXi°Ú[Ùi_þ8x Ã,bÇÁWW¾|uñÇøïÅþð&`–7ü7aâO_X²5÷ŽuKkË;/ÀÚй[‘­M ðM ™´6qI·‚ñÒÏñ›þ } 7ìÅð3á'Ç9µkø×áÅ8¿ø’š ,¼'à{ˆOŽ>&³Éuñ^³•nßâO‹þŠ/†WÈöö×ÍsmgtfIo­"‚ök=>k‰,-»Ÿ„øÿ…YðÓ#þÿƒpHÁ#þÍ78>Ù8õ5øÿ€øõà[­_Ãv¿°ÇÙ’ø“S•õ? ü(†óí~#×õ/߯ðÙþÓSÛÃWÚµÄV±%ÅËEh$·W3,“É÷÷ÃÛkâ¯Ão‡¶Éÿíý½ïßÀþ/-<9û/5­Úàéñ­Í³OûTÛÎmç %„͘ÝLÆùEø|~O™e”°uñøYáéfåW9Jœ•zq)ÊQTç7£^“´Ô_¾´ºvú¬&eÇTÄÑÂb!Z¦jž&1SN”ܪEFNQŠmÊ•Eî¹/uëf¯úoE~0~×_ðU_?³¿ÂkˆÞÿ‚hþØÞ#Ö—Ç> ðä ñ­Á*çÇx“W]2 ø|0øÏñoÆZ¯Ä›èå7Ðô ·Õn,®-u3£é­u¯é_¬ß ¼c©|Bøyà¿kñŸÂÝOÅÞÒ,ñG…ôm?ézD7–n…­|@Òô«5}`YÚiúF»®Xéö‹l×í ±Akm N'IMÆÖ{“4’Jïöô–ÿ ¦ñ¿Åñ—¿á(ÔÇ‹ô…¶¿ÿ…S¯xïÈÓÇÃ_¬ÿµ´¯ ë¶ö¾]É»Ÿû2K¸§‹í?kkdŽö)fòëËO„Çá7Äg_‡8ÖÔ|hVª~ ø‘FœÄž3_âàÁg£bÙ.Ÿk‹BÏþ±}‚øi’é“Ámëà3j˜G8×Lm…«‡£B­y{,<ªJ U¥ Ƭ#((4”cùŸ¾ºùø¬¾ž#’Tœ0ÕV"jµiÒ´¬ ¤:’Œ©ÊJNIÞR’N+Ý}>8ý—þ xÿâÆïøcÇ~=ñLj4Cˆõ´ŸÅþ"´–ÞúÓÂúÈ‚îÎûNÔ¬õ +…ŽiíÚkK¨[K›«9Œ–·WÉú_¨|>ÐSâO„ì…ÿŽ 7øƒu#·Ä߉/v²Ùëß ¢‰`¿5õµ»¥ôÆêÎÚæ+KéRÎkØ.&Óì$¶þ:¾|Aý´>þÕ²ü8ñÅOƒ>ð?‰~k¾2øoâ?Ú×Å_ô/\išö“iã/ Èþø¿àÝNñ?ƒ$Öô 49íRÔ|ª&¢×šÕþ™â{Û_¯üg®~Ø^-±´>øëû k-§ÝãSü ø±¥=¨»†O±®¥pÿ´t±ºÜ[£i *ìmî,nWô~0áZî"ļ¥e˜<ºL6¥L®–C(Nª­IahZr¯NJn1Ua*u#9B¬$þ#†³ú¸\’ŠÌeŽÄãj¾2ñò¬±ò£iJÝ:WÝTæœT¥É(Î1”$—ôÿðçM·ÑõOŠ:m¤š„Ööß,„rjš¶©®_·ðËáÅÃý£UÖ¯5 Rì‰&uˆÝ^L`€Em—m1Géõø‡ûh?ðS ¾jOáÿ‹ÿ°äVðœk"oøH>|x×碌O‡÷ºê:OíC§Z=¿‘ötŽ/%ä‰ÒEyË^ÿÂ9ÿMÿ¢Éûâ5~Ñ_ýùV7 ðxÌ^ ÔW…Ä×Ã:°·%GB¬é{HòÊqåŸ'4m)+5iIjÿ@Â×úÖ ‰PtÖ"…ê¿4=­8Ôä•ãxóYÞ1wZÅ=ßôWæ7ükÁðS/èßãÿ‚ƒüLøKãmÿâ·wðDðLJ%âdž< 6¯¨²Z|Nñn“âmWÁ·v>JÚ¿ƒ<=e'"ÿŠu|d¶z'ö%šê7?èÚu—ü"ÿbûuödºdÚý½_“ŸµßÇßøCö~ø)û5|‡ÆGísñêëáÏÿ„Íyð¯ÆÚ¤ Àw>ñÆÚÞ—wáø­µÿþÏÞ°ºñMÕ•“ß[x¯Æ—?þDÂãǺtôùÛû`ê^ý±?i­ø6àxûöiýŒ|aâØK©ø¿Xø¦üUý®%Ðì ñ~³•â[ÄörxösðƵƒômbÊ(ôïüqñ7Ä )ÉÖþiw ðfâ?²ÿÅ|øQc­øcÁ¿õ|wøa†<)fñ\.³y¢Šßâ°‹F¸!¼ ã}FoiF(`† üWÓ|3¥Eý‘à?.Ëö/öÈý•e‹öeýš¿goÙGá‡Ä¿øoà¥Æ¡bÐê~ñ}–¹soq¥¨x³Äú÷Œ4} üOâÿøŽãTñ/‹õçšëV×üO«êÚö§¾êþyŸä/~Èß´…þëîŸðwÇšoÇÿƒ,><üÓÃZ½Çü$úφ|0Ú/ˆ~ÜêºMž£g¦é_ü©xßá«sy þÈ·ñŠøŽ;sw£éóGûÇâ² Ÿ‚òÜïá<Ã1ÁçØÇW†3jXJØÜN®‡uq4êf1«W 8WÃS©€t£‹£†ªªsÓŒ—äœI‡Íó>(Çet0ÜEƒÁbrœ2§žåÕ1°Ô+ÓÄP¬©Ð©§N»q•*ó†3ÚKR½7Y8e׌µ=/CÔu­:êë[¿ð÷‡¯5Ë‹ïZµìšÝΉa6°ošhx®—R{¥¸·+ÙfW·B"'ég‰?o_Ÿ¿bÙlü!ñŸŒ,¾6ü:øtþ*ø¡£éþ:¸ðÿÃFñ˜ÿ„/áªÞ^xᯊ|öÿ‹4]V×\?>(|htۆqü^ñDÚ—ƒôÅ/üøßûNø†OÚ à·ÂOx»á_ÅÍ'Ã>5ðGˆSE6 ¨hš·†t‰"ûVŸ5½ö¨ZL³XêZuä]Xj×6w¬°¸¯é«Ã?~øšßö}ø—ñ àßïübø3àm>ÇáÇÄ|<ðέñ/áMνám7Jñm§‚ß8øs­}¾øNµ-kUÕþÇ)øœmãû=Æ»všwkqäòÜý±ÒY&þT~3ü*Òÿljß~ ø»Ã2|rðœºÄ߃Zö±§øŸN°ð¿ü)¨Ú!½Ônï´ Lè> ðxÅV6²5Þ§áok6¬Fswm_önºÃÿÅÞiž ‹Æž$·ð†±á‹‰5m[Ä_þ&ü8ºñŸ‡þ#|5ñŽ•¢ÜMaâ? x’=CHžXâ›LÔNmJÂöm6ÿJ¹¿ýËøAÿ±ð¿Á_?Œ¼-ñƒ_¿ÔßI¼ÑÌ ð–u`-o¥µšYZvµ¥\yêÖ‘ˆØÝ³†‰ÉR¿þÖŸ°f›ðÓãÿ¼uâω—š'ìáûTüIð§þ4j^ðÄ:]ÃÚvïD·øð'âÞ¥iªkúÍšxãu¤z/ì÷ãíN9l¥ƒÇv_³Ôâ ,õ궿Ѹr9Í|;Ï'™¦7)Äfuq ö’xƒ¬«áà°Q¡N¥*¸EO–8fëÓäöÎj”ø¥ͪe”qXÌ«*`0¹…:8ÌWÔŸ×=½7N¼ž)Öœ'O)Ý×µ©{8ÁÔ“§_ðN_J׿gÛWD¿SÒî¾ x“ì·ÑA{mÇ‘§è6ó•ƒQµ²½O*â >}¬Eš&xÃÂÑÊÿy×Ο²çìï¦~Ì cøY£x–ÿÅzu¿ˆ5vßTÔì-ôëÕþØû+Ík4V³Ï¾LðJñ΂ Å*Dщ¦›èºü+ˆq8\nžc05+ÖÀâó|˃­‰„!‰­…¯­WW p§NêR”'VéÓ„j9(BJ+õœš†# ”eXl]:T±X|·CJ„¥:4ñ°´©Ö§Fs”ç*P©Fœ§9ÊPIÊRm¶QEãžQEçß>,|3ø1á‡ñ¯ÅŸxSáÇ„c¿²Òäñ/Œµ»è‘jƒ:ÙÚ˨êSAk³ùRº‡‘BÅ Ó9Xa•Óâ?ØA×¾8x¯ÆßðP¿‰Z>¥£k~ÆÚV¦u¿&¡¥^ªM¡xóöˆÖVŽÿ­ MVÇO¿øSðÛÄPÉðŽÞZõßÛ‹ö"ø3ÿø/ìéñúo¯Ã ÿø'ÆÚí‡|Eÿž³®¿µ˜õË/ÜëñY^j:³qÙkÇF}7ZŸK’æßLÖ4«™Rö£>|=ð—ÂøcáÇ4Û#ÂÒmôMO¼Ö5¿ÞÛØ[n)öíÄºŽ±ânúgy'½ÕµÍWQÕu ©e»¿½¹¹–I\ó’?‹ÿ¶Áÿ‚®Oð‰ü/­Ã¯Á¤½‹Rñð‡öðêkðšÂÈ?[ÇÒ|C’oIá…ý®d×Ç„ ·½²|¾oÇ+ŸÔú(¥ËF&ܧMâœêÉÞU~±Åâ駥퇣ˆ¥ƒ¦œ§jXj|®å¥L–µkTZF§Õùi¯†—°Áap³äJÉ{z˜yâªZ1½lEG.i¹TŸÀ¿ãÿi³ïúÃŽW^,ý©?fW“÷z~â[[ßÚ³àÆœN"ŠmâF»cû@èlæëSÓ¾9xãOÑ­#Ð>]_¿ëÉ~*|ð—Å˯…ú§ˆ'Ö´­àçÅO ü^øâO Þ[iúÞ‹â]ËXðþ­b·7v:ŒxÇ^ñ?Œ¾øßN6ÂmOÁ>2ñžŸ{¤êÒiÚÎëTÀ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Îþ.|*ð/Ç?†>ø9ñ;C‡ÄŸþ&xO[ð_‹´Y¤–{¢köX^}–òÝ£»Óu+d˜]éZ½„Öú–©Áiªi·6×ö–óÇè”PÀ¿±—ÆÿAeâoÙKö‹ñ•µïí=û8øIøiªëÞ!»°ÓuÚÀÖ‡â/ü ý |?k¾µGâÏÃoøšïÇúv‹ '‡þ.ü4øá¡ZÚ Âê7}Wæ·Åÿø&€>*þß³_ü?‹ÿ¼=ñö{¾ñ?Ú~KâI|Mð{Ç:/ˆþx³áŒVqøcZv¼ð¥¡ÿÂC¥Íá-RÛÂßÚ³x³R»ð]ÇŠV;)8iìµ |Ë®].êXEL:eôH"‹+ÝÈ)¥X)Åf¯¹0ï†@^§<Ò¨zÒ·|À;µ)Ë­òÚ¢üð4‡Ã` 샹øð–¸W O6ò×çØ~ÿøKRíÿÿPK!Øý¬¶ppt/tableStyles.xml ÌI‚0@Ὁwhþ}-CQ$ +wê*”!é@h£ãÝeùò’/Í?J¢—Xìd4ÿàº5ݤ{ƒc@ÖqÝqi´`° y¶ß¥ŸÝßM]¾Q°]xFsQðU.O”+h­CµÚúV }“T^l ¸ÕÉ8M'I+”á‡yÿ—y[×J‹•ëLèA#á&JêÂ…1áë¡z‡:0ü&'ã”'—µÒº®ôü0™t¥ä7jUAÜÒÃÊ¥®úˆ¡®´o^UO;ò܇Rh˜MEŽ;o˜Ò ©/~‰¥÷7Ò´þ0çrëU£ Û|0ÎèÞ{zŒ²#Ë‹MÍš¾cˆÂº7£Q²Ü¶þ›3g±àãQ/ðØÒ'³Þ„8œ5Φ‘ÒµÆÀvÝ1¦ü‹nrŒDÿRLŒnPhè K'$ýÉL’iOYJ¶E×%œ"òžæ7ý9ÿÿPK!®­XHdšdocProps/core.xml ¢( |’]Oà …ïMü ÷-Ðnn’®KtÙ…q‰Éf4Þx·[h÷ñï¥ÝV»h¼ä=‡‡s€|z¨ÊhÖ)£'ˆ&E …‘Jo&èu5Ç(ržkÉK£a‚Žàд¸½ÉEÍ„±ðbM Ö+pQ iÇD=A[ïk†±[¨¸K‚CqmlÅ}XÚ ®¹øäÀ)!w¸Ï%÷7À¸îˆèŒ”¢CÖ_¶lR`(¡í¦ Å?^¶rnh•ž³RþX‡Nç¸}¶'±sœêŒûý>ÙgmŒŸâ÷Åó²­+ÝÜ•TäR0¯| ŲT"šãnÒhÂ÷ÆOf«£™V¾ ›Ë-¹ó‹ðkòáØóýÖ»…jÞ° iŽûëpXÛût"È(4a§Þå-{œ­æ¨H %1Åd¼"–Øðþ£Éuµ¿ivTçtÿiLhœÑUš²tÈ}âP´‰¯Sñ ÿÿPK!ÂG³‘ûzdocProps/app.xml ¢( œTMÚ0½Wê°|j`Q…ãUÅjÅ¡$²»g7ž«ÆŽl—Ýí¯ïÄNX>ªVmNó•™÷ÞØf·/{M༲&§ãáˆ0¥•ÊìrúPÜf”ø ŒÚÈé+xzËß¿cgpA'ØÂøœÖ!4ó,óe {ᇘ6˜©¬Û‹€®Ûe¶ªT w¶ü±²Éhô)ƒ—F‚4dž4uœÂÿ6•¶lñùÇâµAÀœ6]¨=ðÙ ËÞ<ödô|Ʋd°ÏM£U)ÊÁWªtÖÛ*uN6öÜÆ*XvZˆb€GFñ·ûH˜¯ÍÀ—ÀmmŸÉ‡éüæ#Ë~SÈ6‰Mqœxl«•Ïqg±¯6``IJd°¥’L—Åð™ÏV«…VM¬ïM¶-…†ŠÃ+¡=`ëc€-A´‹ßåÿ`K\·Óm“E-Ìd_sh/ÏczJøx2áïIkÿhð_ÿÿPK-!Úe=õJ [Content_Types].xmlPK-!høt¡â ._rels/.relsPK-!c\#´Á7 dppt/slides/_rels/slide1.xml.relsPK-!Kõ=ì¿7 cppt/slides/_rels/slide3.xml.relsPK-!EÌF"Ú` ppt/_rels/presentation.xml.relsPK-!Kõ=ì¿7 Ç ppt/slides/_rels/slide2.xml.relsPK-!FŸÎYÚ Ä ppt/presentation.xmlPK-!¢›¦’ydOppt/slides/slide2.xmlPK-!™Xh; gppt/slides/slide3.xmlPK-!¡u=z‰½}O!ppt/slides/slide1.xmlPK-!ÕÑ’ñ¾7, 6ppt/slideLayouts/_rels/slideLayout9.xml.relsPK-!i¢_!Ç,7ppt/slideMasters/_rels/slideMaster1.xml.relsPK-!ÕÑ’ñ¾7-{8ppt/slideLayouts/_rels/slideLayout11.xml.relsPK-!ÕÑ’ñ¾7-„9ppt/slideLayouts/_rels/slideLayout10.xml.relsPK-!ÕÑ’ñ¾7,:ppt/slideLayouts/_rels/slideLayout2.xml.relsPK-!ÕÑ’ñ¾7,•;ppt/slideLayouts/_rels/slideLayout3.xml.relsPK-!ÕÑ’ñ¾7,<ppt/slideLayouts/_rels/slideLayout7.xml.relsPK-!ÕÑ’ñ¾7,¥=ppt/slideLayouts/_rels/slideLayout6.xml.relsPK-!ÕÑ’ñ¾7,­>ppt/slideLayouts/_rels/slideLayout5.xml.relsPK-!ÕÑ’ñ¾7,µ?ppt/slideLayouts/_rels/slideLayout4.xml.relsPK-!ÕÑ’ñ¾7,½@ppt/slideLayouts/_rels/slideLayout1.xml.relsPK-!ÕÑ’ñ¾7,ÅAppt/slideLayouts/_rels/slideLayout8.xml.relsPK-!–¤•Íc( "ÍBppt/slideLayouts/slideLayout10.xmlPK-!WQ瑈´!pFppt/slideLayouts/slideLayout3.xmlPK-!6ÈÞlLñ !7Kppt/slideLayouts/slideLayout2.xmlPK-!ÛüžJ8`!ÂNppt/slideLayouts/slideLayout1.xmlPK-!ÃN—2/!9Sppt/slideMasters/slideMaster1.xmlPK-!dB!Ã![ppt/slideLayouts/slideLayout4.xmlPK-!›€?Çn’!a_ppt/slideLayouts/slideLayout5.xmlPK-!9÷*×!eppt/slideLayouts/slideLayout6.xmlPK-!„ƒSñ¨Â!$hppt/slideLayouts/slideLayout7.xmlPK-!ëì¡î! kppt/slideLayouts/slideLayout8.xmlPK-!øœ¬Œ!8pppt/slideLayouts/slideLayout9.xmlPK-!¸<² "#uppt/slideLayouts/slideLayout11.xmlPK-!ùÏ 9ƒ\yppt/theme/theme1.xmlPK- !Š=@@ÊdocProps/thumbnail.jpegPK-!X›Âªÿ¿ppt/presProps.xmlPK-!Øý¬¶ØÀppt/tableStyles.xmlPK-!­š¸ühµÁppt/viewProps.xmlPK-!®­XHdšsÃdocProps/core.xmlPK-!ÂG³‘ûzÆdocProps/app.xmlPK))o ?Éejml-0.28/docs/logo/ejml_icon.gif000066400000000000000000000104761256171534400167300ustar00rootroot00000000000000GIF89a×Úç¼      %& (!!!"""%8%%%#'+***+++...1J///222333 6Q55577749@$=[<<<1>O>>>???@@@BBB+GkDDDFFFGGGHHHIIIJJJEKT1QzRRR4WƒTTTUUU7[‰WWWG[rYYYZZZ\\\^^^g9}е«Nª¬z[S«S¨dÓÆ+V­[–f¹¾›MUºxMâºà”PÞ¿"í8½€ °áŽ{Ú9ÌX£`„K®˜Àâɘ#>Žœ¹3ÃÊ—=‹F¸¹ðèÓA£^-°4kÔª_Ÿv-[tìÚžiãÎ|{7ÑWŽ‚ N¼¸q/N!02μ¹óçУKg>ÉÞéÓ98m‚½»÷ïà…þOºžù™­…Ê«_¿ž¼#?ðãËŸOßðOø?8e‚¿¿ÿÿŸg‘€H‘o Wß‚õ݇_[aà„7 …bx † Çà‡ñ9˜ß~ˆ D'F”"D+’¥ ˆŠø „NIXb-:”cC;2Ô#V/¸ ŒŸè7â÷£BK&Ô$BO.¤ôI#6Þ¥A[Ô%A_5%•òY$‰I†)š¼°ÉfPc’ Ÿ™WfI¡›¢˜§Š{¦§œfžydš}>„§#"JןdZ§–…ê)“úX)Ê9_ ‚"yç¥L‚ꤨP’*e¦š†…~ªè†þ¯Nt¨{©–¹*…Fzj¢©\òꥯ`+&ªµrúÉ"ºšè²Æê£TûINå l³ÌÂJk­sÞJ!²N-2á¬Ø–;´BJ;mµã »¦»mÂû&Pè¨.¸ˆû¹ÚšÛá{ÜÚçm‰Ô`í¾ò&ì,Ÿ ûIlªê»•¾8*œ­¬ðÂù°¦¯k0 j±¿Ïn èÀ%âKq…!KÚ2¥/[3¦ìMƒS1Ô¬óÎ3_ÅstwluÇÏDƒç^ÑÌÝ @ÎH7{‰&éŸÊJšÜèÈýž«°Ôþ|p½ ò‹qÏRÊuTƒ#ÖcCÝìÙýyÍrÀ“]ªÝÍû“þÙp"ÉÄj3(¶žx+ÅwßL8¥BàC²M¸Û°ö&[au´Ž3 ùØ’ã—8\žnæ,fLïÖSî”åt®ù¢¨wþyè­“.ráI.¹êœQ;îÁ?Þ>é.ùì¿_ü8ì¿ëHçýñÞEÀ®—Þ¼PÆK~„SPo»Ë›}…l5}±ßÃ>Ãã+¹=Ý£}õ.ƽ#å;u>Çé˼¾õí«ÐûâÇ¿ùõfQk_pò€ý]Í€üßí(œ pb Õõ4A gÐ_•÷:­uPr‚S°‡“EdjqÚw§PA†HS .ÐÐ;Ì%þ8ô’³œ ò,%¸˜ÁV,c’;4´áw–S,q0h ý\ö….þÀ) ØBÇHÆ2v¬DŒké"‰+nE¦ÐbGåˆ1naNùA÷8Æ3º*y(Á…ܸ•,4Ñ#[„¿€0òq~lÀ¸E<ˆ°b„„Œ_>’H™‘ñŽy|¤Q&¹4ViÁÅc2)‚8v¤“ NéHQv1’»š¤üZ2‹¦dMøáF`©Á2‚z´åp 2@¶Ä˜Ì¤IBë%jŒD@¤ÀÍnzS wç"ÆIÎršóœ‹çØÀÎvºóðdƒ:MAÏzÚóžøþ̧)¨é;ð…•Y¬æí®iL<þò M¨BÊІ:¡B`ÅEˆIGc®àͨF7ÊÑŽf ü( ­WFxô¤(M©J—x€Zs¤·#cVJÓšÚT¡ÁÌZÛšEÆÜô§@­é \©ÓåÁjŒFø%~ÀÔ¦2• PƒT§JÕªZU P¥‚¶ÊÕ®:!-«Xǃ² á¬hM«Z×ÊÖ¶ºU­½À& >ž~á˜[±@œ"ƒG2Ó?¦Ü*-̓‚4#½[eàF),a+Xàã_+¦K nð"³hÂA#:Ì9*V n\A-ÀWÉ’²oµÕe)¢ÊƒŠ€¯ôþlÞ‚ó…\q‘ýÂc’[2N¶j•¡J"M7^ 4IìlÁÈ%&s´¥åóP\ªd•„Ì‚0)Û^ [é@w €ÞÞò´pK­ªV +fr¨"Qn¯vÐØ=’}õ-zϦÞn±÷!œ dKØ]/íŠù/dõ;Ýñõ·nUtãa üBŠ0B;K¬¥}£{ÞßOtöìCV)„íRxŠÅâ-gô X:+a…)L\’‡[aZs0|Cçh>VÚûðœó8%=>nŽë*‘6^ BÒ€S‚à_e*óÁ•ä‰|R™­h …0êÂVðP7+ÛË"ÞÉþ–ya—+–L-˜r™ÍìW‡-Í:Ù2+ÜØ9±a+l%M[Ý.Y}QâÉ,§8 ‚´tù/º"„n¤Bªþ씡ÕQÒ“öÞµ,Û.;…v©r4Ó@jJâ9'ÊˇV+N`h¬f0¥KVa†¸w‰;°ó‚Týé\/SØ‚U. ±†3èaCIlq!ƒdnÙúÆî𮈠,QE 1©{­ìö¥¿ªÎö± ¹™ýA„´-=Yüs+3ˆ»adk)dÍ1“œbCP‚[ÑÃéÈÍ^1ŽVÚþìÆÅl NQ´y± 8… §7/þ|E¤è›n€¿s ð…ÜÀ)E HœR믂¼"g°,qc·\!pÊR‰­lboý3·\NN½”¯Ô?GÈ+¶2‚¤b+@:à —7¯v=guÔ2Š­4 hGöB­[Ú—K”èð*®F§‹î§|Éê·Ã”N^"~µï;‚±˜8Ôñ.Ø—mb+ p€ä%¿8ø½¨1uX¨ p,le ‹/ü_Š­4‚ ±ØJ.¿Sƒ´y‰°%üï¾€x „~ÛiÅVø@_C‚õF%Èž¯(„åÎÞóNý Çn]À)d ˆ"¶²ñž8­W„’þö¾Ð½x!)pŠr§x`áDCÎoˆC²xŠ ±‚S àJX`À)S@?Ï¢¸Dï±ûß§¦@N±f°$à   !G2·DDÕ+ÅÆrÞÂ;uÀ_´Eq3„$w0oþòkfWLèŸó8w×3pàm[‡€=l3mœ¡X%=[qRih7¡Ð‰P ÃRaJ7W6ès(s‚\Ã+xhþà övEùKˆ„ö ¸ƒU؃NH…Šw[G؃¢„„¢‚¡×…4r¦H7èY)h(iY¦f “s,R¨nb†h´…MÈ<‰¢t.UQo‡þà:è*|øj8'}àFÅÇE‡èbàÐ 8‡Ëçˆ7'B¶rç†VH!ˆ ›Øˆ£f‡ócdK„\žT‰–è ‰’ÄŠj˜ü·" ‡c¸‚%rŠN¡Š¹¨»Øpn{1E‹µ·xŒV˜Œ!‚N1‰$åŒýAŒ©(\(ˆ¡h[qâ6‹¥x#—¸X€˜†à(˜vE²H‰ç8Œ¨hŒìȉtV‡y,š× ÊR“ŽÑ˜ºøŽñ€axTÚè܈Àu&$ÖLvUèh‹ëÈ2Yi1mŒæH†Ró‰ŒÙJç…‘©Ž”Õþ‘¼†…PCKTI6C6É~GD“à¡èD–“BDD<3ta ?9qàFÜA”ÞÁ<ÉÕ4(’:ád5èñz[Qˆ@I&Ç•1|K„DxåH– †N±–aécÉ– x[1C¡–tù÷VXùb¹— !k[ÁŒK¡—‚yÙ]˜‰iâ8p™–[1™d±8Žù˜PØ—aAˆù˜ ébˆ›)˜9—^š{y•nqšlY„ ‚pk`´¬É•]çS¸»  °D 0¡hªén £¨OI,é¿Öœ»±w[1xa þàC0 ‡€4‡ /áKh‰x8Ž@à)° ¡ à\ð¿Vš¯á•gѹÀN!ÑN0Až¾a–^מ° @ê0QŸ»±œ–9P™±J±0 ×ˆv©ñ×™vh [q º˜ kùé)°øK¢:YÀ9U„Iš a[1y’7œNA 1¡a—ª¹˜!Ñ[¡ Ô'3Ê`x™1¡¡[á 1NA¹ Dzny¡n„—a [¡ ¡b @Qje*Q¸D¿ ²0N¡áN‘41¦€1§þ¼0š`ŸÁUq q Û ‰PqúÓ&©Y«ôp(`( nÄ ç9-z»€„ jWžx1ª²iµ °P1zqa˜±ºD"Л«$q ™€@6Á†A|Ë9Š‘ "pˆ q–n¡smÈ ¦à–ÊzÌúq… ¬°œK'×*®E9š™™®¿šQ3pªo‘®ñêP%&ð:_£a¯üÊP"€­ïzs!¬™$W²°jQ‘Æ5M¸±¯iá°KdH¾Á°dA± ]l)±cá°p´—ëÖ诂Ùfhz¿6°œIªëV¤°-›¬±3{³8›³:»³<Û³5;ejml-0.28/docs/logo/ejml_logo.gif000077500000000000000000000241621256171534400167400ustar00rootroot00000000000000GIF89aÚçÿ         # ( &  !!#!$8#$"$%##')&'%'(&()'*+)+-*,-+-., 1J/1.02/130231$5O3424636757968973:@&<[9;8;=:0?O<>;=?<>@=@B?ACA,GlCEBEGDFHEGIFHIGIJHJKIDLSJLJ/Q{LNKNPMOQOQSP6W‚RTQTUSUVT3[‹VWUVXUWYVH[qY[XZ\Y[]Z\^[5dš]_\^`]_a^`b_ac`bdaPg‚decefd?m£fhehighjgikhjlibmylnknpmoqn\tqspFz·rtqsurH|¹tvsvxuwyvG‚Åy{xz|y|~{}|~€}M‡Ê~€‚ƒ€‚„R‹Ïƒ…‚LØ…‡„nЬ†ˆ…‡‰†ˆŠ‡‰‹ˆ€Œ™ŠŒ‰ŒŠŒŽs”¼‘Ž’‘“’”‘“•’”–“–˜•—™–}žÆ™›˜›™œž›Ÿœž Ÿ¡ž ¢Ÿ¡£ ¢¤¡—¦¹£¥¢¤¦£¥§¤¦¨¥‡¬Û§©¦¨ª§©«¨ª¬©‹±ß«­ª¬®«­¯¬Ž´ã¯±®±³¯²´±´¶³µ·´¶¸µ·¹¶¸º·¹»¸®½Ñº¼¹»½º½¿¼¿Á¾ÁÿÂÄÁÃÅ·ÇÚÄÆÃÅÇÄÇÉÆÈÊÇÉËÈÊÌÉ»ÏèËÎÊÍÏËÎÐÌÏÑÎÐÒÏÑÓÐÂÕïÒÔÑÓÕÒÔÖÓÕ×ÔÅÙòÖØÕØÚÖÙÛØÛÝÚÜÞÛÝßÜÞàÝßáÞàâßáäàãåáäæãåçäæèåçéæèêçéëèêìéëîêíïëîðíïñîðòïñóðòôñóõòô÷óöøô÷ùöøú÷ùûøúüùûýúüÿûþÿü!þCreated with GIMP,Úþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝ[s\!¾€ lQK€È+^̘p¡Ã.KžL9n½Ãˆ+kÞÌ9ìã‘;‹MêåÉK«^ÍèçЭcËžýòtfÚ¸së™ òîßÀƒG܇áð.áÈ“+ÿ·ê0†}Ë£KŸMüðªéس“nà¹öïà%þWp=¼ùó€¹{GϾýÜñåÝËŸ¯V=túøó‡…¯¿¿­öý'à€PñGàdÕ#Ž3¿È‚J,Ûì ‚Ëñ£O=ï¨3N6ÏóK-§p2‰ x¬ñ…Fü0à !d A@ùeK@  J`aF{âÈ$”Lbe@‘ƒ`&e‚èf |Ñ|!Ä–E±ÄRXÑÅi¸!‡òH%œˆò -½ ƒL3ÓdãÍ8ç¬óÎ<öè³?õ³>öÐ;z“Í4Í 3L/¶Ä‚Š(œPòˆ!è!GhŒÁER<¡„Epù… ÞhäÈ2ê(Aþ1ô€b´ ‰ ™d#‚èñÆTÁƒ %dð@ŒpÉDÍ@¡A”SF+í´Sê”22R«í¶˜A0‘=£ìQÇ,R (­èRL4Þ˜óŽ=÷íC;ælãÌ0¶ ÂÉ#ÜÁF^|ñ Yº÷·'¬ð ÏÑ8 G,¥4e ñ¤êS?+\¼ðDJx¬pd]Ù^¶"§¬2Ú\¤ÎÊ «"´0OëÅO±Ô¬íD(ë<%HÉCÌÐDmôÑH7r íôÓPG-õÔT;­Œ>W=àóÖ>§€Í\KYŠDÅ…-å8>É`¶”­YHU]õ‡Å!÷Ýxç­7þÑÊ\ÅÛ€G¼ÎE%ÀظÃ<8Ð^BÜ{; f¼T®ùæ›_…‚á sËÌE?nŠD1ÎÀ<<¸måÄÜbûí¸ç®û-Dsãû ‡ÁáûðÄÏ Ñ!_‘ò1OÕ ¡G?--YaºD@>ÉNÑÎ@ìnAûîäïÞ»ï©`ñì?tòï/óóS•½ôøcÖ²Er~ŠDK0Ü•,.<ÜÆW¾Úî|¿ ^ûŒç<‰T0"„H¡’„üyð„ÿ$’н"'â&¶°q,¹‘¾Ã¬o‚ÃÛ CtØ2ćþL©‚󇆋¨Âp¨ˆ@wƒœ´t`!àÒÚohÅ^„‡CßQ!_LH2F¤ŒaˆøƒÂE„a8™Ed¡;ÆMÚѵMN" ܪhÅÜ͆êë¢ûˆ?BÊÏôC$UÜ€Féñà"Ó0\|ˆÐIá&Ý &ÒÀUé(Dë#ùþÈ -r‡e4H* ²J‚´’(zhdôPp‘sŽqDôÀQ{H t³“È/ݶ=PM”W$†ñj€Nð•æ?¤)Í |F–¼ˆ> × ‰ô&to¨É%¢‡ƒ‰Tpà#2y‡E㙲‹Ô¬Ÿå‰AzFeØþ +’GÀ0"£ˆ^â1“},tâ«à’hÌÚ­w¤¤ QiχÄS‘óĨT8‘Oбã"",$ é9b&¨Þ&âÀÙBÈŒh)%øÌŠîЦ=ÄéuÊ”StÔp²È  ‰ìBz¸L\ =5J$¤nLE)Sf:“‚<cVŸU2v)²øiàRS‘®¨þú^à/ 1à–1Õ>Êt¦[¬©F5øUUö••-Š[Åê¶\\¤ “…D–?Ä$øÃDT8kÔÕŠw F ÙwÑBzÖ*Å ¬ÛHqFŽz‰$þöŠfä aþªÛÂqÙÞ•L8 Ú×ÙC~¶*ÎíÚŠY‘?®ñFþ–ð)䯞Û×ЇB´íÓìa‚ÁÙÀ¤·‰¼Š6„k6?„0p/9<¨±•(7 ”GÚ:ð¶¸ÕmwY{SþæÔ¿;0S F^®­á"ž.$²˜%hð`"&ÒÀõþ įvÀÝâw"žJƒ ¼5,\$g€Ó…DàáA¸c%ê¨#è(1!¸ v–!v'˜ÛìÖÃÞf§9äje$Þš.â¸KÄ6ø;ÄJö0DOLÄn›@RBiÝî8»˜ép‹LfkÕÌJÙGþ’}fƒ‹4#pljÈ6=ˆ¬¡dô #bV³y`ËÇì2;•)ÈÿxÌhöj¢⩬Yg´´È{ÝÖ ðåo)á‘+(¸M€vh—ñë» ‹y¿q™±ÒÏG«l…±%à|!E¶%úÐ&!®m¡æÕl!ûØÈ^4RÎéj•%à"òœT%’gN»$¡h¤%‚ص!ØÉ~Z+0ÓŠp›[oXé@³Wv~H{"eóàJMò94RL"g\À}î£ÛØýøÔ°RoÀ}áˆG?,T¨x¸cê0Ç8¶!e c& Aˆ:˜Á IVþ"Ð3nÝÑ"2öÙ0&‚#4f£$µe{!áµQ!Ô…äðLíÅ@zÕ¾½Šl×–€Ñ‰ë؆2ta J Z@ J |àt™à”-梄 %™o#Ï1Óší 8?¤Î‡g螋ںæ+×"öµ-‹)-_[1&’:4€º! ­,å18®íÁ ÍùÚ¹Ás.ÿ|îߺU ë¶m/…€3ÆDx Ë@Œ ØT*D¨¼6Æ%^í‹Ï¯)èA§:£X9àxÉ”º›¬!6+€¨¶‘8–H%×ßÓ'2õÜHF˜wÉ«òDñ´Û>ÊÝ›­oé ,­þ .`1„Û&L;ŧ‡Ñów‹Y(%t[=šÒg³ÑU"Ε%¨?2Ž’{0Š¡KkCcå‡z© ˜ >×|ÐGd hd@‘ok#zIA€ctaØgñù´A nÃ}Æ÷|Èç;è#°€ìç|°wk`aMñ€ã Aù$AGùTñMfÃVFqQ'È x Øzí×_Xaxkã5·6Ï0lÐQÓÐÇM % ¶6¨U‚U„Ü‚+¨„.XO (|8½Çq8÷öFAÐQI@¤@iiw|Ex„€ fø€g(‚8þðФ·6W(k˜O !‚usqDzׇ&(†d8ˆ¯‡†X¡4ncMqˆncYA?e^±3‡bfÓ š†bˆŒ hKø_XA‰kcyJ!€kór!Šùö{øSˆ¶à6ØP‹h(†¾“o  ‹…è~iå6˜Æãä6ľ˜O›^×Q{4Gµ6´U€~(†ƒ¹È€Ÿ(wXPnSDLÑkTáùdfÏ(VÅ¿à6’›(†Ä`wÚˆ˜¸6PJ! €3sÁ‘b•^a{ù´¡VkCxi‹9õ¸N»þ`X!‹kC‚I‘Rnã‘q‘õmË#Z(Çà6v†ÓHC#‘-HˆL‰¹8 °r"‘æÀ ´€ zÀ? @€Vñ €óŽA“5…!{„e“áZO(rGîã’KI‘Lx i8O€ Úü°ò`ÙÀ ÃÀ ¸ ¯  ¥   •0 Žp€0h O 6 ЕÜÂsn# ¢¥ñ{b…uÑ=fólp©rI4[pדÙx— µn³¡ €ƒ6á ¢E¤($Z`™Zk7¯Ù_±94³à‡ñ’vu›¼xÊ ›þSNÑdkSœ$\Öá@^†5Ù°6ÖœÿõœµC‡á³SÖ)“W\ÚÉ0—¤Ä8à È \P_ƒÂum1i\i´#pr# pà ý¦û q° 󇨙ŸÓ‘nCvñfÂU cä¥y‘BfJA¡xc\À42n)±®ƒ«@"± º0R¦ø¹6 ©œÂ5ɱD^´8ëe69£7Z5*¡UŠl)A`R‚¸'å¤  Ñ¡\x1^ä¥X ! P`(²6:Èžö™HЧWp €yú§€¨¤FQþoW—( Ò¢À)æ ¦ ³` €ƒ¦6¥ ±$¦“1ba³ovºõ§ˆ°‡qšª:¨zå‰(±C-…à£ñ2Ž*:¤nÓÁ¥Â… qÌF^¢9ï°6yªgVH€º§Чªšª¬Ê[,h›Û(ì«S‚èîp«ÜR¬¡ aó1§ÂU ¡ IF¢k£TÚ”‡¨¥zªÑ*¨_†|ëg­+±Ü1-.°¨dàª-ɨaº6‰ˆ­IF°±yG^”úô°6Ì¥¬\Å”ê¬Ðš¯y:­ûåª+Q8-q°¡e;þ%®©¾6*ðJbr >•dõ-;¯vù_z¯€ª «"‹U…ê¯.1Ú:%=ºøÐ²Ó"®aÃ:q±$–X{˜—d*ù°6 ¤±ŠÆ¬{`yжnû¶yÐ r t[·v{·x rÛ ŸÐ·~û·€¸Ÿ°·ãP¸†{¸ˆ›¸Š;´Ê«oÑâ_Zj&µÑÂa«k¶akF\šIv1gaS¶+ Šõ´¦j¹²¤ÔgîæºR’±Áô5¦[`ІÖ¸ Q¹aãT©‹«Kª;@´‹M™ ¼ ÑÍ‹eÀÇþ*1»I†¢qk¶¤!½fc¼F‰¼x ¨N0½ù䥡¾]a°kCº!¾I†*ûýдäÕ¾f³ŸÇ[‘É«}à¾Ø”²a¿ÍkuȆájq@ ùhþ6\¾|¾yúŒFE±¡½Í{ Á²\S#––d†ãjÌ5–À¸ù| Ô2WÃ:œÃÐÑðÃ@ÄB<Ä‘ÐÃ@HœÄJL[àNüÄP¼%B T\ÅV|ÅXœÅZ¼ÅW¼-Üڊá¹D9 œd @ û5óe6à 6ç³Aw¾B‹`‡AÑz´@–´þôy­Á´Úò¼qî+’Èn½ !Â6L:ã Þ6ûgì3êj¶ŒVfyJÑ’j€ƒ ª~L<ýÈ.QoH-°ÛÀê»wP 8ŽŒcÛÁÔòHѶ6(,ÄË5V@ÇáU¯y-;§°Ç¦¼¯©—ÊTõ~”°Òâ¨È5;½qš·¼6—ü&\3- 5I¦bÿ€½º»6&ÆÉ~ű$0% PÊŠ0ʇÏ€zʈF²‡Ê¿Î1Iá©ÍË©±»–<ò»5 i¶Iá63ÛÌ5p¥Î€Å”Î*%D‹Ìʬ¯„‘ÕªÊ)!Ͳš¿Ѩê ÂñËaþÇ ÑfCô ÎäE¦ú»«AÆacšíJdÆ ­‹$¨òô²Ì¼xÎ\‚ü1+%<.:½îšÌ5aµ>ó4*\І(½5Q ZëBÂü|ðÃÆ˜‘©šÌÀÇõ\ÔkwÔ˜Ía Ò¾$¡¦ÓË«‘É[CK­3ÿÀ)‡MÅ'Ð[cÒ qÍ\Ócý‚Í3nSÂÖ@MÊm½ÑE×¶%×±Ô†\fj¹ €Cäê3öDÃé®Í5Íßj67“Ó‘×€Â@7Rò±iÑDmÙ'ˆÙ÷¥Ù°Z Ò#ÁXê›°1ÚñÙ5 +VÁ<ßþ¬3Ù þ¼5hÇoYJ4Y€Os9‡‘9Û=p*Áã@Ü$!xÓ[Ëá«Üá–aƒÂHXÀXÐ\¬aÕ:C‡Ú½Ýóˆ÷4¶=ãMÞVÑ îÛ]Ý×a ó+ðÝQ0J,–‰Pº6b0¯>4Öw¶5àâ½áNƒ¢Ûš„ ð ÒÑ 7(ù€ô ï°ç0Þ€ Ï€ ¿` ¥p `E­†ó¶†Íà‘—a¶¥óS2=¸»6¼&–j6.ÛByˆ*%g`E p[àeÄP´EëÛÜ=Á N†ð0 »À ‹Ð ¾«Që6á½\³³þÿ ç²ôÈ-ú­3Š ¥­3Y.Ã×9 0Ÿ1Ä˜á ƒfæ ‹æ:–Ô=1ÁfùIaÓa9Ùa£×ú+WùÁ¥fÓM!©XÞØª@ˆ– J> æ•né}ÜÑϬé€LŸ€Ÿ@4¼Þë€üëXñ2È×½5/ìj6ÿy’ŒFuZ‡®3™@&6‰ŽÁ3ì;*%”ŽL¹>àíß.­¾ŽÔXaŠoÉ$m6ß3Í5â*~€M_H°n6@"ŠïÔžÁÑŽRòµþí‡Qne^ðÏTѤ ¿Wn6@ªh6yþ'=@«Ì]3Ÿ$êÍ5ù>„õYãeøPp*¿òØì;avfãé¹6ž9.Ï5ÑX^ÐH?_Î5ã)•¼5ü­èwÚ×Dnáî@&åÖô•ÍòS!fCì?ö[sr!õ[‡ÁšCôÕ1”k¢ì¸6Ùö¢ÚUK-ï@KŸòro´‘ŸÙhÆÅÀ ˜ ë¾öàL’fska÷[ƒßñäùsÁAú?~î3±ÍøËêÚŠâÝeoß •¿Ût¸ nRè½!ã6 »³Ïfþú\âA CTåÁäaÃe¹6Œ­åè »€é»³ô¿oùm×Öüª@AyîØáï3[Ú6ÂpýUÒÃ÷ñ”@à@‚ 4ˆäßB† :T…PâăZ^ĘQãFމ}ì˜ñ#±Žõ0,òoä-–-]¾„ùi`E5mÞÄ™s%Lž=Gn¤WAàŒ^˼ ŒRéR¦ gP„ÕYSªU«jŠšᓪ@´~Ø #%°e%:Ò(Ëì×UI­ÍŠÅê\ºZ½»1ŽÁq*?öüRˆÀ9 Þ8p^Œœ&XçT ‘º•—¢€«5©eÎt eþŽú¥ª Ðma”— tYì4²Z=1FÕN±Z霛)㦼/Z3XhabÅ=[Í<œÜ&ñâ0};L"0LC¬ èÓáÛiÏqowƒoªb&OpóÅ7é¡ÊÕXÊ=AU1ÍH%ü~‡Ï•úgh Â`ŸáþjΧÁ(L¹ä˜K°%’@ NZf iøëìüêCúâÃþ¨JƒUÉÈ"I#OLÌ ªI>”bÄý&äˆÇU B†!#¼…˜ã¢ÉAÆŒpByÒ¥¡sÊEǺx1a¬Ü¯'©J5üDÑh‰,B£LLL ªE>äŠËìxôþ¤Œê1È"!$Ò¥lPIœ˜LpBŠ#E3¹Q Sä¬*Ÿ3€ÒìV0ñQªL¼0£_ΈŽý°ªÏð[ÂÒÜèÔhB- rmObú|é£#HRÐåø¤µH;1Ž"OTeÊPÀwÂëgi|!¥‘;ÂP‡6hÀ€FˆÆªLô…*{L¬d#Î4àŽÞ4±ªüø0%b-cU¤_BÆ Lúã•Ö‘ˆ L×›mnÂiJ …(”y•çØb0£’\¦QÇ@ŽúÁgu¼aæU*ù'jØË¬Ž¨Šž¥¡jÙȱ,»èˆ#kêŽ]þx¸²zíº·¡}N"ÈeíUÂH k"¸8C¦!—ª4h޲‘8ì‰&¨ê`Ï¡* Ù¨_4¦#>^‡ªöð#»3zÌÉf™^` …CôXã )ŽèaDÐ ‚´ €€ÄÚ­èÊc|hÍ‚¬y¨jÅFRà.˜Zϳ¼¡v¢¥¡ˆ*ÆkŽ˜»vƒ¨*–—^ÊlüPÜU©Ž7lj Yš}ê‰gq¼™F`lYÅ“IÁ#,”øÁ…Þ^íƒÞRÿ/uvò¼ètÀ@‡Z ©vß'ô‚\T†€ˆgÙ3†íø7™ÈUQ†‰þðÀ‘×}H¹Û‡‚Ô”2 °vçI5¸Av4/:8B’p A U¸Ân©BC!úüO#º° í0P,˜UùÔ‡ÌÃ(|(]!AË~A•£äðX¸» ¥ø‘FäSÄ¢y1LdÑ‹ÜÈb€¾üc* €l¨‘W8Ql,8‰DC•Z˜( ƇæØ1¼¨uM±‚Ae ~‘„€@ARhÈ,žp[Œ4äFÆ¡2\‚ @ԱƌˆB“S¶ö¡@T&CH05Ÿc(% /:UиɵérsáÍxRÆö}¤tƒú7„þ ¤B˜ÇDf2A÷Ë]a.#Ž@H+8™‘ûÐòL{\Ê.^Ä Ú˜HO±YzV°)¼¨SL1“5? âò^ HZåKfR-˜Ç„ƒ@NL~s™õdU(:@„kš©¢:_Īèáx62‘~JB¾î\b)éü˜šb…â§íÄ˽09Í“õ´'1IL³ŸÊ¤'@ï÷o á8¨FÑQ «)èù>ªb¥*$Â#â±”#¼ˆmM OÝ£V%/?*È.êtR”Ž$™ù À>_ŠÌ2sh9íˆÏ¤:`4Åwø)Uæö!Ê„ž±™ÎRôþ¡=P…k%ÏoÒ™%=Š©YïyL–À¥cåFYyV´n„ €uOݘ2×Á‡*ºœOÈIe0å¯&"Sn€YÛ¤ ªT¹Ë« ÂK{qU¦*ýª>!+Lɖ޲•͈#YkÞudh̨UÌ`",¥Ý#Slð"3P%Ã] ^ÛÎ`d_ˆµ­bq»Òbî¶·Sû-p/ÒCì®&®L1E–ZY•.˜H»Kùàj¾»¼ˆ TaA{A#„í^N@*.ÑÂ;ÙÅ"¬bëyé7Sõ†ä .šÒ_ÀV)çϘrŠØ(µ)6QŽš’ à ^ÊH°Jþ ‚¥¦k0c)ÐRÈJXWé­pC¼Ôb¸Ì)º{‘h­s)úÈÀjÆ@ âG!M)‘Í‚Íù@¶`_—Ëàñ&3ú¼F„Çì[ y#?ÐòZÎÙ‘|„ Kß±JT?TÃ¥$b5Ë Š’L•Ä,m€qúö:XuÄÇ‚òj?¯±ãDBÍ f³3Ý,]C—%kJ!j–˜1—~(Mqäà4ª ÔD8  r; •¾ÖªÕ$È*b¼fôæ™gÒÜÏG+ÉËn鬣²É,Ce&â]8ŒŸ På²™™óRö!PeÛÊžÍlMDDi»Æt¯ËœÌIþ ÄÒÄæõ„5½i¥TÜagHä!è,É.,þЛr¨µ$`U™À‹\Û” Ý{"¥HtH@+ΡûÆ‘~)°… ïtË›ÞT±³Ã'Ò\:ë9K€žËL$ªÌÒ,Õ­J"M$ªPTä1(º­r×|3}ÿ±¯‘ÙîJsüâmþøCd}󂬡#ú¸ð™;î|¨U9\¦¦U»)bbzA§óª ™¤îºÜÑ×ÍO›¬ñú¼“¾‘„‡Ý šàH>”p¬;ÔE(²%UJ ÌEÕ¥Êáíÿý¼*Ú,ˆ®1¨öÝýÝo:¤‘>w†|kñ4ŠÙÏ3ºØþ<=„¬ -ÌâÓª(Þ=WoŠë™N€~D\#G3·Uá®ùµ³] ǼÚ9¯Ù‡íyÇàÏtƒÊ€}>P¤J?L–Ðc.ÏÆOà—‚}»×Èö™xhkñ® Ý”¾#ä3·4¹{‰ú@ù(º„¨`€ã³Š¿û  Ïû¼ni eÈ¢E[ÄP\!1ŠAaEb(-AÜO »Rº€ ›±«‹ÃE´ x`¨@´º ‚ ¥¥¨¯<¸¦ÐN”"O*ˆ88Åeì ?¼¢PTìPE‡%0=‡ƒf{ˆ< £²ŒUB4 (s¨ x™ð†Ê0‡"Çq‚ul zhƒX¼à#ˆ’Ú´| ~þœF.é‡~à~؇}Ї|¸{¨z˜‡x€wh‡uXu8s ‡qpð†ŽÜmȆlÀk˜†’4Iiˆ†hx†gpghfXe8c(›ê]À…Z€U(Pà„JpBàƒ9Hƒ.€‚"˜p¾x€gÐ[xGÛµ€Šü:@ Ê‹˜‡qˆ†a°TàJp„CH„E8Aø=¨ƒ8`4 /È*€‚%8!¸h(à €l±Ö ͽÃ$áÈÊÅäzІ] `ðÀ0†kœ$`ÌÛC.` xH €„ÌLÉyXþsðlxe^°…W0OÀ„IH@Ѓ70/ %¨@Ø€ €€Çá>MYŸ‚ð¹~I,Íé„l¨ºËêÔÎí”Ù"éÜ´ÄäÎñr8Ô"ÏôTOñÇ\¾öÏõ”Oº€‡øP—ùÔÏý¬ ÜKÒD6PLþ$ЦÀ‡sL(ÐeЋ8‚¨¸÷ŒÎ¥Pè‡êŽà‡ åPþä¹"äAñìÐeˆ$\ @CUQò½ŒÏ¤ƒÏÑXˆJ¨Ð(ÅÑÒ„<÷ HÍQ e†oƒ‹¨½5Ò€4¬¤ÉÊ=R‡ë\‹þÃ&¥RÎ ¿ñSE­RþÄËÌ ^ØÒ0¥7žPªdR1ÕÏb¨Q‚€B4uS´‚A€ÌJ-}SõD2°x±:ÕSNšBЪܠ]ÀNè…#–3ÝSò¼°paLÔG<9¬ÜHçKH˜—!+SHÝN¤ŠŠhb!Ö‰UÅ\x¶%pT5YŒhϼÜ\]”LP ‡yÙÖ“>^0PP›Ø}xQÿˆsÓ \“yôØyåÙ¤UZ7+„“ˆð|P…ÕŽEˆ…Q°Ó,m•Ú¥åÚ®µ¡”ÝÔþ €"]ˆ\蟠ùX¯eÛ¶µ”R8†hQ ¸Øº¸Óü\ˆ·ˆœ }˜šuÛ¿Üý€Õ†èÓXÙìØÕERŒ¿‡YÛÀ…ÜÈ­ŒÁ]ˆ$ˆ_ÌŽQÚ„†ðŠ@Ùñ[ÉÝÑU þÊý‡+åû ¡u†h«îDZÒ•ÝÙ}Á‚X2å ‚Pp„¿[B¯ ]Ú^Ò5ˆ€VÓðØ;ƒˆ€‚•ñØá•^·-ÞÂýSɇ;ÈÅ8£ýI €Þñ¥Þ¤߈Þg•†_(†V]£Sa5ò•_¯uΊm4dÐÀ€…åNðM×ù`›%}¹]Xu_õ„ßV`žˆa‡Š €ÿUOÿ]à –XŠØ…¨<þL` öàr…‹"ÖþE×6áf] -¨[òìàvaQ-‹"àß .á¶áDý `máöa1=ß¾^ ¥à6â*å9ƒÀ€Uagˆø=â(ÎÑ$&ˆBhb-b)Öb¥â(„nÐÞâ1¦Ð$Ö‚®Ð,&ã5.л’a*ÕœÃeã9žÏÒá-݇/¦ã=ÖψÁ€!æã@dv`bA6äCFäDVäEfäFväG†ä¤ ;ejml-0.28/docs/logo/ejml_logo_153x51.gif000066400000000000000000000067051256171534400176660ustar00rootroot00000000000000GIF89a™3çÿ      & "$!':&'%(=*C()'!,6*,),-+'.4".C-/,&1;/1/2316U342/6<463675/:E3:A5:<9;8/>N<>;+A`?@>'CgAB@>ELIDCBFHEGD=K\IKHKMJNPMFQ]3T~@ShDSdPRO>VpUVTWXVRY`H[q?_ŠK^t[]ZZ_a~€û™cÃꟾ}ûò)^̸q>|ý$îÔ Â 6|q¢³ 6X áÁAûYð`‚ 4°… Ø ¼†“x ð¥v Lœ±a‚|ñ9kF½Y6=ZªuëVÍܹïç¼þ•onÜxò’ _Ï~w’u´GS[÷ú˜® Ò~ÌÀi°·‚=Ás (tŠ*­LÑÇ5ÊÐÂN<Â3:òÄ#O;Ú¤“a<ó #Q?œ´g"o>˜CÐí±1Ð;´÷ ±bßz. 4 ìÝCñ¨²É›”ÒŒ\$³M.÷TÎ<ås”-3Ñ+'žƒ6±Ñb”1²7A- ½…‰v ¤ ëñcCAnâ‰'E63L‡€Ãä@ýŒCå?øœ#AVJ„K–&’0 A„|9P˜ì}‘BÂ@ºmi“{O¼ÉPœsi 8o„1L/M ÔçŸZåDþÈ Úž… „I{qdép"ÔZÐ<[œÈˆš°W…§ ™É²™”bÌ7Ñ(aI/“ D=í“¶¯J´Œ‰È‰öÀ7°@ZaÉ^®-p"¦y“À‰œ äÍìm‘ÏCñØòË¿¿èbK/Æ€¡Å*¹$œ°-H-ãð];,¢DÏ´×Å;ôd<ÏÆò¬£ Qþ ®hb ^„YÞ$Ð8&°7Fµ ÁCN?€ýÃ/ÔDCŽŒ2眱̃3?ø”ÏÑÿøúÐ4íB3C³7AlšHŠAë4%ºÿ”³ÂºS+OÊíL 5ßÈq$tÊK=_ JèDÓÀžþÔÓÞÕ{bðe+¢ÏÔÖ{¨ˆ¶Î<¯  ƒ„êÉÜu»*ÓM³ën]ÐÃbˆ)†>ôLN{i$¢`ÿ#OÖ&Ž391°—HÙ MÚ’·á„$t^N# SÞ-‘6î®—ŒbGlŒ‘Å8ˆPAí´wAcgYÅŸê!Zø?çÔÀ&}57‰å³ÏÎÑH#M4ͤ0È(üÇÏ>‡¡G9ÞA:~pî+F;ˆ6¼&«áL¢ òðA^€(p PU<rް‡íû0žAÂg CÇHá1ŠQ!ˆâ§ E1Tx ]ä¢8ìÅÄ )È"dþñ(œ¤BeíáAÔ‡(6¤† |S:rÀVDÆ!¾H<'Ž<`€ ^ð"”‘Œ2*#P„$$¡[Ì#cp¤>ø1‹à Ë Ù8&@DÞ@`ÉG âADA`ýˆ™¬®øuPq=VtAÞa»ˆ;¸ \ ƒ%4á“KBx@J! ¨LåºÐëE ¸·þ±Ç>îf±û?Ú¯QhHÄzÊ%‚¨Ãìy#kö8J„p¨ÀP¨ ØLA @ xó-§8ù‚œ F ¸ÁùÆñJ[Š`‡á%!‡ù947 þ¸ØÃHG&s™ É¢@útü`;*qm8ô·E&6±F]Øãt=Ý>ž!…Ô€ËÔ†ÉúHÎÉs LÎZÀÀÕ`-Ž9ehïÈéÙ¦œâ# °A X`…O4H…/PQЦ–â !Å Æp>5ÝS8x¶ …'0Á9 Á'“ dqÃIÀŒ%°WåÍoÒAöÈ fc†:Ò‘uhƒëèë:n Bhb(ˆ…&*щJhâª@…dQQŒ„¬£’ñܺÚ!Áãë(3¼¬]2Ž ŠŽøbÇç`þż֣¦T8w-üH·oðc_Œ8@Á¿¨!iH.(QŠ¡m¢²{@ z´‡œp 0u„¯=IøG(>€ þwvÅkïš™²u˜`pÒ Jà3œÁ i¨D)ˆ” èîÃõjHÕ.Å;˶'i§p@Ÿ`µ‡…á„kP«rPp=6Åb3+Ù…,bC¢Ó°†3œú•“'ú«KLt!€dÈ·ØSƒ "ÄÚxA˜Ñž¶KfÿØÅ¦Øs[µµù.n!BÐwxe`ƒ5@L¤CxÀ ÷Íï~‡Äâ}T¡>øCFÖž´hBþZ`0ÀL8_*Ø“€­=*Raëz À®à°çˆ/K­pЀ aà"˜ D¾p…'€õ}±Ð<:;sh#Aè7˜êTQ€¨Ã4Áé¦VvY`!Z·YØR8„ËÖC2 $äÝ‚­bº̵|ëÉOñµ 7H¶Þ„‡Áå‡y¦18$Àç@%ÁíF˜â2F0x‹ms•í+6„s0¤P|õnª`ã\x8+XÔ@É›ð­Â ¯@€=CKÞhö@1+»W´À:ÎÜ4P"aP8®¡Š:P< f€n?þ.Ú~Ü áqØ×?¼Ñ#PE é ïK %&{ÄümXáûG“¡0YDâ&¦8%®! !Pã®ð¸‰Cž„@Øÿ¸í  â òJáEÚ Àb’éˆv}Ö@W èúè7±Å¥1Œ2”!QO:Õ#²FÉ»dòr{&°=‘ ÉÂzé÷õøGG|”7 …޶xp-°ˆ±.ÈˇŒÂög 'œð–h³†ØŠ!L»@JdóÀAðǃU…®Ø‹ Á /†  ˆ´À°íà‹Ì¸| ‘hOKÍxazc˜D#œˆÍȧ!:qé Žê¨ ô ^B;ejml-0.28/docs/release-checklist.txt000066400000000000000000000010041256171534400174550ustar00rootroot00000000000000- Update version number in UtilEjml.VERSION - Update change.txt - Update version in build.gradle - Commit and tag release - Create zip of source code - Create jar file "gradle createLibraryDirectory" - Update documentation on website ----- Push to central: - gradle uploadArchives - Then go to the website https://oss.sonatype.org/ * click close button * double check the files * click release button --------- Once a year: - Update copy right - Update year in ant script - update year on docs/bottom.txt ejml-0.28/examples/000077500000000000000000000000001256171534400142205ustar00rootroot00000000000000ejml-0.28/examples/build.gradle000066400000000000000000000001551256171534400165000ustar00rootroot00000000000000dependencies { compile project(':main:all') } idea { module { name = "EJML Examples" } }ejml-0.28/examples/build.xml000066400000000000000000000053021256171534400160410ustar00rootroot00000000000000 ejml-0.28/examples/readme.txt000066400000000000000000000031551256171534400162220ustar00rootroot00000000000000Here are some examples of common algorithms created using EJML library. Each example is designed to provided a practicle example of how the library can be used. There are two different algorithms provided as examples; Kalman filter and Levenberg-Marquardt. The Kalman filter is implemented different ways to show the library can be used to write code easily and/or very efficiently. Levenberg-Marquardt shows another type of algorithm and how to effectively use reshaping to avoid creating new memory unnecisarily. ------------------------------- Three different example of how to program a Kalman filter using this library are provided. One example uses the simplified interface, the other uses generic matrix operation functions, the last one uses direct calls to an algorithm to speed things up. These represent three different levels in terms of coding complexity and performance. KalmanFilterSimple - uses the simplified interface. - easiest to program. - slowest to run. KalmanFilterOps - Uses generic functions. - Reduces the amount of memory created/destroyed significantly. - Requires more work to program. - Runs about 23% faster than the simplified case KalmanFilterAlg - Uses a specialized algorithm for performing the matrix inversion operation. - Requires knowedge of which algorithms to use and how to use them. - No new memory is created after initialization. - Runs about 28% faster than the simplified case. To run the speed benchmark application tell ant to run "kalman-benchmark". --------------------------------- The provided ant script can compile all the example code and run the unit tests. - Peter Abelesejml-0.28/examples/src/000077500000000000000000000000001256171534400150075ustar00rootroot00000000000000ejml-0.28/examples/src/org/000077500000000000000000000000001256171534400155765ustar00rootroot00000000000000ejml-0.28/examples/src/org/ejml/000077500000000000000000000000001256171534400165255ustar00rootroot00000000000000ejml-0.28/examples/src/org/ejml/example/000077500000000000000000000000001256171534400201605ustar00rootroot00000000000000ejml-0.28/examples/src/org/ejml/example/BenchmarkKalmanPerformance.java000066400000000000000000000116751256171534400262350ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import java.util.ArrayList; import java.util.List; /** * Compares how fast the filters all run relative to each other. * * @author Peter Abeles */ public class BenchmarkKalmanPerformance { private static final int NUM_TRIALS = 200; private static final int MAX_STEPS = 1000; private static final double T = 1.0; private static int measDOF = 8; List filters = new ArrayList(); public void run() { DenseMatrix64F priorX = new DenseMatrix64F(9,1, true, 0.5, -0.2, 0, 0, 0.2, -0.9, 0, 0.2, -0.5); DenseMatrix64F priorP = CommonOps.identity(9); DenseMatrix64F trueX = new DenseMatrix64F(9,1, true, 0, 0, 0, 0.2, 0.2, 0.2, 0.5, 0.1, 0.6); List meas = createSimulatedMeas(trueX); DenseMatrix64F F = createF(T); DenseMatrix64F Q = createQ(T,0.1); DenseMatrix64F H = createH(); for(KalmanFilter f : filters ) { long timeBefore = System.currentTimeMillis(); f.configure(F,Q,H); for( int trial = 0; trial < NUM_TRIALS; trial++ ) { f.setState(priorX,priorP); processMeas(f,meas); } long timeAfter = System.currentTimeMillis(); System.out.println("Filter = "+f.getClass().getSimpleName()); System.out.println("Elapsed time: "+(timeAfter-timeBefore)); System.gc(); } } private List createSimulatedMeas( DenseMatrix64F x ) { List ret = new ArrayList(); DenseMatrix64F F = createF(T); DenseMatrix64F H = createH(); // UtilEjml.print(F); // UtilEjml.print(H); DenseMatrix64F x_next = new DenseMatrix64F(x); DenseMatrix64F z = new DenseMatrix64F(H.numRows,1); for( int i = 0; i < MAX_STEPS; i++ ) { CommonOps.mult(F,x,x_next); CommonOps.mult(H,x_next,z); ret.add(z.copy()); x.set(x_next); } return ret; } private void processMeas( KalmanFilter f , List meas ) { DenseMatrix64F R = CommonOps.identity(measDOF); for(DenseMatrix64F z : meas ) { f.predict(); f.update(z,R); } } public static DenseMatrix64F createF( double T ) { double []a = new double[]{ 1, 0 , 0 , T , 0 , 0 , 0.5*T*T , 0 , 0 , 0, 1 , 0 , 0 , T , 0 , 0 , 0.5*T*T , 0 , 0, 0 , 1 , 0 , 0 , T , 0 , 0 , 0.5*T*T , 0, 0 , 0 , 1 , 0 , 0 , T , 0 , 0 , 0, 0 , 0 , 0 , 1 , 0 , 0 , T , 0 , 0, 0 , 0 , 0 , 0 , 1 , 0 , 0 , T , 0, 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0, 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 }; return new DenseMatrix64F(9,9, true, a); } public static DenseMatrix64F createQ( double T , double var ) { DenseMatrix64F Q = new DenseMatrix64F(9,9); double a00 = (1.0/4.0)*T*T*T*T*var; double a01 = (1.0/2.0)*T*T*T*var; double a02 = (1.0/2.0)*T*T*var; double a11 = T*T*var; double a12 = T*var; double a22 = var; for( int i = 0; i < 3; i++ ) { Q.set(i,i,a00); Q.set(i,3+i,a01); Q.set(i,6+i,a02); Q.set(3+i,3+i,a11); Q.set(3+i,6+i,a12); Q.set(6+i,6+i,a22); } for( int y = 1; y < 9; y++ ) { for( int x = 0; x < y; x++ ) { Q.set(y,x, Q.get(x,y)); } } return Q; } public static DenseMatrix64F createH() { DenseMatrix64F H = new DenseMatrix64F(measDOF,9); for( int i = 0; i < measDOF; i++ ) { H.set(i,i,1.0); } return H; } public static void main( String args[] ) { BenchmarkKalmanPerformance benchmark = new BenchmarkKalmanPerformance(); benchmark.filters.add( new KalmanFilterOperations()); benchmark.filters.add( new KalmanFilterSimple()); benchmark.filters.add( new KalmanFilterEquation()); benchmark.run(); } } ejml-0.28/examples/src/org/ejml/example/EquationCustomFunction.java000066400000000000000000000067041256171534400255200ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.equation.*; import org.ejml.ops.CommonOps; import org.ejml.simple.SimpleMatrix; import java.util.List; import java.util.Random; /** * Demonstration on how to create and use a custom function in Equation. A custom function must implement * ManagerFunctions.Input1 or ManagerFunctions.InputN, depending on the number of inputs it takes. * * @author Peter Abeles */ public class EquationCustomFunction { public static void main(String[] args) { Random rand = new Random(234); Equation eq = new Equation(); eq.getFunctions().add("multTransA",createMultTransA()); SimpleMatrix A = new SimpleMatrix(1,1); // will be resized SimpleMatrix B = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix C = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(A,"A",B,"B",C,"C"); eq.process("A=multTransA(B,C)"); System.out.println("Found"); System.out.println(A); System.out.println("Expected"); B.transpose().mult(C).print(); } /** * Create the function. Be sure to handle all possible input types and combinations correctly and provide * meaningful error messages. The output matrix should be resized to fit the inputs. */ public static ManagerFunctions.InputN createMultTransA() { return new ManagerFunctions.InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager ) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs required"); final Variable varA = inputs.get(0); final Variable varB = inputs.get(1); Operation.Info ret = new Operation.Info(); if( varA instanceof VariableMatrix && varB instanceof VariableMatrix ) { // The output matrix or scalar variable must be created with the provided manager final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("multTransA-mm") { @Override public void process() { DenseMatrix64F mA = ((VariableMatrix)varA).matrix; DenseMatrix64F mB = ((VariableMatrix)varB).matrix; output.matrix.reshape(mA.numCols,mB.numCols); CommonOps.multTransA(mA,mB,output.matrix); } }; } else { throw new IllegalArgumentException("Expected both inputs to be a matrix"); } return ret; } }; } } ejml-0.28/examples/src/org/ejml/example/ExampleComplexMath.java000066400000000000000000000040271256171534400245630ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.Complex64F; import org.ejml.data.ComplexPolar64F; import org.ejml.ops.ComplexMath64F; /** * Demonstration of different operations that can be performed on complex numbers. * * @author Peter Abeles */ public class ExampleComplexMath { public static void main( String []args ) { Complex64F a = new Complex64F(1,2); Complex64F b = new Complex64F(-1,-0.6); Complex64F c = new Complex64F(); ComplexPolar64F polarC = new ComplexPolar64F(); System.out.println("a = "+a); System.out.println("b = "+b); System.out.println("------------------"); ComplexMath64F.plus(a, b, c); System.out.println("a + b = "+c); ComplexMath64F.minus(a, b, c); System.out.println("a - b = "+c); ComplexMath64F.multiply(a, b, c); System.out.println("a * b = "+c); ComplexMath64F.divide(a, b, c); System.out.println("a / b = "+c); System.out.println("------------------"); ComplexPolar64F polarA = new ComplexPolar64F(); ComplexMath64F.convert(a, polarA); System.out.println("polar notation of a = "+polarA); ComplexMath64F.pow(polarA, 3, polarC); System.out.println("a ** 3 = "+polarC); ComplexMath64F.convert(polarC, c); System.out.println("a ** 3 = "+c); } } ejml-0.28/examples/src/org/ejml/example/ExampleFixedSizedMatrix.java000066400000000000000000000055551256171534400255740ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.alg.fixed.FixedOps3; import org.ejml.data.DenseMatrix64F; import org.ejml.data.FixedMatrix3_64F; import org.ejml.data.FixedMatrix3x3_64F; import org.ejml.ops.ConvertMatrixType; import org.ejml.simple.SimpleMatrix; /** * In some applications a small fixed sized matrix can speed things up a lot, e.g. 8 times faster. One application * which uses small matrices is graphics and rigid body motion, which extensively uses 3x3 and 4x4 matrices. This * example is to show some examples of how you can use a fixed sized matrix. * * @author Peter Abeles */ public class ExampleFixedSizedMatrix { public static void main( String args[] ) { // declare the matrix FixedMatrix3x3_64F a = new FixedMatrix3x3_64F(); FixedMatrix3x3_64F b = new FixedMatrix3x3_64F(); // Can assign values the usual way for( int i = 0; i < 3; i++ ) { for( int j = 0; j < 3; j++ ) { a.set(i,j,i+j+1); } } // Direct manipulation of each value is the fastest way to assign/read values a.a11 = 12; a.a23 = 64; // can print the usual way too a.print(); // most of the standard operations are support FixedOps3.transpose(a,b); b.print(); System.out.println("Determinant = "+FixedOps3.det(a)); // matrix-vector operations are also supported // Constructors for vectors and matrices can be used to initialize its value FixedMatrix3_64F v = new FixedMatrix3_64F(1,2,3); FixedMatrix3_64F result = new FixedMatrix3_64F(); FixedOps3.mult(a,v,result); // Conversion into DenseMatrix64F can also be done DenseMatrix64F dm = ConvertMatrixType.convert(a,null); dm.print(); // This can be useful if you need do more advanced operations SimpleMatrix sv = SimpleMatrix.wrap(dm).svd().getV(); // can then convert it back into a fixed matrix FixedMatrix3x3_64F fv = ConvertMatrixType.convert(sv.getMatrix(),(FixedMatrix3x3_64F)null); System.out.println("Original simple matrix and converted fixed matrix"); sv.print(); fv.print(); } } ejml-0.28/examples/src/org/ejml/example/ExampleMatrixIO.java000066400000000000000000000050521256171534400240350ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.MatrixIO; import org.ejml.simple.SimpleMatrix; import java.io.IOException; /** * Examples for reading and writing matrices to files in different formats * * @author Peter Abeles */ public class ExampleMatrixIO { public static void csv() { DenseMatrix64F A = new DenseMatrix64F(2,3,true,new double[]{1,2,3,4,5,6}); try { MatrixIO.saveCSV(A, "matrix_file.csv"); DenseMatrix64F B = MatrixIO.loadCSV("matrix_file.csv"); B.print(); } catch (IOException e) { throw new RuntimeException(e); } } public static void csv_simple() { SimpleMatrix A = new SimpleMatrix(2,3,true,new double[]{1,2,3,4,5,6}); try { A.saveToFileCSV("matrix_file.csv"); SimpleMatrix B = new SimpleMatrix().loadCSV("matrix_file.csv"); B.print(); } catch (IOException e) { throw new RuntimeException(e); } } public static void serializedBinary() { DenseMatrix64F A = new DenseMatrix64F(2,3,true,new double[]{1,2,3,4,5,6}); try { MatrixIO.saveBin(A, "matrix_file.data"); DenseMatrix64F B = MatrixIO.loadBin("matrix_file.data"); B.print(); } catch (IOException e) { throw new RuntimeException(e); } } public static void csv_serializedBinary() { SimpleMatrix A = new SimpleMatrix(2,3,true,new double[]{1,2,3,4,5,6}); try { A.saveToFileBinary("matrix_file.data"); SimpleMatrix B = SimpleMatrix.loadBinary("matrix_file.data"); B.print(); } catch (IOException e) { throw new RuntimeException(e); } } public static void main( String args[] ) { csv(); serializedBinary(); } } ejml-0.28/examples/src/org/ejml/example/KalmanFilter.java000066400000000000000000000045451256171534400234040ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; /** *

* This is an interface for a discrete time Kalman filter with no control input:
*
* xk = Fk xk-1 + wk
* zk = Hk xk + vk
*
* wk ~ N(0,Qk)
* vk ~ N(0,Rk)
*

* * @author Peter Abeles */ public interface KalmanFilter { /** * Specify the kinematics model of the Kalman filter. This must be called * first before any other functions. * * @param F State transition matrix. * @param Q plant noise. * @param H measurement projection matrix. */ public void configure( DenseMatrix64F F, DenseMatrix64F Q , DenseMatrix64F H); /** * The prior state estimate and covariance. * * @param x The estimated system state. * @param P The covariance of the estimated system state. */ public void setState( DenseMatrix64F x , DenseMatrix64F P ); /** * Predicts the state of the system forward one time step. */ public void predict(); /** * Updates the state provided the observation from a sensor. * * @param z Measurement. * @param R Measurement covariance. */ public void update( DenseMatrix64F z , DenseMatrix64F R ); /** * Returns the current estimated state of the system. * * @return The state. */ public DenseMatrix64F getState(); /** * Returns the estimated state's covariance matrix. * * @return The covariance. */ public DenseMatrix64F getCovariance(); } ejml-0.28/examples/src/org/ejml/example/KalmanFilterEquation.java000066400000000000000000000057211256171534400251070ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.equation.Equation; import org.ejml.equation.Sequence; /** * Example of how the equation interface can greatly simplify code * * @author Peter Abeles */ public class KalmanFilterEquation implements KalmanFilter{ // system state estimate private DenseMatrix64F x,P; private Equation eq; // Storage for precompiled code for predict and update Sequence predictX,predictP; Sequence updateY,updateK,updateX,updateP; @Override public void configure(DenseMatrix64F F, DenseMatrix64F Q, DenseMatrix64F H) { int dimenX = F.numCols; x = new DenseMatrix64F(dimenX,1); P = new DenseMatrix64F(dimenX,dimenX); eq = new Equation(); // Provide aliases between the symbolic variables and matrices we normally interact with // The names do not have to be the same. eq.alias(x,"x",P,"P",Q,"Q",F,"F",H,"H"); // Dummy matrix place holder to avoid compiler errors. Will be replaced later on eq.alias(new DenseMatrix64F(1,1),"z"); eq.alias(new DenseMatrix64F(1,1),"R"); // Pre-compile so that it doesn't have to compile it each time it's invoked. More cumbersome // but for small matrices the overhead is significant predictX = eq.compile("x = F*x"); predictP = eq.compile("P = F*P*F' + Q"); updateY = eq.compile("y = z - H*x"); updateK = eq.compile("K = P*H'*inv( H*P*H' + R )"); updateX = eq.compile("x = x + K*y"); updateP = eq.compile("P = P-K*(H*P)"); } @Override public void setState(DenseMatrix64F x, DenseMatrix64F P) { this.x.set(x); this.P.set(P); } @Override public void predict() { predictX.perform(); predictP.perform(); } @Override public void update(DenseMatrix64F z, DenseMatrix64F R) { // Alias will overwrite the reference to the previous matrices with the same name eq.alias(z,"z"); eq.alias(R,"R"); updateY.perform(); updateK.perform(); updateX.perform(); updateP.perform(); } @Override public DenseMatrix64F getState() { return x; } @Override public DenseMatrix64F getCovariance() { return P; } }ejml-0.28/examples/src/org/ejml/example/KalmanFilterOperations.java000066400000000000000000000066561256171534400254550ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import static org.ejml.ops.CommonOps.*; /** * A Kalman filter that is implemented using the operations API, which is procedural. Much of the excessive * memory creation/destruction has been reduced from the KalmanFilterSimple. A specialized solver is * under to invert the SPD matrix. * * @author Peter Abeles */ public class KalmanFilterOperations implements KalmanFilter{ // kinematics description private DenseMatrix64F F,Q,H; // system state estimate private DenseMatrix64F x,P; // these are predeclared for efficiency reasons private DenseMatrix64F a,b; private DenseMatrix64F y,S,S_inv,c,d; private DenseMatrix64F K; private LinearSolver solver; @Override public void configure(DenseMatrix64F F, DenseMatrix64F Q, DenseMatrix64F H) { this.F = F; this.Q = Q; this.H = H; int dimenX = F.numCols; int dimenZ = H.numRows; a = new DenseMatrix64F(dimenX,1); b = new DenseMatrix64F(dimenX,dimenX); y = new DenseMatrix64F(dimenZ,1); S = new DenseMatrix64F(dimenZ,dimenZ); S_inv = new DenseMatrix64F(dimenZ,dimenZ); c = new DenseMatrix64F(dimenZ,dimenX); d = new DenseMatrix64F(dimenX,dimenZ); K = new DenseMatrix64F(dimenX,dimenZ); x = new DenseMatrix64F(dimenX,1); P = new DenseMatrix64F(dimenX,dimenX); // covariance matrices are symmetric positive semi-definite solver = LinearSolverFactory.symmPosDef(dimenX); } @Override public void setState(DenseMatrix64F x, DenseMatrix64F P) { this.x.set(x); this.P.set(P); } @Override public void predict() { // x = F x mult(F,x,a); x.set(a); // P = F P F' + Q mult(F,P,b); multTransB(b,F, P); addEquals(P,Q); } @Override public void update(DenseMatrix64F z, DenseMatrix64F R) { // y = z - H x mult(H,x,y); subtract(z, y, y); // S = H P H' + R mult(H,P,c); multTransB(c,H,S); addEquals(S,R); // K = PH'S^(-1) if( !solver.setA(S) ) throw new RuntimeException("Invert failed"); solver.invert(S_inv); multTransA(H,S_inv,d); mult(P,d,K); // x = x + Ky mult(K,y,a); addEquals(x,a); // P = (I-kH)P = P - (KH)P = P-K(HP) mult(H,P,c); mult(K,c,b); subtractEquals(P, b); } @Override public DenseMatrix64F getState() { return x; } @Override public DenseMatrix64F getCovariance() { return P; } }ejml-0.28/examples/src/org/ejml/example/KalmanFilterSimple.java000066400000000000000000000053521256171534400245530ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.simple.SimpleMatrix; /** * A Kalman filter implemented using SimpleMatrix. The code tends to be easier to * read and write, but the performance is degraded due to excessive creation/destruction of * memory and the use of more generic algorithms. This also demonstrates how code can be * seamlessly implemented using both SimpleMatrix and DenseMatrix64F. This allows code * to be quickly prototyped or to be written either by novices or experts. * * @author Peter Abeles */ public class KalmanFilterSimple implements KalmanFilter{ // kinematics description private SimpleMatrix F,Q,H; // sytem state estimate private SimpleMatrix x,P; @Override public void configure(DenseMatrix64F F, DenseMatrix64F Q, DenseMatrix64F H) { this.F = new SimpleMatrix(F); this.Q = new SimpleMatrix(Q); this.H = new SimpleMatrix(H); } @Override public void setState(DenseMatrix64F x, DenseMatrix64F P) { this.x = new SimpleMatrix(x); this.P = new SimpleMatrix(P); } @Override public void predict() { // x = F x x = F.mult(x); // P = F P F' + Q P = F.mult(P).mult(F.transpose()).plus(Q); } @Override public void update(DenseMatrix64F _z, DenseMatrix64F _R) { // a fast way to make the matrices usable by SimpleMatrix SimpleMatrix z = SimpleMatrix.wrap(_z); SimpleMatrix R = SimpleMatrix.wrap(_R); // y = z - H x SimpleMatrix y = z.minus(H.mult(x)); // S = H P H' + R SimpleMatrix S = H.mult(P).mult(H.transpose()).plus(R); // K = PH'S^(-1) SimpleMatrix K = P.mult(H.transpose().mult(S.invert())); // x = x + Ky x = x.plus(K.mult(y)); // P = (I-kH)P = P - KHP P = P.minus(K.mult(H).mult(P)); } @Override public DenseMatrix64F getState() { return x.getMatrix(); } @Override public DenseMatrix64F getCovariance() { return P.getMatrix(); } } ejml-0.28/examples/src/org/ejml/example/LevenbergMarquardt.java000066400000000000000000000256551256171534400246320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import static org.ejml.ops.CommonOps.*; import static org.ejml.ops.SpecializedOps.diffNormF; /** *

* This is a straight forward implementation of the Levenberg-Marquardt (LM) algorithm. LM is used to minimize * non-linear cost functions:
*
* S(P) = Sum{ i=1:m , [yi - f(xi,P)]2}
*
* where P is the set of parameters being optimized. *

* *

* In each iteration the parameters are updated using the following equations:
*
* Pi+1 = (H + λ I)-1 d
* d = (1/N) Sum{ i=1..N , (f(xi;Pi) - yi) * jacobian(:,i) }
* H = (1/N) Sum{ i=1..N , jacobian(:,i) * jacobian(:,i)T } *

*

* Whenever possible the allocation of new memory is avoided. This is accomplished by reshaping matrices. * A matrix that is reshaped won't grow unless the new shape requires more memory than it has available. *

* @author Peter Abeles */ public class LevenbergMarquardt { // how much the numerical jacobian calculation perturbs the parameters by. // In better implementation there are better ways to compute this delta. See Numerical Recipes. private final static double DELTA = 1e-8; private double initialLambda; // the function that is optimized private Function func; // the optimized parameters and associated costs private DenseMatrix64F param; private double initialCost; private double finalCost; // used by matrix operations private DenseMatrix64F d; private DenseMatrix64F H; private DenseMatrix64F negDelta; private DenseMatrix64F tempParam; private DenseMatrix64F A; // variables used by the numerical jacobian algorithm private DenseMatrix64F temp0; private DenseMatrix64F temp1; // used when computing d and H variables private DenseMatrix64F tempDH; // Where the numerical Jacobian is stored. private DenseMatrix64F jacobian; /** * Creates a new instance that uses the provided cost function. * * @param funcCost Cost function that is being optimized. */ public LevenbergMarquardt( Function funcCost ) { this.initialLambda = 1; // declare data to some initial small size. It will grow later on as needed. int maxElements = 1; int numParam = 1; this.temp0 = new DenseMatrix64F(maxElements,1); this.temp1 = new DenseMatrix64F(maxElements,1); this.tempDH = new DenseMatrix64F(maxElements,1); this.jacobian = new DenseMatrix64F(numParam,maxElements); this.func = funcCost; this.param = new DenseMatrix64F(numParam,1); this.d = new DenseMatrix64F(numParam,1); this.H = new DenseMatrix64F(numParam,numParam); this.negDelta = new DenseMatrix64F(numParam,1); this.tempParam = new DenseMatrix64F(numParam,1); this.A = new DenseMatrix64F(numParam,numParam); } public double getInitialCost() { return initialCost; } public double getFinalCost() { return finalCost; } public DenseMatrix64F getParameters() { return param; } /** * Finds the best fit parameters. * * @param initParam The initial set of parameters for the function. * @param X The inputs to the function. * @param Y The "observed" output of the function * @return true if it succeeded and false if it did not. */ public boolean optimize( DenseMatrix64F initParam , DenseMatrix64F X , DenseMatrix64F Y ) { configure(initParam,X,Y); // save the cost of the initial parameters so that it knows if it improves or not initialCost = cost(param,X,Y); // iterate until the difference between the costs is insignificant // or it iterates too many times if( !adjustParam(X, Y, initialCost) ) { finalCost = Double.NaN; return false; } return true; } /** * Iterate until the difference between the costs is insignificant * or it iterates too many times */ private boolean adjustParam(DenseMatrix64F X, DenseMatrix64F Y, double prevCost) { // lambda adjusts how big of a step it takes double lambda = initialLambda; // the difference between the current and previous cost double difference = 1000; for( int iter = 0; iter < 20 || difference < 1e-6 ; iter++ ) { // compute some variables based on the gradient computeDandH(param,X,Y); // try various step sizes and see if any of them improve the // results over what has already been done boolean foundBetter = false; for( int i = 0; i < 5; i++ ) { computeA(A,H,lambda); if( !solve(A,d,negDelta) ) { return false; } // compute the candidate parameters subtract(param, negDelta, tempParam); double cost = cost(tempParam,X,Y); if( cost < prevCost ) { // the candidate parameters produced better results so use it foundBetter = true; param.set(tempParam); difference = prevCost - cost; prevCost = cost; lambda /= 10.0; } else { lambda *= 10.0; } } // it reached a point where it can't improve so exit if( !foundBetter ) break; } finalCost = prevCost; return true; } /** * Performs sanity checks on the input data and reshapes internal matrices. By reshaping * a matrix it will only declare new memory when needed. */ protected void configure( DenseMatrix64F initParam , DenseMatrix64F X , DenseMatrix64F Y ) { if( Y.getNumRows() != X.getNumRows() ) { throw new IllegalArgumentException("Different vector lengths"); } else if( Y.getNumCols() != 1 || X.getNumCols() != 1 ) { throw new IllegalArgumentException("Inputs must be a column vector"); } int numParam = initParam.getNumElements(); int numPoints = Y.getNumRows(); if( param.getNumElements() != initParam.getNumElements() ) { // reshaping a matrix means that new memory is only declared when needed this.param.reshape(numParam,1, false); this.d.reshape(numParam,1, false); this.H.reshape(numParam,numParam, false); this.negDelta.reshape(numParam,1, false); this.tempParam.reshape(numParam,1, false); this.A.reshape(numParam,numParam, false); } param.set(initParam); // reshaping a matrix means that new memory is only declared when needed temp0.reshape(numPoints,1, false); temp1.reshape(numPoints,1, false); tempDH.reshape(numPoints,1, false); jacobian.reshape(numParam,numPoints, false); } /** * Computes the d and H parameters. Where d is the average error gradient and * H is an approximation of the hessian. */ private void computeDandH( DenseMatrix64F param , DenseMatrix64F x , DenseMatrix64F y ) { func.compute(param,x, tempDH); subtractEquals(tempDH, y); computeNumericalJacobian(param,x,jacobian); int numParam = param.getNumElements(); int length = x.getNumElements(); // d = average{ (f(x_i;p) - y_i) * jacobian(:,i) } for( int i = 0; i < numParam; i++ ) { double total = 0; for( int j = 0; j < length; j++ ) { total += tempDH.get(j,0)*jacobian.get(i,j); } d.set(i,0,total/length); } // compute the approximation of the hessian multTransB(jacobian,jacobian,H); scale(1.0/length,H); } /** * A = H + lambda*I
*
* where I is an identity matrix. */ private void computeA( DenseMatrix64F A , DenseMatrix64F H , double lambda ) { final int numParam = param.getNumElements(); A.set(H); for( int i = 0; i < numParam; i++ ) { A.set(i,i, A.get(i,i) + lambda); } } /** * Computes the "cost" for the parameters given. * * cost = (1/N) Sum (f(x;p) - y)^2 */ private double cost( DenseMatrix64F param , DenseMatrix64F X , DenseMatrix64F Y) { func.compute(param,X, temp0); double error = diffNormF(temp0,Y); return error*error / (double)X.numRows; } /** * Computes a simple numerical Jacobian. * * @param param The set of parameters that the Jacobian is to be computed at. * @param pt The point around which the Jacobian is to be computed. * @param deriv Where the jacobian will be stored */ protected void computeNumericalJacobian( DenseMatrix64F param , DenseMatrix64F pt , DenseMatrix64F deriv ) { double invDelta = 1.0/DELTA; func.compute(param,pt, temp0); // compute the jacobian by perturbing the parameters slightly // then seeing how it effects the results. for( int i = 0; i < param.numRows; i++ ) { param.data[i] += DELTA; func.compute(param,pt, temp1); // compute the difference between the two parameters and divide by the delta add(invDelta,temp1,-invDelta,temp0,temp1); // copy the results into the jacobian matrix System.arraycopy(temp1.data,0,deriv.data,i*pt.numRows,pt.numRows); param.data[i] -= DELTA; } } /** * The function that is being optimized. */ public interface Function { /** * Computes the output for each value in matrix x given the set of parameters. * * @param param The parameter for the function. * @param x the input points. * @param y the resulting output. */ public void compute( DenseMatrix64F param , DenseMatrix64F x , DenseMatrix64F y ); } } ejml-0.28/examples/src/org/ejml/example/PolynomialFit.java000066400000000000000000000117651256171534400236230ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.alg.dense.linsol.AdjustableLinearSolver; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; /** *

* This example demonstrates how a polynomial can be fit to a set of data. This is done by * using a least squares solver that is adjustable. By using an adjustable solver elements * can be inexpensively removed and the coefficients recomputed. This is much less expensive * than resolving the whole system from scratch. *

*

* The following is demonstrated:
*

    *
  1. Creating a solver using LinearSolverFactory
  2. *
  3. Using an adjustable solver
  4. *
  5. reshaping
  6. *
* @author Peter Abeles */ public class PolynomialFit { // Vandermonde matrix DenseMatrix64F A; // matrix containing computed polynomial coefficients DenseMatrix64F coef; // observation matrix DenseMatrix64F y; // solver used to compute AdjustableLinearSolver solver; /** * Constructor. * * @param degree The polynomial's degree which is to be fit to the observations. */ public PolynomialFit( int degree ) { coef = new DenseMatrix64F(degree+1,1); A = new DenseMatrix64F(1,degree+1); y = new DenseMatrix64F(1,1); // create a solver that allows elements to be added or removed efficiently solver = LinearSolverFactory.adjustable(); } /** * Returns the computed coefficients * * @return polynomial coefficients that best fit the data. */ public double[] getCoef() { return coef.data; } /** * Computes the best fit set of polynomial coefficients to the provided observations. * * @param samplePoints where the observations were sampled. * @param observations A set of observations. */ public void fit( double samplePoints[] , double[] observations ) { // Create a copy of the observations and put it into a matrix y.reshape(observations.length,1,false); System.arraycopy(observations,0, y.data,0,observations.length); // reshape the matrix to avoid unnecessarily declaring new memory // save values is set to false since its old values don't matter A.reshape(y.numRows, coef.numRows,false); // set up the A matrix for( int i = 0; i < observations.length; i++ ) { double obs = 1; for( int j = 0; j < coef.numRows; j++ ) { A.set(i,j,obs); obs *= samplePoints[i]; } } // process the A matrix and see if it failed if( !solver.setA(A) ) throw new RuntimeException("Solver failed"); // solver the the coefficients solver.solve(y,coef); } /** * Removes the observation that fits the model the worst and recomputes the coefficients. * This is done efficiently by using an adjustable solver. Often times the elements with * the largest errors are outliers and not part of the system being modeled. By removing them * a more accurate set of coefficients can be computed. */ public void removeWorstFit() { // find the observation with the most error int worstIndex=-1; double worstError = -1; for( int i = 0; i < y.numRows; i++ ) { double predictedObs = 0; for( int j = 0; j < coef.numRows; j++ ) { predictedObs += A.get(i,j)*coef.get(j,0); } double error = Math.abs(predictedObs- y.get(i,0)); if( error > worstError ) { worstError = error; worstIndex = i; } } // nothing left to remove, so just return if( worstIndex == -1 ) return; // remove that observation removeObservation(worstIndex); // update A solver.removeRowFromA(worstIndex); // solve for the parameters again solver.solve(y,coef); } /** * Removes an element from the observation matrix. * * @param index which element is to be removed */ private void removeObservation( int index ) { final int N = y.numRows-1; final double d[] = y.data; // shift for( int i = index; i < N; i++ ) { d[i] = d[i+1]; } y.numRows--; } } ejml-0.28/examples/src/org/ejml/example/PolynomialRootFinder.java000066400000000000000000000057151256171534400251520ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; /** *

* Eigenvalue decomposition can be used to find the roots in a polynomial by constructing the * so called companion matrix. While faster techniques do exist for root finding, this is * one of the most stable and probably the easiest to implement. *

* *

* Because the companion matrix is not symmetric a generalized eigenvalue decomposition is needed. * The roots of the polynomial may also be complex. Complex eigenvalues is the only instance in * which EJML supports complex arithmetic. Depending on the application one might need to check * to see if the eigenvalues are real or complex. *

* *

* For more algorithms and robust solution for finding polynomial roots check out http://ddogleg.org *

* * @author Peter Abeles */ public class PolynomialRootFinder { /** *

* Given a set of polynomial coefficients, compute the roots of the polynomial. Depending on * the polynomial being considered the roots may contain complex number. When complex numbers are * present they will come in pairs of complex conjugates. *

* *

* Coefficients are ordered from least to most significant, e.g: y = c[0] + x*c[1] + x*x*c[2]. *

* * @param coefficients Coefficients of the polynomial. * @return The roots of the polynomial */ public static Complex64F[] findRoots(double... coefficients) { int N = coefficients.length-1; // Construct the companion matrix DenseMatrix64F c = new DenseMatrix64F(N,N); double a = coefficients[N]; for( int i = 0; i < N; i++ ) { c.set(i,N-1,-coefficients[i]/a); } for( int i = 1; i < N; i++ ) { c.set(i,i-1,1); } // use generalized eigenvalue decomposition to find the roots EigenDecomposition evd = DecompositionFactory.eig(N,false); evd.decompose(c); Complex64F[] roots = new Complex64F[N]; for( int i = 0; i < N; i++ ) { roots[i] = evd.getEigenvalue(i); } return roots; } } ejml-0.28/examples/src/org/ejml/example/PrincipalComponentAnalysis.java000066400000000000000000000216771256171534400263500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.NormOps; import org.ejml.ops.SingularOps; /** *

* The following is a simple example of how to perform basic principal component analysis in EJML. *

* *

* Principal Component Analysis (PCA) is typically used to develop a linear model for a set of data * (e.g. face images) which can then be used to test for membership. PCA works by converting the * set of data to a new basis that is a subspace of the original set. The subspace is selected * to maximize information. *

*

* PCA is typically derived as an eigenvalue problem. However in this implementation {@link org.ejml.interfaces.decomposition.SingularValueDecomposition SVD} * is used instead because it will produce a more numerically stable solution. Computation using EVD requires explicitly * computing the variance of each sample set. The variance is computed by squaring the residual, which can * cause loss of precision. *

* *

* Usage:
* 1) call setup()
* 2) For each sample (e.g. an image ) call addSample()
* 3) After all the samples have been added call computeBasis()
* 4) Call sampleToEigenSpace() , eigenToSampleSpace() , errorMembership() , response() *

* * @author Peter Abeles */ public class PrincipalComponentAnalysis { // principal component subspace is stored in the rows private DenseMatrix64F V_t; // how many principal components are used private int numComponents; // where the data is stored private DenseMatrix64F A = new DenseMatrix64F(1,1); private int sampleIndex; // mean values of each element across all the samples double mean[]; public PrincipalComponentAnalysis() { } /** * Must be called before any other functions. Declares and sets up internal data structures. * * @param numSamples Number of samples that will be processed. * @param sampleSize Number of elements in each sample. */ public void setup( int numSamples , int sampleSize ) { mean = new double[ sampleSize ]; A.reshape(numSamples,sampleSize,false); sampleIndex = 0; numComponents = -1; } /** * Adds a new sample of the raw data to internal data structure for later processing. All the samples * must be added before computeBasis is called. * * @param sampleData Sample from original raw data. */ public void addSample( double[] sampleData ) { if( A.getNumCols() != sampleData.length ) throw new IllegalArgumentException("Unexpected sample size"); if( sampleIndex >= A.getNumRows() ) throw new IllegalArgumentException("Too many samples"); for( int i = 0; i < sampleData.length; i++ ) { A.set(sampleIndex,i,sampleData[i]); } sampleIndex++; } /** * Computes a basis (the principal components) from the most dominant eigenvectors. * * @param numComponents Number of vectors it will use to describe the data. Typically much * smaller than the number of elements in the input vector. */ public void computeBasis( int numComponents ) { if( numComponents > A.getNumCols() ) throw new IllegalArgumentException("More components requested that the data's length."); if( sampleIndex != A.getNumRows() ) throw new IllegalArgumentException("Not all the data has been added"); if( numComponents > sampleIndex ) throw new IllegalArgumentException("More data needed to compute the desired number of components"); this.numComponents = numComponents; // compute the mean of all the samples for( int i = 0; i < A.getNumRows(); i++ ) { for( int j = 0; j < mean.length; j++ ) { mean[j] += A.get(i,j); } } for( int j = 0; j < mean.length; j++ ) { mean[j] /= A.getNumRows(); } // subtract the mean from the original data for( int i = 0; i < A.getNumRows(); i++ ) { for( int j = 0; j < mean.length; j++ ) { A.set(i,j,A.get(i,j)-mean[j]); } } // Compute SVD and save time by not computing U SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows, A.numCols, false, true, false); if( !svd.decompose(A) ) throw new RuntimeException("SVD failed"); V_t = svd.getV(null,true); DenseMatrix64F W = svd.getW(null); // Singular values are in an arbitrary order initially SingularOps.descendingOrder(null,false,W,V_t,true); // strip off unneeded components and find the basis V_t.reshape(numComponents,mean.length,true); } /** * Returns a vector from the PCA's basis. * * @param which Which component's vector is to be returned. * @return Vector from the PCA basis. */ public double[] getBasisVector( int which ) { if( which < 0 || which >= numComponents ) throw new IllegalArgumentException("Invalid component"); DenseMatrix64F v = new DenseMatrix64F(1,A.numCols); CommonOps.extract(V_t,which,which+1,0,A.numCols,v,0,0); return v.data; } /** * Converts a vector from sample space into eigen space. * * @param sampleData Sample space data. * @return Eigen space projection. */ public double[] sampleToEigenSpace( double[] sampleData ) { if( sampleData.length != A.getNumCols() ) throw new IllegalArgumentException("Unexpected sample length"); DenseMatrix64F mean = DenseMatrix64F.wrap(A.getNumCols(),1,this.mean); DenseMatrix64F s = new DenseMatrix64F(A.getNumCols(),1,true,sampleData); DenseMatrix64F r = new DenseMatrix64F(numComponents,1); CommonOps.subtract(s, mean, s); CommonOps.mult(V_t,s,r); return r.data; } /** * Converts a vector from eigen space into sample space. * * @param eigenData Eigen space data. * @return Sample space projection. */ public double[] eigenToSampleSpace( double[] eigenData ) { if( eigenData.length != numComponents ) throw new IllegalArgumentException("Unexpected sample length"); DenseMatrix64F s = new DenseMatrix64F(A.getNumCols(),1); DenseMatrix64F r = DenseMatrix64F.wrap(numComponents,1,eigenData); CommonOps.multTransA(V_t,r,s); DenseMatrix64F mean = DenseMatrix64F.wrap(A.getNumCols(),1,this.mean); CommonOps.add(s,mean,s); return s.data; } /** *

* The membership error for a sample. If the error is less than a threshold then * it can be considered a member. The threshold's value depends on the data set. *

*

* The error is computed by projecting the sample into eigenspace then projecting * it back into sample space and *

* * @param sampleA The sample whose membership status is being considered. * @return Its membership error. */ public double errorMembership( double[] sampleA ) { double[] eig = sampleToEigenSpace(sampleA); double[] reproj = eigenToSampleSpace(eig); double total = 0; for( int i = 0; i < reproj.length; i++ ) { double d = sampleA[i] - reproj[i]; total += d*d; } return Math.sqrt(total); } /** * Computes the dot product of each basis vector against the sample. Can be used as a measure * for membership in the training sample set. High values correspond to a better fit. * * @param sample Sample of original data. * @return Higher value indicates it is more likely to be a member of input dataset. */ public double response( double[] sample ) { if( sample.length != A.numCols ) throw new IllegalArgumentException("Expected input vector to be in sample space"); DenseMatrix64F dots = new DenseMatrix64F(numComponents,1); DenseMatrix64F s = DenseMatrix64F.wrap(A.numCols,1,sample); CommonOps.mult(V_t,s,dots); return NormOps.normF(dots); } } ejml-0.28/examples/src/org/ejml/example/QRExampleEquation.java000066400000000000000000000100131256171534400243620ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.equation.Equation; import org.ejml.ops.CommonOps; import org.ejml.ops.NormOps; /** *

* Example code for computing the QR decomposition of a matrix. It demonstrates how to * extract a submatrix and insert one matrix into another one using the operator interface. *

* * Note: This code is horribly inefficient and is for demonstration purposes only. * * @author Peter Abeles */ public class QRExampleEquation { // where the QR decomposition is stored private DenseMatrix64F QR; // used for computing Q private double gammas[]; /** * Computes the QR decomposition of the provided matrix. * * @param A Matrix which is to be decomposed. Not modified. */ public void decompose( DenseMatrix64F A ) { Equation eq = new Equation(); this.QR = A.copy(); int N = Math.min(A.numCols,A.numRows); gammas = new double[ A.numCols ]; for( int i = 0; i < N; i++ ) { // update temporary variables eq.alias(QR.numRows-i,"Ni",QR,"QR",i,"i"); // Place the column that should be zeroed into v eq.process("v=QR(i:,i)"); // Note that v is lazily created above. Need direct access to it, which is done below. DenseMatrix64F v = eq.lookupMatrix("v"); double maxV = CommonOps.elementMaxAbs(v); eq.alias(maxV,"maxV"); if( maxV > 0 && v.getNumElements() > 1 ) { // normalize to reduce overflow issues eq.process("v=v/maxV"); // compute the magnitude of the vector double tau = NormOps.normF(v); if( v.get(0) < 0 ) tau *= -1.0; eq.alias(tau,"tau"); eq.process("u_0 = v(0,0)+tau"); eq.process("gamma = u_0/tau"); eq.process("v=v/u_0"); eq.process("v(0,0)=1"); eq.process("QR(i:,i:) = (eye(Ni) - gamma*v*v')*QR(i:,i:)"); eq.process("QR(i:,i) = v"); eq.process("QR(i,i) = -1*tau*maxV"); // save gamma for recomputing Q later on gammas[i] = eq.lookupDouble("gamma"); } } } /** * Returns the Q matrix. */ public DenseMatrix64F getQ() { Equation eq = new Equation(); DenseMatrix64F Q = CommonOps.identity(QR.numRows); DenseMatrix64F u = new DenseMatrix64F(QR.numRows,1); int N = Math.min(QR.numCols,QR.numRows); eq.alias(u,"u",Q,"Q",QR,"QR",QR.numRows,"r"); // compute Q by first extracting the householder vectors from the columns of QR and then applying it to Q for( int j = N-1; j>= 0; j-- ) { eq.alias(j,"j",gammas[j],"gamma"); eq.process("u(j:,0) = [1 ; QR(j+1:,j)]"); eq.process("Q=(eye(r)-gamma*u*u')*Q"); } return Q; } /** * Returns the R matrix. */ public DenseMatrix64F getR() { DenseMatrix64F R = new DenseMatrix64F(QR.numRows,QR.numCols); int N = Math.min(QR.numCols,QR.numRows); for( int i = 0; i < N; i++ ) { for( int j = i; j < QR.numCols; j++ ) { R.unsafe_set(i,j, QR.unsafe_get(i,j)); } } return R; } }ejml-0.28/examples/src/org/ejml/example/QRExampleOperations.java000066400000000000000000000113541256171534400247310ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.NormOps; /** *

* Example code for computing the QR decomposition of a matrix. It demonstrates how to * extract a submatrix and insert one matrix into another one using the operator interface. *

* * Note: This code is horribly inefficient and is for demonstration purposes only. * * @author Peter Abeles */ public class QRExampleOperations { // where the QR decomposition is stored private DenseMatrix64F QR; // used for computing Q private double gammas[]; /** * Computes the QR decomposition of the provided matrix. * * @param A Matrix which is to be decomposed. Not modified. */ public void decompose( DenseMatrix64F A ) { this.QR = A.copy(); int N = Math.min(A.numCols,A.numRows); gammas = new double[ A.numCols ]; DenseMatrix64F A_small = new DenseMatrix64F(A.numRows,A.numCols); DenseMatrix64F A_mod = new DenseMatrix64F(A.numRows,A.numCols); DenseMatrix64F v = new DenseMatrix64F(A.numRows,1); DenseMatrix64F Q_k = new DenseMatrix64F(A.numRows,A.numRows); for( int i = 0; i < N; i++ ) { // reshape temporary variables A_small.reshape(QR.numRows-i,QR.numCols-i,false); A_mod.reshape(A_small.numRows,A_small.numCols,false); v.reshape(A_small.numRows,1,false); Q_k.reshape(v.getNumElements(),v.getNumElements(),false); // use extract matrix to get the column that is to be zeroed CommonOps.extract(QR,i,QR.numRows,i,i+1,v,0,0); double max = CommonOps.elementMaxAbs(v); if( max > 0 && v.getNumElements() > 1 ) { // normalize to reduce overflow issues CommonOps.divide(v,max); // compute the magnitude of the vector double tau = NormOps.normF(v); if( v.get(0) < 0 ) tau *= -1.0; double u_0 = v.get(0) + tau; double gamma = u_0/tau; CommonOps.divide(v,u_0); v.set(0,1.0); // extract the submatrix of A which is being operated on CommonOps.extract(QR,i,QR.numRows,i,QR.numCols,A_small,0,0); // A = (I - γ*u*uT)A CommonOps.setIdentity(Q_k); CommonOps.multAddTransB(-gamma,v,v,Q_k); CommonOps.mult(Q_k,A_small,A_mod); // save the results CommonOps.insert(A_mod, QR, i,i); CommonOps.insert(v, QR, i,i); QR.unsafe_set(i,i,-tau*max); // save gamma for recomputing Q later on gammas[i] = gamma; } } } /** * Returns the Q matrix. */ public DenseMatrix64F getQ() { DenseMatrix64F Q = CommonOps.identity(QR.numRows); DenseMatrix64F Q_k = new DenseMatrix64F(QR.numRows,QR.numRows); DenseMatrix64F u = new DenseMatrix64F(QR.numRows,1); DenseMatrix64F temp = new DenseMatrix64F(QR.numRows,QR.numRows); int N = Math.min(QR.numCols,QR.numRows); // compute Q by first extracting the householder vectors from the columns of QR and then applying it to Q for( int j = N-1; j>= 0; j-- ) { CommonOps.extract(QR,j, QR.numRows,j,j+1,u,j,0); u.set(j,1.0); // A = (I - γ*u*uT)*A
CommonOps.setIdentity(Q_k); CommonOps.multAddTransB(-gammas[j],u,u,Q_k); CommonOps.mult(Q_k,Q,temp); Q.set(temp); } return Q; } /** * Returns the R matrix. */ public DenseMatrix64F getR() { DenseMatrix64F R = new DenseMatrix64F(QR.numRows,QR.numCols); int N = Math.min(QR.numCols,QR.numRows); for( int i = 0; i < N; i++ ) { for( int j = i; j < QR.numCols; j++ ) { R.unsafe_set(i,j, QR.unsafe_get(i,j)); } } return R; } }ejml-0.28/examples/src/org/ejml/example/QRExampleSimple.java000066400000000000000000000074561256171534400240470ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.simple.SimpleMatrix; import static org.ejml.simple.SimpleMatrix.END; /** *

* Example code for computing the QR decomposition of a matrix. It demonstrates how to * extract a submatrix and insert one matrix into another one using SimpleMatrix. *

* * Note: This code is horribly inefficient and is for demonstration purposes only. * * @author Peter Abeles */ public class QRExampleSimple { // where the QR decomposition is stored private SimpleMatrix QR; // used for computing Q private double gammas[]; /** * Computes the QR decomposition of the provided matrix. * * @param A Matrix which is to be decomposed. Not modified. */ public void decompose( SimpleMatrix A ) { this.QR = A.copy(); int N = Math.min(A.numCols(),A.numRows()); gammas = new double[ A.numCols() ]; for( int i = 0; i < N; i++ ) { // use extract matrix to get the column that is to be zeroed SimpleMatrix v = QR.extractMatrix(i, END,i,i+1); double max = v.elementMaxAbs(); if( max > 0 && v.getNumElements() > 1 ) { // normalize to reduce overflow issues v = v.divide(max); // compute the magnitude of the vector double tau = v.normF(); if( v.get(0) < 0 ) tau *= -1.0; double u_0 = v.get(0) + tau; double gamma = u_0/tau; v = v.divide(u_0); v.set(0,1.0); // extract the submatrix of A which is being operated on SimpleMatrix A_small = QR.extractMatrix(i,END,i,END); // A = (I - γ*u*uT)A A_small = A_small.plus(-gamma,v.mult(v.transpose()).mult(A_small)); // save the results QR.insertIntoThis(i,i,A_small); QR.insertIntoThis(i+1,i,v.extractMatrix(1,END,0,1)); // save gamma for recomputing Q later on gammas[i] = gamma; } } } /** * Returns the Q matrix. */ public SimpleMatrix getQ() { SimpleMatrix Q = SimpleMatrix.identity(QR.numRows()); int N = Math.min(QR.numCols(),QR.numRows()); // compute Q by first extracting the householder vectors from the columns of QR and then applying it to Q for( int j = N-1; j>= 0; j-- ) { SimpleMatrix u = new SimpleMatrix(QR.numRows(),1); u.insertIntoThis(j,0,QR.extractMatrix(j, END,j,j+1)); u.set(j,1.0); // A = (I - γ*u*uT)*A
Q = Q.plus(-gammas[j],u.mult(u.transpose()).mult(Q)); } return Q; } /** * Returns the R matrix. */ public SimpleMatrix getR() { SimpleMatrix R = new SimpleMatrix(QR.numRows(),QR.numCols()); int N = Math.min(QR.numCols(),QR.numRows()); for( int i = 0; i < N; i++ ) { for( int j = i; j < QR.numCols(); j++ ) { R.set(i,j, QR.get(i,j)); } } return R; } }ejml-0.28/examples/src/org/ejml/example/StatisticsMatrix.java000066400000000000000000000073631256171534400243530ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleBase; import java.util.Random; /** * Example of how to extend "SimpleMatrix" and add your own functionality. In this case * two basic statistic operations are added. Since SimpleBase is extended and StatisticsMatrix * is specified as the generics type, all "SimpleMatrix" operations return a matrix of * type StatisticsMatrix, ensuring strong typing. * * @author Peter Abeles */ public class StatisticsMatrix extends SimpleBase { public StatisticsMatrix( int numRows , int numCols ) { super(numRows,numCols); } protected StatisticsMatrix(){} /** * Wraps a StatisticsMatrix around 'm'. Does NOT create a copy of 'm' but saves a reference * to it. */ public static StatisticsMatrix wrap( DenseMatrix64F m ) { StatisticsMatrix ret = new StatisticsMatrix(); ret.mat = m; return ret; } /** * Computes the mean or average of all the elements. * * @return mean */ public double mean() { double total = 0; final int N = getNumElements(); for( int i = 0; i < N; i++ ) { total += get(i); } return total/N; } /** * Computes the unbiased standard deviation of all the elements. * * @return standard deviation */ public double stdev() { double m = mean(); double total = 0; final int N = getNumElements(); if( N <= 1 ) throw new IllegalArgumentException("There must be more than one element to compute stdev"); for( int i = 0; i < N; i++ ) { double x = get(i); total += (x - m)*(x - m); } total /= (N-1); return Math.sqrt(total); } /** * Returns a matrix of StatisticsMatrix type so that SimpleMatrix functions create matrices * of the correct type. */ @Override protected StatisticsMatrix createMatrix(int numRows, int numCols) { return new StatisticsMatrix(numRows,numCols); } public static void main( String args[] ) { Random rand = new Random(24234); int N = 500; // create two vectors whose elements are drawn from uniform distributions StatisticsMatrix A = StatisticsMatrix.wrap(RandomMatrices.createRandom(N,1,0,1,rand)); StatisticsMatrix B = StatisticsMatrix.wrap(RandomMatrices.createRandom(N,1,1,2,rand)); // the mean should be about 0.5 System.out.println("Mean of A is "+A.mean()); // the mean should be about 1.5 System.out.println("Mean of B is "+B.mean()); StatisticsMatrix C = A.plus(B); // the mean should be about 2.0 System.out.println("Mean of C = A + B is "+C.mean()); System.out.println("Standard deviation of A is "+A.stdev()); System.out.println("Standard deviation of B is "+B.stdev()); System.out.println("Standard deviation of C is "+C.stdev()); } } ejml-0.28/examples/test/000077500000000000000000000000001256171534400151775ustar00rootroot00000000000000ejml-0.28/examples/test/org/000077500000000000000000000000001256171534400157665ustar00rootroot00000000000000ejml-0.28/examples/test/org/ejml/000077500000000000000000000000001256171534400167155ustar00rootroot00000000000000ejml-0.28/examples/test/org/ejml/example/000077500000000000000000000000001256171534400203505ustar00rootroot00000000000000ejml-0.28/examples/test/org/ejml/example/TestCompareKalmanResults.java000066400000000000000000000052311256171534400261500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * Make sure all the filters produce exactly the same results. * * @author Peter Abeles */ public class TestCompareKalmanResults { private static final double T = 0.5; /** * See if all the filters produce the same reslts. */ @Test public void checkIdentical() { KalmanFilterSimple simple = new KalmanFilterSimple(); List all = new ArrayList(); all.add( new KalmanFilterOperations() ); all.add( new KalmanFilterEquation() ); all.add( simple ); DenseMatrix64F priorX = new DenseMatrix64F(9,1, true, 0.5, -0.2, 0, 0, 0.2, -0.9, 0, 0.2, -0.5); DenseMatrix64F priorP = CommonOps.identity(9); DenseMatrix64F F = BenchmarkKalmanPerformance.createF(T); DenseMatrix64F Q = BenchmarkKalmanPerformance.createQ(T,0.1); DenseMatrix64F H = BenchmarkKalmanPerformance.createH(); for( KalmanFilter f : all ) { f.configure(F,Q,H); f.setState(priorX,priorP); f.predict(); } for( KalmanFilter f : all ) { compareFilters(simple,f); } DenseMatrix64F z = new DenseMatrix64F(H.numRows,1); DenseMatrix64F R = CommonOps.identity(H.numRows); for( KalmanFilter f : all ) { f.update(z,R); } for( KalmanFilter f : all ) { compareFilters(simple,f); } } private void compareFilters( KalmanFilter a, KalmanFilter b ) { DenseMatrix64F testX = b.getState(); DenseMatrix64F testP = b.getCovariance(); DenseMatrix64F X = a.getState(); DenseMatrix64F P = a.getCovariance(); EjmlUnitTests.assertEquals(testX,X,1e-8); EjmlUnitTests.assertEquals(testP,P,1e-8); } }ejml-0.28/examples/test/org/ejml/example/TestLevenbergMarquardt.java000066400000000000000000000101641256171534400256470ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestLevenbergMarquardt { int NUM_PTS = 50; Random rand = new Random(7264); /** * Give it a simple function and see if it computes something close to it for its results. */ @Test public void testNumericalJacobian() { JacobianTestFunction func = new JacobianTestFunction(); DenseMatrix64F param = new DenseMatrix64F(3,1, true, 2, -1, 4); LevenbergMarquardt alg = new LevenbergMarquardt(func); DenseMatrix64F X = RandomMatrices.createRandom(NUM_PTS,1,rand); DenseMatrix64F numJacobian = new DenseMatrix64F(3,NUM_PTS); DenseMatrix64F analyticalJacobian = new DenseMatrix64F(3,NUM_PTS); alg.configure(param,X,new DenseMatrix64F(NUM_PTS,1)); alg.computeNumericalJacobian(param,X,numJacobian); func.deriv(X,analyticalJacobian); EjmlUnitTests.assertEquals(analyticalJacobian,numJacobian,1e-6); } /** * See if it can solve an easy optimization problem. */ @Test public void testTrivial() { // the number of sample points is equal to the max allowed points runTrivial(NUM_PTS); // do the same thing but with a different number of poitns from the max allowed runTrivial(20); } /** * Runs the simple optimization problem with a set of randomly generated inputs. * * @param numPoints How many sample points there are. */ public void runTrivial( int numPoints ) { JacobianTestFunction func = new JacobianTestFunction(); DenseMatrix64F paramInit = new DenseMatrix64F(3,1); DenseMatrix64F param = new DenseMatrix64F(3,1, true, 2, -1, 4); LevenbergMarquardt alg = new LevenbergMarquardt(func); DenseMatrix64F X = RandomMatrices.createRandom(numPoints,1,rand); DenseMatrix64F Y = new DenseMatrix64F(numPoints,1); func.compute(param,X,Y); alg.optimize(paramInit,X,Y); DenseMatrix64F foundParam = alg.getParameters(); assertEquals(0,alg.getFinalCost(),1e-8); EjmlUnitTests.assertEquals(param,foundParam,1e-6); } /** * A very simple function to test how well the numerical jacobian is computed. */ private static class JacobianTestFunction implements LevenbergMarquardt.Function { public void deriv( DenseMatrix64F x, DenseMatrix64F deriv) { double dataX[] = x.data; int length = x.numRows; for( int j = 0; j < length; j++ ) { double v = dataX[j]; double dA = 1; double dB = v; double dC = v*v; deriv.set(0,j,dA); deriv.set(1,j,dB); deriv.set(2,j,dC); } } @Override public void compute(DenseMatrix64F param, DenseMatrix64F x, DenseMatrix64F y) { double a = param.data[0]; double b = param.data[1]; double c = param.data[2]; double dataX[] = x.data; double dataY[] = y.data; int length = x.numRows; for( int i = 0; i < length; i++ ) { double v = dataX[i]; dataY[i] = a + b*v + c*v*v; } } } } ejml-0.28/examples/test/org/ejml/example/TestPolynomialFit.java000066400000000000000000000052621256171534400246460ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestPolynomialFit { /** * Test with perfect data */ @Test public void testPerfect() { double coef[] = new double[]{1,-2,3}; double x[] = new double[]{-2,1,0.5,2,3,4,5,7,8,9.2,10.2,4.3,6.7}; double y[] = new double[ x.length ]; for( int i = 0; i < y.length; i++ ) { double v = 0; double xx = 1; for (double c : coef) { v += c * xx; xx *= x[i]; } y[i] = v; } PolynomialFit alg = new PolynomialFit(2); alg.fit(x,y); double found[] = alg.getCoef(); for( int i = 0; i < coef.length; i++ ) { assertEquals(coef[i],found[i],1e-8); } } /** * Make one of the observations way off and see if it is removed */ @Test public void testNoise() { double coef[] = new double[]{1,-2,3}; double x[] = new double[]{-2,1,0.5,2,3,4,5,7,8,9.2,10.2,4.3,6.7}; double y[] = new double[ x.length ]; for( int i = 0; i < y.length; i++ ) { double v = 0; double xx = 1; for (double c : coef) { v += c * xx; xx *= x[i]; } y[i] = v; } y[4] += 3.5; PolynomialFit alg = new PolynomialFit(2); alg.fit(x,y); double found[] = alg.getCoef(); // the coefficients that it initialy computes should be incorrect for( int i = 0; i < coef.length; i++ ) { assertTrue(Math.abs(coef[i]-found[i])>1e-8); } //remove the outlier alg.removeWorstFit(); // now see if the solution is perfect found = alg.getCoef(); for( int i = 0; i < coef.length; i++ ) { assertEquals(coef[i],found[i],1e-8); } } } ejml-0.28/examples/test/org/ejml/example/TestPolynomialRootFinder.java000066400000000000000000000027671256171534400262060ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.Complex64F; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestPolynomialRootFinder { @Test public void findRoots() { Complex64F[] roots = PolynomialRootFinder.findRoots(4, 3, 2, 1); int numReal = 0; for( Complex64F c : roots ) { if( c.isReal() ) { checkRoot(c.real,4,3,2,1); numReal++; } } assertTrue(numReal>0); } private void checkRoot( double root , double ...coefs ) { double total = 0; double a = 1; for( double c : coefs ) { total += a*c; a *= root; } assertEquals(0,total,1e-8); } }ejml-0.28/examples/test/org/ejml/example/TestPrincipleComponentAnalysis.java000066400000000000000000000076471256171534400274050ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestPrincipleComponentAnalysis { Random rand = new Random(234345); /** * Sees if the projection error increases as the DOF decreases in the number of basis vectors. */ @Test public void checkBasisError() { int M = 30; int N = 5; double obs[][] = new double[M][]; PrincipalComponentAnalysis pca = new PrincipalComponentAnalysis(); // add observations pca.setup(M,N); for( int i = 0; i < M; i++ ) { obs[i] = RandomMatrices.createRandom(N,1,-1,1,rand).data; pca.addSample(obs[i]); } // as a more crude estimate is made of the input data the error should increase pca.computeBasis(N); double errorPrev = computeError(pca,obs); assertEquals(errorPrev,0,1e-8); for( int i = N-1; i >= 1; i-- ) { pca.computeBasis(i); double error = computeError(pca,obs); assertTrue(error > errorPrev ); errorPrev = error; } } private double computeError(PrincipalComponentAnalysis pca, double[][] obs ) { double error = 0; for (double[] o : obs) { error += pca.errorMembership(o); } return error; } /** * Checks sampleToEigenSpace and sampleToEigenSpace when the basis vectors can * fully describe the vector. */ @Test public void sampleToEigenSpace() { int M = 30; int N = 5; double obs[][] = new double[M][]; PrincipalComponentAnalysis pca = new PrincipalComponentAnalysis(); // add observations pca.setup(M,N); for( int i = 0; i < M; i++ ) { obs[i] = RandomMatrices.createRandom(N,1,-1,1,rand).data; pca.addSample(obs[i]); } // when the basis is N vectors it should perfectly describe the vector pca.computeBasis(N); for( int i = 0; i < M; i++ ) { double s[] = pca.sampleToEigenSpace(obs[i]); assertTrue(error(s,obs[i]) > 1e-8 ); double o[] = pca.eigenToSampleSpace(s); assertTrue(error(o,obs[i]) <= 1e-8 ); } } private double error( double[] a , double []b ) { double ret = 0; for( int i = 0; i < a.length; i++ ) { ret += Math.abs(a[i]-b[i]); } return ret; } /** * Makes sure the response is not zero. Perhaps this is too simple of a test */ @Test public void response() { int M = 30; int N = 5; double obs[][] = new double[M][]; PrincipalComponentAnalysis pca = new PrincipalComponentAnalysis(); // add observations pca.setup(M,N); for( int i = 0; i < M; i++ ) { obs[i] = RandomMatrices.createRandom(N,1,-1,1,rand).data; pca.addSample(obs[i]); } pca.computeBasis(N-2); for( int i = 0; i < M; i++ ) { double responseObs = pca.response(obs[i]); assertTrue(responseObs > 0 ); } } } ejml-0.28/examples/test/org/ejml/example/TestQRExampleEquation.java000066400000000000000000000032101256171534400254130ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRExampleEquation { Random rand = new Random(23423); @Test public void basic() { checkMatrix(7,5); checkMatrix(5,5); checkMatrix(7,7); } private void checkMatrix( int numRows , int numCols ) { DenseMatrix64F A = RandomMatrices.createRandom(numRows,numCols,-1,1,rand); QRExampleEquation alg = new QRExampleEquation(); alg.decompose(A); DenseMatrix64F Q = alg.getQ(); DenseMatrix64F R = alg.getR(); DenseMatrix64F A_found = new DenseMatrix64F(numRows,numCols); CommonOps.mult(Q,R,A_found); assertTrue( MatrixFeatures.isIdentical(A,A_found,1e-8)); } }ejml-0.28/examples/test/org/ejml/example/TestQRExampleOps.java000066400000000000000000000032101256171534400243670ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRExampleOps { Random rand = new Random(23423); @Test public void basic() { checkMatrix(7,5); checkMatrix(5,5); checkMatrix(7,7); } private void checkMatrix( int numRows , int numCols ) { DenseMatrix64F A = RandomMatrices.createRandom(numRows,numCols,-1,1,rand); QRExampleOperations alg = new QRExampleOperations(); alg.decompose(A); DenseMatrix64F Q = alg.getQ(); DenseMatrix64F R = alg.getR(); DenseMatrix64F A_found = new DenseMatrix64F(numRows,numCols); CommonOps.mult(Q,R,A_found); assertTrue( MatrixFeatures.isIdentical(A,A_found,1e-8)); } }ejml-0.28/examples/test/org/ejml/example/TestQRExampleSimple.java000066400000000000000000000026751256171534400250750ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.example;import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRExampleSimple { Random rand = new Random(23423); @Test public void basic() { checkMatrix(7,5); checkMatrix(5,5); checkMatrix(7,7); } private void checkMatrix( int numRows , int numCols ) { SimpleMatrix A = SimpleMatrix.random(numRows,numCols,-1,1,rand); QRExampleSimple alg = new QRExampleSimple(); alg.decompose(A); SimpleMatrix Q = alg.getQ(); SimpleMatrix R = alg.getR(); SimpleMatrix A_found = Q.mult(R); assertTrue( A.isIdentical(A_found,1e-8)); } } ejml-0.28/main/000077500000000000000000000000001256171534400133265ustar00rootroot00000000000000ejml-0.28/main/all/000077500000000000000000000000001256171534400140765ustar00rootroot00000000000000ejml-0.28/main/all/EJML All.iml000066400000000000000000000044051256171534400160240ustar00rootroot00000000000000 ejml-0.28/main/all/build.gradle000066400000000000000000000003761256171534400163630ustar00rootroot00000000000000dependencies { compile project(':main:core') compile project(':main:dense64') compile project(':main:denseC64') compile project(':main:equation') compile project(':main:simple') } idea { module { name = "EJML All" } }ejml-0.28/main/all/src/000077500000000000000000000000001256171534400146655ustar00rootroot00000000000000ejml-0.28/main/all/src/org/000077500000000000000000000000001256171534400154545ustar00rootroot00000000000000ejml-0.28/main/all/src/org/ejml/000077500000000000000000000000001256171534400164035ustar00rootroot00000000000000ejml-0.28/main/all/src/org/ejml/All.java000066400000000000000000000015401256171534400177560ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; /** * A class which does nothing so that an All jar is created and gradle uploadArchive will not bitch * @author Peter Abeles */ public class All { } ejml-0.28/main/build.gradle000066400000000000000000000000471256171534400156060ustar00rootroot00000000000000subprojects { } //dependencies { //} ejml-0.28/main/core/000077500000000000000000000000001256171534400142565ustar00rootroot00000000000000ejml-0.28/main/core/build.gradle000066400000000000000000000003111256171534400165300ustar00rootroot00000000000000dependencies { testCompile project(':main:dense64') testCompile project(':main:denseC64') testCompile project(':main:experimental') } idea { module { name = "EJML Core" } }ejml-0.28/main/core/src/000077500000000000000000000000001256171534400150455ustar00rootroot00000000000000ejml-0.28/main/core/src/org/000077500000000000000000000000001256171534400156345ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/000077500000000000000000000000001256171534400165635ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/EjmlParameters.java000066400000000000000000000056331256171534400223500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; /** * This is a list of parameters that are used across the code. To tune performance * for a particular system change these values. * * @author Peter Abeles */ public class EjmlParameters { public static final float TOL32 = 1e-4f; public static final double TOL64 = 1e-8; /** * Used to adjust which algorithms are used. Often there is a trade off between memory usage * and speed. */ public static MemoryUsage MEMORY = MemoryUsage.FASTER; /** *

* In modern computers there are high speed memory caches. It is assumed that a square * block with this width can be contained entirely in one of those caches. Settings this * value too large can have a dramatic effect on performance in some situations. Setting * it too low results in a less dramatic performance hit. The optimal value is dependent * on the computer's memory architecture. *

*/ // See design notes public static int BLOCK_WIDTH = 60; public static int BLOCK_WIDTH_CHOL = 20; /** * Number of elements in a block. */ public static int BLOCK_SIZE = BLOCK_WIDTH*BLOCK_WIDTH; public static int TRANSPOSE_SWITCH = 375; /** * At what point does it switch from a small matrix multiply to the reorder version. */ public static int MULT_COLUMN_SWITCH = 15; public static int MULT_TRANAB_COLUMN_SWITCH = 40; public static int MULT_INNER_SWITCH = 100; public static int CMULT_COLUMN_SWITCH = 7; /** *

* At which point should it switch to the block cholesky algorithm. *

*

* In benchmarks the basic actually performed slightly better at 1000 * but in JVM 1.6 it some times get stuck in a mode where the basic version was very slow * in that case the block performed much better. *

*/ public static int SWITCH_BLOCK64_CHOLESKY = 1000; public static int SWITCH_BLOCK64_QR = 1500; public static enum MemoryUsage { /** * Use lower memory algorithm while not totally sacrificing speed. */ LOW_MEMORY, /** * Always favor faster algorithms even if they use more memory. */ FASTER } } ejml-0.28/main/core/src/org/ejml/UtilEjml.java000066400000000000000000000066211256171534400211600ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import org.ejml.data.DenseMatrix64F; import java.util.Arrays; import java.util.Comparator; /** * Various functions that are useful but don't have a clear location that they belong in. * * @author Peter Abeles */ public class UtilEjml { /** * Version string used to indicate which version of EJML is being used. */ public static String VERSION = "0.28"; /** * Default tolerance. */ public static double TOLERANCE = 1e-8; public static double EPS = Math.pow(2,-52); public static boolean isUncountable( double val ) { return Double.isNaN(val) || Double.isInfinite(val); } public static void memset( double[] data , double val ) { for( int i = 0; i < data.length; i++ ) { data[i] = val; } } public static void memset( double[] data , double val , int length ) { for( int i = 0; i < length; i++ ) { data[i] = val; } } public static void memset( int[] data , int val , int length ) { for( int i = 0; i < length; i++ ) { data[i] = val; } } public static void setnull( T[] array ) { for( int i = 0; i < array.length; i++ ) { array[i] = null; } } public static double max( double array[], int start , int length ) { double max = array[start]; final int end = start+length; for( int i = start+1; i < end; i++ ) { double v = array[i]; if( v > max ) { max = v; } } return max; } /** * Give a string of numbers it returns a DenseMatrix */ public static DenseMatrix64F parseMatrix( String s , int numColumns ) { String []vals = s.split("(\\s)+"); // there is the possibility the first element could be empty int start = vals[0].isEmpty() ? 1 : 0; // covert it from string to doubles int numRows = (vals.length-start) / numColumns; DenseMatrix64F ret = new DenseMatrix64F(numRows,numColumns); int index = start; for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numColumns; j++ ) { ret.set(i,j, Double.parseDouble(vals[ index++ ])); } } return ret; } public static Integer[] sortByIndex( final double []data , int size ) { Integer[] idx = new Integer[size]; for( int i = 0; i < size; i++ ) { idx[i] = i; } Arrays.sort(idx, new Comparator() { @Override public int compare(final Integer o1, final Integer o2) { return Double.compare(data[o1], data[o2]); } }); return idx; } } ejml-0.28/main/core/src/org/ejml/alg/000077500000000000000000000000001256171534400173265ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/alg/dense/000077500000000000000000000000001256171534400204245ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/alg/dense/linsol/000077500000000000000000000000001256171534400217245ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/alg/dense/linsol/LinearSolverSafe.java000066400000000000000000000054521256171534400260010ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.ReshapeMatrix; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.ejml.interfaces.linsol.LinearSolver; /** * Ensures that any linear solver it is wrapped around will never modify * the input matrices. * * @author Peter Abeles */ @SuppressWarnings({"unchecked"}) public class LinearSolverSafe implements LinearSolver { // the solver it is wrapped around private LinearSolver alg; // local copies of input matrices that can be modified. private T A; private T B; /** * * @param alg The solver it is wrapped around. */ public LinearSolverSafe(LinearSolver alg) { this.alg = alg; } @Override public boolean setA(T A) { if( alg.modifiesA() ) { if( this.A == null ) { this.A = (T)A.copy(); } else { if( this.A.getNumRows() != A.getNumRows() || this.A.getNumCols() != A.getNumCols() ) { this.A.reshape(A.getNumRows(),A.getNumCols()); } this.A.set(A); } return alg.setA(this.A); } return alg.setA(A); } @Override public double quality() { return alg.quality(); } @Override public void solve(T B, T X) { if( alg.modifiesB() ) { if( this.B == null ) { this.B = (T)B.copy(); } else { if( this.B.getNumRows() != B.getNumRows() || this.B.getNumCols() != B.getNumCols() ) { this.B.reshape(A.getNumRows(),B.getNumCols()); } this.B.set(B); } B = this.B; } alg.solve(B,X); } @Override public void invert(T A_inv) { alg.invert(A_inv); } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public D getDecomposition() { return alg.getDecomposition(); } } ejml-0.28/main/core/src/org/ejml/data/000077500000000000000000000000001256171534400174745ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/data/BlockMatrix64F.java000066400000000000000000000111071256171534400230360ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.EjmlParameters; import org.ejml.ops.MatrixIO; /** * A row-major block matrix declared on to one continuous array. * * @author Peter Abeles */ public class BlockMatrix64F extends D1Matrix64F { public int blockLength; public BlockMatrix64F( int numRows , int numCols , int blockLength) { this.data = new double[ numRows * numCols ]; this.blockLength = blockLength; this.numRows = numRows; this.numCols = numCols; } public BlockMatrix64F( int numRows , int numCols ) { this(numRows,numCols, EjmlParameters.BLOCK_WIDTH); } public BlockMatrix64F(){} public void set( BlockMatrix64F A ) { this.blockLength = A.blockLength; this.numRows = A.numRows; this.numCols = A.numCols; int N = numCols*numRows; if( data.length < N ) data = new double[ N ]; System.arraycopy(A.data,0,data,0,N); } public static BlockMatrix64F wrap( double data[] , int numRows , int numCols , int blockLength ) { BlockMatrix64F ret = new BlockMatrix64F(); ret.data = data; ret.numRows = numRows; ret.numCols = numCols; ret.blockLength = blockLength; return ret; } @Override public double[] getData() { return data; } @Override public void reshape(int numRows, int numCols, boolean saveValues) { if( numRows*numCols <= data.length ) { this.numRows = numRows; this.numCols = numCols; } else { double[] data = new double[ numRows*numCols ]; if( saveValues ) { System.arraycopy(this.data,0,data,0,getNumElements()); } this.numRows = numRows; this.numCols = numCols; this.data = data; } } public void reshape(int numRows, int numCols, int blockLength , boolean saveValues) { this.blockLength = blockLength; this.reshape(numRows,numCols,saveValues); } @Override public int getIndex( int row, int col ) { // find the block it is inside int blockRow = row / blockLength; int blockCol = col / blockLength; int localHeight = Math.min(numRows - blockRow*blockLength , blockLength); int index = blockRow*blockLength*numCols + blockCol* localHeight * blockLength; int localLength = Math.min(numCols - blockLength*blockCol , blockLength); row = row % blockLength; col = col % blockLength; return index + localLength * row + col; } @Override public double get( int row, int col) { return data[ getIndex(row,col)]; } @Override public double unsafe_get( int row, int col) { return data[ getIndex(row,col)]; } @Override public void set( int row, int col, double val) { data[ getIndex(row,col)] = val; } @Override public void unsafe_set( int row, int col, double val) { data[ getIndex(row,col)] = val; } @Override public int getNumRows() { return numRows; } @Override public int getNumCols() { return numCols; } @Override public void set(Matrix original) { if( original instanceof BlockMatrix64F ) { set((BlockMatrix64F)original); } else { RealMatrix64F m = (RealMatrix64F) original; for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { set(i, j, m.get(i, j)); } } } } @Override public int getNumElements() { return numRows*numCols; } @Override public void print() { MatrixIO.print(System.out,this); } public BlockMatrix64F copy() { BlockMatrix64F A = new BlockMatrix64F(numRows,numCols,blockLength); A.set(this); return A; } } ejml-0.28/main/core/src/org/ejml/data/CD1Matrix64F.java000066400000000000000000000061531256171534400223600ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixDimensionException; /** * A generic abstract class for matrices whose data is stored in a single 1D array of doubles. The * format of the elements in this array is not specified. For example row major, column major, * and block row major are all common formats. * * @author Peter Abeles */ public abstract class CD1Matrix64F implements ComplexMatrix64F, ReshapeMatrix{ /** * Where the raw data for the matrix is stored. The format is type dependent. */ public double[] data; /** * Number of rows in the matrix. */ public int numRows; /** * Number of columns in the matrix. */ public int numCols; /** * Used to get a reference to the internal data. * * @return Reference to the matrix's data. */ public double[] getData() { return data; } /** * Changes the internal array reference. */ public void setData( double[] data ) { this.data = data; } /** * Returns the internal array index for the specified row and column. * * @param row Row index. * @param col Column index. * @return Internal array index. */ public abstract int getIndex( int row, int col ); /** * Sets the value of this matrix to be the same as the value of the provided matrix. Both * matrices must have the same shape:
*
* aij = bij
*
* * @param b The matrix that this matrix is to be set equal to. */ public void set( CD1Matrix64F b ) { if( numRows != b.numRows || numCols != b.numCols ) { throw new MatrixDimensionException("The two matrices do not have compatible shapes."); } int dataLength = b.getDataLength(); System.arraycopy(b.data, 0, this.data, 0, dataLength); } /** * {@inheritDoc} */ @Override public int getNumRows() { return numRows; } /** * {@inheritDoc} */ @Override public int getNumCols() { return numCols; } /** * Sets the number of rows. * * @param numRows Number of rows */ public void setNumRows(int numRows) { this.numRows = numRows; } /** * Sets the number of columns. * * @param numCols Number of columns */ public void setNumCols(int numCols) { this.numCols = numCols; } }ejml-0.28/main/core/src/org/ejml/data/CDenseMatrix64F.java000066400000000000000000000142701256171534400231510ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Dense matrix for complex numbers. Internally it stores its data in a single row-major array with the real * and imaginary components interlaces, in that order. The total number of elements in the array will be * numRows*numColumns*2. * * @author Peter Abeles */ public class CDenseMatrix64F extends CD1Matrix64F { /** *

* Creates a matrix with the values and shape defined by the 2D array 'data'. * It is assumed that 'data' has a row-major formatting:
*
* data[ row ][ column ] *

* @param data 2D array representation of the matrix. Not modified. */ public CDenseMatrix64F( double data[][] ) { this.numRows = data.length; this.numCols = data[0].length/2; this.data = new double[ numRows * numCols * 2 ]; for (int i = 0; i < numRows; i++) { double[] row = data[i]; if( row.length != numCols*2 ) throw new IllegalArgumentException("Unexpected row size in input data at row "+i); System.arraycopy(row,0,this.data,i*numCols*2,row.length); } } public CDenseMatrix64F(int numRows, int numCols, boolean rowMajor, double... data) { if( data.length != numRows*numCols*2 ) throw new RuntimeException("Unexpected length for data"); this.data = new double[ numRows * numCols * 2 ]; this.numRows = numRows; this.numCols = numCols; set(numRows,numCols, rowMajor, data); } /** * Creates a new {@link org.ejml.data.CDenseMatrix64F} which is a copy of the passed in matrix. * @param original Matrix which is to be copied */ public CDenseMatrix64F(CDenseMatrix64F original) { this(original.numRows, original.numCols); set(original); } /** * Creates a new matrix with the specified number of rows and columns * * @param numRows number of rows * @param numCols number of columns */ public CDenseMatrix64F(int numRows, int numCols) { this.numRows = numRows; this.numCols = numCols; this.data = new double[numRows*numCols*2]; } @Override public int getIndex(int row, int col) { return row*numCols*2 + col*2; } @Override public void reshape( int numRows , int numCols ) { int newLength = numRows*numCols*2; if( newLength > data.length ) { data = new double[newLength]; } this.numRows = numRows; this.numCols = numCols; } @Override public void get(int row, int col, Complex64F output) { int index = row*numCols*2 + col*2; output.real = data[index]; output.imaginary = data[index+1]; } @Override public void set(int row, int col, double real, double imaginary) { int index = row*numCols*2 + col*2; data[index] = real; data[index+1] = imaginary; } @Override public double getReal(int row, int col) { return data[row*numCols*2 + col*2]; } @Override public void setReal(int row, int col, double val) { data[row*numCols*2 + col*2] = val; } @Override public double getImaginary(int row, int col) { return data[row*numCols*2 + col*2 + 1]; } @Override public void setImaginary(int row, int col, double val) { data[row*numCols*2 + col*2 + 1] = val; } @Override public int getDataLength() { return numRows*numCols*2; } public void set( CDenseMatrix64F original ) { reshape(original.numRows,original.numCols); int columnSize = numCols*2; for (int y = 0; y < numRows; y++) { int index = y*numCols*2; System.arraycopy(original.data,index,data,index,columnSize); } } @Override public CDenseMatrix64F copy() { return new CDenseMatrix64F(this); } @Override public void set(Matrix original) { reshape(original.getNumRows(),original.getNumCols()); ComplexMatrix64F n = (ComplexMatrix64F)original; Complex64F c = new Complex64F(); for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { n.get(i,j,c); set(i,j,c.real,c.imaginary); } } } @Override public void print() { MatrixIO.print(System.out, this); } /** * Number of array elements in the matrix's row. */ public int getRowStride() { return numCols*2; } /** * Sets this matrix equal to the matrix encoded in the array. * * @param numRows The number of rows. * @param numCols The number of columns. * @param rowMajor If the array is encoded in a row-major or a column-major format. * @param data The formatted 1D array. Not modified. */ public void set(int numRows, int numCols, boolean rowMajor, double ...data) { reshape(numRows,numCols); int length = numRows*numCols*2; if( length > data.length ) throw new RuntimeException("Passed in array not long enough"); if( rowMajor ) { System.arraycopy(data,0,this.data,0,length); } else { int index = 0; int stride = numRows*2; for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { this.data[index++] = data[j*stride+i*2]; this.data[index++] = data[j*stride+i*2+1]; } } } } } ejml-0.28/main/core/src/org/ejml/data/Complex64F.java000066400000000000000000000053471256171534400222370ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.ComplexMath64F; import java.io.Serializable; /** *

* Represents a complex number using 64bit floating point numbers. A complex number is composed of * a real and imaginary components. *

*/ public class Complex64F implements Serializable { public double real; public double imaginary; public Complex64F(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } public Complex64F() { } public double getReal() { return real; } public double getMagnitude() { return Math.sqrt(real*real + imaginary*imaginary); } public double getMagnitude2() { return real*real + imaginary*imaginary; } public void setReal(double real) { this.real = real; } public double getImaginary() { return imaginary; } public void setImaginary(double imaginary) { this.imaginary = imaginary; } public void set(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } public void set(Complex64F a) { this.real = a.real; this.imaginary = a.imaginary; } public boolean isReal() { return imaginary == 0.0; } public String toString() { if( imaginary == 0 ) { return ""+real; } else { return real+" "+imaginary+"i"; } } public Complex64F plus( Complex64F a ) { Complex64F ret = new Complex64F(); ComplexMath64F.plus(this,a,ret); return ret; } public Complex64F minus( Complex64F a ) { Complex64F ret = new Complex64F(); ComplexMath64F.minus(this, a, ret); return ret; } public Complex64F times( Complex64F a ) { Complex64F ret = new Complex64F(); ComplexMath64F.multiply(this,a,ret); return ret; } public Complex64F divide( Complex64F a ) { Complex64F ret = new Complex64F(); ComplexMath64F.divide(this,a,ret); return ret; } } ejml-0.28/main/core/src/org/ejml/data/ComplexMatrix64F.java000066400000000000000000000053401256171534400234150ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * Interface for all complex 64 bit floating point rectangular matrices. * * @author Peter Abeles */ public interface ComplexMatrix64F extends Matrix { /** * Returns the complex value of the matrix's element * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param output Storage for the complex number */ public void get( int row , int col , Complex64F output ); /** * Set's the complex value of the matrix's element * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param real The real component * @param imaginary The imaginary component */ public void set( int row , int col , double real , double imaginary ); /** * Returns the real component of the matrix's element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @return The specified element's value. */ public double getReal(int row, int col); /** * Sets the real component of the matrix's element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param val The element's new value. */ public void setReal(int row, int col, double val); /** * Returns the imaginary component of the matrix's element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @return The specified element's value. */ public double getImaginary(int row, int col); /** * Sets the imaginary component of the matrix's element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param val The element's new value. */ public void setImaginary(int row, int col, double val); /** * Returns the number of elements in the internal data array * * @return Number of elements in the data array. */ public int getDataLength(); } ejml-0.28/main/core/src/org/ejml/data/ComplexPolar64F.java000066400000000000000000000032241256171534400232250ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.ComplexMath64F; /** *

* {@link Complex64F} number in polar notation.
* z = r*(cos(θ) + i*sin(θ))
* where r and θ are polar coordinate parameters *

* @author Peter Abeles */ public class ComplexPolar64F { public double r; public double theta; public ComplexPolar64F(double r, double theta) { this.r = r; this.theta = theta; } public ComplexPolar64F( Complex64F n ) { ComplexMath64F.convert(n, this); } public ComplexPolar64F() { } public Complex64F toStandard() { Complex64F ret = new Complex64F(); ComplexMath64F.convert(this, ret); return ret; } public double getR() { return r; } public void setR(double r) { this.r = r; } public double getTheta() { return theta; } public void setTheta(double theta) { this.theta = theta; } public String toString() { return "( r = "+r+" theta = "+theta+" )"; } } ejml-0.28/main/core/src/org/ejml/data/D1Matrix32F.java000066400000000000000000000216621256171534400222520ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * A generic abstract class for matrices whose data is stored in a single 1D array of floats. The * format of the elements in this array is not specified. For example row major, column major, * and block row major are all common formats. * * @author Peter Abeles */ public abstract class D1Matrix32F implements ReshapeMatrix, RealMatrix32F { /** * Where the raw data for the matrix is stored. The format is type dependent. */ public float[] data; /** * Number of rows in the matrix. */ public int numRows; /** * Number of columns in the matrix. */ public int numCols; /** * Used to get a reference to the internal data. * * @return Reference to the matrix's data. */ public float[] getData() { return data; } /** * Changes the internal array reference. */ public void setData( float[] data ) { this.data = data; } /** * Returns the internal array index for the specified row and column. * * @param row Row index. * @param col Column index. * @return Internal array index. */ public abstract int getIndex( int row, int col ); /** * Sets the value of this matrix to be the same as the value of the provided matrix. Both * matrices must have the same shape:
*
* aij = bij
*
* * @param b The matrix that this matrix is to be set equal to. */ public void set( D1Matrix32F b ) { this.reshape(b.numRows,b.numCols); int dataLength = b.getNumElements(); System.arraycopy(b.data, 0, this.data, 0, dataLength); } /** * Returns the value of the matrix at the specified internal array index. The element at which row and column * returned by this function depends upon the matrix's internal structure, e.g. row-major, column-major, or block. * * @param index Internal array index. * @return Value at the specified index. */ public float get( int index ) { return data[index]; } /** * Sets the element's value at the specified index. The element at which row and column * modified by this function depends upon the matrix's internal structure, e.g. row-major, column-major, or block. * * @param index Index of element that is to be set. * @param val The new value of the index. */ public float set( int index , float val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] = val; } /** *

* Adds the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] += val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being added. */ public float plus( int index , float val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] += val; } /** *

* Subtracts the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] -= val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being subtracted. */ public float minus( int index , float val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] -= val; } /** *

* Multiplies the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] *= val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being multiplied. */ public float times( int index , float val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] *= val; } /** *

* Divides the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] /= val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being divided. */ public float div( int index , float val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] /= val; } /** *

* Changes the number of rows and columns in the matrix, allowing its size to grow or shrink. * If the saveValues flag is set to true, then the previous values will be maintained, but * reassigned to new elements in a row-major ordering. If saveValues is false values will only * be maintained when the requested size is less than or equal to the internal array size. * The primary use for this function is to encourage data reuse and avoid unnecessarily declaring * and initialization of new memory. *

* *

* Examples:
* [ 1 2 ; 3 4 ] -> reshape( 2 , 3 , true ) = [ 1 2 3 ; 4 0 0 ]
* [ 1 2 ; 3 4 ] -> reshape( 1 , 2 , true ) = [ 1 2 ]
* [ 1 2 ; 3 4 ] -> reshape( 1 , 2 , false ) = [ 1 2 ]
* [ 1 2 ; 3 4 ] -> reshape( 2 , 3 , false ) = [ 0 0 0 ; 0 0 0 ] *

* * @param numRows The new number of rows in the matrix. * @param numCols The new number of columns in the matrix. * @param saveValues If true then the value of each element will be save using a row-major reordering. Typically this should be false. */ public abstract void reshape(int numRows, int numCols, boolean saveValues); /** * Equivalent to invoking reshape(numRows,numCols,false); * * @param numRows The new number of rows in the matrix. * @param numCols The new number of columns in the matrix. */ @Override public void reshape( int numRows , int numCols ) { reshape(numRows,numCols,false); } /** * Creates a new iterator for traversing through a submatrix inside this matrix. It can be traversed * by row or by column. Range of elements is inclusive, e.g. minRow = 0 and maxRow = 1 will include rows * 0 and 1. The iteration starts at (minRow,minCol) and ends at (maxRow,maxCol) * * @param rowMajor true means it will traverse through the submatrix by row first, false by columns. * @param minRow first row it will start at. * @param minCol first column it will start at. * @param maxRow last row it will stop at. * @param maxCol last column it will stop at. * @return A new MatrixIterator */ public MatrixIterator32F iterator(boolean rowMajor, int minRow, int minCol, int maxRow, int maxCol) { return new MatrixIterator32F(this,rowMajor, minRow, minCol, maxRow, maxCol); } /** * {@inheritDoc} */ @Override public int getNumRows() { return numRows; } /** * {@inheritDoc} */ @Override public int getNumCols() { return numCols; } /** * Sets the number of rows. * * @param numRows Number of rows */ public void setNumRows(int numRows) { this.numRows = numRows; } /** * Sets the number of columns. * * @param numCols Number of columns */ public void setNumCols(int numCols) { this.numCols = numCols; } }ejml-0.28/main/core/src/org/ejml/data/D1Matrix64F.java000066400000000000000000000217011256171534400222510ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * A generic abstract class for matrices whose data is stored in a single 1D array of doubles. The * format of the elements in this array is not specified. For example row major, column major, * and block row major are all common formats. * * @author Peter Abeles */ public abstract class D1Matrix64F implements ReshapeMatrix, RealMatrix64F { /** * Where the raw data for the matrix is stored. The format is type dependent. */ public double[] data; /** * Number of rows in the matrix. */ public int numRows; /** * Number of columns in the matrix. */ public int numCols; /** * Used to get a reference to the internal data. * * @return Reference to the matrix's data. */ public double[] getData() { return data; } /** * Changes the internal array reference. */ public void setData( double[] data ) { this.data = data; } /** * Returns the internal array index for the specified row and column. * * @param row Row index. * @param col Column index. * @return Internal array index. */ public abstract int getIndex( int row, int col ); /** * Sets the value of this matrix to be the same as the value of the provided matrix. Both * matrices must have the same shape:
*
* aij = bij
*
* * @param b The matrix that this matrix is to be set equal to. */ public void set( D1Matrix64F b ) { this.reshape(b.numRows,b.numCols); int dataLength = b.getNumElements(); System.arraycopy(b.data, 0, this.data, 0, dataLength); } /** * Returns the value of the matrix at the specified internal array index. The element at which row and column * returned by this function depends upon the matrix's internal structure, e.g. row-major, column-major, or block. * * @param index Internal array index. * @return Value at the specified index. */ public double get( int index ) { return data[index]; } /** * Sets the element's value at the specified index. The element at which row and column * modified by this function depends upon the matrix's internal structure, e.g. row-major, column-major, or block. * * @param index Index of element that is to be set. * @param val The new value of the index. */ public double set( int index , double val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] = val; } /** *

* Adds the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] += val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being added. */ public double plus( int index , double val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] += val; } /** *

* Subtracts the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] -= val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being subtracted. */ public double minus( int index , double val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] -= val; } /** *

* Multiplies the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] *= val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being multiplied. */ public double times( int index , double val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] *= val; } /** *

* Divides the specified value to the internal data array at the specified index.
*
* Equivalent to: this.data[index] /= val; *

* *

* Intended for use in highly optimized code. The row/column coordinate of the modified element is * dependent upon the matrix's internal structure. *

* * @param index The index which is being modified. * @param val The value that is being divided. */ public double div( int index , double val ) { // See benchmarkFunctionReturn. Pointless return does not degrade performance. Tested on JDK 1.6.0_21 return data[index] /= val; } /** *

* Changes the number of rows and columns in the matrix, allowing its size to grow or shrink. * If the saveValues flag is set to true, then the previous values will be maintained, but * reassigned to new elements in a row-major ordering. If saveValues is false values will only * be maintained when the requested size is less than or equal to the internal array size. * The primary use for this function is to encourage data reuse and avoid unnecessarily declaring * and initialization of new memory. *

* *

* Examples:
* [ 1 2 ; 3 4 ] -> reshape( 2 , 3 , true ) = [ 1 2 3 ; 4 0 0 ]
* [ 1 2 ; 3 4 ] -> reshape( 1 , 2 , true ) = [ 1 2 ]
* [ 1 2 ; 3 4 ] -> reshape( 1 , 2 , false ) = [ 1 2 ]
* [ 1 2 ; 3 4 ] -> reshape( 2 , 3 , false ) = [ 0 0 0 ; 0 0 0 ] *

* * @param numRows The new number of rows in the matrix. * @param numCols The new number of columns in the matrix. * @param saveValues If true then the value of each element will be save using a row-major reordering. Typically this should be false. */ public abstract void reshape(int numRows, int numCols, boolean saveValues); /** * Equivalent to invoking reshape(numRows,numCols,false); * * @param numRows The new number of rows in the matrix. * @param numCols The new number of columns in the matrix. */ @Override public void reshape( int numRows , int numCols ) { reshape(numRows,numCols,false); } /** * Creates a new iterator for traversing through a submatrix inside this matrix. It can be traversed * by row or by column. Range of elements is inclusive, e.g. minRow = 0 and maxRow = 1 will include rows * 0 and 1. The iteration starts at (minRow,minCol) and ends at (maxRow,maxCol) * * @param rowMajor true means it will traverse through the submatrix by row first, false by columns. * @param minRow first row it will start at. * @param minCol first column it will start at. * @param maxRow last row it will stop at. * @param maxCol last column it will stop at. * @return A new MatrixIterator */ public MatrixIterator64F iterator(boolean rowMajor, int minRow, int minCol, int maxRow, int maxCol) { return new MatrixIterator64F(this,rowMajor, minRow, minCol, maxRow, maxCol); } /** * {@inheritDoc} */ @Override public int getNumRows() { return numRows; } /** * {@inheritDoc} */ @Override public int getNumCols() { return numCols; } /** * Sets the number of rows. * * @param numRows Number of rows */ public void setNumRows(int numRows) { this.numRows = numRows; } /** * Sets the number of columns. * * @param numCols Number of columns */ public void setNumCols(int numCols) { this.numCols = numCols; } }ejml-0.28/main/core/src/org/ejml/data/D1Submatrix64F.java000066400000000000000000000047301256171534400227660ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** *

* Describes a rectangular submatrix inside of a {@link D1Matrix64F}. *

* *

* Rows are row0 <= i < row1 and Columns are col0 <= j < col1 *

* * @author Peter Abeles */ public class D1Submatrix64F { public D1Matrix64F original; // bounding rows and columns public int row0,col0; public int row1,col1; public D1Submatrix64F() { } public D1Submatrix64F(D1Matrix64F original) { set(original); } public D1Submatrix64F(D1Matrix64F original, int row0, int row1, int col0, int col1) { set(original,row0,row1,col0,col1); } public void set(D1Matrix64F original, int row0, int row1, int col0, int col1) { this.original = original; this.row0 = row0; this.col0 = col0; this.row1 = row1; this.col1 = col1; } public void set(D1Matrix64F original) { this.original = original; row1 = original.numRows; col1 = original.numCols; } public int getRows() { return row1 - row0; } public int getCols() { return col1 - col0; } public double get(int row, int col ) { return original.get(row+row0,col+col0); } public void set(int row, int col, double value) { original.set(row+row0,col+col0,value); } public DenseMatrix64F extract() { DenseMatrix64F ret = new DenseMatrix64F(row1-row0,col1-col0); for( int i = 0; i < ret.numRows; i++ ) { for( int j = 0; j < ret.numCols; j++ ) { ret.set(i,j,get(i,j)); } } return ret; } public void print() { MatrixIO.print(System.out,original,"%6.3f",row0,row1,col0,col1); } } ejml-0.28/main/core/src/org/ejml/data/DenseMatrix32F.java000066400000000000000000000302441256171534400230400ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Arrays; /** *

* DenseMatrix64F is a dense matrix with elements that are 32-bit floats. A matrix * is the fundamental data structure in linear algebra. Unlike a sparse matrix, there is no * compression in a dense matrix and every element is stored in memory. This allows for fast * reads and writes to the matrix. *

* *

* The matrix is stored internally in a row-major 1D array format:
*
* data[ y*numCols + x ] = data[y][x]
*
* For example:
* data = *

*
 * a[0]  a[1]   a[2]   a[3]
 * a[4]  a[5]   a[6]   a[7]
 * a[8]  a[9]   a[10]  a[11]
 * a[12] a[13]  a[14]  a[15]
 * 
* * @author Peter Abeles */ public class DenseMatrix32F extends D1Matrix32F { /** *

* Creates a new matrix which has the same value as the matrix encoded in the * provided array. The input matrix's format can either be row-major or * column-major. *

* *

* Note that 'data' is a variable argument type, so either 1D arrays or a set of numbers can be * passed in:
* DenseMatrix a = new DenseMatrix(2,2,true,new float[]{1,2,3,4});
* DenseMatrix b = new DenseMatrix(2,2,true,1,2,3,4);
*
* Both are equivalent. *

* * @param numRows The number of rows. * @param numCols The number of columns. * @param rowMajor If the array is encoded in a row-major or a column-major format. * @param data The formatted 1D array. Not modified. */ public DenseMatrix32F(int numRows, int numCols, boolean rowMajor, float... data) { final int length = numRows * numCols; this.data = new float[ length ]; this.numRows = numRows; this.numCols = numCols; set(numRows,numCols, rowMajor, data); } /** *

* Creates a matrix with the values and shape defined by the 2D array 'data'. * It is assumed that 'data' has a row-major formatting:
*
* data[ row ][ column ] *

* @param data 2D array representation of the matrix. Not modified. */ public DenseMatrix32F(float data[][]) { this.numRows = data.length; this.numCols = data[0].length; this.data = new float[ numRows*numCols ]; int pos = 0; for( int i = 0; i < numRows; i++ ) { float []row = data[i]; if( row.length != numCols ) { throw new IllegalArgumentException("All rows must have the same length"); } System.arraycopy(row,0,this.data,pos,numCols); pos += numCols; } } /** * Creates a new Matrix with the specified shape whose elements initially * have the value of zero. * * @param numRows The number of rows in the matrix. * @param numCols The number of columns in the matrix. */ public DenseMatrix32F(int numRows, int numCols) { data = new float[ numRows * numCols ]; this.numRows = numRows; this.numCols = numCols; } /** * Creates a new matrix which is equivalent to the provided matrix. Note that * the length of the data will be determined by the shape of the matrix. * * @param orig The matrix which is to be copied. This is not modified or saved. */ public DenseMatrix32F(DenseMatrix32F orig) { this(orig.numRows,orig.numCols); System.arraycopy(orig.data, 0, this.data, 0, orig.getNumElements()); } /** * This declares an array that can store a matrix up to the specified length. This is use full * when a matrix's size will be growing and it is desirable to avoid reallocating memory. * * @param length The size of the matrice's data array. */ public DenseMatrix32F(int length) { data = new float[ length ]; } /** * Default constructor in which nothing is configured. THIS IS ONLY PUBLICLY ACCESSIBLE SO THAT THIS * CLASS CAN BE A JAVA BEAN. DON'T USE IT UNLESS YOU REALLY KNOW WHAT YOU'RE DOING! */ public DenseMatrix32F(){} /** * Creates a new DenseMatrix64F which contains the same information as the provided Matrix64F. * * @param mat Matrix whose values will be copied. Not modified. */ public DenseMatrix32F(RealMatrix32F mat) { this(mat.getNumRows(),mat.getNumCols()); for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { set(i,j, mat.get(i,j)); } } } /** * Creates a new DenseMatrix64F around the provided data. The data must encode * a row-major matrix. Any modification to the returned matrix will modify the * provided data. * * @param numRows Number of rows in the matrix. * @param numCols Number of columns in the matrix. * @param data Data that is being wrapped. Referenced Saved. * @return A matrix which references the provided data internally. */ public static DenseMatrix32F wrap( int numRows , int numCols , float []data ) { DenseMatrix32F s = new DenseMatrix32F(); s.data = data; s.numRows = numRows; s.numCols = numCols; return s; } /** * @inheritDoc */ @Override public void reshape(int numRows, int numCols, boolean saveValues) { if( data.length < numRows * numCols ) { float []d = new float[ numRows*numCols ]; if( saveValues ) { System.arraycopy(data,0,d,0,getNumElements()); } this.data = d; } this.numRows = numRows; this.numCols = numCols; } /** *

* Assigns the element in the Matrix to the specified value. Performs a bounds check to make sure * the requested element is part of the matrix.
*
* aij = value
*

* * @param row The row of the element. * @param col The column of the element. * @param value The element's new value. */ @Override public void set( int row , int col , float value ) { if( col < 0 || col >= numCols || row < 0 || row >= numRows ) { throw new IllegalArgumentException("Specified element is out of bounds: ("+row+" , "+col+")"); } data[ row * numCols + col ] = value; } @Override public void unsafe_set( int row , int col , float value ) { data[ row * numCols + col ] = value; } /** *

* Adds 'value' to the specified element in the matrix.
*
* aij = aij + value
*

* * @param row The row of the element. * @param col The column of the element. * @param value The value that is added to the element */ // todo move to commonops public void add( int row , int col , float value ) { if( col < 0 || col >= numCols || row < 0 || row >= numRows ) { throw new IllegalArgumentException("Specified element is out of bounds"); } data[ row * numCols + col ] += value; } /** * Returns the value of the specified matrix element. Performs a bounds check to make sure * the requested element is part of the matrix. * * @param row The row of the element. * @param col The column of the element. * @return The value of the element. */ @Override public float get( int row , int col ) { if( col < 0 || col >= numCols || row < 0 || row >= numRows ) { throw new IllegalArgumentException("Specified element is out of bounds: "+row+" "+col); } return data[ row * numCols + col ]; } @Override public float unsafe_get( int row , int col ) { return data[ row * numCols + col ]; } @Override public int getIndex( int row , int col ) { return row * numCols + col; } /** * Determins if the specified element is inside the bounds of the Matrix. * * @param row The element's row. * @param col The elements' column. * @return True if it is inside the matrices bound, false otherwise. */ public boolean isInBounds( int row , int col ) { return( col >= 0 && col < numCols && row >= 0 && row < numRows ); } /** * Returns the number of elements in this matrix, which is equal to * the number of rows times the number of columns. * * @return The number of elements in the matrix. */ @Override public int getNumElements() { return numRows*numCols; } /** * Sets this matrix equal to the matrix encoded in the array. * * @param numRows The number of rows. * @param numCols The number of columns. * @param rowMajor If the array is encoded in a row-major or a column-major format. * @param data The formatted 1D array. Not modified. */ public void set(int numRows, int numCols, boolean rowMajor, float ...data) { reshape(numRows,numCols); int length = numRows*numCols; if( length > this.data.length ) throw new IllegalArgumentException("The length of this matrix's data array is too small."); if( rowMajor ) { System.arraycopy(data,0,this.data,0,length); } else { int index = 0; for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { this.data[index++] = data[j*numRows+i]; } } } } /** * Sets all elements equal to zero. */ public void zero() { Arrays.fill(data, 0, getNumElements(), 0.0f); } /** * Creates and returns a matrix which is idential to this one. * * @return A new identical matrix. */ @SuppressWarnings({"unchecked"}) public DenseMatrix32F copy() { return new DenseMatrix32F(this); } @Override public void set(Matrix original) { RealMatrix32F m = (RealMatrix32F)original; reshape(original.getNumRows(),original.getNumCols()); if( original instanceof DenseMatrix32F) { // do a faster copy if its of type DenseMatrix64F System.arraycopy(((DenseMatrix32F)m).data,0,data,0,numRows*numCols); } else { int index = 0; for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { data[index++] = m.get(i, j); } } } } /** * Prints the value of this matrix to the screen. For more options see * {@link org.ejml.UtilEjml} * */ @Override public void print() { MatrixIO.print(System.out,this); } /** *

* Prints the value of this matrix to the screen using the same format as {@link java.io.PrintStream#printf). *

* * @param format The format which each element is printed uses. */ public void print( String format ) { MatrixIO.print(System.out,this,format); } /** *

* Converts the array into a string format for display purposes. * The conversion is done using {@link org.ejml.ops.MatrixIO#print(java.io.PrintStream, org.ejml.data.RealMatrix64F)}. *

* * @return String representation of the matrix. */ @Override public String toString() { ByteArrayOutputStream stream = new ByteArrayOutputStream(); MatrixIO.print(new PrintStream(stream),this); return stream.toString(); } } ejml-0.28/main/core/src/org/ejml/data/DenseMatrix64F.java000066400000000000000000000302721256171534400230460ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.UtilEjml; import org.ejml.ops.MatrixIO; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Arrays; /** *

* DenseMatrix64F is a dense matrix with real elements that are 64-bit floats. A matrix * is the fundamental data structure in linear algebra. Unlike a sparse matrix, there is no * compression in a dense matrix and every element is stored in memory. This allows for fast * reads and writes to the matrix. *

* *

* The matrix is stored internally in a row-major 1D array format:
*
* data[ y*numCols + x ] = data[y][x]
*
* For example:
* data = *

*
 * a[0]  a[1]   a[2]   a[3]
 * a[4]  a[5]   a[6]   a[7]
 * a[8]  a[9]   a[10]  a[11]
 * a[12] a[13]  a[14]  a[15]
 * 
* @author Peter Abeles */ public class DenseMatrix64F extends RowD1Matrix64F { /** *

* Creates a new matrix which has the same value as the matrix encoded in the * provided array. The input matrix's format can either be row-major or * column-major. *

* *

* Note that 'data' is a variable argument type, so either 1D arrays or a set of numbers can be * passed in:
* DenseMatrix a = new DenseMatrix(2,2,true,new double[]{1,2,3,4});
* DenseMatrix b = new DenseMatrix(2,2,true,1,2,3,4);
*
* Both are equivalent. *

* * @param numRows The number of rows. * @param numCols The number of columns. * @param rowMajor If the array is encoded in a row-major or a column-major format. * @param data The formatted 1D array. Not modified. */ public DenseMatrix64F(int numRows, int numCols, boolean rowMajor, double... data) { final int length = numRows * numCols; this.data = new double[ length ]; this.numRows = numRows; this.numCols = numCols; set(numRows,numCols, rowMajor, data); } /** *

* Creates a matrix with the values and shape defined by the 2D array 'data'. * It is assumed that 'data' has a row-major formatting:
*
* data[ row ][ column ] *

* @param data 2D array representation of the matrix. Not modified. */ public DenseMatrix64F( double data[][] ) { this.numRows = data.length; this.numCols = data[0].length; this.data = new double[ numRows*numCols ]; int pos = 0; for( int i = 0; i < numRows; i++ ) { double []row = data[i]; if( row.length != numCols ) { throw new IllegalArgumentException("All rows must have the same length"); } System.arraycopy(row,0,this.data,pos,numCols); pos += numCols; } } /** * Creates a new Matrix with the specified shape whose elements initially * have the value of zero. * * @param numRows The number of rows in the matrix. * @param numCols The number of columns in the matrix. */ public DenseMatrix64F( int numRows , int numCols ) { data = new double[ numRows * numCols ]; this.numRows = numRows; this.numCols = numCols; } /** * Creates a new matrix which is equivalent to the provided matrix. Note that * the length of the data will be determined by the shape of the matrix. * * @param orig The matrix which is to be copied. This is not modified or saved. */ public DenseMatrix64F( DenseMatrix64F orig ) { this(orig.numRows,orig.numCols); System.arraycopy(orig.data, 0, this.data, 0, orig.getNumElements()); } /** * This declares an array that can store a matrix up to the specified length. This is use full * when a matrix's size will be growing and it is desirable to avoid reallocating memory. * * @param length The size of the matrice's data array. */ public DenseMatrix64F( int length ) { data = new double[ length ]; } /** * Default constructor in which nothing is configured. THIS IS ONLY PUBLICLY ACCESSIBLE SO THAT THIS * CLASS CAN BE A JAVA BEAN. DON'T USE IT UNLESS YOU REALLY KNOW WHAT YOU'RE DOING! */ public DenseMatrix64F(){} /** * Creates a new DenseMatrix64F which contains the same information as the provided Matrix64F. * * @param mat Matrix whose values will be copied. Not modified. */ public DenseMatrix64F(RealMatrix64F mat) { this(mat.getNumRows(),mat.getNumCols()); for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { set(i,j, mat.get(i,j)); } } } /** * Creates a new DenseMatrix64F around the provided data. The data must encode * a row-major matrix. Any modification to the returned matrix will modify the * provided data. * * @param numRows Number of rows in the matrix. * @param numCols Number of columns in the matrix. * @param data Data that is being wrapped. Referenced Saved. * @return A matrix which references the provided data internally. */ public static DenseMatrix64F wrap( int numRows , int numCols , double []data ) { DenseMatrix64F s = new DenseMatrix64F(); s.data = data; s.numRows = numRows; s.numCols = numCols; return s; } /** * @inheritDoc */ @Override public void reshape(int numRows, int numCols, boolean saveValues) { if( data.length < numRows * numCols ) { double []d = new double[ numRows*numCols ]; if( saveValues ) { System.arraycopy(data,0,d,0,getNumElements()); } this.data = d; } this.numRows = numRows; this.numCols = numCols; } /** *

* Assigns the element in the Matrix to the specified value. Performs a bounds check to make sure * the requested element is part of the matrix.
*
* aij = value
*

* * @param row The row of the element. * @param col The column of the element. * @param value The element's new value. */ @Override public void set( int row , int col , double value ) { if( col < 0 || col >= numCols || row < 0 || row >= numRows ) { throw new IllegalArgumentException("Specified element is out of bounds: ("+row+" , "+col+")"); } data[ row * numCols + col ] = value; } @Override public void unsafe_set( int row , int col , double value ) { data[ row * numCols + col ] = value; } /** *

* Adds 'value' to the specified element in the matrix.
*
* aij = aij + value
*

* * @param row The row of the element. * @param col The column of the element. * @param value The value that is added to the element */ // todo move to commonops public void add( int row , int col , double value ) { if( col < 0 || col >= numCols || row < 0 || row >= numRows ) { throw new IllegalArgumentException("Specified element is out of bounds"); } data[ row * numCols + col ] += value; } /** * Returns the value of the specified matrix element. Performs a bounds check to make sure * the requested element is part of the matrix. * * @param row The row of the element. * @param col The column of the element. * @return The value of the element. */ @Override public double get( int row , int col ) { if( col < 0 || col >= numCols || row < 0 || row >= numRows ) { throw new IllegalArgumentException("Specified element is out of bounds: "+row+" "+col); } return data[ row * numCols + col ]; } @Override public double unsafe_get( int row , int col ) { return data[ row * numCols + col ]; } @Override public int getIndex( int row , int col ) { return row * numCols + col; } /** * Determins if the specified element is inside the bounds of the Matrix. * * @param row The element's row. * @param col The elements' column. * @return True if it is inside the matrices bound, false otherwise. */ public boolean isInBounds( int row , int col ) { return( col >= 0 && col < numCols && row >= 0 && row < numRows ); } /** * Returns the number of elements in this matrix, which is equal to * the number of rows times the number of columns. * * @return The number of elements in the matrix. */ @Override public int getNumElements() { return numRows*numCols; } /** * Sets this matrix equal to the matrix encoded in the array. * * @param numRows The number of rows. * @param numCols The number of columns. * @param rowMajor If the array is encoded in a row-major or a column-major format. * @param data The formatted 1D array. Not modified. */ public void set(int numRows, int numCols, boolean rowMajor, double ...data) { reshape(numRows,numCols); int length = numRows*numCols; if( length > this.data.length ) throw new IllegalArgumentException("The length of this matrix's data array is too small."); if( rowMajor ) { System.arraycopy(data,0,this.data,0,length); } else { int index = 0; for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { this.data[index++] = data[j*numRows+i]; } } } } /** * Sets all elements equal to zero. */ public void zero() { Arrays.fill(data, 0, getNumElements(), 0.0); } /** * Creates and returns a matrix which is idential to this one. * * @return A new identical matrix. */ @SuppressWarnings({"unchecked"}) public DenseMatrix64F copy() { return new DenseMatrix64F(this); } @Override public void set(Matrix original) { RealMatrix64F m = (RealMatrix64F)original; reshape(original.getNumRows(),original.getNumCols()); if( original instanceof DenseMatrix64F ) { // do a faster copy if its of type DenseMatrix64F System.arraycopy(((DenseMatrix64F)m).data,0,data,0,numRows*numCols); } else { int index = 0; for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { data[index++] = m.get(i, j); } } } } /** * Prints the value of this matrix to the screen. For more options see * {@link UtilEjml} * */ @Override public void print() { MatrixIO.print(System.out,this); } /** *

* Prints the value of this matrix to the screen using the same format as {@link java.io.PrintStream#printf). *

* * @param format The format which each element is printed uses. */ public void print( String format ) { MatrixIO.print(System.out,this,format); } /** *

* Converts the array into a string format for display purposes. * The conversion is done using {@link MatrixIO#print(java.io.PrintStream, RealMatrix64F)}. *

* * @return String representation of the matrix. */ @Override public String toString() { ByteArrayOutputStream stream = new ByteArrayOutputStream(); MatrixIO.print(new PrintStream(stream),this); return stream.toString(); } } ejml-0.28/main/core/src/org/ejml/data/Eigenpair64F.java000066400000000000000000000021541256171534400225240ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * An eigenpair is a set composed of an eigenvalue and an eigenvector. In this library since only real * matrices are supported, all eigenpairs are real valued. * * @author Peter Abeles */ public class Eigenpair64F { public double value; public DenseMatrix64F vector; public Eigenpair64F(double value, DenseMatrix64F vector) { this.value = value; this.vector = vector; } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix2_64F.java000066400000000000000000000061311256171534400232650ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized vector with 2 elements. Can represent a 2 x 1 or 1 x 2 matrix, context dependent. * * @author Peter Abeles */ public class FixedMatrix2_64F implements FixedMatrix64F { public double a1,a2; public FixedMatrix2_64F() { } public FixedMatrix2_64F(double a1,double a2) { this.a1 = a1; this.a2 = a2; } public FixedMatrix2_64F(FixedMatrix2_64F o) { this.a1 = o.a1; this.a2 = o.a2; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { return a1; } else if( w == 1 ) { return a2; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { a1 = val; } else if( w == 1 ) { a2 = val; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(Matrix original) { RealMatrix64F m = (RealMatrix64F)original; if( m.getNumCols() == 1 && m.getNumRows() == 2 ) { a1 = m.get(0,0); a2 = m.get(1,0); } else if( m.getNumRows() == 1 && m.getNumCols() == 2 ){ a1 = m.get(0,0); a2 = m.get(0,1); } else { throw new IllegalArgumentException("Incompatible shape"); } } @Override public int getNumRows() { return 2; } @Override public int getNumCols() { return 1; } @Override public int getNumElements() { return 2; } @Override public T copy() { return (T)new FixedMatrix2_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix2x2_64F.java000066400000000000000000000066731256171534400235520ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized 2 by FixedMatrix2x2_64F matrix. The matrix is stored as class variables for very fast read/write. aXY is the * value of row = X and column = Y. * * @author Peter Abeles */ public class FixedMatrix2x2_64F implements FixedMatrix64F { public double a11,a12; public double a21,a22; public FixedMatrix2x2_64F() { } public FixedMatrix2x2_64F( double a11,double a12, double a21,double a22) { this.a11 = a11; this.a12 = a12; this.a21 = a21; this.a22 = a22; } public FixedMatrix2x2_64F( FixedMatrix2x2_64F o ) { this.a11 = o.a11; this.a12 = o.a12; this.a21 = o.a21; this.a22 = o.a22; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row == 0 ) { if( col == 0 ) { return a11; } else if( col == 1 ) { return a12; } } else if( row == 1 ) { if( col == 0 ) { return a21; } else if( col == 1 ) { return a22; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row == 0 ) { if( col == 0 ) { a11 = val; return; } else if( col == 1 ) { a12 = val; return; } } else if( row == 1 ) { if( col == 0 ) { a21 = val; return; } else if( col == 1 ) { a22 = val; return; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(Matrix original) { if( original.getNumCols() != 2 || original.getNumRows() != 2 ) throw new IllegalArgumentException("Rows and/or columns do not match"); RealMatrix64F m = (RealMatrix64F)original; a11 = m.get(0,0); a12 = m.get(0,1); a21 = m.get(1,0); a22 = m.get(1,1); } @Override public int getNumRows() { return 2; } @Override public int getNumCols() { return 2; } @Override public int getNumElements() { return 4; } @Override public T copy() { return (T)new FixedMatrix2x2_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix3_64F.java000066400000000000000000000064671256171534400233020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized vector with 3 elements. Can represent a 3 x 1 or 1 x 3 matrix, context dependent. * * @author Peter Abeles */ public class FixedMatrix3_64F implements FixedMatrix64F { public double a1,a2,a3; public FixedMatrix3_64F() { } public FixedMatrix3_64F(double a1,double a2,double a3) { this.a1 = a1; this.a2 = a2; this.a3 = a3; } public FixedMatrix3_64F(FixedMatrix3_64F o) { this.a1 = o.a1; this.a2 = o.a2; this.a3 = o.a3; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { return a1; } else if( w == 1 ) { return a2; } else if( w == 2 ) { return a3; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { a1 = val; } else if( w == 1 ) { a2 = val; } else if( w == 2 ) { a3 = val; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(Matrix original) { RealMatrix64F m = (RealMatrix64F)original; if( m.getNumCols() == 1 && m.getNumRows() == 3 ) { a1 = m.get(0,0); a2 = m.get(1,0); a3 = m.get(2,0); } else if( m.getNumRows() == 1 && m.getNumCols() == 3 ){ a1 = m.get(0,0); a2 = m.get(0,1); a3 = m.get(0,2); } else { throw new IllegalArgumentException("Incompatible shape"); } } @Override public int getNumRows() { return 3; } @Override public int getNumCols() { return 1; } @Override public int getNumElements() { return 3; } @Override public T copy() { return (T)new FixedMatrix3_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix3x3_64F.java000066400000000000000000000112451256171534400235430ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized 3 by FixedMatrix3x3_64F matrix. The matrix is stored as class variables for very fast read/write. aXY is the * value of row = X and column = Y. * * @author Peter Abeles */ public class FixedMatrix3x3_64F implements FixedMatrix64F { public double a11,a12,a13; public double a21,a22,a23; public double a31,a32,a33; public FixedMatrix3x3_64F() { } public FixedMatrix3x3_64F( double a11,double a12,double a13, double a21,double a22,double a23, double a31,double a32,double a33) { this.a11 = a11; this.a12 = a12; this.a13 = a13; this.a21 = a21; this.a22 = a22; this.a23 = a23; this.a31 = a31; this.a32 = a32; this.a33 = a33; } public FixedMatrix3x3_64F( FixedMatrix3x3_64F o ) { this.a11 = o.a11; this.a12 = o.a12; this.a13 = o.a13; this.a21 = o.a21; this.a22 = o.a22; this.a23 = o.a23; this.a31 = o.a31; this.a32 = o.a32; this.a33 = o.a33; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row == 0 ) { if( col == 0 ) { return a11; } else if( col == 1 ) { return a12; } else if( col == 2 ) { return a13; } } else if( row == 1 ) { if( col == 0 ) { return a21; } else if( col == 1 ) { return a22; } else if( col == 2 ) { return a23; } } else if( row == 2 ) { if( col == 0 ) { return a31; } else if( col == 1 ) { return a32; } else if( col == 2 ) { return a33; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row == 0 ) { if( col == 0 ) { a11 = val; return; } else if( col == 1 ) { a12 = val; return; } else if( col == 2 ) { a13 = val; return; } } else if( row == 1 ) { if( col == 0 ) { a21 = val; return; } else if( col == 1 ) { a22 = val; return; } else if( col == 2 ) { a23 = val; return; } } else if( row == 2 ) { if( col == 0 ) { a31 = val; return; } else if( col == 1 ) { a32 = val; return; } else if( col == 2 ) { a33 = val; return; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(Matrix original) { if( original.getNumCols() != 3 || original.getNumRows() != 3 ) throw new IllegalArgumentException("Rows and/or columns do not match"); RealMatrix64F m = (RealMatrix64F)original; a11 = m.get(0,0); a12 = m.get(0,1); a13 = m.get(0,2); a21 = m.get(1,0); a22 = m.get(1,1); a23 = m.get(1,2); a31 = m.get(2,0); a32 = m.get(2,1); a33 = m.get(2,2); } @Override public int getNumRows() { return 3; } @Override public int getNumCols() { return 3; } @Override public int getNumElements() { return 9; } @Override public T copy() { return (T)new FixedMatrix3x3_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix4_64F.java000066400000000000000000000070251256171534400232720ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized vector with 4 elements. Can represent a 4 x 1 or 1 x 4 matrix, context dependent. * * @author Peter Abeles */ public class FixedMatrix4_64F implements FixedMatrix64F { public double a1,a2,a3,a4; public FixedMatrix4_64F() { } public FixedMatrix4_64F(double a1,double a2,double a3,double a4) { this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; } public FixedMatrix4_64F(FixedMatrix4_64F o) { this.a1 = o.a1; this.a2 = o.a2; this.a3 = o.a3; this.a4 = o.a4; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { return a1; } else if( w == 1 ) { return a2; } else if( w == 2 ) { return a3; } else if( w == 3 ) { return a4; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { a1 = val; } else if( w == 1 ) { a2 = val; } else if( w == 2 ) { a3 = val; } else if( w == 3 ) { a4 = val; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(Matrix original) { RealMatrix64F m = (RealMatrix64F)original; if( m.getNumCols() == 1 && m.getNumRows() == 4 ) { a1 = m.get(0,0); a2 = m.get(1,0); a3 = m.get(2,0); a4 = m.get(3,0); } else if( m.getNumRows() == 1 && m.getNumCols() == 4 ){ a1 = m.get(0,0); a2 = m.get(0,1); a3 = m.get(0,2); a4 = m.get(0,3); } else { throw new IllegalArgumentException("Incompatible shape"); } } @Override public int getNumRows() { return 4; } @Override public int getNumCols() { return 1; } @Override public int getNumElements() { return 4; } @Override public T copy() { return (T)new FixedMatrix4_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix4x4_64F.java000066400000000000000000000145241256171534400235500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized 4 by FixedMatrix4x4_64F matrix. The matrix is stored as class variables for very fast read/write. aXY is the * value of row = X and column = Y. * * @author Peter Abeles */ public class FixedMatrix4x4_64F implements FixedMatrix64F { public double a11,a12,a13,a14; public double a21,a22,a23,a24; public double a31,a32,a33,a34; public double a41,a42,a43,a44; public FixedMatrix4x4_64F() { } public FixedMatrix4x4_64F( double a11,double a12,double a13,double a14, double a21,double a22,double a23,double a24, double a31,double a32,double a33,double a34, double a41,double a42,double a43,double a44) { this.a11 = a11; this.a12 = a12; this.a13 = a13; this.a14 = a14; this.a21 = a21; this.a22 = a22; this.a23 = a23; this.a24 = a24; this.a31 = a31; this.a32 = a32; this.a33 = a33; this.a34 = a34; this.a41 = a41; this.a42 = a42; this.a43 = a43; this.a44 = a44; } public FixedMatrix4x4_64F( FixedMatrix4x4_64F o ) { this.a11 = o.a11; this.a12 = o.a12; this.a13 = o.a13; this.a14 = o.a14; this.a21 = o.a21; this.a22 = o.a22; this.a23 = o.a23; this.a24 = o.a24; this.a31 = o.a31; this.a32 = o.a32; this.a33 = o.a33; this.a34 = o.a34; this.a41 = o.a41; this.a42 = o.a42; this.a43 = o.a43; this.a44 = o.a44; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row == 0 ) { if( col == 0 ) { return a11; } else if( col == 1 ) { return a12; } else if( col == 2 ) { return a13; } else if( col == 3 ) { return a14; } } else if( row == 1 ) { if( col == 0 ) { return a21; } else if( col == 1 ) { return a22; } else if( col == 2 ) { return a23; } else if( col == 3 ) { return a24; } } else if( row == 2 ) { if( col == 0 ) { return a31; } else if( col == 1 ) { return a32; } else if( col == 2 ) { return a33; } else if( col == 3 ) { return a34; } } else if( row == 3 ) { if( col == 0 ) { return a41; } else if( col == 1 ) { return a42; } else if( col == 2 ) { return a43; } else if( col == 3 ) { return a44; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row == 0 ) { if( col == 0 ) { a11 = val; return; } else if( col == 1 ) { a12 = val; return; } else if( col == 2 ) { a13 = val; return; } else if( col == 3 ) { a14 = val; return; } } else if( row == 1 ) { if( col == 0 ) { a21 = val; return; } else if( col == 1 ) { a22 = val; return; } else if( col == 2 ) { a23 = val; return; } else if( col == 3 ) { a24 = val; return; } } else if( row == 2 ) { if( col == 0 ) { a31 = val; return; } else if( col == 1 ) { a32 = val; return; } else if( col == 2 ) { a33 = val; return; } else if( col == 3 ) { a34 = val; return; } } else if( row == 3 ) { if( col == 0 ) { a41 = val; return; } else if( col == 1 ) { a42 = val; return; } else if( col == 2 ) { a43 = val; return; } else if( col == 3 ) { a44 = val; return; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(Matrix original) { if( original.getNumCols() != 4 || original.getNumRows() != 4 ) throw new IllegalArgumentException("Rows and/or columns do not match"); RealMatrix64F m = (RealMatrix64F)original; a11 = m.get(0,0); a12 = m.get(0,1); a13 = m.get(0,2); a14 = m.get(0,3); a21 = m.get(1,0); a22 = m.get(1,1); a23 = m.get(1,2); a24 = m.get(1,3); a31 = m.get(2,0); a32 = m.get(2,1); a33 = m.get(2,2); a34 = m.get(2,3); a41 = m.get(3,0); a42 = m.get(3,1); a43 = m.get(3,2); a44 = m.get(3,3); } @Override public int getNumRows() { return 4; } @Override public int getNumCols() { return 4; } @Override public int getNumElements() { return 16; } @Override public T copy() { return (T)new FixedMatrix4x4_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix5_64F.java000066400000000000000000000073631256171534400233000ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized vector with 5 elements. Can represent a 5 x 1 or 1 x 5 matrix, context dependent. * * @author Peter Abeles */ public class FixedMatrix5_64F implements FixedMatrix64F { public double a1,a2,a3,a4,a5; public FixedMatrix5_64F() { } public FixedMatrix5_64F(double a1,double a2,double a3,double a4,double a5) { this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; } public FixedMatrix5_64F(FixedMatrix5_64F o) { this.a1 = o.a1; this.a2 = o.a2; this.a3 = o.a3; this.a4 = o.a4; this.a5 = o.a5; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { return a1; } else if( w == 1 ) { return a2; } else if( w == 2 ) { return a3; } else if( w == 3 ) { return a4; } else if( w == 4 ) { return a5; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { a1 = val; } else if( w == 1 ) { a2 = val; } else if( w == 2 ) { a3 = val; } else if( w == 3 ) { a4 = val; } else if( w == 4 ) { a5 = val; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(Matrix original) { RealMatrix64F m = (RealMatrix64F)original; if( m.getNumCols() == 1 && m.getNumRows() == 5 ) { a1 = m.get(0,0); a2 = m.get(1,0); a3 = m.get(2,0); a4 = m.get(3,0); a5 = m.get(4,0); } else if( m.getNumRows() == 1 && m.getNumCols() == 5 ){ a1 = m.get(0,0); a2 = m.get(0,1); a3 = m.get(0,2); a4 = m.get(0,3); a5 = m.get(0,4); } else { throw new IllegalArgumentException("Incompatible shape"); } } @Override public int getNumRows() { return 5; } @Override public int getNumCols() { return 1; } @Override public int getNumElements() { return 5; } @Override public T copy() { return (T)new FixedMatrix5_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix5x5_64F.java000066400000000000000000000207061256171534400235510ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized 5 by FixedMatrix5x5_64F matrix. The matrix is stored as class variables for very fast read/write. aXY is the * value of row = X and column = Y. * * @author Peter Abeles */ public class FixedMatrix5x5_64F implements FixedMatrix64F { public double a11,a12,a13,a14,a15; public double a21,a22,a23,a24,a25; public double a31,a32,a33,a34,a35; public double a41,a42,a43,a44,a45; public double a51,a52,a53,a54,a55; public FixedMatrix5x5_64F() { } public FixedMatrix5x5_64F( double a11,double a12,double a13,double a14,double a15, double a21,double a22,double a23,double a24,double a25, double a31,double a32,double a33,double a34,double a35, double a41,double a42,double a43,double a44,double a45, double a51,double a52,double a53,double a54,double a55) { this.a11 = a11; this.a12 = a12; this.a13 = a13; this.a14 = a14; this.a15 = a15; this.a21 = a21; this.a22 = a22; this.a23 = a23; this.a24 = a24; this.a25 = a25; this.a31 = a31; this.a32 = a32; this.a33 = a33; this.a34 = a34; this.a35 = a35; this.a41 = a41; this.a42 = a42; this.a43 = a43; this.a44 = a44; this.a45 = a45; this.a51 = a51; this.a52 = a52; this.a53 = a53; this.a54 = a54; this.a55 = a55; } public FixedMatrix5x5_64F( FixedMatrix5x5_64F o ) { this.a11 = o.a11; this.a12 = o.a12; this.a13 = o.a13; this.a14 = o.a14; this.a15 = o.a15; this.a21 = o.a21; this.a22 = o.a22; this.a23 = o.a23; this.a24 = o.a24; this.a25 = o.a25; this.a31 = o.a31; this.a32 = o.a32; this.a33 = o.a33; this.a34 = o.a34; this.a35 = o.a35; this.a41 = o.a41; this.a42 = o.a42; this.a43 = o.a43; this.a44 = o.a44; this.a45 = o.a45; this.a51 = o.a51; this.a52 = o.a52; this.a53 = o.a53; this.a54 = o.a54; this.a55 = o.a55; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row == 0 ) { if( col == 0 ) { return a11; } else if( col == 1 ) { return a12; } else if( col == 2 ) { return a13; } else if( col == 3 ) { return a14; } else if( col == 4 ) { return a15; } } else if( row == 1 ) { if( col == 0 ) { return a21; } else if( col == 1 ) { return a22; } else if( col == 2 ) { return a23; } else if( col == 3 ) { return a24; } else if( col == 4 ) { return a25; } } else if( row == 2 ) { if( col == 0 ) { return a31; } else if( col == 1 ) { return a32; } else if( col == 2 ) { return a33; } else if( col == 3 ) { return a34; } else if( col == 4 ) { return a35; } } else if( row == 3 ) { if( col == 0 ) { return a41; } else if( col == 1 ) { return a42; } else if( col == 2 ) { return a43; } else if( col == 3 ) { return a44; } else if( col == 4 ) { return a45; } } else if( row == 4 ) { if( col == 0 ) { return a51; } else if( col == 1 ) { return a52; } else if( col == 2 ) { return a53; } else if( col == 3 ) { return a54; } else if( col == 4 ) { return a55; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row == 0 ) { if( col == 0 ) { a11 = val; return; } else if( col == 1 ) { a12 = val; return; } else if( col == 2 ) { a13 = val; return; } else if( col == 3 ) { a14 = val; return; } else if( col == 4 ) { a15 = val; return; } } else if( row == 1 ) { if( col == 0 ) { a21 = val; return; } else if( col == 1 ) { a22 = val; return; } else if( col == 2 ) { a23 = val; return; } else if( col == 3 ) { a24 = val; return; } else if( col == 4 ) { a25 = val; return; } } else if( row == 2 ) { if( col == 0 ) { a31 = val; return; } else if( col == 1 ) { a32 = val; return; } else if( col == 2 ) { a33 = val; return; } else if( col == 3 ) { a34 = val; return; } else if( col == 4 ) { a35 = val; return; } } else if( row == 3 ) { if( col == 0 ) { a41 = val; return; } else if( col == 1 ) { a42 = val; return; } else if( col == 2 ) { a43 = val; return; } else if( col == 3 ) { a44 = val; return; } else if( col == 4 ) { a45 = val; return; } } else if( row == 4 ) { if( col == 0 ) { a51 = val; return; } else if( col == 1 ) { a52 = val; return; } else if( col == 2 ) { a53 = val; return; } else if( col == 3 ) { a54 = val; return; } else if( col == 4 ) { a55 = val; return; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(Matrix original) { if( original.getNumCols() != 5 || original.getNumRows() != 5 ) throw new IllegalArgumentException("Rows and/or columns do not match"); RealMatrix64F m = (RealMatrix64F)original; a11 = m.get(0,0); a12 = m.get(0,1); a13 = m.get(0,2); a14 = m.get(0,3); a15 = m.get(0,4); a21 = m.get(1,0); a22 = m.get(1,1); a23 = m.get(1,2); a24 = m.get(1,3); a25 = m.get(1,4); a31 = m.get(2,0); a32 = m.get(2,1); a33 = m.get(2,2); a34 = m.get(2,3); a35 = m.get(2,4); a41 = m.get(3,0); a42 = m.get(3,1); a43 = m.get(3,2); a44 = m.get(3,3); a45 = m.get(3,4); a51 = m.get(4,0); a52 = m.get(4,1); a53 = m.get(4,2); a54 = m.get(4,3); a55 = m.get(4,4); } @Override public int getNumRows() { return 5; } @Override public int getNumCols() { return 5; } @Override public int getNumElements() { return 25; } @Override public T copy() { return (T)new FixedMatrix5x5_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix64F.java000066400000000000000000000015441256171534400230470ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * Interface which all fixed sized matrices must implement * * @author Peter Abeles */ public interface FixedMatrix64F extends RealMatrix64F { } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix6_64F.java000066400000000000000000000077211256171534400232770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized vector with 6 elements. Can represent a 6 x 1 or 1 x 6 matrix, context dependent. * * @author Peter Abeles */ public class FixedMatrix6_64F implements FixedMatrix64F { public double a1,a2,a3,a4,a5,a6; public FixedMatrix6_64F() { } public FixedMatrix6_64F(double a1,double a2,double a3,double a4,double a5,double a6) { this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.a6 = a6; } public FixedMatrix6_64F(FixedMatrix6_64F o) { this.a1 = o.a1; this.a2 = o.a2; this.a3 = o.a3; this.a4 = o.a4; this.a5 = o.a5; this.a6 = o.a6; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { return a1; } else if( w == 1 ) { return a2; } else if( w == 2 ) { return a3; } else if( w == 3 ) { return a4; } else if( w == 4 ) { return a5; } else if( w == 5 ) { return a6; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row != 0 && col != 0 ) throw new IllegalArgumentException("Row or column must be zero since this is a vector"); int w = Math.max(row,col); if( w == 0 ) { a1 = val; } else if( w == 1 ) { a2 = val; } else if( w == 2 ) { a3 = val; } else if( w == 3 ) { a4 = val; } else if( w == 4 ) { a5 = val; } else if( w == 5 ) { a6 = val; } else { throw new IllegalArgumentException("Out of range. "+w); } } @Override public void set(Matrix original) { RealMatrix64F m = (RealMatrix64F)original; if( m.getNumCols() == 1 && m.getNumRows() == 6 ) { a1 = m.get(0,0); a2 = m.get(1,0); a3 = m.get(2,0); a4 = m.get(3,0); a5 = m.get(4,0); a6 = m.get(5,0); } else if( m.getNumRows() == 1 && m.getNumCols() == 6 ){ a1 = m.get(0,0); a2 = m.get(0,1); a3 = m.get(0,2); a4 = m.get(0,3); a5 = m.get(0,4); a6 = m.get(0,5); } else { throw new IllegalArgumentException("Incompatible shape"); } } @Override public int getNumRows() { return 6; } @Override public int getNumCols() { return 1; } @Override public int getNumElements() { return 6; } @Override public T copy() { return (T)new FixedMatrix6_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/FixedMatrix6x6_64F.java000066400000000000000000000257741256171534400235650ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.MatrixIO; /** * Fixed sized 6 by FixedMatrix6x6_64F matrix. The matrix is stored as class variables for very fast read/write. aXY is the * value of row = X and column = Y. * * @author Peter Abeles */ public class FixedMatrix6x6_64F implements FixedMatrix64F { public double a11,a12,a13,a14,a15,a16; public double a21,a22,a23,a24,a25,a26; public double a31,a32,a33,a34,a35,a36; public double a41,a42,a43,a44,a45,a46; public double a51,a52,a53,a54,a55,a56; public double a61,a62,a63,a64,a65,a66; public FixedMatrix6x6_64F() { } public FixedMatrix6x6_64F( double a11,double a12,double a13,double a14,double a15,double a16, double a21,double a22,double a23,double a24,double a25,double a26, double a31,double a32,double a33,double a34,double a35,double a36, double a41,double a42,double a43,double a44,double a45,double a46, double a51,double a52,double a53,double a54,double a55,double a56, double a61,double a62,double a63,double a64,double a65,double a66) { this.a11 = a11; this.a12 = a12; this.a13 = a13; this.a14 = a14; this.a15 = a15; this.a16 = a16; this.a21 = a21; this.a22 = a22; this.a23 = a23; this.a24 = a24; this.a25 = a25; this.a26 = a26; this.a31 = a31; this.a32 = a32; this.a33 = a33; this.a34 = a34; this.a35 = a35; this.a36 = a36; this.a41 = a41; this.a42 = a42; this.a43 = a43; this.a44 = a44; this.a45 = a45; this.a46 = a46; this.a51 = a51; this.a52 = a52; this.a53 = a53; this.a54 = a54; this.a55 = a55; this.a56 = a56; this.a61 = a61; this.a62 = a62; this.a63 = a63; this.a64 = a64; this.a65 = a65; this.a66 = a66; } public FixedMatrix6x6_64F( FixedMatrix6x6_64F o ) { this.a11 = o.a11; this.a12 = o.a12; this.a13 = o.a13; this.a14 = o.a14; this.a15 = o.a15; this.a16 = o.a16; this.a21 = o.a21; this.a22 = o.a22; this.a23 = o.a23; this.a24 = o.a24; this.a25 = o.a25; this.a26 = o.a26; this.a31 = o.a31; this.a32 = o.a32; this.a33 = o.a33; this.a34 = o.a34; this.a35 = o.a35; this.a36 = o.a36; this.a41 = o.a41; this.a42 = o.a42; this.a43 = o.a43; this.a44 = o.a44; this.a45 = o.a45; this.a46 = o.a46; this.a51 = o.a51; this.a52 = o.a52; this.a53 = o.a53; this.a54 = o.a54; this.a55 = o.a55; this.a56 = o.a56; this.a61 = o.a61; this.a62 = o.a62; this.a63 = o.a63; this.a64 = o.a64; this.a65 = o.a65; this.a66 = o.a66; } @Override public double get(int row, int col) { return unsafe_get(row,col); } @Override public double unsafe_get(int row, int col) { if( row == 0 ) { if( col == 0 ) { return a11; } else if( col == 1 ) { return a12; } else if( col == 2 ) { return a13; } else if( col == 3 ) { return a14; } else if( col == 4 ) { return a15; } else if( col == 5 ) { return a16; } } else if( row == 1 ) { if( col == 0 ) { return a21; } else if( col == 1 ) { return a22; } else if( col == 2 ) { return a23; } else if( col == 3 ) { return a24; } else if( col == 4 ) { return a25; } else if( col == 5 ) { return a26; } } else if( row == 2 ) { if( col == 0 ) { return a31; } else if( col == 1 ) { return a32; } else if( col == 2 ) { return a33; } else if( col == 3 ) { return a34; } else if( col == 4 ) { return a35; } else if( col == 5 ) { return a36; } } else if( row == 3 ) { if( col == 0 ) { return a41; } else if( col == 1 ) { return a42; } else if( col == 2 ) { return a43; } else if( col == 3 ) { return a44; } else if( col == 4 ) { return a45; } else if( col == 5 ) { return a46; } } else if( row == 4 ) { if( col == 0 ) { return a51; } else if( col == 1 ) { return a52; } else if( col == 2 ) { return a53; } else if( col == 3 ) { return a54; } else if( col == 4 ) { return a55; } else if( col == 5 ) { return a56; } } else if( row == 5 ) { if( col == 0 ) { return a61; } else if( col == 1 ) { return a62; } else if( col == 2 ) { return a63; } else if( col == 3 ) { return a64; } else if( col == 4 ) { return a65; } else if( col == 5 ) { return a66; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(int row, int col, double val) { unsafe_set(row,col,val); } @Override public void unsafe_set(int row, int col, double val) { if( row == 0 ) { if( col == 0 ) { a11 = val; return; } else if( col == 1 ) { a12 = val; return; } else if( col == 2 ) { a13 = val; return; } else if( col == 3 ) { a14 = val; return; } else if( col == 4 ) { a15 = val; return; } else if( col == 5 ) { a16 = val; return; } } else if( row == 1 ) { if( col == 0 ) { a21 = val; return; } else if( col == 1 ) { a22 = val; return; } else if( col == 2 ) { a23 = val; return; } else if( col == 3 ) { a24 = val; return; } else if( col == 4 ) { a25 = val; return; } else if( col == 5 ) { a26 = val; return; } } else if( row == 2 ) { if( col == 0 ) { a31 = val; return; } else if( col == 1 ) { a32 = val; return; } else if( col == 2 ) { a33 = val; return; } else if( col == 3 ) { a34 = val; return; } else if( col == 4 ) { a35 = val; return; } else if( col == 5 ) { a36 = val; return; } } else if( row == 3 ) { if( col == 0 ) { a41 = val; return; } else if( col == 1 ) { a42 = val; return; } else if( col == 2 ) { a43 = val; return; } else if( col == 3 ) { a44 = val; return; } else if( col == 4 ) { a45 = val; return; } else if( col == 5 ) { a46 = val; return; } } else if( row == 4 ) { if( col == 0 ) { a51 = val; return; } else if( col == 1 ) { a52 = val; return; } else if( col == 2 ) { a53 = val; return; } else if( col == 3 ) { a54 = val; return; } else if( col == 4 ) { a55 = val; return; } else if( col == 5 ) { a56 = val; return; } } else if( row == 5 ) { if( col == 0 ) { a61 = val; return; } else if( col == 1 ) { a62 = val; return; } else if( col == 2 ) { a63 = val; return; } else if( col == 3 ) { a64 = val; return; } else if( col == 4 ) { a65 = val; return; } else if( col == 5 ) { a66 = val; return; } } throw new IllegalArgumentException("Row and/or column out of range. "+row+" "+col); } @Override public void set(Matrix original) { if( original.getNumCols() != 6 || original.getNumRows() != 6 ) throw new IllegalArgumentException("Rows and/or columns do not match"); RealMatrix64F m = (RealMatrix64F)original; a11 = m.get(0,0); a12 = m.get(0,1); a13 = m.get(0,2); a14 = m.get(0,3); a15 = m.get(0,4); a16 = m.get(0,5); a21 = m.get(1,0); a22 = m.get(1,1); a23 = m.get(1,2); a24 = m.get(1,3); a25 = m.get(1,4); a26 = m.get(1,5); a31 = m.get(2,0); a32 = m.get(2,1); a33 = m.get(2,2); a34 = m.get(2,3); a35 = m.get(2,4); a36 = m.get(2,5); a41 = m.get(3,0); a42 = m.get(3,1); a43 = m.get(3,2); a44 = m.get(3,3); a45 = m.get(3,4); a46 = m.get(3,5); a51 = m.get(4,0); a52 = m.get(4,1); a53 = m.get(4,2); a54 = m.get(4,3); a55 = m.get(4,4); a56 = m.get(4,5); a61 = m.get(5,0); a62 = m.get(5,1); a63 = m.get(5,2); a64 = m.get(5,3); a65 = m.get(5,4); a66 = m.get(5,5); } @Override public int getNumRows() { return 6; } @Override public int getNumCols() { return 6; } @Override public int getNumElements() { return 36; } @Override public T copy() { return (T)new FixedMatrix6x6_64F(this); } @Override public void print() { MatrixIO.print(System.out, this); } } ejml-0.28/main/core/src/org/ejml/data/Matrix.java000066400000000000000000000026731256171534400216130ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import java.io.Serializable; /** * Base interface for all rectangular matrices * * @author Peter Abeles */ public interface Matrix extends Serializable { /** * Returns the number of rows in this matrix. * * @return Number of rows. */ public int getNumRows(); /** * Returns the number of columns in this matrix. * * @return Number of columns. */ public int getNumCols(); /** * Creates an exact copy of the matrix */ public T copy(); /** * Sets this matrix to be identical to the 'original' matrix passed in. */ public void set( Matrix original ); /** * Prints the matrix to standard out. */ public void print(); } ejml-0.28/main/core/src/org/ejml/data/MatrixIterator32F.java000066400000000000000000000103731256171534400235740ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import java.util.Iterator; /** * This is a matrix iterator for traversing through a submatrix. For speed it is recommended * that you directly access the elements in the matrix, but there are some situations where this * can be a better design. * * @author Peter Abeles */ public class MatrixIterator32F implements Iterator { // the matrix which is being iterated through private D1Matrix32F a; // should it iterate through by row or by column private boolean rowMajor; // the first row and column it returns private int minCol; private int minRow; // where in the iteration it is private int index = 0; // how many elements inside will it return private int size; // how wide the submatrix is private int submatrixStride; // the current element int subRow,subCol; /** * Creates a new iterator for traversing through a submatrix inside this matrix. It can be traversed * by row or by column. Range of elements is inclusive, e.g. minRow = 0 and maxRow = 1 will include rows * 0 and 1. The iteration starts at (minRow,minCol) and ends at (maxRow,maxCol) * * @param a the matrix it is iterating through * @param rowMajor true means it will traverse through the submatrix by row first, false by columns. * @param minRow first row it will start at. * @param minCol first column it will start at. * @param maxRow last row it will stop at. * @param maxCol last column it will stop at. * @return A new MatrixIterator */ public MatrixIterator32F(D1Matrix32F a, boolean rowMajor, int minRow, int minCol, int maxRow, int maxCol ) { if( maxCol < minCol ) throw new IllegalArgumentException("maxCol has to be more than or equal to minCol"); if( maxRow < minRow ) throw new IllegalArgumentException("maxRow has to be more than or equal to minCol"); if( maxCol >= a.numCols) throw new IllegalArgumentException("maxCol must be < numCols"); if( maxRow >= a.numRows) throw new IllegalArgumentException("maxRow must be < numCRows"); this.a = a; this.rowMajor = rowMajor; this.minCol = minCol; this.minRow = minRow; size = (maxCol-minCol+1)*(maxRow-minRow+1); if( rowMajor ) submatrixStride = maxCol-minCol+1; else submatrixStride = maxRow-minRow+1; } @Override public boolean hasNext() { return index < size; } @Override public Float next() { if( rowMajor ) { subRow = index / submatrixStride; subCol = index % submatrixStride; } else { subRow = index % submatrixStride; subCol = index / submatrixStride; } index++; return a.get(subRow+minRow,subCol+minCol); } @Override public void remove() { throw new RuntimeException("Operation not supported"); } /** * Which element in the submatrix was returned by next() * * @return Submatrix element's index. */ public int getIndex() { return index-1; } /** * True if it is iterating through the matrix by rows and false if by columns. * @return row major or column major */ public boolean isRowMajor() { return rowMajor; } /** * Sets the value of the current element. * * @param value The element's new value. */ public void set( float value ) { a.set(subRow+minRow,subCol+minCol,value); } } ejml-0.28/main/core/src/org/ejml/data/MatrixIterator64F.java000066400000000000000000000103761256171534400236040ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import java.util.Iterator; /** * This is a matrix iterator for traversing through a submatrix. For speed it is recommended * that you directly access the elements in the matrix, but there are some situations where this * can be a better design. * * @author Peter Abeles */ public class MatrixIterator64F implements Iterator { // the matrix which is being iterated through private D1Matrix64F a; // should it iterate through by row or by column private boolean rowMajor; // the first row and column it returns private int minCol; private int minRow; // where in the iteration it is private int index = 0; // how many elements inside will it return private int size; // how wide the submatrix is private int submatrixStride; // the current element int subRow,subCol; /** * Creates a new iterator for traversing through a submatrix inside this matrix. It can be traversed * by row or by column. Range of elements is inclusive, e.g. minRow = 0 and maxRow = 1 will include rows * 0 and 1. The iteration starts at (minRow,minCol) and ends at (maxRow,maxCol) * * @param a the matrix it is iterating through * @param rowMajor true means it will traverse through the submatrix by row first, false by columns. * @param minRow first row it will start at. * @param minCol first column it will start at. * @param maxRow last row it will stop at. * @param maxCol last column it will stop at. * @return A new MatrixIterator */ public MatrixIterator64F(D1Matrix64F a, boolean rowMajor, int minRow, int minCol, int maxRow, int maxCol ) { if( maxCol < minCol ) throw new IllegalArgumentException("maxCol has to be more than or equal to minCol"); if( maxRow < minRow ) throw new IllegalArgumentException("maxRow has to be more than or equal to minCol"); if( maxCol >= a.numCols) throw new IllegalArgumentException("maxCol must be < numCols"); if( maxRow >= a.numRows) throw new IllegalArgumentException("maxRow must be < numCRows"); this.a = a; this.rowMajor = rowMajor; this.minCol = minCol; this.minRow = minRow; size = (maxCol-minCol+1)*(maxRow-minRow+1); if( rowMajor ) submatrixStride = maxCol-minCol+1; else submatrixStride = maxRow-minRow+1; } @Override public boolean hasNext() { return index < size; } @Override public Double next() { if( rowMajor ) { subRow = index / submatrixStride; subCol = index % submatrixStride; } else { subRow = index % submatrixStride; subCol = index / submatrixStride; } index++; return a.get(subRow+minRow,subCol+minCol); } @Override public void remove() { throw new RuntimeException("Operation not supported"); } /** * Which element in the submatrix was returned by next() * * @return Submatrix element's index. */ public int getIndex() { return index-1; } /** * True if it is iterating through the matrix by rows and false if by columns. * @return row major or column major */ public boolean isRowMajor() { return rowMajor; } /** * Sets the value of the current element. * * @param value The element's new value. */ public void set( double value ) { a.set(subRow+minRow,subCol+minCol,value); } } ejml-0.28/main/core/src/org/ejml/data/RealMatrix32F.java000066400000000000000000000053671256171534400226750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * Interface for all 32 bit floating point rectangular matrices. * * @author Peter Abeles */ public interface RealMatrix32F extends Matrix { /** * Returns the value of value of the specified matrix element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @return The specified element's value. */ public float get(int row, int col); /** * Same as {@link #get} but does not perform bounds check on input parameters. This results in about a 25% * speed increase but potentially sacrifices stability and makes it more difficult to track down simple errors. * It is not recommended that this function be used, except in highly optimized code where the bounds are * implicitly being checked. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @return The specified element's value. */ public float unsafe_get(int row, int col); /** * Sets the value of the specified matrix element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param val The element's new value. */ public void set(int row, int col, float val); /** * Same as {@link #set} but does not perform bounds check on input parameters. This results in about a 25% * speed increase but potentially sacrifices stability and makes it more difficult to track down simple errors. * It is not recommended that this function be used, except in highly optimized code where the bounds are * implicitly being checked. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param val The element's new value. */ public void unsafe_set(int row, int col, float val); /** * Returns the number of elements in this matrix, which is the number of rows * times the number of columns. * * @return Number of elements in this matrix. */ public int getNumElements(); } ejml-0.28/main/core/src/org/ejml/data/RealMatrix64F.java000066400000000000000000000053731256171534400226770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * Interface for all 64 bit floating point rectangular matrices. * * @author Peter Abeles */ public interface RealMatrix64F extends Matrix { /** * Returns the value of value of the specified matrix element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @return The specified element's value. */ public double get(int row, int col); /** * Same as {@link #get} but does not perform bounds check on input parameters. This results in about a 25% * speed increase but potentially sacrifices stability and makes it more difficult to track down simple errors. * It is not recommended that this function be used, except in highly optimized code where the bounds are * implicitly being checked. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @return The specified element's value. */ public double unsafe_get(int row, int col); /** * Sets the value of the specified matrix element. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param val The element's new value. */ public void set(int row, int col, double val); /** * Same as {@link #set} but does not perform bounds check on input parameters. This results in about a 25% * speed increase but potentially sacrifices stability and makes it more difficult to track down simple errors. * It is not recommended that this function be used, except in highly optimized code where the bounds are * implicitly being checked. * * @param row Matrix element's row index.. * @param col Matrix element's column index. * @param val The element's new value. */ public void unsafe_set(int row, int col, double val); /** * Returns the number of elements in this matrix, which is the number of rows * times the number of columns. * * @return Number of elements in this matrix. */ public int getNumElements(); } ejml-0.28/main/core/src/org/ejml/data/ReshapeMatrix.java000066400000000000000000000021061256171534400231120ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * Matrix which can be reshaped * * @author Peter Abeles */ public interface ReshapeMatrix extends Matrix{ /** * Equivalent to invoking reshape(numRows,numCols,false); * * @param numRows The new number of rows in the matrix. * @param numCols The new number of columns in the matrix. */ public void reshape( int numRows , int numCols ); } ejml-0.28/main/core/src/org/ejml/data/RowD1Matrix64F.java000066400000000000000000000015661256171534400227500ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * Interface for a row-major matrix that uses a single array internally. * * @author Peter Abeles */ public abstract class RowD1Matrix64F extends D1Matrix64F { } ejml-0.28/main/core/src/org/ejml/interfaces/000077500000000000000000000000001256171534400207065ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/000077500000000000000000000000001256171534400235625ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/BidiagonalDecomposition.java000066400000000000000000000045561256171534400312250ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Matrix; /** *

* Computes a matrix decomposition such that:
*
* A = U*B*VT
*
* where A is m by n, U is orthogonal and m by m, B is an m by n bidiagonal matrix, V is orthogonal and n by n. * This is used as a first step in computing the SVD of a matrix for the QR algorithm approach. *

*

* A bidiagonal matrix has zeros in every element except for the two diagonals.
*
* b_ij = 0 if i > j or i < j-1
*

* * * @author Peter Abeles */ public interface BidiagonalDecomposition extends DecompositionInterface { /** * Returns the bidiagonal matrix. * * @param B If not null the results are stored here, if null a new matrix is created. * @return The bidiagonal matrix. */ public T getB( T B , boolean compact ); /** * Returns the orthogonal U matrix. * * @param U If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public T getU( T U , boolean transpose , boolean compact ); /** * Returns the orthogonal V matrix. * * @param V If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public T getV( T V , boolean transpose , boolean compact ); /** * Extracts the diagonal and off diagonal elements from the decomposition. * * @param diag diagonal elements from B. * @param off off diagonal elements form B. */ public void getDiagonal( double diag[], double off[] ); }ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/CholeskyDecomposition.java000066400000000000000000000043431256171534400307470ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.Matrix; /** *

* Cholesky decomposition for {@link DenseMatrix64F}. It decomposes positive-definite symmetric matrices (real) * or hermitian-positive definite (complex) into either upper or lower triangles:
*
* L*LH=A
* RH*R=A
*
* where L is a lower triangular matrix and R is an upper triangular matrix. This is typically * used to invert matrices, such as a covariance matrix.
*

* * @author Peter Abeles */ public interface CholeskyDecomposition extends DecompositionInterface { /** * If true the decomposition was for a lower triangular matrix. * If false it was for an upper triangular matrix. * * @return True if lower, false if upper. */ public boolean isLower(); /** *

* Returns the triangular matrix from the decomposition. *

* *

* If an input is provided that matrix is used to write the results to. * Otherwise a new matrix is created and the results written to it. *

* * @param T If not null then the decomposed matrix is written here. * @return A lower or upper triangular matrix. */ public MatrixType getT( MatrixType T ); /** * Computes the matrix's determinant using the decomposition. * * @return The determinant. */ public Complex64F computeDeterminant(); }ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/CholeskyLDLDecomposition.java000066400000000000000000000047041256171534400313040ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Matrix; /** *

* Cholesky LDLT decomposition for {@link org.ejml.data.DenseMatrix64F}. *

*

* A Cholesky LDL decomposition decomposes positive-definite symmetric matrices into:
*
* L*D*LT=A
*
* where L is a lower triangular matrix and D is a diagonal matrix. The main advantage of LDL versus LL or RR Cholesky is that * it avoid a square root operation. *

* * @see org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionLDL_D64 * * @author Peter Abeles */ public interface CholeskyLDLDecomposition extends DecompositionInterface { /** *

* Returns the lower triangular matrix from the decomposition. *

* *

* If an input is provided that matrix is used to write the results to. * Otherwise a new matrix is created and the results written to it. *

* * @param L If not null then the decomposed matrix is written here. * @return A lower triangular matrix. */ public MatrixType getL(MatrixType L); /** * Returns the elements in the diagonal matrix * @return array with diagonal elements. Array might be larger than the number of elements. */ public double[] getDiagonal(); /** *

* Returns the diagonal matrixfrom the decomposition. *

* *

* If an input is provided that matrix is used to write the results to. * Otherwise a new matrix is created and the results written to it. *

* * @param D If not null it will be used to store the diagonal matrix * @return D Square diagonal matrix */ public MatrixType getD(MatrixType D); }ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/DecompositionInterface.java000066400000000000000000000043401256171534400310630ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Matrix; /** *

* An interface for performing matrix decompositions on a {@link org.ejml.data.DenseMatrix64F}. *

* *

* A matrix decomposition is an algorithm which decomposes the input matrix into a set of equivalent * matrices that store the same information as the original. Decompositions are useful * in that they allow specialized efficient algorithms to be run on generic input * matrices. *

* *

* By default most decompositions will modify the input matrix. This is done to save * memory and simply code by reducing the number of cases which need to be tested. *

* * @author Peter Abeles */ public interface DecompositionInterface { /** * Computes the decomposition of the input matrix. Depending on the implementation * the input matrix might be stored internally or modified. If it is modified then * the function {@link #inputModified()} will return true and the matrix should not be * modified until the decomposition is no longer needed. * * @param orig The matrix which is being decomposed. Modification is implementation dependent. * @return Returns if it was able to decompose the matrix. */ public boolean decompose( T orig ); /** * Is the input matrix to {@link #decompose(org.ejml.data.Matrix)} is modified during * the decomposition process. * * @return true if the input matrix to decompose() is modified. */ public boolean inputModified(); } ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/EigenDecomposition.java000066400000000000000000000062451256171534400302200ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Complex64F; import org.ejml.data.Matrix; /** *

* This is a generic interface for computing the eigenvalues and eigenvectors of a matrix. * Eigenvalues and eigenvectors have the following property:
*
* A*v=λ*v
*
* where A is a square matrix and v is an eigenvector associated with the eigenvalue λ. *

* *

* In general, both eigenvalues and eigenvectors can be complex numbers. For symmetric matrices the * eigenvalues and eigenvectors are always real numbers. EJML does not support complex matrices but * it does have minimal support for complex numbers. As a result complex eigenvalues are found, but only * the real eigenvectors are computed. *

* *

* To create a new instance of {@link EigenDecomposition} use {@link org.ejml.factory.DecompositionFactory}. If the matrix * is known to be symmetric be sure to use the symmetric decomposition, which is much faster and more accurate * than the general purpose one. *

* @author Peter Abeles */ public interface EigenDecomposition extends DecompositionInterface { /** * Returns the number of eigenvalues/eigenvectors. This is the matrix's dimension. * * @return number of eigenvalues/eigenvectors. */ public int getNumberOfEigenvalues(); /** *

* Returns an eigenvalue as a complex number. For symmetric matrices the returned eigenvalue will always be a real * number, which means the imaginary component will be equal to zero. *

* *

* NOTE: The order of the eigenvalues is dependent upon the decomposition algorithm used. This means that they may * or may not be ordered by magnitude. For example the QR algorithm will returns results that are partially * ordered by magnitude, but this behavior should not be relied upon. *

* * @param index Index of the eigenvalue eigenvector pair. * @return An eigenvalue. */ public Complex64F getEigenvalue( int index ); /** *

* Used to retrieve real valued eigenvectors. If an eigenvector is associated with a complex eigenvalue * then null is returned instead. *

* * @param index Index of the eigenvalue eigenvector pair. * @return If the associated eigenvalue is real then an eigenvector is returned, null otherwise. */ public MatrixType getEigenVector( int index ); } ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/LUDecomposition.java000066400000000000000000000072321256171534400275060ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Complex64F; import org.ejml.data.Matrix; /** *

* LU Decomposition refactors the original matrix such that:
*

PT*L*U = A
* where P is a pivot matrix, L is a lower triangular matrix, U is an upper triangular matrix and A is * the original matrix. *

* *

* LU Decomposition is useful since once the decomposition has been performed linear * equations can be quickly solved and the original matrix A inverted. Different algorithms * can be selected to perform the decomposition, all will have the same end result. *

*

* To use this class first specify the size of the matrix that will be decomposed by it in * the constructor. Only square m by m matrices can be decomposed. Then to decompose a matrix * call {@link #decompose}. If it encounters any problems an exception will be thrown. After * that all the other functions will be available for solving and inverting matrices. *

* * @author Peter Abeles */ public interface LUDecomposition extends DecompositionInterface { /** *

* Returns the L matrix from the decomposition. Should only * be called after {@link #decompose(org.ejml.data.Matrix)} has * been called. *

* *

* If parameter 'lower' is not null, then that matrix is used to store the L matrix. Otherwise * a new matrix is created. *

* * @param lower Storage for T matrix. If null then a new matrix is returned. Modified. * @return The L matrix. */ public T getLower( T lower ); /** *

* Returns the U matrix from the decomposition. Should only * be called after {@link #decompose(org.ejml.data.Matrix)} has * been called. *

* *

* If parameter 'upper' is not null, then that matrix is used to store the U matrix. Otherwise * a new matrix is created. *

* * @param upper Storage for U matrix. If null then a new matrix is returned. Modified. * @return The U matrix. */ public T getUpper( T upper ); /** *

* For numerical stability there are often row interchanges. This computes * a pivot matrix that will undo those changes. *

* * @param pivot Storage for the pivot matrix. If null then a new matrix is returned. Modified. * @return The pivot matrix. */ public T getPivot( T pivot ); /** * Returns true if the decomposition detected a singular matrix. This check * will not work 100% of the time due to machine precision issues. * * @return True if the matrix is singular and false if it is not. */ // TODO Remove? If singular decomposition will fail. public boolean isSingular(); /** * Computes the matrix's determinant using the LU decomposition. * * @return The determinant. */ public Complex64F computeDeterminant(); } ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/QRDecomposition.java000066400000000000000000000063761256171534400275200ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Matrix; /** *

* QR decompositions decompose a rectangular matrix 'A' such that 'A=QR'. Where * A ∈ ℜ n × m , n ≥ m, Q ∈ ℜ n × n is an orthogonal matrix, * and R ∈ ℜ n × m is an upper triangular matrix. Some implementations * of QR decomposition require that A has full rank. *

*

* Some features of QR decompositions: *

    *
  • Can decompose rectangular matrices.
  • *
  • Numerically stable solutions to least-squares problem, but not as stable as SVD
  • *
  • Can incrementally add and remove columns from the decomposed matrix. See {@link org.ejml.alg.dense.linsol.qr.AdjLinearSolverQr_D64}
  • *
*

*

* Orthogonal matrices have the following properties: *

    *
  • QQT=I
  • *
  • QT=Q-1
  • *
*

* @see org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholder_D64 * @see org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderColumn_D64 * * @author Peter Abeles */ public interface QRDecomposition extends DecompositionInterface { /** *

* Returns the Q matrix from the decomposition. Should only * be called after {@link #decompose(org.ejml.data.Matrix)} has * been called. *

* *

* If parameter Q is not null, then that matrix is used to store the Q matrix. Otherwise * a new matrix is created. *

* * @param Q If not null then the Q matrix is written to it. Modified. * @param compact If true an m by n matrix is created, otherwise n by n. * @return The Q matrix. */ public T getQ( T Q, boolean compact); /** *

* Returns the R matrix from the decomposition. Should only be * called after {@link #decompose(org.ejml.data.Matrix)} has been. *

*

* If setZeros is true then an n × m matrix is required and all the elements are set. * If setZeros is false then the matrix must be at least m × m and only the upper triangular * elements are set. *

* *

* If parameter R is not null, then that matrix is used to store the R matrix. Otherwise * a new matrix is created. *

* * @param R If not null then the R matrix is written to it. Modified. * @param compact If true only the upper triangular elements are set * @return The R matrix. */ public T getR( T R, boolean compact); } ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/QRPDecomposition.java000066400000000000000000000043451256171534400276320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.DenseMatrix64F; import org.ejml.data.Matrix; /** *

* Similar to {@link QRDecomposition} but it can handle the rank deficient case by * performing column pivots during the decomposition. The final decomposition has the * following structure:
* A*P=Q*R
* where A is the original matrix, P is a pivot matrix, Q is an orthogonal matrix, and R is * upper triangular. *

* * @author Peter Abeles */ public interface QRPDecomposition extends QRDecomposition { /** *

* Specifies the threshold used to flag a column as being singular. The specified threshold is relative * and will very depending on the system. The default value is UtilEJML.EPS. *

* * @param threshold Singular threshold. */ public void setSingularThreshold( double threshold ); /** * Returns the rank as determined by the algorithm. This is dependent upon a fixed threshold * and might not be appropriate for some applications. * * @return Matrix's rank */ public int getRank(); /** * Ordering of each column after pivoting. The current column i was original at column pivot[i]. * * @return Order of columns. */ public int[] getPivots(); /** * Creates the pivot matrix. * * @param P Optional storage for pivot matrix. If null a new matrix will be created. * @return The pivot matrix. */ public DenseMatrix64F getPivotMatrix( DenseMatrix64F P ); } ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/SingularValueDecomposition.java000066400000000000000000000117101256171534400317430ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Matrix; /** *

* This is an abstract class for computing the singular value decomposition (SVD) of a matrix, which is defined * as:
*

A = U * W * V T

* where A is m by n, and U and V are orthogonal matrices, and W is a diagonal matrix. *

* *

* The dimension of U,W,V depends if it is a compact SVD or not. If not compact then U is m by m, W is m by n, V is n by n. * If compact then let s be the number of singular values, U is m by s, W is s by s, and V is n by s. *

* *

* Accessor functions for decomposed matrices can return an internally constructed matrix if null is passed in for the * optional storage parameter. The exact behavior is implementation specific. If an internally maintained matrix is * returned then on the next call to decompose the matrix will be modified. The advantage of this approach is reduced * memory overhead. *

* *

* To create a new instance of SingularValueDecomposition see {@link org.ejml.factory.DecompositionFactory#svd(int, int, boolean, boolean, boolean)} * and {@link org.ejml.ops.SingularOps} contains additional helpful SVD related functions. *

* *

* *Note* that the ordering of singular values is not guaranteed, unless done so by a specific implementation. * The singular values can be put into descending order while adjusting U and V using {@link org.ejml.ops.SingularOps#descendingOrder(org.ejml.data.DenseMatrix64F, boolean, org.ejml.data.DenseMatrix64F, org.ejml.data.DenseMatrix64F, boolean)} SingularOps.descendingOrder()}. *

* * @author Peter Abeles */ public abstract interface SingularValueDecomposition extends DecompositionInterface { /** * Returns the singular values. This is the diagonal elements of the W matrix in the decomposition. * Ordering of singular values is not guaranteed.. * * @return Singular values. Note this array can be longer than the number of singular values. * Extra elements have no meaning. */ public double [] getSingularValues(); /** * The number of singular values in the matrix. This is equal to the length of the smallest side. * * @return Number of singular values in the matrix. */ public int numberOfSingularValues(); /** * If true then compact matrices are returned. * * @return true if results use compact notation. */ public boolean isCompact(); /** *

* Returns the orthogonal 'U' matrix. *

*

* Internally the SVD algorithm might compute U transposed or it might not. To avoid an * unnecessary double transpose the option is provided to select if the transpose is returned. *

* * @param U Optional storage for U. If null a new instance or internally maintained matrix is returned. Modified. * @param transposed If the returned U is transposed. * @return An orthogonal matrix. */ public T getU( T U , boolean transposed ); /** *

* Returns the orthogonal 'V' matrix. *

* *

* Internally the SVD algorithm might compute V transposed or it might not. To avoid an * unnecessary double transpose the option is provided to select if the transpose is returned. *

* * @param V Optional storage for v. If null a new instance or internally maintained matrix is returned. Modified. * @param transposed If the returned V is transposed. * @return An orthogonal matrix. */ public T getV( T V , boolean transposed ); /** * Returns a diagonal matrix with the singular values. Order of the singular values * is not guaranteed. * * @param W Optional storage for W. If null a new instance or internally maintained matrix is returned. Modified. * @return Diagonal matrix with singular values along the diagonal. */ public T getW( T W ); /** * Number of rows in the decomposed matrix. * @return Number of rows in the decomposed matrix. */ public int numRows(); /** * Number of columns in the decomposed matrix. * @return Number of columns in the decomposed matrix. */ public int numCols(); } ejml-0.28/main/core/src/org/ejml/interfaces/decomposition/TridiagonalSimilarDecomposition.java000066400000000000000000000040561256171534400327450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.decomposition; import org.ejml.data.Matrix; /** *

* Finds the decomposition of a matrix in the form of:
*
* A = O*T*OT
*
* where A is a symmetric m by m matrix, O is an orthogonal matrix, and T is a tridiagonal matrix. *

* * @author Peter Abeles */ public interface TridiagonalSimilarDecomposition extends DecompositionInterface { /** * Extracts the tridiagonal matrix found in the decomposition. * * @param T If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted T matrix. */ public MatrixType getT( MatrixType T ); /** * An orthogonal matrix that has the following property: T = QTAQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public MatrixType getQ( MatrixType Q , boolean transposed ); /** * Extracts the diagonal and off diagonal elements of the decomposed tridiagonal matrix. * Since it is symmetric only one off diagonal array is returned. * * @param diag Diagonal elements. Modified. * @param off off diagonal elements. Modified. */ public void getDiagonal( double []diag, double []off ); } ejml-0.28/main/core/src/org/ejml/interfaces/linsol/000077500000000000000000000000001256171534400222065ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/interfaces/linsol/LinearSolver.java000066400000000000000000000132571256171534400254660ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.linsol; import org.ejml.data.Matrix; import org.ejml.interfaces.decomposition.DecompositionInterface; /** *

* An implementation of LinearSolver solves a linear system or inverts a matrix. It masks more complex * implementation details, while giving the programmer control over memory management and performance. * To quickly detect nearly singular matrices without computing the SVD the {@link #quality()} * function is provided. *

* *

* A linear system is defined as: * A*X = B.
* where A ∈ ℜ m × n, X ∈ ℜ n × p, * B ∈ ℜ m × p. Different implementations can solve different * types and shapes in input matrices and have different memory and runtime performance. *

*

* To solve a system:
*

    *
  1. Call {@link #setA(org.ejml.data.Matrix)} *
  2. Call {@link #solve(org.ejml.data.Matrix, org.ejml.data.Matrix)}. *
*

* *

* To invert a matrix:
*

    *
  1. Call {@link #setA(org.ejml.data.Matrix)} *
  2. Call {@link #invert(org.ejml.data.Matrix)}. *
* A matrix can also be inverted by passing in an identity matrix to solve, but this will be * slower and more memory intensive than the specialized invert() function. *

* *

* IMPORTANT: Depending upon the implementation, input matrices might be overwritten by * the solver. This * reduces memory and computational requirements and give more control to the programmer. If * the input matrices need to be not modified then {@link org.ejml.alg.dense.linsol.LinearSolverSafe} can be used. The * functions {@link #modifiesA()} and {@link #modifiesB()} specify which input matrices are being * modified. *

* * @author Peter Abeles */ public interface LinearSolver< T extends Matrix> { /** *

* Specifies the A matrix in the linear equation. A reference might be saved * and it might also be modified depending on the implementation. If it is modified * then {@link #modifiesA()} will return true. *

* *

* If this value returns true that does not guarantee a valid solution was generated. This * is because some decompositions don't detect singular matrices. *

* * @param A The 'A' matrix in the linear equation. Might be modified or save the reference. * @return true if it can be processed. */ public boolean setA( T A ); /** *

* Returns a very quick to compute measure of how singular the system is. This measure will * be invariant to the scale of the matrix and always be positive, with larger values * indicating it is less singular. If not supported by the solver then the runtime * exception IllegalArgumentException is thrown. This is NOT the matrix's condition. *

* *

* How this function is implemented is not specified. One possible implementation is the following: * In many decompositions a triangular matrix * is extracted. The determinant of a triangular matrix is easily computed and once normalized * to be scale invariant and its absolute value taken it will provide functionality described above. *

* * @return The quality of the linear system. */ public double quality(); /** *

* Solves for X in the linear system, A*X=B. *

*

* In some implementations 'B' and 'X' can be the same instance of a variable. Call * {@link #modifiesB()} to determine if 'B' is modified. *

* * @param B A matrix ℜ m × p. Might be modified. * @param X A matrix ℜ n × p, where the solution is written to. Modified. */ public void solve( T B , T X ); /** * Computes the inverse of of the 'A' matrix passed into {@link #setA(org.ejml.data.Matrix)} * and writes the results to the provided matrix. If 'A_inv' needs to be different from 'A' * is implementation dependent. * * @param A_inv Where the inverted matrix saved. Modified. */ public void invert( T A_inv ); /** * Returns true if the passed in matrix to {@link #setA(org.ejml.data.Matrix)} * is modified. * * @return true if A is modified in setA(). */ public boolean modifiesA(); /** * Returns true if the passed in 'B' matrix to {@link #solve(org.ejml.data.Matrix, org.ejml.data.Matrix)} * is modified. * * @return true if B is modified in solve(B,X). */ public boolean modifiesB(); /** * If a decomposition class was used internally then this will return that class. * Most linear solvers decompose the input matrix into a more simplistic form. * However some solutions do not require decomposition, e.g. inverse by minor. * @param Decomposition type * @return Internal decomposition class. If there is none then null. */ public D getDecomposition(); } ejml-0.28/main/core/src/org/ejml/interfaces/linsol/ReducedRowEchelonForm.java000066400000000000000000000041401256171534400272350ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.interfaces.linsol; import org.ejml.data.RealMatrix64F; /** *

* An augmented system matrix is said to be in reduced row echelon form (RREF) if the following are true: *

* *
    *
  1. If a row has non-zero entries, then the first non-zero entry is 1. This is known as the leading one.
  2. *
  3. If a column contains a leading one then all other entries in that column are zero.
  4. *
  5. If a row contains a leading 1, then each row above contains a leading 1 further to the left.
  6. *
* *

* [1] Page 19 in, Otter Bretscherm "Linear Algebra with Applications" Prentice-Hall Inc, 1997 *

* * @author Peter Abeles */ public interface ReducedRowEchelonForm { /** * Puts the augmented matrix into RREF. The coefficient matrix is stored in * columns less than coefficientColumns. * * * @param A Input: Augmented matrix. Output: RREF. Modified. * @param coefficientColumns Number of coefficients in the system matrix. */ public void reduce( T A , int coefficientColumns ); /** * Specifies tolerance for determining if the system is singular and it should stop processing. * A reasonable value is: tol = EPS/max(||tol||). * * @param tol Tolerance for singular matrix. A reasonable value is: tol = EPS/max(||tol||). Or just set to zero. */ public void setTolerance(double tol); } ejml-0.28/main/core/src/org/ejml/ops/000077500000000000000000000000001256171534400173645ustar00rootroot00000000000000ejml-0.28/main/core/src/org/ejml/ops/ComplexMath64F.java000066400000000000000000000144611256171534400227360ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.Complex64F; import org.ejml.data.ComplexPolar64F; /** * Basic math operations on complex numbers. * * @author Peter Abeles */ public class ComplexMath64F { /** * Complex conjugate * @param input Input complex number * @param conj Complex conjugate of the input number */ public static void conj( Complex64F input , Complex64F conj ) { conj.real = input.real; conj.imaginary = -input.imaginary; } /** *

* Addition: result = a + b *

* * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void plus( Complex64F a , Complex64F b , Complex64F result ) { result.real = a.real + b.real; result.imaginary = a.imaginary + b.imaginary; } /** *

* Subtraction: result = a - b *

* * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void minus( Complex64F a , Complex64F b , Complex64F result ) { result.real = a.real - b.real; result.imaginary = a.imaginary - b.imaginary; } /** *

* Multiplication: result = a * b *

* * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void multiply(Complex64F a, Complex64F b, Complex64F result) { result.real = a.real * b.real - a.imaginary*b.imaginary; result.imaginary = a.real*b.imaginary + a.imaginary*b.real; } /** *

* Division: result = a / b *

* * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void divide(Complex64F a, Complex64F b, Complex64F result) { double norm = b.getMagnitude2(); result.real = (a.real * b.real + a.imaginary*b.imaginary)/norm; result.imaginary = (a.imaginary*b.real - a.real*b.imaginary)/norm; } /** *

* Converts a complex number into polar notation. *

* * @param input Standard notation * @param output Polar notation */ public static void convert( Complex64F input , ComplexPolar64F output ) { output.r = input.getMagnitude(); output.theta = Math.atan2(input.imaginary, input.real); } /** *

* Converts a complex number in polar notation into standard notation. *

* * @param input Standard notation * @param output Polar notation */ public static void convert( ComplexPolar64F input , Complex64F output ) { output.real = input.r*Math.cos(input.theta); output.imaginary = input.r*Math.sin(input.theta); } /** * Division in polar notation. * * @param a Complex number in polar notation. Not modified. * @param b Complex number in polar notation. Not modified. * @param result Storage for output. */ public static void multiply(ComplexPolar64F a, ComplexPolar64F b, ComplexPolar64F result) { result.r = a.r*b.r; result.theta = a.theta + b.theta; } /** * Division in polar notation. * * @param a Complex number in polar notation. Not modified. * @param b Complex number in polar notation. Not modified. * @param result Storage for output. */ public static void divide(ComplexPolar64F a, ComplexPolar64F b, ComplexPolar64F result) { result.r = a.r/b.r; result.theta = a.theta - b.theta; } /** * Computes the power of a complex number in polar notation * * @param a Complex number * @param N Power it is to be multiplied by * @param result Result */ public static void pow( ComplexPolar64F a , int N , ComplexPolar64F result ) { result.r = Math.pow(a.r,N); result.theta = N*a.theta; } /** * Computes the Nth root of a complex number in polar notation. There are * N distinct Nth roots. * * @param a Complex number * @param N The root's magnitude * @param k Specifies which root. 0 ≤ k < N * @param result Computed root */ public static void root( ComplexPolar64F a , int N , int k , ComplexPolar64F result ) { result.r = Math.pow(a.r,1.0/N); result.theta = (a.theta + 2.0*k*Math.PI)/N; } /** * Computes the Nth root of a complex number. There are * N distinct Nth roots. * * @param a Complex number * @param N The root's magnitude * @param k Specifies which root. 0 ≤ k < N * @param result Computed root */ public static void root( Complex64F a , int N , int k , Complex64F result ) { double r = a.getMagnitude(); double theta = Math.atan2(a.imaginary,a.real); r = Math.pow(r,1.0/N); theta = (theta + 2.0*k*Math.PI)/N; result.real = r*Math.cos(theta); result.imaginary = r*Math.sin(theta); } /** * Computes the square root of the complex number. * * @param input Input complex number. * @param root Output. The square root of the input */ public static void sqrt(Complex64F input, Complex64F root) { double r = input.getMagnitude(); double a = input.real; root.real = Math.sqrt((r+a)/2.0); root.imaginary = Math.sqrt((r-a)/2.0); if( input.imaginary < 0 ) root.imaginary = -root.imaginary; } } ejml-0.28/main/core/src/org/ejml/ops/ConvertMatrixType.java000066400000000000000000000653301256171534400237050ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.*; /** * Functions for converting between matrix types. Both matrices must be the same size and their values will * be copied. * * @author Peter Abeles */ public class ConvertMatrixType { /** * Generic, but slow, conversion function. * * @param input Input matrix. * @param output Output matrix. */ public static void convert( RealMatrix64F input , RealMatrix64F output ) { if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); for( int i = 0; i < input.getNumRows(); i++ ) { for( int j = 0; j < input.getNumCols(); j++ ) { output.unsafe_set(i,j,input.unsafe_get(i,j)); } } } /** * Converts {@link FixedMatrix2x2_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix2x2_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(2,2); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.data[0] = input.a11; output.data[1] = input.a12; output.data[2] = input.a21; output.data[3] = input.a22; return output; } /** * Converts {@link FixedMatrix3x3_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix3x3_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(3,3); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.data[0] = input.a11; output.data[1] = input.a12; output.data[2] = input.a13; output.data[3] = input.a21; output.data[4] = input.a22; output.data[5] = input.a23; output.data[6] = input.a31; output.data[7] = input.a32; output.data[8] = input.a33; return output; } /** * Converts {@link FixedMatrix4x4_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix4x4_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(4,4); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.data[0] = input.a11; output.data[1] = input.a12; output.data[2] = input.a13; output.data[3] = input.a14; output.data[4] = input.a21; output.data[5] = input.a22; output.data[6] = input.a23; output.data[7] = input.a24; output.data[8] = input.a31; output.data[9] = input.a32; output.data[10] = input.a33; output.data[11] = input.a34; output.data[12] = input.a41; output.data[13] = input.a42; output.data[14] = input.a43; output.data[15] = input.a44; return output; } /** * Converts {@link FixedMatrix5x5_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix5x5_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(5,5); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.data[0] = input.a11; output.data[1] = input.a12; output.data[2] = input.a13; output.data[3] = input.a14; output.data[4] = input.a15; output.data[5] = input.a21; output.data[6] = input.a22; output.data[7] = input.a23; output.data[8] = input.a24; output.data[9] = input.a25; output.data[10] = input.a31; output.data[11] = input.a32; output.data[12] = input.a33; output.data[13] = input.a34; output.data[14] = input.a35; output.data[15] = input.a41; output.data[16] = input.a42; output.data[17] = input.a43; output.data[18] = input.a44; output.data[19] = input.a45; output.data[20] = input.a51; output.data[21] = input.a52; output.data[22] = input.a53; output.data[23] = input.a54; output.data[24] = input.a55; return output; } /** * Converts {@link FixedMatrix6x6_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix6x6_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(6,6); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.data[0] = input.a11; output.data[1] = input.a12; output.data[2] = input.a13; output.data[3] = input.a14; output.data[4] = input.a15; output.data[5] = input.a16; output.data[6] = input.a21; output.data[7] = input.a22; output.data[8] = input.a23; output.data[9] = input.a24; output.data[10] = input.a25; output.data[11] = input.a26; output.data[12] = input.a31; output.data[13] = input.a32; output.data[14] = input.a33; output.data[15] = input.a34; output.data[16] = input.a35; output.data[17] = input.a36; output.data[18] = input.a41; output.data[19] = input.a42; output.data[20] = input.a43; output.data[21] = input.a44; output.data[22] = input.a45; output.data[23] = input.a46; output.data[24] = input.a51; output.data[25] = input.a52; output.data[26] = input.a53; output.data[27] = input.a54; output.data[28] = input.a55; output.data[29] = input.a56; output.data[30] = input.a61; output.data[31] = input.a62; output.data[32] = input.a63; output.data[33] = input.a64; output.data[34] = input.a65; output.data[35] = input.a66; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix2x2_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix2x2_64F convert( DenseMatrix64F input , FixedMatrix2x2_64F output ) { if( output == null) output = new FixedMatrix2x2_64F(); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.a11 = input.data[0]; output.a12 = input.data[1]; output.a21 = input.data[2]; output.a22 = input.data[3]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix3x3_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix3x3_64F convert( DenseMatrix64F input , FixedMatrix3x3_64F output ) { if( output == null) output = new FixedMatrix3x3_64F(); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.a11 = input.data[0]; output.a12 = input.data[1]; output.a13 = input.data[2]; output.a21 = input.data[3]; output.a22 = input.data[4]; output.a23 = input.data[5]; output.a31 = input.data[6]; output.a32 = input.data[7]; output.a33 = input.data[8]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix4x4_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix4x4_64F convert( DenseMatrix64F input , FixedMatrix4x4_64F output ) { if( output == null) output = new FixedMatrix4x4_64F(); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.a11 = input.data[0]; output.a12 = input.data[1]; output.a13 = input.data[2]; output.a14 = input.data[3]; output.a21 = input.data[4]; output.a22 = input.data[5]; output.a23 = input.data[6]; output.a24 = input.data[7]; output.a31 = input.data[8]; output.a32 = input.data[9]; output.a33 = input.data[10]; output.a34 = input.data[11]; output.a41 = input.data[12]; output.a42 = input.data[13]; output.a43 = input.data[14]; output.a44 = input.data[15]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix5x5_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix5x5_64F convert( DenseMatrix64F input , FixedMatrix5x5_64F output ) { if( output == null) output = new FixedMatrix5x5_64F(); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.a11 = input.data[0]; output.a12 = input.data[1]; output.a13 = input.data[2]; output.a14 = input.data[3]; output.a15 = input.data[4]; output.a21 = input.data[5]; output.a22 = input.data[6]; output.a23 = input.data[7]; output.a24 = input.data[8]; output.a25 = input.data[9]; output.a31 = input.data[10]; output.a32 = input.data[11]; output.a33 = input.data[12]; output.a34 = input.data[13]; output.a35 = input.data[14]; output.a41 = input.data[15]; output.a42 = input.data[16]; output.a43 = input.data[17]; output.a44 = input.data[18]; output.a45 = input.data[19]; output.a51 = input.data[20]; output.a52 = input.data[21]; output.a53 = input.data[22]; output.a54 = input.data[23]; output.a55 = input.data[24]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix6x6_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix6x6_64F convert( DenseMatrix64F input , FixedMatrix6x6_64F output ) { if( output == null) output = new FixedMatrix6x6_64F(); if( input.getNumRows() != output.getNumRows() ) throw new IllegalArgumentException("Number of rows do not match"); if( input.getNumCols() != output.getNumCols() ) throw new IllegalArgumentException("Number of columns do not match"); output.a11 = input.data[0]; output.a12 = input.data[1]; output.a13 = input.data[2]; output.a14 = input.data[3]; output.a15 = input.data[4]; output.a16 = input.data[5]; output.a21 = input.data[6]; output.a22 = input.data[7]; output.a23 = input.data[8]; output.a24 = input.data[9]; output.a25 = input.data[10]; output.a26 = input.data[11]; output.a31 = input.data[12]; output.a32 = input.data[13]; output.a33 = input.data[14]; output.a34 = input.data[15]; output.a35 = input.data[16]; output.a36 = input.data[17]; output.a41 = input.data[18]; output.a42 = input.data[19]; output.a43 = input.data[20]; output.a44 = input.data[21]; output.a45 = input.data[22]; output.a46 = input.data[23]; output.a51 = input.data[24]; output.a52 = input.data[25]; output.a53 = input.data[26]; output.a54 = input.data[27]; output.a55 = input.data[28]; output.a56 = input.data[29]; output.a61 = input.data[30]; output.a62 = input.data[31]; output.a63 = input.data[32]; output.a64 = input.data[33]; output.a65 = input.data[34]; output.a66 = input.data[35]; return output; } /** * Converts {@link FixedMatrix2_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix2_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(2,1); if( output.getNumRows() != 1 && output.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(output.getNumRows(),output.getNumCols()); if( length != 2 ) throw new IllegalArgumentException("Length of input vector is not 2. It is "+length); output.data[0] = input.a1; output.data[1] = input.a2; return output; } /** * Converts {@link FixedMatrix3_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix3_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(3,1); if( output.getNumRows() != 1 && output.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(output.getNumRows(),output.getNumCols()); if( length != 3 ) throw new IllegalArgumentException("Length of input vector is not 3. It is "+length); output.data[0] = input.a1; output.data[1] = input.a2; output.data[2] = input.a3; return output; } /** * Converts {@link FixedMatrix4_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix4_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(4,1); if( output.getNumRows() != 1 && output.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(output.getNumRows(),output.getNumCols()); if( length != 4 ) throw new IllegalArgumentException("Length of input vector is not 4. It is "+length); output.data[0] = input.a1; output.data[1] = input.a2; output.data[2] = input.a3; output.data[3] = input.a4; return output; } /** * Converts {@link FixedMatrix5_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix5_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(5,1); if( output.getNumRows() != 1 && output.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(output.getNumRows(),output.getNumCols()); if( length != 5 ) throw new IllegalArgumentException("Length of input vector is not 5. It is "+length); output.data[0] = input.a1; output.data[1] = input.a2; output.data[2] = input.a3; output.data[3] = input.a4; output.data[4] = input.a5; return output; } /** * Converts {@link FixedMatrix6_64F} into {@link DenseMatrix64F}. * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( FixedMatrix6_64F input , DenseMatrix64F output ) { if( output == null) output = new DenseMatrix64F(6,1); if( output.getNumRows() != 1 && output.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(output.getNumRows(),output.getNumCols()); if( length != 6 ) throw new IllegalArgumentException("Length of input vector is not 6. It is "+length); output.data[0] = input.a1; output.data[1] = input.a2; output.data[2] = input.a3; output.data[3] = input.a4; output.data[4] = input.a5; output.data[5] = input.a6; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix2_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix2_64F convert( DenseMatrix64F input , FixedMatrix2_64F output ) { if( output == null) output = new FixedMatrix2_64F(); if( input.getNumRows() != 1 && input.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(input.getNumRows(),input.getNumCols()); if( length != 2 ) throw new IllegalArgumentException("Length of input vector is not 2. It is "+length); output.a1 = input.data[0]; output.a2 = input.data[1]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix3_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix3_64F convert( DenseMatrix64F input , FixedMatrix3_64F output ) { if( output == null) output = new FixedMatrix3_64F(); if( input.getNumRows() != 1 && input.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(input.getNumRows(),input.getNumCols()); if( length != 3 ) throw new IllegalArgumentException("Length of input vector is not 3. It is "+length); output.a1 = input.data[0]; output.a2 = input.data[1]; output.a3 = input.data[2]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix4_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix4_64F convert( DenseMatrix64F input , FixedMatrix4_64F output ) { if( output == null) output = new FixedMatrix4_64F(); if( input.getNumRows() != 1 && input.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(input.getNumRows(),input.getNumCols()); if( length != 4 ) throw new IllegalArgumentException("Length of input vector is not 4. It is "+length); output.a1 = input.data[0]; output.a2 = input.data[1]; output.a3 = input.data[2]; output.a4 = input.data[3]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix5_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix5_64F convert( DenseMatrix64F input , FixedMatrix5_64F output ) { if( output == null) output = new FixedMatrix5_64F(); if( input.getNumRows() != 1 && input.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(input.getNumRows(),input.getNumCols()); if( length != 5 ) throw new IllegalArgumentException("Length of input vector is not 5. It is "+length); output.a1 = input.data[0]; output.a2 = input.data[1]; output.a3 = input.data[2]; output.a4 = input.data[3]; output.a5 = input.data[4]; return output; } /** * Converts {@link DenseMatrix64F} into {@link FixedMatrix6_64F} * * @param input Input matrix. * @param output Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static FixedMatrix6_64F convert( DenseMatrix64F input , FixedMatrix6_64F output ) { if( output == null) output = new FixedMatrix6_64F(); if( input.getNumRows() != 1 && input.getNumCols() != 1 ) throw new IllegalArgumentException("One row or column must have a length of 1 for it to be a vector"); int length = Math.max(input.getNumRows(),input.getNumCols()); if( length != 6 ) throw new IllegalArgumentException("Length of input vector is not 6. It is "+length); output.a1 = input.data[0]; output.a2 = input.data[1]; output.a3 = input.data[2]; output.a4 = input.data[3]; output.a5 = input.data[4]; output.a6 = input.data[5]; return output; } /** * Converts {@link DenseMatrix64F} into {@link BlockMatrix64F} * * Can't handle null output matrix since block size needs to be specified. * * @param src Input matrix. * @param dst Output matrix. */ public static void convert( DenseMatrix64F src , BlockMatrix64F dst ) { if( src.numRows != dst.numRows || src.numCols != dst.numCols ) throw new IllegalArgumentException("Must be the same size."); for( int i = 0; i < dst.numRows; i += dst.blockLength ) { int blockHeight = Math.min( dst.blockLength , dst.numRows - i); for( int j = 0; j < dst.numCols; j += dst.blockLength ) { int blockWidth = Math.min( dst.blockLength , dst.numCols - j); int indexDst = i*dst.numCols + blockHeight*j; int indexSrcRow = i*dst.numCols + j; for( int k = 0; k < blockHeight; k++ ) { System.arraycopy(src.data,indexSrcRow,dst.data,indexDst,blockWidth); indexDst += blockWidth; indexSrcRow += dst.numCols; } } } } /** * Converts {@link BlockMatrix64F} into {@link DenseMatrix64F} * * @param src Input matrix. * @param dst Output matrix. If null a new matrix will be declared. * @return Converted matrix. */ public static DenseMatrix64F convert( BlockMatrix64F src , DenseMatrix64F dst ) { if( dst != null ) { if( dst.numRows != src.numRows || dst.numCols != src.numCols ) throw new IllegalArgumentException("Must be the same size."); } else { dst = new DenseMatrix64F(src.numRows,src.numCols); } for( int i = 0; i < src.numRows; i += src.blockLength ) { int blockHeight = Math.min( src.blockLength , src.numRows - i); for( int j = 0; j < src.numCols; j += src.blockLength ) { int blockWidth = Math.min( src.blockLength , src.numCols - j); int indexSrc = i*src.numCols + blockHeight*j; int indexDstRow = i*dst.numCols + j; for( int k = 0; k < blockHeight; k++ ) { System.arraycopy(src.data,indexSrc,dst.data,indexDstRow,blockWidth); indexSrc += blockWidth; indexDstRow += dst.numCols; } } } return dst; } } ejml-0.28/main/core/src/org/ejml/ops/MatrixDimensionException.java000066400000000000000000000020321256171534400252150ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; /** * If two matrices did not have compatible dimensions for the operation this exception * is thrown. * * @author Peter Abeles */ public class MatrixDimensionException extends RuntimeException { public MatrixDimensionException(){} public MatrixDimensionException(String message ) { super(message); } } ejml-0.28/main/core/src/org/ejml/ops/MatrixIO.java000066400000000000000000000201671256171534400217310ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.*; import java.io.*; /** * Provides simple to use routines for reading and writing matrices to and from files. * * @author Peter Abeles */ public class MatrixIO { /** * Saves a matrix to disk using Java binary serialization. * * @param A The matrix being saved. * @param fileName Name of the file its being saved at. * @throws java.io.IOException */ public static void saveBin(RealMatrix64F A, String fileName) throws IOException { FileOutputStream fileStream = new FileOutputStream(fileName); ObjectOutputStream stream = new ObjectOutputStream(fileStream); try { stream.writeObject(A); stream.flush(); } finally { // clean up try { stream.close(); } finally { fileStream.close(); } } } /** * Loads a DeneMatrix64F which has been saved to file using Java binary * serialization. * * @param fileName The file being loaded. * @return DenseMatrix64F * @throws IOException */ public static T loadBin(String fileName) throws IOException { FileInputStream fileStream = new FileInputStream(fileName); ObjectInputStream stream = new ObjectInputStream(fileStream); T ret; try { ret = (T)stream.readObject(); if( stream.available() != 0 ) { throw new RuntimeException("File not completely read?"); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } stream.close(); return (T)ret; } /** * Saves a matrix to disk using in a Column Space Value (CSV) format. For a * description of the format see {@link MatrixIO#loadCSV(String)}. * * @param A The matrix being saved. * @param fileName Name of the file its being saved at. * @throws java.io.IOException */ public static void saveCSV( RealMatrix64F A , String fileName ) throws IOException { PrintStream fileStream = new PrintStream(fileName); fileStream.println(A.getNumRows() + " " + A.getNumCols() + " real"); for( int i = 0; i < A.getNumRows(); i++ ) { for( int j = 0; j < A.getNumCols(); j++ ) { fileStream.print(A.get(i,j)+" "); } fileStream.println(); } fileStream.close(); } /** * Reads a matrix in which has been encoded using a Column Space Value (CSV) * file format. The number of rows and columns are read in on the first line. Then * each row is read in the subsequent lines. * * @param fileName The file being loaded. * @return DenseMatrix64F * @throws IOException */ public static DenseMatrix64F loadCSV( String fileName ) throws IOException { FileInputStream fileStream = new FileInputStream(fileName); ReadMatrixCsv csv = new ReadMatrixCsv(fileStream); DenseMatrix64F ret = csv.read(); fileStream.close(); return ret; } /** * Reads a matrix in which has been encoded using a Column Space Value (CSV) * file format. For a description of the format see {@link MatrixIO#loadCSV(String)}. * * @param fileName The file being loaded. * @param numRows number of rows in the matrix. * @param numCols number of columns in the matrix. * @return DenseMatrix64F * @throws IOException */ public static DenseMatrix64F loadCSV( String fileName , int numRows , int numCols ) throws IOException { FileInputStream fileStream = new FileInputStream(fileName); ReadMatrixCsv csv = new ReadMatrixCsv(fileStream); DenseMatrix64F ret = csv.readReal(numRows, numCols); fileStream.close(); return ret; } public static void print( PrintStream out , RealMatrix64F mat ) { print(out,mat,6,3); } public static void print(PrintStream out, RealMatrix64F mat , int numChar , int precision ) { String format = "%"+numChar+"."+precision+"f "; print(out, mat,format); } public static void print(PrintStream out , RealMatrix64F mat , String format ) { String type = ReshapeMatrix.class.isAssignableFrom(mat.getClass()) ? "dense" : "dense fixed"; out.println("Type = "+type+" real , numRows = "+mat.getNumRows()+" , numCols = "+mat.getNumCols()); format += " "; for( int y = 0; y < mat.getNumRows(); y++ ) { for( int x = 0; x < mat.getNumCols(); x++ ) { out.printf(format,mat.get(y,x)); } out.println(); } } public static void print( PrintStream out , RealMatrix32F mat ) { print(out,mat,6,3); } public static void print(PrintStream out, RealMatrix32F mat , int numChar , int precision ) { String format = "%"+numChar+"."+precision+"f "; print(out, mat,format); } public static void print(PrintStream out , RealMatrix32F mat , String format ) { String type = ReshapeMatrix.class.isAssignableFrom(mat.getClass()) ? "dense" : "dense fixed"; out.println("Type = "+type+" , numRows = "+mat.getNumRows()+" , numCols = "+mat.getNumCols()); format += " "; for( int y = 0; y < mat.getNumRows(); y++ ) { for( int x = 0; x < mat.getNumCols(); x++ ) { out.printf(format,mat.get(y,x)); } out.println(); } } public static void print( PrintStream out , RealMatrix64F mat , String format , int row0 , int row1, int col0 , int col1 ) { out.println("Type = submatrix , rows "+row0+" to "+row1+" columns "+col0+" to "+col1); format += " "; for( int y = row0; y < row1; y++ ) { for( int x = col0; x < col1; x++ ) { out.printf(format,mat.get(y,x)); } out.println(); } } public static void print( PrintStream out , ComplexMatrix64F mat ) { print(out,mat,6,3); } public static void print(PrintStream out, ComplexMatrix64F mat , int numChar , int precision ) { String format = "%"+numChar+"."+precision+"f + %"+numChar+"."+precision+"fi"; print(out, mat,format); } public static void print(PrintStream out , ComplexMatrix64F mat , String format ) { String type = "dense"; out.println("Type = "+type+" complex , numRows = "+mat.getNumRows()+" , numCols = "+mat.getNumCols()); format += " "; Complex64F c = new Complex64F(); for( int y = 0; y < mat.getNumRows(); y++ ) { for( int x = 0; x < mat.getNumCols(); x++ ) { mat.get(y,x,c); out.printf(format,c.real,c.imaginary); if( x < mat.getNumCols()-1 ) { out.print(" , "); } } out.println(); } } // public static void main( String []args ) { // Random rand = new Random(234234); // DenseMatrix64F A = RandomMatrices.createRandom(50,70,rand); // // SingularValueDecomposition decomp = DecompositionFactory.svd(); // // decomp.decompose(A); // // displayMatrix(A,"Original"); // displayMatrix(decomp.getU(false),"U"); // displayMatrix(decomp.getV(false),"V"); // displayMatrix(decomp.getW(null),"W"); // } } ejml-0.28/main/core/src/org/ejml/ops/ReadCsv.java000066400000000000000000000107231256171534400215610ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; /** *

* Base class for reading CSV formatted files. CSV stands for column-space-value where text strings are separated * by a space character. The values are typically stored in a human readable format. The encoded text for a single * variable is referred to as a word. *

* *

* Comments are allowed and identified by starting a line with the comment character. The comment character is user * configurable. By default there is no comment character. *

* * @author Peter Abeles */ public class ReadCsv { // if there is a comment character private boolean hasComment = false; // what the comment character is private char comment; // reader for the input stream private BufferedReader in; // number of lines that have been read private int lineNumber = 0; /** * Constructor for ReadCsv * * @param in Where the input comes from. */ public ReadCsv(InputStream in) { this.in = new BufferedReader(new InputStreamReader(in)); } /** * Sets the comment character. All lines that start with this character will be ignored. * * @param comment The new comment character. */ public void setComment(char comment) { hasComment = true; this.comment = comment; } /** * Returns how many lines have been read. * * @return Line number */ public int getLineNumber() { return lineNumber; } /** * Returns the reader that it is using internally. * @return The reader. */ public BufferedReader getReader() { return in; } /** * Finds the next valid line of words in the stream and extracts them. * * @return List of valid words on the line. null if the end of the file has been reached. * @throws java.io.IOException */ protected List extractWords() throws IOException { while( true ) { lineNumber++; String line = in.readLine(); if( line == null ) { return null; } // skip comment lines if( hasComment ) { if( line.charAt(0) == comment ) continue; } // extract the words, which are the variables encoded return parseWords(line); } } /** * Extracts the words from a string. Words are seperated by a space character. * * @param line The line that is being parsed. * @return A list of words contained on the line. */ protected List parseWords(String line) { List words = new ArrayList(); boolean insideWord = !isSpace(line.charAt(0)); int last = 0; for( int i = 0; i < line.length(); i++) { char c = line.charAt(i); if( insideWord ) { // see if its at the end of a word if( isSpace(c)) { words.add( line.substring(last,i) ); insideWord = false; } } else { if( !isSpace(c)) { last = i; insideWord = true; } } } // if the line ended add the final word if( insideWord ) { words.add( line.substring(last)); } return words; } /** * Checks to see if 'c' is a space character or not. * * @param c The character being tested. * @return if it is a space character or not. */ private boolean isSpace(char c) { return c == ' ' || c == '\t'; } } ejml-0.28/main/core/src/org/ejml/ops/ReadMatrixCsv.java000066400000000000000000000101211256171534400227360ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.Matrix; import java.io.IOException; import java.io.InputStream; import java.util.List; /** * Reads in a matrix that is in a column-space-value (CSV) format. * * @author Peter Abeles */ public class ReadMatrixCsv extends ReadCsv { /** * Specifies where input comes from. * * @param in Where the input comes from. */ public ReadMatrixCsv(InputStream in) { super(in); } /** * Reads in a DenseMatrix64F from the IO stream. * @return DenseMatrix64F * @throws IOException If anything goes wrong. */ public M read() throws IOException { List words = extractWords(); if( words.size() != 3 ) throw new IOException("Unexpected number of words on first line."); int numRows = Integer.parseInt(words.get(0)); int numCols = Integer.parseInt(words.get(1)); boolean real = words.get(2).compareToIgnoreCase("real") == 0; if( numRows < 0 || numCols < 0) throw new IOException("Invalid number of rows and/or columns: "+numRows+" "+numCols); if( real ) return (M)readReal(numRows, numCols); else return (M)readComplex(numRows, numCols); } /** * Reads in a DenseMatrix64F from the IO stream where the user specifies the matrix dimensions. * * @param numRows Number of rows in the matrix * @param numCols Number of columns in the matrix * @return DenseMatrix64F * @throws IOException */ public DenseMatrix64F readReal(int numRows, int numCols) throws IOException { DenseMatrix64F A = new DenseMatrix64F(numRows,numCols); for( int i = 0; i < numRows; i++ ) { List words = extractWords(); if( words == null ) throw new IOException("Too few rows found. expected "+numRows+" actual "+i); if( words.size() != numCols ) throw new IOException("Unexpected number of words in column. Found "+words.size()+" expected "+numCols); for( int j = 0; j < numCols; j++ ) { A.set(i,j,Double.parseDouble(words.get(j))); } } return A; } /** * Reads in a CDenseMatrix64F from the IO stream where the user specifies the matrix dimensions. * * @param numRows Number of rows in the matrix * @param numCols Number of columns in the matrix * @return DenseMatrix64F * @throws IOException */ public CDenseMatrix64F readComplex(int numRows, int numCols) throws IOException { CDenseMatrix64F A = new CDenseMatrix64F(numRows,numCols); int wordsCol = numCols*2; for( int i = 0; i < numRows; i++ ) { List words = extractWords(); if( words == null ) throw new IOException("Too few rows found. expected "+numRows+" actual "+i); if( words.size() != wordsCol ) throw new IOException("Unexpected number of words in column. Found "+words.size()+" expected "+wordsCol); for( int j = 0; j < wordsCol; j += 2 ) { double real = Double.parseDouble(words.get(j)); double imaginary = Double.parseDouble(words.get(j+1)); A.set(i, j, real, imaginary); } } return A; } } ejml-0.28/main/core/test/000077500000000000000000000000001256171534400152355ustar00rootroot00000000000000ejml-0.28/main/core/test/org/000077500000000000000000000000001256171534400160245ustar00rootroot00000000000000ejml-0.28/main/core/test/org/ejml/000077500000000000000000000000001256171534400167535ustar00rootroot00000000000000ejml-0.28/main/core/test/org/ejml/TestUtilEjml.java000066400000000000000000000041531256171534400222060ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestUtilEjml { Random rand = new Random(23423); @Test public void max_array() { double a[] = new double[]{-1,2,3,4,5,6,3,4,5,7,8,2,3,-5,-6}; assertTrue(8==UtilEjml.max(a,0,a.length)); assertTrue(5==UtilEjml.max(a,6,3)); } /** * Provide it a couple of different strings to parse. Then compare * the results against the expect answer */ @Test public void testParseMatrix() { String a = "-0.779094 1.682750\n" + " 1.304014 -1.880739\n"; DenseMatrix64F m = UtilEjml.parseMatrix(a,2); assertEquals(2,m.numCols); assertEquals(2,m.numRows); assertEquals(-0.779094 , m.get(0,0) , 1e-5); assertEquals(1.682750 , m.get(0,1) , 1e-5); assertEquals(1.304014 , m.get(1,0) , 1e-5); assertEquals(-1.880739 , m.get(1,1) , 1e-5); // give it a matrix with a space in the first element, see if that screws it up a = " -0.779094 1.682750 5\n" + " 1.304014 -1.880739 8\n"; m = UtilEjml.parseMatrix(a,3); assertEquals(3,m.numCols); assertEquals(2,m.numRows); assertEquals(-0.779094 , m.get(0,0) , 1e-5); } } ejml-0.28/main/core/test/org/ejml/alg/000077500000000000000000000000001256171534400175165ustar00rootroot00000000000000ejml-0.28/main/core/test/org/ejml/alg/dense/000077500000000000000000000000001256171534400206145ustar00rootroot00000000000000ejml-0.28/main/core/test/org/ejml/alg/dense/linsol/000077500000000000000000000000001256171534400221145ustar00rootroot00000000000000ejml-0.28/main/core/test/org/ejml/alg/dense/linsol/TestLinearSolverSafe.java000066400000000000000000000130031256171534400270200ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.ejml.interfaces.linsol.LinearSolver; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestLinearSolverSafe { Random rand = new Random(234); DenseMatrix64F Ainput = new DenseMatrix64F(1,1); DenseMatrix64F Binput = new DenseMatrix64F(1,1); /** * Checks to see if the input matrix is copied after multiple calls. This was an actual bug. */ @Test public void multipleCalls_setA() { DummySolver dummy = new DummySolver(true,false); dummy.expectedA = 5; LinearSolver s = new LinearSolverSafe(dummy); Ainput.set(0,5); s.setA(Ainput); // call it a second time and see if the input matrix has been reset to the // correct value s.setA(Ainput); assertTrue(dummy.passedin != Ainput); } /** * Checks to see if the input matrix is copied after multiple calls. This was an actual bug. */ @Test public void multipleCalls_setB() { DummySolver dummy = new DummySolver(false,true); dummy.expectedB = 5; LinearSolver s = new LinearSolverSafe(dummy); Binput.set(0,5); s.solve(Binput,new DenseMatrix64F(1,1)); // call it a second time and see if the input matrix has been reset to the // correct value s.solve(Binput,new DenseMatrix64F(1,1)); assertTrue(dummy.passedin != Ainput); } @Test public void testSetA_notMod() { DummySolver dummy = new DummySolver(false,false); LinearSolver s = new LinearSolverSafe(dummy); s.setA(Ainput); assertTrue(dummy.passedin == Ainput); } @Test public void testSetA_mod() { DummySolver dummy = new DummySolver(true,false); LinearSolver s = new LinearSolverSafe(dummy); s.setA(Ainput); assertTrue(dummy.passedin != Ainput); } @Test public void testSolver_notMod() { DummySolver dummy = new DummySolver(false,false); LinearSolver s = new LinearSolverSafe(dummy); s.solve(Binput,new DenseMatrix64F(1,1)); assertTrue(dummy.passedin == Binput); } @Test public void testSolver_mod() { DummySolver dummy = new DummySolver(false,true); LinearSolver s = new LinearSolverSafe(dummy); s.solve(Binput,new DenseMatrix64F(1,1)); assertTrue(dummy.passedin != Binput); } @Test public void quality() { DummySolver dummy = new DummySolver(false,false); LinearSolver s = new LinearSolverSafe(dummy); assertTrue(s.quality()==dummy.quality()); } @Test public void modifies() { LinearSolver s = new LinearSolverSafe(null); assertFalse(s.modifiesA()); assertFalse(s.modifiesB()); } private class DummySolver implements LinearSolver { boolean modifiesA; boolean modifiesB; DenseMatrix64F passedin; // the expected value of the input matrix double expectedA = Double.NaN; double expectedB = Double.NaN; private DummySolver(boolean modifiesA, boolean modifiesB) { this.modifiesA = modifiesA; this.modifiesB = modifiesB; } @Override public boolean setA(DenseMatrix64F A) { passedin = A; // the input matrix has an expected input value if( !Double.isNaN(expectedA)) assertEquals(expectedA,A.get(0),1e-8); if( modifiesA ) { A.set(0,0,rand.nextDouble()); } return true; } @Override public double quality() { return 1.1; } @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { passedin = B; // the input matrix has an expected input value if( !Double.isNaN(expectedB)) assertEquals(expectedB,B.get(0),1e-8); if( modifiesB ) { B.set(0,0,rand.nextDouble()); } } @Override public void invert(DenseMatrix64F A_inv) { } @Override public boolean modifiesA() { return modifiesA; } @Override public boolean modifiesB() { return modifiesB; } @Override public D getDecomposition() { return null; } } } ejml-0.28/main/core/test/org/ejml/data/000077500000000000000000000000001256171534400176645ustar00rootroot00000000000000ejml-0.28/main/core/test/org/ejml/data/GenericTestsD1Matrix32F.java000066400000000000000000000033051256171534400247540ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public abstract class GenericTestsD1Matrix32F extends GenericTestsMatrix32F { protected abstract D1Matrix32F createMatrix( int numRows , int numCols ); public void allTests() { super.allTests(); testReshape(); testSetAndGet_1D(); } public void testReshape() { D1Matrix32F mat = createMatrix(3,2); float []origData = mat.getData(); mat.reshape(6,1, false); assertTrue(origData == mat.getData()); assertEquals(1,mat.getNumCols()); assertEquals(6,mat.getNumRows()); } public void testSetAndGet_1D() { D1Matrix32F mat = createMatrix(3,4); int indexA = mat.getIndex(1,2); int indexB = mat.getIndex(2,1); assertTrue(indexA!=indexB); mat.set(indexA,2.0f); assertEquals(0,mat.get(indexB),1e-6); assertEquals(2,mat.get(indexA),1e-6); } }ejml-0.28/main/core/test/org/ejml/data/GenericTestsD1Matrix64F.java000066400000000000000000000033051256171534400247610ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public abstract class GenericTestsD1Matrix64F extends GenericTestsMatrix64F { protected abstract D1Matrix64F createMatrix( int numRows , int numCols ); public void allTests() { super.allTests(); testReshape(); testSetAndGet_1D(); } public void testReshape() { D1Matrix64F mat = createMatrix(3,2); double []origData = mat.getData(); mat.reshape(6,1, false); assertTrue(origData == mat.getData()); assertEquals(1,mat.getNumCols()); assertEquals(6,mat.getNumRows()); } public void testSetAndGet_1D() { D1Matrix64F mat = createMatrix(3,4); int indexA = mat.getIndex(1,2); int indexB = mat.getIndex(2,1); assertTrue(indexA!=indexB); mat.set(indexA,2.0); assertEquals(0,mat.get(indexB),1e-6); assertEquals(2,mat.get(indexA),1e-6); } }ejml-0.28/main/core/test/org/ejml/data/GenericTestsMatrix32F.java000066400000000000000000000056701256171534400245760ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public abstract class GenericTestsMatrix32F { protected abstract RealMatrix32F createMatrix( int numRows , int numCols ); public void allTests() { testGetNumRows(); testGetNumCols(); testSetAndGet_2D(); testSetAndGet_2D_unsafe(); } public void testGetNumRows() { RealMatrix32F mat = createMatrix(2,3); assertEquals(2,mat.getNumRows()); } public void testGetNumCols() { RealMatrix32F mat = createMatrix(2,3); assertEquals(3,mat.getNumCols()); } public void testSetAndGet_2D() { // test a variety of different shapes. Added rigor needed // to properly test block matrix. checkSetAndGet(10, 12); checkSetAndGet(12, 10); checkSetAndGet(10, 10); checkSetAndGet(19, 5); checkSetAndGet(5, 19); checkSetAndGet(19, 19); } private void checkSetAndGet(int m, int n) { RealMatrix32F mat = createMatrix(m, n); for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { mat.set(i,j, i* m +j); } } for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { double found = mat.get(i,j); assertEquals(i* m +j,found,1e-8); } } } public void testSetAndGet_2D_unsafe() { // test a variety of different shapes. Added rigor needed // to properly test block matrix. checkSetAndGet_unsafe(10, 12); checkSetAndGet_unsafe(12, 10); checkSetAndGet_unsafe(10, 10); checkSetAndGet_unsafe(19, 5); checkSetAndGet_unsafe(5, 19); checkSetAndGet_unsafe(19, 19); } private void checkSetAndGet_unsafe(int m, int n) { RealMatrix32F mat = createMatrix(m, n); for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { mat.unsafe_set(i,j, i* m +j); } } for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { double found = mat.unsafe_get(i,j); assertEquals(i* m +j,found,1e-8); } } } } ejml-0.28/main/core/test/org/ejml/data/GenericTestsMatrix64F.java000066400000000000000000000056701256171534400246030ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public abstract class GenericTestsMatrix64F { protected abstract RealMatrix64F createMatrix( int numRows , int numCols ); public void allTests() { testGetNumRows(); testGetNumCols(); testSetAndGet_2D(); testSetAndGet_2D_unsafe(); } public void testGetNumRows() { RealMatrix64F mat = createMatrix(2,3); assertEquals(2,mat.getNumRows()); } public void testGetNumCols() { RealMatrix64F mat = createMatrix(2,3); assertEquals(3,mat.getNumCols()); } public void testSetAndGet_2D() { // test a variety of different shapes. Added rigor needed // to properly test block matrix. checkSetAndGet(10, 12); checkSetAndGet(12, 10); checkSetAndGet(10, 10); checkSetAndGet(19, 5); checkSetAndGet(5, 19); checkSetAndGet(19, 19); } private void checkSetAndGet(int m, int n) { RealMatrix64F mat = createMatrix(m, n); for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { mat.set(i,j, i* m +j); } } for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { double found = mat.get(i,j); assertEquals(i* m +j,found,1e-8); } } } public void testSetAndGet_2D_unsafe() { // test a variety of different shapes. Added rigor needed // to properly test block matrix. checkSetAndGet_unsafe(10, 12); checkSetAndGet_unsafe(12, 10); checkSetAndGet_unsafe(10, 10); checkSetAndGet_unsafe(19, 5); checkSetAndGet_unsafe(5, 19); checkSetAndGet_unsafe(19, 19); } private void checkSetAndGet_unsafe(int m, int n) { RealMatrix64F mat = createMatrix(m, n); for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { mat.unsafe_set(i,j, i* m +j); } } for( int i = 0; i < m; i++ ) { for( int j = 0; j < n; j++ ) { double found = mat.unsafe_get(i,j); assertEquals(i* m +j,found,1e-8); } } } } ejml-0.28/main/core/test/org/ejml/data/TestBlockMatrix64F.java000066400000000000000000000021441256171534400240670ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.junit.Test; /** * @author Peter Abeles */ public class TestBlockMatrix64F { @Test public void testGeneric() { GenericTestsD1Matrix64F g; g = new GenericTestsD1Matrix64F() { protected D1Matrix64F createMatrix(int numRows, int numCols) { return new BlockMatrix64F(numRows,numCols,10); } }; g.allTests(); } } ejml-0.28/main/core/test/org/ejml/data/TestCD1Matrix64F.java000066400000000000000000000034271256171534400234110ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestCD1Matrix64F { @Test public void set_matrix() { CD1Matrix64F a = new CDenseMatrix64F(3,4); a.set(1,3,9,2); CD1Matrix64F b = new CDenseMatrix64F(3,4); b.set(a); for (int i = 0; i < a.getDataLength(); i++) { assertEquals(a.data[i],b.data[i],1e-8); } assertEquals(9, b.getReal(1, 3), 1e-8); } @Test public void getNumRows() { CD1Matrix64F a = new CDenseMatrix64F(3,4); assertEquals(3,a.getNumRows()); } @Test public void getNumCols() { CD1Matrix64F a = new CDenseMatrix64F(3,4); assertEquals(4,a.getNumCols()); } @Test public void setNumRows() { CD1Matrix64F a = new CDenseMatrix64F(3,4); a.setNumRows(6); assertEquals(6, a.getNumRows()); } @Test public void setNumCols() { CD1Matrix64F a = new CDenseMatrix64F(3,4); a.setNumCols(6); assertEquals(6,a.getNumCols()); } }ejml-0.28/main/core/test/org/ejml/data/TestCDenseMatrix64F.java000066400000000000000000000117101256171534400241750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCDenseMatrix64F { Random rand = new Random(234); @Test public void constructor_darray() { CDenseMatrix64F a = new CDenseMatrix64F(new double[][]{{1,2,3,4},{5,6,7,8},{5,6,7,8}}); CDenseMatrix64F b = new CDenseMatrix64F(3,2,true,1,2,3,4,5,6,7,8,5,6,7,8); EjmlUnitTests.assertEquals(a, b, 1e-8); } @Test public void constructor_cmatrix() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.set(1,3,9,2); CDenseMatrix64F b = new CDenseMatrix64F(a); for (int i = 0; i < a.getDataLength(); i++) { assertEquals(a.data[i],b.data[i],1e-8); } } @Test public void constructor_shape() { CDenseMatrix64F a = new CDenseMatrix64F(5,7); assertEquals(5,a.numRows); assertEquals(7,a.numCols); assertEquals(5*7*2,a.data.length); } @Test public void getIndex() { CDenseMatrix64F a = new CDenseMatrix64F(5,7); assertEquals(2*14+6,a.getIndex(2,3)); } @Test public void reshape() { CDenseMatrix64F a = new CDenseMatrix64F(5,7); assertEquals(5*7*2,a.data.length); assertEquals(5, a.numRows); assertEquals(7,a.numCols); // make it larger a.reshape(10,6); assertEquals(10*6*2,a.data.length); assertEquals(10,a.numRows); assertEquals(6,a.numCols); // make it smaller a.reshape(3,2); assertTrue(a.data.length > 3*2*2); assertEquals(3,a.numRows); assertEquals(2,a.numCols); } @Test public void get() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.data[2*4*2 + 2] = 5; a.data[2*4*2 + 3] = 6; Complex64F c = new Complex64F(); a.get(2,1,c); assertEquals(c.real,5,1e-8); assertEquals(c.imaginary, 6, 1e-8); } @Test public void set_rowcolumn() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.set(2, 1, 5, 6); assertEquals(5,a.data[2*4*2+2],1e-8); assertEquals(6,a.data[2*4*2+3],1e-8); } @Test public void getReal() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.data[2*4*2 + 2] = 5; a.data[2*4*2 + 3] = 6; Complex64F c = new Complex64F(); a.get(2,1,c); assertEquals(a.getReal(2, 1), 5, 1e-8); } @Test public void setReal() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.setReal(2,1,5); assertEquals(5, a.data[2 * 4 * 2 + 2], 1e-8); } @Test public void getImaginary() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.data[2*4*2 + 2] = 5; a.data[2*4*2 + 3] = 6; Complex64F c = new Complex64F(); a.get(2,1,c); assertEquals(a.getImaginary(2, 1), 6, 1e-8); } @Test public void setImaginary() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.setImaginary(2, 1, 6); assertEquals(6, a.data[2 * 4 * 2 + 3], 1e-8); } @Test public void getDataLength() { assertEquals(3*4*2,new CDenseMatrix64F(3,4).getDataLength()); } @Test public void copy() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); a.set(1, 3, 9, 2); CDenseMatrix64F b = a.copy(); for (int i = 0; i < a.getDataLength(); i++) { assertEquals(a.data[i],b.data[i],1e-8); } } @Test public void getRowStride() { CDenseMatrix64F a = new CDenseMatrix64F(3,4); assertEquals(4*2,a.getRowStride()); } @Test public void set_array() { CDenseMatrix64F A = CRandomMatrices.createRandom(3,4,rand); CDenseMatrix64F B = new CDenseMatrix64F(1,1); B.set(3,4,true,A.data); assertTrue(CMatrixFeatures.isEquals(A,B)); CDenseMatrix64F A_tran = new CDenseMatrix64F(4,3); CCommonOps.transpose(A,A_tran); B.set(3,4,false,A_tran.data); assertTrue(CMatrixFeatures.isEquals(A,B)); } } ejml-0.28/main/core/test/org/ejml/data/TestD1Submatrix64F.java000066400000000000000000000035001256171534400240100ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestD1Submatrix64F { Random rand = new Random(234234); @Test public void get() { DenseMatrix64F A = RandomMatrices.createRandom(5,10,-1,1,rand); D1Submatrix64F S = new D1Submatrix64F(A,2,4,1,10); assertEquals(A.get(3,2),S.get(1,1),1e-8); } @Test public void set() { DenseMatrix64F A = RandomMatrices.createRandom(5,10,-1,1,rand); D1Submatrix64F S = new D1Submatrix64F(A,2,4,1,10); S.set(1,1,5); assertEquals(A.get(3,2),5,1e-8); } @Test public void extract() { DenseMatrix64F A = RandomMatrices.createRandom(5,10,-1,1,rand); D1Submatrix64F S = new D1Submatrix64F(A,2,4,1,10); DenseMatrix64F M = S.extract(); DenseMatrix64F E = CommonOps.extract(A,2,4,1,10); assertTrue(MatrixFeatures.isEquals(E,M)); } } ejml-0.28/main/core/test/org/ejml/data/TestDenseMatrix32F.java000066400000000000000000000145661256171534400241010ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.EjmlParameters; import org.ejml.ops.EjmlUnitTests; import org.junit.Ignore; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestDenseMatrix32F { Random rand = new Random(23432); @Test public void testGeneric() { GenericTestsD1Matrix32F g; g = new GenericTestsD1Matrix32F() { protected D1Matrix32F createMatrix(int numRows, int numCols) { return new DenseMatrix32F(numRows,numCols); } }; g.allTests(); } /** * Tests the following constructor: * * DenseMatrix32F( float data[] , int numCols , int numRows ) */ @Test public void testConstructorSingleArray() { float d[] = new float[]{1,2,3,4,5,6}; DenseMatrix32F mat = new DenseMatrix32F(3,2, true, d); assertTrue( mat.data != d ); assertEquals(1,mat.get(0,0),1e-8); assertEquals(2,mat.get(0,1),1e-8); assertEquals(3,mat.get(1,0),1e-8); assertEquals(4,mat.get(1,1),1e-8); assertEquals(5,mat.get(2,0),1e-8); assertEquals(6,mat.get(2,1),1e-8); } /** * Tests the following constructor: * * DenseMatrix32F( float data[][] ) */ @Test public void testConstruactorfloatArray() { float d[][] = new float[][]{{1,2},{3,4},{5,6}}; DenseMatrix32F mat = new DenseMatrix32F(d); assertEquals(1,mat.get(0,0),1e-8); assertEquals(2,mat.get(0,1),1e-8); assertEquals(3,mat.get(1,0),1e-8); assertEquals(4,mat.get(1,1),1e-8); assertEquals(5,mat.get(2,0),1e-8); assertEquals(6,mat.get(2,1),1e-8); } /** * Tests the following constructor: * * DenseMatrix32F( int numCols , int numRows ) */ @Test public void testConstructorShape() { DenseMatrix32F mat = new DenseMatrix32F(7,5); assertEquals(5,mat.getNumCols()); assertEquals(7,mat.getNumRows()); assertEquals(7*5,mat.data.length); } /** * Tests the following constructor: * * DenseMatrix32F( DenseMatrix32F orig ) */ @Test public void testConstructorCopy() { float d[][] = new float[][]{{1,2},{3,4},{5,6}}; DenseMatrix32F mat = new DenseMatrix32F(d); DenseMatrix32F copy = new DenseMatrix32F(mat); assertTrue( mat.data != copy.data ); assertEquals(mat.getNumCols(),copy.getNumCols()); assertEquals(mat.getNumRows(),copy.getNumRows()); for( int i = 0; i < mat.getNumElements(); i++ ) { assertEquals(mat.get(i),copy.get(i),EjmlParameters.TOL32); } } @Test public void wrap() { float d[] = new float[]{1,2,3,4,5,6}; DenseMatrix32F mat = DenseMatrix32F.wrap(3,2,d); assertTrue(mat.data==d); assertEquals(1,mat.get(0,0),1e-8); assertEquals(2,mat.get(0,1),1e-8); assertEquals(3,mat.get(1,0),1e-8); assertEquals(4,mat.get(1,1),1e-8); assertEquals(5,mat.get(2,0),1e-8); assertEquals(6,mat.get(2,1),1e-8); } @Test public void testInBounds() { DenseMatrix32F mat = new DenseMatrix32F(2,3); assertTrue(mat.isInBounds(0,0)); assertTrue(mat.isInBounds(1,2)); assertTrue(mat.isInBounds(0,2)); assertFalse(mat.isInBounds(2,0)); assertFalse(mat.isInBounds(20,30)); } @Test public void testSet_Matrix() { float d[][] = new float[][]{{1,2},{3,4},{5,6}}; DenseMatrix32F mat = new DenseMatrix32F(d); DenseMatrix32F mat2 = new DenseMatrix32F(mat.numRows,mat.numCols); mat2.set(mat); EjmlUnitTests.assertEquals(mat,mat2,EjmlParameters.TOL32); } @Test @Ignore public void set_ColumnMajor() { // todo implement later after basic 32bit operations are done fail("implement"); // DenseMatrix32F A = UtilTestMatrix.random32(3,5,-1,1,rand); // // DenseMatrix32F Atran = A.copy(); // CommonOps.transpose(Atran); // DenseMatrix32F Afound = new DenseMatrix32F(3,5); // Afound.set(3,5, false, Atran.data); // // assertTrue(MatrixFeatures.isIdentical(Afound,A,EjmlParameters.TOL32)); } @Test @Ignore public void set_RowMajor() { // todo implement later after basic 32bit operations are done fail("implement"); // DenseMatrix32F A = UtilTestMatrix.random32(3, 5, -1, 1, rand); // // DenseMatrix32F Afound = new DenseMatrix32F(3,5); // Afound.set(3,5, true, A.data); // // assertTrue(MatrixFeatures.isIdentical(Afound,A,EjmlParameters.TOL32)); // assertTrue(A.data != Afound.data); } @Test public void testset_Matrix() { float d[][] = new float[][]{{1,2},{3,4},{5,6}}; DenseMatrix32F mat = new DenseMatrix32F(d); DenseMatrix32F mat2 = new DenseMatrix32F(5,5); mat2.set(mat); assertEquals(mat.getNumCols(),mat2.getNumCols()); assertEquals(mat.getNumRows(),mat2.getNumRows()); EjmlUnitTests.assertEquals(mat,mat2, EjmlParameters.TOL32); } @Test public void testReshape() { float d[][] = new float[][]{{1,2},{3,4},{5,6}}; DenseMatrix32F mat = new DenseMatrix32F(d); DenseMatrix32F orig = mat.copy(); // first see if reshape saves the data mat.reshape(10,10,true); for( int i = 0; i < 6; i++ ) { assertEquals(mat.data[i],orig.data[i],EjmlParameters.TOL32); } // now make sure it doesn't mat.reshape(11,10,false); for( int i = 0; i < 6; i++ ) { assertTrue(Math.abs(mat.data[i]-orig.data[i])>EjmlParameters.TOL32); } } } ejml-0.28/main/core/test/org/ejml/data/TestDenseMatrix64F.java000066400000000000000000000141131256171534400240720ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestDenseMatrix64F { Random rand = new Random(23432); @Test public void testGeneric() { GenericTestsD1Matrix64F g; g = new GenericTestsD1Matrix64F() { protected D1Matrix64F createMatrix(int numRows, int numCols) { return new DenseMatrix64F(numRows,numCols); } }; g.allTests(); } /** * Tests the following constructor: * * DenseMatrix64F( double data[] , int numCols , int numRows ) */ @Test public void testConstructorSingleArray() { double d[] = new double[]{1,2,3,4,5,6}; DenseMatrix64F mat = new DenseMatrix64F(3,2, true, d); assertTrue( mat.data != d ); assertEquals(1,mat.get(0,0),1e-8); assertEquals(2,mat.get(0,1),1e-8); assertEquals(3,mat.get(1,0),1e-8); assertEquals(4,mat.get(1,1),1e-8); assertEquals(5,mat.get(2,0),1e-8); assertEquals(6,mat.get(2,1),1e-8); } /** * Tests the following constructor: * * DenseMatrix64F( double data[][] ) */ @Test public void testConstruactorDoubleArray() { double d[][] = new double[][]{{1,2},{3,4},{5,6}}; DenseMatrix64F mat = new DenseMatrix64F(d); assertEquals(1,mat.get(0,0),1e-8); assertEquals(2,mat.get(0,1),1e-8); assertEquals(3,mat.get(1,0),1e-8); assertEquals(4,mat.get(1,1),1e-8); assertEquals(5,mat.get(2,0),1e-8); assertEquals(6,mat.get(2,1),1e-8); } /** * Tests the following constructor: * * DenseMatrix64F( int numCols , int numRows ) */ @Test public void testConstructorShape() { DenseMatrix64F mat = new DenseMatrix64F(7,5); assertEquals(5,mat.getNumCols()); assertEquals(7,mat.getNumRows()); assertEquals(7*5,mat.data.length); } /** * Tests the following constructor: * * DenseMatrix64F( DenseMatrix64F orig ) */ @Test public void testConstructorCopy() { double d[][] = new double[][]{{1,2},{3,4},{5,6}}; DenseMatrix64F mat = new DenseMatrix64F(d); DenseMatrix64F copy = new DenseMatrix64F(mat); assertTrue( mat.data != copy.data ); assertEquals(mat.getNumCols(),copy.getNumCols()); assertEquals(mat.getNumRows(),copy.getNumRows()); for( int i = 0; i < mat.getNumElements(); i++ ) { assertEquals(mat.get(i),copy.get(i),1e-10); } } @Test public void wrap() { double d[] = new double[]{1,2,3,4,5,6}; DenseMatrix64F mat = DenseMatrix64F.wrap(3,2,d); assertTrue(mat.data==d); assertEquals(1,mat.get(0,0),1e-8); assertEquals(2,mat.get(0,1),1e-8); assertEquals(3,mat.get(1,0),1e-8); assertEquals(4,mat.get(1,1),1e-8); assertEquals(5,mat.get(2,0),1e-8); assertEquals(6,mat.get(2,1),1e-8); } @Test public void testInBounds() { DenseMatrix64F mat = new DenseMatrix64F(2,3); assertTrue(mat.isInBounds(0,0)); assertTrue(mat.isInBounds(1,2)); assertTrue(mat.isInBounds(0,2)); assertFalse(mat.isInBounds(2,0)); assertFalse(mat.isInBounds(20,30)); } @Test public void testSet_Matrix() { double d[][] = new double[][]{{1,2},{3,4},{5,6}}; DenseMatrix64F mat = new DenseMatrix64F(d); DenseMatrix64F mat2 = new DenseMatrix64F(mat.numRows,mat.numCols); mat2.set(mat); EjmlUnitTests.assertEquals(mat,mat2,1e-10); } @Test public void set_ColumnMajor() { DenseMatrix64F A = RandomMatrices.createRandom(3,5,rand); DenseMatrix64F Atran = A.copy(); CommonOps.transpose(Atran); DenseMatrix64F Afound = new DenseMatrix64F(3,5); Afound.set(3,5, false, Atran.data); assertTrue(MatrixFeatures.isIdentical(Afound,A,1e-10)); } @Test public void set_RowMajor() { DenseMatrix64F A = RandomMatrices.createRandom(3,5,rand); DenseMatrix64F Afound = new DenseMatrix64F(3,5); Afound.set(3,5, true, A.data); assertTrue(MatrixFeatures.isIdentical(Afound,A,1e-10)); assertTrue(A.data != Afound.data); } @Test public void testset_Matrix() { double d[][] = new double[][]{{1,2},{3,4},{5,6}}; DenseMatrix64F mat = new DenseMatrix64F(d); DenseMatrix64F mat2 = new DenseMatrix64F(5,5); mat2.set(mat); assertEquals(mat.getNumCols(),mat2.getNumCols()); assertEquals(mat.getNumRows(),mat2.getNumRows()); EjmlUnitTests.assertEquals(mat,mat2,1e-10); } @Test public void testReshape() { double d[][] = new double[][]{{1,2},{3,4},{5,6}}; DenseMatrix64F mat = new DenseMatrix64F(d); DenseMatrix64F orig = mat.copy(); // first see if reshape saves the data mat.reshape(10,10,true); for( int i = 0; i < 6; i++ ) { assertEquals(mat.data[i],orig.data[i],1e-8); } // now make sure it doesn't mat.reshape(11,10,false); for( int i = 0; i < 6; i++ ) { assertTrue(Math.abs(mat.data[i]-orig.data[i])>1e-8); } } } ejml-0.28/main/core/test/org/ejml/data/TestMatrixIterator32F.java000066400000000000000000000055361256171534400246310ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.EjmlParameters; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestMatrixIterator32F { Random rand = new Random(234234); @Test public void allRow() { DenseMatrix32F A = UtilTestMatrix.random32(3, 6, -1, 1, rand); MatrixIterator32F iter = A.iterator(true,0, 0, A.numRows-1, A.numCols-1); for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(),EjmlParameters.TOL32); } } assertTrue(!iter.hasNext()); } @Test public void allCol() { DenseMatrix32F A = UtilTestMatrix.random32(3, 6,-1,1, rand); MatrixIterator32F iter = A.iterator(false,0, 0, A.numRows-1, A.numCols-1); for( int j = 0; j < A.numCols; j++ ) { for( int i = 0; i < A.numRows; i++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(),EjmlParameters.TOL32); } } assertTrue(!iter.hasNext()); } @Test public void subRow() { DenseMatrix32F A = UtilTestMatrix.random32(3, 6, -1,1,rand); MatrixIterator32F iter = A.iterator(true,1, 2 , A.numRows-2, A.numCols-1); for( int i = 1; i < A.numRows-1; i++ ) { for( int j = 2; j < A.numCols; j++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(),EjmlParameters.TOL32); } } assertTrue(!iter.hasNext()); } @Test public void subCol() { DenseMatrix32F A = UtilTestMatrix.random32(3, 6,-1,1,rand); MatrixIterator32F iter = A.iterator(false,1, 2 , A.numRows-2, A.numCols-1); for( int j = 2; j < A.numCols; j++ ) { for( int i = 1; i < A.numRows-1; i++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(), EjmlParameters.TOL32); } } assertTrue(!iter.hasNext()); } } ejml-0.28/main/core/test/org/ejml/data/TestMatrixIterator64F.java000066400000000000000000000054241256171534400246320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestMatrixIterator64F { Random rand = new Random(234234); @Test public void allRow() { DenseMatrix64F A = RandomMatrices.createRandom(3,6,rand); MatrixIterator64F iter = A.iterator(true,0, 0, A.numRows-1, A.numCols-1); for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(),1e-8); } } assertTrue(!iter.hasNext()); } @Test public void allCol() { DenseMatrix64F A = RandomMatrices.createRandom(3,6,rand); MatrixIterator64F iter = A.iterator(false,0, 0, A.numRows-1, A.numCols-1); for( int j = 0; j < A.numCols; j++ ) { for( int i = 0; i < A.numRows; i++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(),1e-8); } } assertTrue(!iter.hasNext()); } @Test public void subRow() { DenseMatrix64F A = RandomMatrices.createRandom(3,6,rand); MatrixIterator64F iter = A.iterator(true,1, 2 , A.numRows-2, A.numCols-1); for( int i = 1; i < A.numRows-1; i++ ) { for( int j = 2; j < A.numCols; j++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(),1e-8); } } assertTrue(!iter.hasNext()); } @Test public void subCol() { DenseMatrix64F A = RandomMatrices.createRandom(3,6,rand); MatrixIterator64F iter = A.iterator(false,1, 2 , A.numRows-2, A.numCols-1); for( int j = 2; j < A.numCols; j++ ) { for( int i = 1; i < A.numRows-1; i++ ) { assertTrue(iter.hasNext()); assertEquals(A.get(i,j),iter.next(),1e-8); } } assertTrue(!iter.hasNext()); } } ejml-0.28/main/core/test/org/ejml/data/UtilTestMatrix.java000066400000000000000000000067041256171534400235000ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import java.util.Arrays; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** * Contains functions useful for testing the results of matrices * * @author Peter Abeles */ public class UtilTestMatrix { public static void checkMat( DenseMatrix64F mat , double ...d ) { double data[] = mat.getData(); for( int i = 0; i < mat.getNumElements(); i++ ) { assertEquals(d[i],data[i],1e-6); } } public static void checkSameElements( double tol, int length , double a[], double b[] ) { double aa[] = new double[ length ]; double bb[] = new double[ length ]; System.arraycopy(a,0,aa,0,length); System.arraycopy(b,0,bb,0,length); Arrays.sort(aa); Arrays.sort(bb); for( int i = 0; i < length; i++ ) { if( Math.abs(aa[i]-bb[i])> tol ) fail("Mismatched elements"); } } public static void checkNumFound( int expected , double tol , double value , double data[] ) { int numFound = 0; for( int i = 0; i < data.length; i++ ) { if( Math.abs(data[i]-value) <= tol ) numFound++; } assertEquals(expected,numFound); } /** *

* Sets each element in the matrix to a value drawn from an uniform distribution from 'min' to 'max' inclusive. *

* * @param min The minimum value each element can be. * @param max The maximum value each element can be. * @param rand Random number generator used to fill the matrix. */ public static DenseMatrix64F random64( int numRows , int numCols , double min , double max , Random rand ) { DenseMatrix64F mat = new DenseMatrix64F(numRows,numCols); double d[] = mat.getData(); int size = mat.getNumElements(); double r = max-min; for( int i = 0; i < size; i++ ) { d[i] = r*rand.nextDouble()+min; } return mat; } /** *

* Sets each element in the matrix to a value drawn from an uniform distribution from 'min' to 'max' inclusive. *

* * @param min The minimum value each element can be. * @param max The maximum value each element can be. * @param rand Random number generator used to fill the matrix. */ public static DenseMatrix32F random32( int numRows , int numCols , float min , float max , Random rand ) { DenseMatrix32F mat = new DenseMatrix32F(numRows,numCols); float d[] = mat.getData(); int size = mat.getNumElements(); float r = max-min; for( int i = 0; i < size; i++ ) { d[i] = r*rand.nextFloat()+min; } return mat; } } ejml-0.28/main/core/test/org/ejml/ops/000077500000000000000000000000001256171534400175545ustar00rootroot00000000000000ejml-0.28/main/core/test/org/ejml/ops/TestComplexMath64F.java000066400000000000000000000145671256171534400237750ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.Complex64F; import org.ejml.data.ComplexPolar64F; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestComplexMath64F { @Test public void conj() { Complex64F a = new Complex64F(2, 3); Complex64F b = new Complex64F(-3, 6); ComplexMath64F.conj(a, b); assertEquals(a.real, b.real, 1e-8); assertEquals(-a.imaginary, b.imaginary, 1e-8); } @Test public void plus() { Complex64F a = new Complex64F(2, 3); Complex64F b = new Complex64F(-3, 6); Complex64F c = new Complex64F(); ComplexMath64F.plus(a, b, c); assertEquals(-1, c.real, 1e-8); assertEquals(9, c.imaginary, 1e-8); } @Test public void minus() { Complex64F a = new Complex64F(2, 3); Complex64F b = new Complex64F(-3, 6); Complex64F c = new Complex64F(); ComplexMath64F.minus(a, b, c); assertEquals(5, c.real, 1e-8); assertEquals(-3, c.imaginary, 1e-8); } @Test public void multiply() { Complex64F a = new Complex64F(2, 3); Complex64F b = new Complex64F(-3, 6); Complex64F c = new Complex64F(); ComplexMath64F.multiply(a, b, c); assertEquals(-24, c.real, 1e-8); assertEquals(3, c.imaginary, 1e-8); } @Test public void divide() { Complex64F a = new Complex64F(2, 3); Complex64F b = new Complex64F(-3, 6); Complex64F c = new Complex64F(); ComplexMath64F.divide(a, b, c); assertEquals(0.26666666666, c.real, 1e-8); assertEquals(-0.466666666666, c.imaginary, 1e-8); } /** * Test conversion to and from polar form by doing just that and see if it gets the original answer again */ @Test public void convert() { Complex64F a = new Complex64F(2, 3); ComplexPolar64F b = new ComplexPolar64F(); Complex64F c = new Complex64F(); ComplexMath64F.convert(a, b); ComplexMath64F.convert(b, c); assertEquals(a.real, c.real, 1e-8); assertEquals(a.imaginary, c.imaginary, 1e-8); } @Test public void mult_polar() { Complex64F a = new Complex64F(2, 3); Complex64F b = new Complex64F(-3, 6); Complex64F expected = new Complex64F(); ComplexMath64F.multiply(a, b, expected); ComplexPolar64F pa = new ComplexPolar64F(a); ComplexPolar64F pb = new ComplexPolar64F(b); ComplexPolar64F pc = new ComplexPolar64F(); ComplexMath64F.multiply(pa, pb, pc); Complex64F found = pc.toStandard(); assertEquals(expected.real, found.real, 1e-8); assertEquals(expected.imaginary, found.imaginary, 1e-8); } @Test public void div_polar() { Complex64F a = new Complex64F(2, 3); Complex64F b = new Complex64F(-3, 6); Complex64F expected = new Complex64F(); ComplexMath64F.divide(a, b, expected); ComplexPolar64F pa = new ComplexPolar64F(a); ComplexPolar64F pb = new ComplexPolar64F(b); ComplexPolar64F pc = new ComplexPolar64F(); ComplexMath64F.divide(pa, pb, pc); Complex64F found = pc.toStandard(); assertEquals(expected.real, found.real, 1e-8); assertEquals(expected.imaginary, found.imaginary, 1e-8); } @Test public void pow() { ComplexPolar64F a = new ComplexPolar64F(2, 0.2); ComplexPolar64F expected = new ComplexPolar64F(); ComplexPolar64F found = new ComplexPolar64F(); ComplexMath64F.multiply(a, a, expected); ComplexMath64F.multiply(a, expected, expected); ComplexMath64F.pow(a, 3, found); assertEquals(expected.r, found.r, 1e-8); assertEquals(expected.theta, found.theta, 1e-8); } @Test public void root_polar() { ComplexPolar64F expected = new ComplexPolar64F(2, 0.2); ComplexPolar64F root = new ComplexPolar64F(); ComplexPolar64F found = new ComplexPolar64F(); // compute the square root of a complex number then see if the // roots equal the output for (int i = 0; i < 2; i++) { ComplexMath64F.root(expected, 2, 0, root); ComplexMath64F.multiply(root, root, found); Complex64F e = expected.toStandard(); Complex64F f = found.toStandard(); assertEquals(e.real, f.real, 1e-8); assertEquals(e.imaginary, f.imaginary, 1e-8); } } @Test public void root_standard() { Complex64F expected = new Complex64F(2, 0.2); Complex64F root = new Complex64F(); Complex64F found = new Complex64F(); // compute the square root of a complex number then see if the // roots equal the output for (int i = 0; i < 2; i++) { ComplexMath64F.root(expected, 2, 0, root); ComplexMath64F.multiply(root, root, found); assertEquals(expected.real, found.real, 1e-8); assertEquals(expected.imaginary, found.imaginary, 1e-8); } } @Test public void sqrt_standard() { Complex64F input = new Complex64F(2, 0.2); Complex64F root = new Complex64F(); Complex64F found = new Complex64F(); ComplexMath64F.sqrt(input, root); ComplexMath64F.multiply(root, root, found); assertEquals(input.real, found.real, 1e-8); assertEquals(input.imaginary, found.imaginary, 1e-8); input = new Complex64F(2, -0.2); ComplexMath64F.sqrt(input, root); ComplexMath64F.multiply(root, root, found); assertEquals(input.real, found.real, 1e-8); assertEquals(input.imaginary, found.imaginary, 1e-8); } } ejml-0.28/main/core/test/org/ejml/ops/TestConvertMatrixType.java000066400000000000000000000125461256171534400247360ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.FixedMatrix64F; import org.ejml.data.RealMatrix64F; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestConvertMatrixType { Random rand = new Random(234); @Test public void any_to_any() { DenseMatrix64F a = new DenseMatrix64F(2,3,true,1,2,3,4,5,6); DenseMatrix64F b = new DenseMatrix64F(2,3); ConvertMatrixType.convert((RealMatrix64F)a,(RealMatrix64F)b); assertTrue(MatrixFeatures.isIdentical(a,b,1e-12)); } @Test public void checkAll_Fixed_to_DM() throws IllegalAccessException, InstantiationException, InvocationTargetException { Method[] methods = ConvertMatrixType.class.getMethods(); int numFound = 0; for( Method m : methods ) { if( !m.getName().equals("convert") ) continue; Class[]param = m.getParameterTypes(); if( !FixedMatrix64F.class.isAssignableFrom(param[0]) ) { continue; } FixedMatrix64F a = (FixedMatrix64F)param[0].newInstance(); DenseMatrix64F b = new DenseMatrix64F(a.getNumRows(),a.getNumCols()); for( int i = 0; i < b.numRows; i++ ) { for( int j = 0; j < b.numCols; j++ ) { a.set(i, j, rand.nextDouble()); } } Object[] input = new Object[param.length]; input[0] = a; input[1] = b; m.invoke(null,input); checkIdentical(a,b); numFound++; } assertEquals(5+5,numFound); } @Test public void checkAll_DM_to_Fixed() throws IllegalAccessException, InstantiationException, InvocationTargetException { Method[] methods = ConvertMatrixType.class.getMethods(); int numFound = 0; for( Method m : methods ) { if( !m.getName().equals("convert") ) continue; Class[]param = m.getParameterTypes(); if( !FixedMatrix64F.class.isAssignableFrom(param[1]) ) { continue; } FixedMatrix64F b = (FixedMatrix64F)param[1].newInstance(); DenseMatrix64F a = new DenseMatrix64F(b.getNumRows(),b.getNumCols()); for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < a.numCols; j++ ) { a.set(i, j, rand.nextDouble()); } } Object[] input = new Object[param.length]; input[0] = a; input[1] = b; m.invoke(null,input); checkIdentical(a,b); numFound++; } assertEquals(5+5,numFound); } @Test public void BM_to_DM() { for( int rows = 1; rows <= 8; rows++ ) { for( int cols = 1; cols <= 8; cols++ ) { BlockMatrix64F a = BlockMatrixOps.createRandom(rows,cols,-1,2,rand); DenseMatrix64F b = new DenseMatrix64F(rows,cols); ConvertMatrixType.convert(a,b); checkIdentical(a,b); } } } @Test public void DM_to_BM() { for( int rows = 1; rows <= 8; rows++ ) { for( int cols = 1; cols <= 8; cols++ ) { DenseMatrix64F a = RandomMatrices.createRandom(rows,cols,rand); BlockMatrix64F b = new BlockMatrix64F(rows,cols,3); ConvertMatrixType.convert(a,b); checkIdentical(a,b); } } } private void checkIdentical( RealMatrix64F a , RealMatrix64F b ) { for( int i = 0; i < a.getNumRows(); i++ ) { for( int j = 0; j < a.getNumCols(); j++ ) { assertEquals(a.get(i,j),b.get(i,j),1e-8); } } } private void checkIdenticalV( RealMatrix64F a , RealMatrix64F b ) { boolean columnVectorA = a.getNumRows() > a.getNumCols(); boolean columnVectorB = b.getNumRows() > b.getNumCols(); int length = Math.max(a.getNumRows(),b.getNumRows()); for( int i = 0; i < length; i++ ) { double valueA,valueB; if( columnVectorA ) valueA = a.get(i,0); else valueA = a.get(0,i); if( columnVectorB ) valueB = b.get(i,0); else valueB = b.get(0,i); assertEquals(valueA,valueB,1e-8); } } } ejml-0.28/main/core/test/org/ejml/ops/TestMatrixIO.java000066400000000000000000000035621256171534400227610ustar00rootroot00000000000000/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestMatrixIO { Random rand = new Random(23424); @Test public void load_save_binary() throws IOException { DenseMatrix64F A = RandomMatrices.createRandom(6,3,rand); MatrixIO.saveBin(A, "temp.mat"); DenseMatrix64F A_copy = MatrixIO.loadBin("temp.mat"); assertTrue(A != A_copy); assertTrue(MatrixFeatures.isEquals(A,A_copy)); // clean up File f = new File("temp.mat"); assertTrue(f.exists()); assertTrue(f.delete()); } @Test public void load_save_csv() throws IOException { DenseMatrix64F A = RandomMatrices.createRandom(6,3,rand); MatrixIO.saveCSV(A,"temp.csv"); DenseMatrix64F A_copy = MatrixIO.loadCSV("temp.csv"); assertTrue(A != A_copy); assertTrue(MatrixFeatures.isEquals(A,A_copy)); // clean up File f = new File("temp.csv"); assertTrue(f.exists()); assertTrue(f.delete()); } } ejml-0.28/main/core/test/org/ejml/ops/TestReadMatrixCsv.java000066400000000000000000000040331256171534400237730ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.CDenseMatrix64F; import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.IOException; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * @author Peter Abeles */ public class TestReadMatrixCsv { /** * Make sure incorrectly formatted data is handled gracefully */ @Test(expected=IOException.class) public void bad_matrix_row() throws IOException { String s = "3 2 real\n0 0\n1 1"; ReadMatrixCsv alg = new ReadMatrixCsv(new ByteArrayInputStream(s.getBytes())); alg.read(); fail("Should have had an exception"); } @Test(expected=IOException.class) public void bad_matrix_col() throws IOException { String s = "3 2 real\n0 0\n1\n0 3"; ReadMatrixCsv alg = new ReadMatrixCsv(new ByteArrayInputStream(s.getBytes())); alg.read(); fail("Should have had an exception"); } public void complex() throws IOException { String s = "3 2 complex\n0 2 0 -1\n1 2 -1 -1\n0 2 3 10"; ReadMatrixCsv alg = new ReadMatrixCsv(new ByteArrayInputStream(s.getBytes())); CDenseMatrix64F expected = new CDenseMatrix64F(3,2,true,0,2,0,-1,1,2,-1,-1,0,2,3,10); CDenseMatrix64F m = alg.read(); assertTrue(CMatrixFeatures.isIdentical(expected,m,1e-8)); } } ejml-0.28/main/dense64/000077500000000000000000000000001256171534400145765ustar00rootroot00000000000000ejml-0.28/main/dense64/build.gradle000066400000000000000000000003311256171534400170520ustar00rootroot00000000000000dependencies { compile project(':main:core') testCompile project(':main:experimental') testCompile project(':main:core').sourceSets.test.output } idea { module { name = "EJML Dense 64" } }ejml-0.28/main/dense64/generate/000077500000000000000000000000001256171534400163705ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/000077500000000000000000000000001256171534400171575ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/ejml/000077500000000000000000000000001256171534400201065ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/ejml/CodeGeneratorBase.java000066400000000000000000000052571256171534400242760ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; /** *

Base class for code generators.

* * @author Peter Abeles */ public abstract class CodeGeneratorBase { public static final String copyright = "/*\n" + " * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved.\n" + " *\n" + " * This file is part of Efficient Java Matrix Library (EJML).\n" + " *\n" + " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" + " * you may not use this file except in compliance with the License.\n" + " * You may obtain a copy of the License at\n" + " *\n" + " * http://www.apache.org/licenses/LICENSE-2.0\n" + " *\n" + " * Unless required by applicable law or agreed to in writing, software\n" + " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" + " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + " * See the License for the specific language governing permissions and\n" + " * limitations under the License.\n" + " */"; protected PrintStream out; protected String className; /** * Creates * * @throws java.io.FileNotFoundException */ public abstract void generate() throws FileNotFoundException; public void setOutputFile( String className ) throws FileNotFoundException { this.className = className; out = new PrintStream(new FileOutputStream(className + ".java")); out.print(copyright); out.println(); out.println("package " + getPackage() + ";"); out.println(); } public String getPackage() { return getClass().getPackage().getName(); } } ejml-0.28/main/dense64/generate/org/ejml/alg/000077500000000000000000000000001256171534400206515ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/ejml/alg/dense/000077500000000000000000000000001256171534400217475ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400227025ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/ejml/alg/dense/misc/GenerateDeterminantFromMinor.java000066400000000000000000000161061256171534400313270ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.alg.generic.CodeGeneratorMisc; import java.io.FileNotFoundException; import java.io.PrintStream; /** * Generates code for an unrolled determinant by minor. * * NOTE: There are some repeat calculations of inner determinants. Maybe it could be speed up by calculating those? * * @author Peter Abeles */ public class GenerateDeterminantFromMinor { protected PrintStream stream; protected int N; public GenerateDeterminantFromMinor( String fileName ) throws FileNotFoundException { stream = new PrintStream(fileName); } public GenerateDeterminantFromMinor(PrintStream stream) { this.stream = stream; } public void createClass(int N) { printTop(N); printCalls(N); print2(); print3(); for( int i = 4; i <= N; i++ ) { printFunction(i); } stream.print("}\n"); } private void printTop(int N) { String foo = CodeGeneratorMisc.COPYRIGHT + "\n" + "package org.ejml.alg.dense.misc;\n" + "\n" + "import org.ejml.data.RowD1Matrix64F;\n" + "\n" + "\n" + "/**\n" + " * This code was auto generated by {@link GenerateDeterminantFromMinor} and should not be modified\n" + " * directly. \n" + " * \n" + " * @author Peter Abeles\n" + " */\n" + "public class UnrolledDeterminantFromMinor {\n"+ " \n" + " public static final int MAX = "+N+";\n"; stream.print(foo); } private void print2() { stream.print(" public static double det2( RowD1Matrix64F mat )\n" + " {\n" + " return mat.get(0)*mat.get(3) - mat.get(1)*mat.get(2);\n" + " }\n\n"); } private void print3() { stream.print(" public static double det3( RowD1Matrix64F mat )\n" + " {\n" + " double a11 = mat.get( 0 );\n" + " double a12 = mat.get( 1 );\n" + " double a13 = mat.get( 2 );\n" + " double a21 = mat.get( 3 );\n" + " double a22 = mat.get( 4 );\n" + " double a23 = mat.get( 5 );\n" + " double a31 = mat.get( 6 );\n" + " double a32 = mat.get( 7 );\n" + " double a33 = mat.get( 8 );\n" + "\n" + " double a = a11*(a22*a33 - a23*a32);\n" + " double b = a12*(a21*a33 - a23*a31);\n" + " double c = a13*(a21*a32 - a31*a22);\n" + "\n" + " return a-b+c;\n" + " }\n" + "\n"); } private void printCalls( int N ) { stream.print( " \n" + " public static double det( RowD1Matrix64F mat ) {\n"); stream.print( " if( mat.numRows == 2 ) {\n" + " return det2(mat);\n"); for( int i = 3; i <= N; i++ ) { stream.print(" } else if( mat.numRows == "+i+" ) {\n" + " return det"+i+"(mat); \n"); } stream.print(" }\n" + " \n" + " throw new IllegalArgumentException(\"Not supported\");\n" + " }\n\n"); } protected String getInputValue( int element ) { return "mat.get( "+element+" )"; } private void printFunction( int N ) { stream.print(" public static double det"+N+"( RowD1Matrix64F mat )\n" + " {\n"); printFunctionInner(N); stream.print(" return ret;\n"); stream.print(" }\n"); stream.print("\n"); } public void printFunctionInner( int N ) { // extracts the first minor int M = N-1; this.N = M; int matrix[] = new int[M*M]; int index = 0; for( int i = 1; i <= M; i++ ) { int origIndex = i*N+1; for( int j = 1; j <= M; j++ , origIndex++,index++) { matrix[index] = index; stream.print(" double "+a(index)+" = "+getInputValue(origIndex)+";\n"); } } stream.print("\n"); stream.print(" double ret = 0;\n"); stream.print(" ret += "+getInputValue(0)+" * ("); minor(matrix, 0, M); stream.print(");\n"); for( int minor = 2; minor <= N; minor++ ) { for( int i = 1; i <= M; i++ ) { index = (minor-2)+(i-1)*M; int origIndex = minor-2+i*N; stream.print(" "+a(index)+" = "+getInputValue(origIndex)+";\n"); } if( minor % 2 == 0 ) { stream.print(" ret -= "); } else { stream.print(" ret += "); } stream.print(getInputValue(minor-1)+" * ("); minor(matrix,0,M); stream.print(");\n"); } } private void minor( int m[] , int row , int N ) { if( N == 2 ) { stream.print(a(m[0])+"*"+a(m[3])+" - "+a(m[1])+"*"+a(m[2])); } else { int M = N-1; int d[] = new int[ M*M ]; for( int i = 0; i < N; i++ ) { int index = 0; for( int j = 1; j < N; j++ ) { for( int k = 0; k < N; k++ ) { if( k != i ) { d[index++] = m[j*N+k]; } } } int pow = i; if( pow % 2 == 0 ) stream.print(" + "+a(m[i])+"*("); else stream.print(" - "+a(m[i])+"*("); minor(d,row+1,M); stream.print(")"); } } } private String a( int index ) { int i = index/N+1; int j = index%N+1; return "a"+i+""+j; } public static void main( String args[] ) throws FileNotFoundException { GenerateDeterminantFromMinor gen = new GenerateDeterminantFromMinor("UnrolledDeterminantFromMinor.java"); gen.createClass(6); } } ejml-0.28/main/dense64/generate/org/ejml/alg/dense/misc/GenerateInverseFromMinor.java000066400000000000000000000162741256171534400304760ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.alg.generic.CodeGeneratorMisc; import java.io.FileNotFoundException; import java.io.PrintStream; /** * Generates unrolled matrix from minor analytical functions. these can run much faster than LU but will only * work for small matrices. * * When computing the determinants for each minor there are some repeat calculations going on. I manually * removed those by storing them in a local variable and only computing it once. Despite reducing the FLOP count * it didn't seem to noticeably improve performance in a runtime benchmark.. * * @author Peter Abeles */ public class GenerateInverseFromMinor { String className = "UnrolledInverseFromMinor"; PrintStream stream; int N; public GenerateInverseFromMinor( boolean createStream ) throws FileNotFoundException { if( createStream ) stream = new PrintStream(className +".java"); } public void createClass(int N) { printTop(N); printCalls(N); for( int i = 2; i <= N; i++ ) { printFunction(i); } stream.print("}\n"); } private void printTop(int N) { String foo = CodeGeneratorMisc.COPYRIGHT + "\n" + "package org.ejml.alg.dense.misc;\n" + "\n" + "import org.ejml.data.DenseMatrix64F;\n" + "\n" + "\n" + "/**\n" + " * This code was auto generated by {@link GenerateInverseFromMinor} and should not be modified\n" + " * directly. The input matrix is scaled make it much less prone to overflow and underflow issues.\n" + " * \n" + " * @author Peter Abeles\n" + " */\n" + "public class "+className+" {\n"+ " \n" + " public static final int MAX = "+N+";\n"; stream.print(foo); } private void printCalls( int N ) { stream.print( " \n" + " public static void inv( DenseMatrix64F mat , DenseMatrix64F inv ) {\n"); stream.print(" double max = Math.abs(mat.data[0]);\n" + " int N = mat.getNumElements();\n" + " \n" + " for( int i = 1; i < N; i++ ) {\n" + " double a = Math.abs(mat.data[i]);\n" + " if( a > max ) max = a;\n" + " }\n\n"); stream.print( " if( mat.numRows == 2 ) {\n" + " inv2(mat,inv,1.0/max);\n"); for( int i = 3; i <= N; i++ ) { stream.print(" } else if( mat.numRows == "+i+" ) {\n" + " inv"+i+"(mat,inv,1.0/max); \n"); } stream.print(" } else {\n" + " throw new IllegalArgumentException(\"Not supported\");\n" + " }\n" + " }\n\n"); } private void printFunction( int N ) { stream.print(" public static void inv"+N+"( DenseMatrix64F mat , DenseMatrix64F inv , double scale )\n" + " {\n" + " double []data = mat.data;\n"+ "\n"); this.N = N; // extracts the first minor int matrix[] = new int[N*N]; int index = 0; for( int i = 1; i <= N; i++ ) { for( int j = 1; j <= N; j++ , index++) { matrix[index] = index; stream.print(" double "+a(index)+" = "+"data[ "+index+" ]*scale;\n"); } } stream.println(); printMinors(matrix, N, stream); stream.println(); stream.print(" data = inv.data;\n"); index = 0; for( int i = 1; i <= N; i++ ) { for( int j = 1; j <= N; j++ , index++) { stream.print(" "+"data["+index+"] = m"+j+""+i+" / det;\n"); } } stream.println(); stream.print(" }\n"); stream.print("\n"); } /** * Put the core auto-code algorithm here so an external class can call it */ public void printMinors(int matrix[], int N, PrintStream stream) { this.N = N; this.stream = stream; // compute all the minors int index = 0; for( int i = 1; i <= N; i++ ) { for( int j = 1; j <= N; j++ , index++) { stream.print(" double m"+i+""+j+" = "); if( (i+j) % 2 == 1 ) stream.print("-( "); printTopMinor(matrix,i-1,j-1,N); if( (i+j) % 2 == 1 ) stream.print(")"); stream.print(";\n"); } } stream.println(); // compute the determinant stream.print(" double det = (a11*m11"); for( int i = 2; i <= N; i++ ) { stream.print(" + "+a(i-1)+"*m"+1+""+i); } stream.println(")/scale;"); } private void printTopMinor( int m[] , int row , int col , int N ) { int d[] = createMinor(m,row,col,N); det(d,0,N-1); } private int[] createMinor( int m[] , int row , int col , int N ) { int M = N-1; int[] ret = new int[ M*M ]; int index = 0; for( int i = 0; i < N; i++ ) { if( i == row ) continue; for( int j = 0; j < N; j++ ) { if( j == col ) continue; ret[index++] = m[i*N+j]; } } return ret; } private void det( int m[] , int row , int N ) { if( N == 1 ) { stream.print(a(m[0])); } else if( N == 2 ) { stream.print(a(m[0])+"*"+a(m[3])+" - "+a(m[1])+"*"+a(m[2])); } else { int M = N-1; for( int i = 0; i < N; i++ ) { int d[] = createMinor(m,0,i,N); int pow = i; if( pow % 2 == 0 ) stream.print(" + "+a(m[i])+"*("); else stream.print(" - "+a(m[i])+"*("); det(d,row+1,M); stream.print(")"); } } } private String a( int index ) { int i = index/N+1; int j = index%N+1; return "a"+i+""+j; } public static void main( String args[] ) throws FileNotFoundException { GenerateInverseFromMinor gen = new GenerateInverseFromMinor(true); gen.createClass(5); } }ejml-0.28/main/dense64/generate/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400227305ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/ejml/alg/dense/mult/GeneratorMatrixMatrixMult.java000066400000000000000000000535261256171534400307500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.alg.generic.CodeGeneratorMisc; import java.io.FileNotFoundException; import java.io.PrintStream; /** *

* This class generates code for various matrix matrix multiplication operations. The code associated * with these operators is often only slightly different from each other. So to remove some * of the tediousness of writing and maintaining it is autogenerated. *

*

* To create {@link MatrixMatrixMult} simply run this application and copy it to the appropriate location. *

* * @author Peter Abeles */ public class GeneratorMatrixMatrixMult { PrintStream stream; public GeneratorMatrixMatrixMult( String fileName ) throws FileNotFoundException { stream = new PrintStream(fileName); } public void createClass() { String preamble = CodeGeneratorMisc.COPYRIGHT + "\n" + "package org.ejml.alg.dense.mult;\n" + "\n" + "import org.ejml.data.RowD1Matrix64F;\n"+ "import org.ejml.ops.CommonOps;\n" + "\n" + "/**\n" + " *

\n" + " * This class contains various types of matrix matrix multiplication operations for {@link RowD1Matrix64F}.\n" + " *

\n" + " *

\n" + " * Two algorithms that are equivalent can often have very different runtime performance.\n" + " * This is because of how modern computers uses fast memory caches to speed up reading/writing to data.\n" + " * Depending on the order in which variables are processed different algorithms can run much faster than others,\n" + " * even if the number of operations is the same.\n" + " *

\n" + " *\n" + " *

\n" + " * Algorithms that are labeled as 'reorder' are designed to avoid caching jumping issues, some times at the cost\n" + " * of increasing the number of operations. This is important for large matrices. The straight forward \n" + " * implementation seems to be faster for small matrices.\n" + " *

\n" + " * \n" + " *

\n" + " * Algorithms that are labeled as 'aux' use an auxiliary array of length n. This array is used to create\n" + " * a copy of an out of sequence column vector that is referenced several times. This reduces the number\n" + " * of cache misses. If the 'aux' parameter passed in is null then the array is declared internally.\n" + " *

\n" + " *\n" + " *

\n" + " * Typically the straight forward implementation runs about 30% faster on smaller matrices and\n" + " * about 5 times slower on larger matrices. This is all computer architecture and matrix shape/size specific.\n" + " *

\n" + " * \n" + " *

\n" + " *

******** IMPORTANT **********
\n" + " * This class was auto generated using {@link "+getClass().getName()+"}\n" + " *

\n" + " * \n" + " * @author Peter Abeles\n" + " */\n"+ "public class MatrixMatrixMult {\n"; stream.print(preamble); for( int i = 0; i < 2; i++ ) { boolean alpha = i == 1; for( int j = 0; j < 2; j++ ) { boolean add = j == 1; printMult_reroder(alpha,add); stream.print("\n"); printMult_small(alpha,add); stream.print("\n"); printMult_aux(alpha,add); stream.print("\n"); printMultTransA_reorder(alpha,add); stream.print("\n"); printMultTransA_small(alpha,add); stream.print("\n"); printMultTransAB(alpha,add); stream.print("\n"); printMultTransAB_aux(alpha,add); stream.print("\n"); printMultTransB(alpha,add); stream.print("\n"); } } stream.print("}\n"); } private String makeBoundsCheck(boolean tranA, boolean tranB, String auxLength) { String a_numCols = tranA ? "a.numRows" : "a.numCols"; String a_numRows = tranA ? "a.numCols" : "a.numRows"; String b_numCols = tranB ? "b.numRows" : "b.numCols"; String b_numRows = tranB ? "b.numCols" : "b.numRows"; String ret = " if( a == c || b == c )\n" + " throw new IllegalArgumentException(\"Neither 'a' or 'b' can be the same matrix as 'c'\");\n"+ " else if( "+a_numCols+" != "+b_numRows+" ) {\n" + " throw new MatrixDimensionException(\"The 'a' and 'b' matrices do not have compatible dimensions\");\n" + " } else if( "+a_numRows+" != c.numRows || "+b_numCols+" != c.numCols ) {\n" + " throw new MatrixDimensionException(\"The results matrix does not have the desired dimensions\");\n" + " }\n" + "\n"; if( auxLength != null ) { ret += " if( aux == null ) aux = new double[ "+auxLength+" ];\n\n"; } return ret; } private String handleZeros( boolean add ) { String fill = add ? "" : " CommonOps.fill(c,0);\n"; String ret = " if( a.numCols == 0 || a.numRows == 0 ) {\n" + fill + " return;\n" + " }\n"; return ret; } private String makeComment( String nameOp , boolean hasAlpha ) { String a = hasAlpha ? "double, " : ""; String inputs = "("+a+" org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F)"; String ret = " /**\n" + " * @see org.ejml.ops.CommonOps#"+nameOp+inputs+"\n" + " */\n"; return ret; } private String makeHeader(String nameOp, String variant, boolean add, boolean hasAlpha, boolean hasAux, boolean tranA, boolean tranB) { if( add ) nameOp += "Add"; // make the op name if( tranA && tranB ) { nameOp += "TransAB"; } else if( tranA ) { nameOp += "TransA"; } else if( tranB ) { nameOp += "TransB"; } String ret = makeComment(nameOp,hasAlpha)+ " public static void "+nameOp; if( variant != null ) ret += "_"+variant+"( "; else ret += "( "; if( hasAlpha ) ret += "double alpha , "; if( hasAux ) { ret += "RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c , double []aux )\n"; } else { ret += "RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c )\n"; } ret += " {\n"; return ret; } public void printMult_reroder( boolean alpha , boolean add ) { String header,valLine; header = makeHeader("mult","reorder",add,alpha, false, false,false); if( alpha ) { valLine = "valA = alpha*a.get(indexA++);\n"; } else { valLine = "valA = a.get(indexA++);\n"; } String assignment = add ? "plus" : "set"; String foo = header + makeBoundsCheck(false,false, null)+handleZeros(add) + " double valA;\n"+ " int indexCbase= 0;\n" + " int endOfKLoop = b.numRows*b.numCols;\n"+ "\n" + " for( int i = 0; i < a.numRows; i++ ) {\n" + " int indexA = i*a.numCols;\n" + "\n"+ " // need to assign c.data to a value initially\n" + " int indexB = 0;\n" + " int indexC = indexCbase;\n" + " int end = indexB + b.numCols;\n" + "\n" + " "+valLine + "\n" + " while( indexB < end ) {\n" + " c."+assignment+"(indexC++ , valA*b.get(indexB++));\n" + " }\n" + "\n" + " // now add to it\n"+ " while( indexB != endOfKLoop ) { // k loop\n"+ " indexC = indexCbase;\n" + " end = indexB + b.numCols;\n" + "\n" + " "+valLine+ "\n" + " while( indexB < end ) { // j loop\n" + " c.plus(indexC++ , valA*b.get(indexB++));\n" + " }\n" + " }\n" + " indexCbase += c.numCols;\n" + " }\n" + " }\n"; stream.print(foo); } public void printMult_small( boolean alpha , boolean add ) { String header,valLine; header = makeHeader("mult","small",add,alpha, false, false,false); String assignment = add ? "plus" : "set"; if( alpha ) { valLine = " c."+assignment+"( cIndex++ , alpha*total );\n"; } else { valLine = " c."+assignment+"( cIndex++ , total );\n"; } String foo = header + makeBoundsCheck(false,false, null)+ " int aIndexStart = 0;\n" + " int cIndex = 0;\n" + "\n" + " for( int i = 0; i < a.numRows; i++ ) {\n" + " for( int j = 0; j < b.numCols; j++ ) {\n" + " double total = 0;\n" + "\n" + " int indexA = aIndexStart;\n" + " int indexB = j;\n" + " int end = indexA + b.numRows;\n" + " while( indexA < end ) {\n" + " total += a.get(indexA++) * b.get(indexB);\n" + " indexB += b.numCols;\n" + " }\n" + "\n" + valLine + " }\n" + " aIndexStart += a.numCols;\n" + " }\n" + " }\n"; stream.print(foo); } public void printMult_aux( boolean alpha , boolean add ) { String header,valLine; header = makeHeader("mult","aux",add,alpha, true, false,false); String assignment = add ? "plus" : "set"; if( alpha ) { valLine = " c."+assignment+"( i*c.numCols+j , alpha*total );\n"; } else { valLine = " c."+assignment+"( i*c.numCols+j , total );\n"; } String foo = header + makeBoundsCheck(false,false, "b.numRows")+ " for( int j = 0; j < b.numCols; j++ ) {\n" + " // create a copy of the column in B to avoid cache issues\n" + " for( int k = 0; k < b.numRows; k++ ) {\n" + " aux[k] = b.unsafe_get(k,j);\n" + " }\n" + "\n" + " int indexA = 0;\n" + " for( int i = 0; i < a.numRows; i++ ) {\n" + " double total = 0;\n" + " for( int k = 0; k < b.numRows; ) {\n" + " total += a.get(indexA++)*aux[k++];\n" + " }\n" + valLine + " }\n" + " }\n" + " }\n"; stream.print(foo); } public void printMultTransA_reorder( boolean alpha , boolean add ) { String header,valLine1,valLine2; header = makeHeader("mult","reorder",add,alpha, false, true,false); String assignment = add ? "plus" : "set"; if( alpha ) { valLine1 = "valA = alpha*a.get(i);\n"; valLine2 = "valA = alpha*a.unsafe_get(k,i);\n"; } else { valLine1 = "valA = a.get(i);\n"; valLine2 = "valA = a.unsafe_get(k,i);\n"; } String foo = header + makeBoundsCheck(true,false, null)+handleZeros(add)+ " double valA;\n" + "\n" + " for( int i = 0; i < a.numCols; i++ ) {\n" + " int indexC_start = i*c.numCols;\n" + "\n" + " // first assign R\n" + " " +valLine1+ " int indexB = 0;\n" + " int end = indexB+b.numCols;\n" + " int indexC = indexC_start;\n" + " while( indexBCommon matrix operations for fixed sized matrices which are "+dimen+" x "+dimen+" or "+dimen+" element vectors.

\n" + " *

DO NOT MODIFY. Automatically generated code created by "+getClass().getSimpleName()+"

\n" + " *\n" + " * @author Peter Abeles\n" + " */\n" + "public class "+className+" {\n"); } private void add(int dimen){ out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * c = a + b
\n" + " * cij = aij + bij
\n" + " *

\n" + " *\n" + " *

\n" + " * Matrix C can be the same instance as Matrix A and/or B.\n" + " *

\n" + " *\n" + " * @param a A Matrix. Not modified.\n" + " * @param b A Matrix. Not modified.\n" + " * @param c A Matrix where the results are stored. Modified.\n" + " */\n" + " public static void add( " + nameMatrix + " a , " + nameMatrix + " b , " + nameMatrix + " c ) {\n"); for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { String n = y+""+x; out.print(" c.a"+n+" = a.a"+n+" + b.a"+n+";\n"); } } out.print(" }\n\n"); } private void vector_add( int dimen ) { out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * c = a + b
\n" + " * ci = ai + bi
\n" + " *

\n" + " *\n" + " *

\n" + " * Vector C can be the same instance as Vector A and/or B.\n" + " *

\n" + " *\n" + " * @param a A Vector. Not modified.\n" + " * @param b A Vector. Not modified.\n" + " * @param c A Vector where the results are stored. Modified.\n" + " */\n" + " public static void add( " + nameVector + " a , " + nameVector + " b , " + nameVector + " c ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" c.a"+y+" = a.a"+y+" + b.a"+y+";\n"); } out.print(" }\n\n"); } private void addEquals( int dimen ){ out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * a = a + b
\n" + " * aij = aij + bij
\n" + " *

\n" + " *\n" + " * @param a A Matrix. Modified.\n" + " * @param b A Matrix. Not modified.\n" + " */\n" + " public static void addEquals( " + nameMatrix + " a , " + nameMatrix + " b ) {\n"); for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { String n = y+""+x; out.print(" a.a"+n+" += b.a"+n+";\n"); } } out.print(" }\n\n"); } private void vector_addEquals( int dimen ) { out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * a = a + b
\n" + " * ai = ai + bi
\n" + " *

\n" + " *\n" + " * @param a A Vector. Modified.\n" + " * @param b A Vector. Not modified.\n" + " */\n" + " public static void addEquals( " + nameVector + " a , " + nameVector + " b ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" a.a"+y+" += b.a"+y+";\n"); } out.print(" }\n\n"); } private void subtract(int dimen){ out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * c = a - b
\n" + " * cij = aij - bij
\n" + " *

\n" + " *\n" + " *

\n" + " * Matrix C can be the same instance as Matrix A and/or B.\n" + " *

\n" + " *\n" + " * @param a A Matrix. Not modified.\n" + " * @param b A Matrix. Not modified.\n" + " * @param c A Matrix where the results are stored. Modified.\n" + " */\n" + " public static void subtract( " + nameMatrix + " a , " + nameMatrix + " b , " + nameMatrix + " c ) {\n"); for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { String n = y+""+x; out.print(" c.a"+n+" = a.a"+n+" - b.a"+n+";\n"); } } out.print(" }\n\n"); } private void vector_subtract( int dimen ) { out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * c = a - b
\n" + " * ci = ai - bi
\n" + " *

\n" + " *\n" + " *

\n" + " * Vector C can be the same instance as Vector A and/or B.\n" + " *

\n" + " *\n" + " * @param a A Vector. Not modified.\n" + " * @param b A Vector. Not modified.\n" + " * @param c A Vector where the results are stored. Modified.\n" + " */\n" + " public static void subtract( "+nameVector+" a , "+nameVector+" b , "+nameVector+" c ) {\n"); for( int y = 1; y <= dimen; y++) { out.print(" c.a" + y + " = a.a" + y + " - b.a" + y + ";\n"); } out.print(" }\n\n"); } private void subtractEquals(int dimen) { out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * a = a - b
\n" + " * aij = aij - bij
\n" + " *

\n" + " *\n" + " * @param a A Matrix. Modified.\n" + " * @param b A Matrix. Not modified.\n" + " */\n" + " public static void subtractEquals( "+nameMatrix+" a , "+nameMatrix+" b ) {\n"); for( int y = 1; y <= dimen; y++ ) { for (int x = 1; x <= dimen; x++) { String n = y + "" + x; out.print(" a.a" + n + " -= b.a" + n + ";\n"); } } out.print(" }\n\n"); } private void vector_subtractEquals( int dimen ) { out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * a = a - b
\n" + " * ai = ai - bi
\n" + " *

\n" + " *\n" + " * @param a A Vector. Modified.\n" + " * @param b A Vector. Not modified.\n" + " */\n" + " public static void subtractEquals( "+nameVector+" a , "+nameVector+" b ) {\n"); for( int y = 1; y <= dimen; y++ ) { String n = ""+y; out.print(" a.a"+n+" -= b.a"+n+";\n"); } out.print(" }\n\n"); } private void transpose_one( int dimen ){ out.print(" /**\n" + " * Performs an in-place transpose. This algorithm is only efficient for square\n" + " * matrices.\n" + " *\n" + " * @param m The matrix that is to be transposed. Modified.\n" + " */\n" + " public static void transpose( " + nameMatrix + " m ) {\n" + " double tmp;\n"); for (int y = 1; y <= dimen; y++) { for (int x = y + 1; x <= dimen; x++) { String f = +y + "" + x; String t = +x + "" + y; out.print(" tmp = m.a"+f+"; m.a"+f+" = m.a"+t+"; m.a"+t+" = tmp;\n"); } } out.print(" }\n\n"); } private void transpose_two( int dimen ){ out.print(" /**\n" + " *

\n" + " * Transposes matrix 'a' and stores the results in 'b':
\n" + " *
\n" + " * bij = aji
\n" + " * where 'b' is the transpose of 'a'.\n" + " *

\n" + " *\n" + " * @param input The original matrix. Not modified.\n" + " * @param output Where the transpose is stored. If null a new matrix is created. Modified.\n" + " * @return The transposed matrix.\n" + " */\n" + " public static " + nameMatrix + " transpose( " + nameMatrix + " input , " + nameMatrix + " output ) {\n" + " if( input == null )\n" + " input = new " + nameMatrix + "();\n\n"); for (int y = 1; y <= dimen; y++) { for (int x = 1; x <= dimen; x++) { String f = +y + "" + x; String t = +x+""+y; out.print(" output.a"+f+" = input.a"+t+";\n"); } } out.print("\n return output;\n" + " }\n\n"); } private void mult( int dimen , boolean add ){ String plus = add ? "+" : ""; String name = add ? "multAdd" : "mult"; out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * c "+plus+"= a * b
\n" + " *
\n" + " * cij "+plus+"= ∑k=1:n { aik * bkj}\n" + " *

\n" + " *\n" + " * @param a The left matrix in the multiplication operation. Not modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void "+name+"( "+nameMatrix+" a , "+nameMatrix+" b , "+nameMatrix+" c) {\n"); for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { out.print(" c.a"+y+""+x+" "+plus+"= "); for( int k = 1; k <= dimen; k++ ) { out.print("a.a"+y+""+k+"*b.a"+k+""+x); if( k < dimen ) out.print(" + "); else out.print(";\n"); } } } out.print(" }\n\n"); } private void multTransA( int dimen , boolean add ){ String plus = add ? "+" : ""; String name = add ? "multAddTransA" : "multTransA"; out.print(" /**\n" + " *

Performs the following operation:
\n" + " *
\n" + " * c " + plus + "= aT * b
\n" + " *
\n" + " * cij " + plus + "= ∑k=1:n { aki * bkj}\n" + " *

\n" + " *\n" + " * @param a The left matrix in the multiplication operation. Not modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void " + name + "( " + nameMatrix + " a , " + nameMatrix + " b , " + nameMatrix + " c) {\n"); for (int y = 1; y <= dimen; y++) { for (int x = 1; x <= dimen; x++) { out.print(" c.a" + y + "" + x + " " + plus + "= "); for (int k = 1; k <= dimen; k++) { out.print("a.a" + k + "" + y + "*b.a" + k + "" + x); if (k < dimen) out.print(" + "); else out.print(";\n"); } } } out.printf(" }\n\n"); } private void multTransAB( int dimen , boolean add ){ String plus = add ? "+" : ""; String name = add ? "multAddTransAB" : "multTransAB"; out.printf(" /**\n" + " *

\n" + " * Performs the following operation:
\n" + " *
\n" + " * c " + plus + "= aT * bT
\n" + " * cij " + plus + "= ∑k=1:n { aki * bjk}\n" + " *

\n" + " *\n" + " * @param a The left matrix in the multiplication operation. Not modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void " + name + "( " + nameMatrix + " a , " + nameMatrix + " b , " + nameMatrix + " c) {\n"); for (int y = 1; y <= dimen; y++) { for (int x = 1; x <= dimen; x++) { out.print(" c.a" + y + "" + x + " " + plus + "= "); for (int k = 1; k <= dimen; k++) { out.print("a.a" + k + "" + y + "*b.a" + x + "" + k); if (k < dimen) out.print(" + "); else out.print(";\n"); } } } out.print(" }\n\n"); } private void multTransB( int dimen , boolean add ){ String plus = add ? "+" : ""; String name = add ? "multAddTransB" : "multTransB"; out.print(" /**\n" + " *

\n" + " * Performs the following operation:
\n" + " *
\n" + " * c "+plus+"= a * bT
\n" + " * cij "+plus+"= ∑k=1:n { aik * bjk}\n" + " *

\n" + " *\n" + " * @param a The left matrix in the multiplication operation. Not modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void " + name + "( " + nameMatrix + " a , " + nameMatrix + " b , " + nameMatrix + " c) {\n"); for (int y = 1; y <= dimen; y++) { for (int x = 1; x <= dimen; x++) { out.print(" c.a" + y + "" + x + " " + plus + "= "); for (int k = 1; k <= dimen; k++) { out.print("a.a" + y + "" + k + "*b.a" + x + "" + k); if (k < dimen ) out.print(" + "); else out.print(";\n"); } } } out.print(" }\n\n"); } private void mult_m_v_v( int dimen ){ out.print(" /**\n" + " *

Performs matrix to vector multiplication:
\n" + " *
\n" + " * c = a * b
\n" + " *
\n" + " * ci = ∑k=1:n { aik * bk}\n" + " *

\n" + " *\n" + " * @param a The left matrix in the multiplication operation. Not modified.\n" + " * @param b The right vector in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void mult( " + nameMatrix + " a , " + nameVector + " b , " + nameVector + " c) {\n"); for (int y = 1; y <= dimen; y++) { out.print(" c.a" + y + " = "); for (int x = 1; x <= dimen; x++) { out.print("a.a" + y + "" + x + "*b.a"+x); if( x < dimen ) out.print(" + "); else out.print(";\n"); } } out.printf(" }\n\n"); } private void mult_v_m_v( int dimen ){ out.print(" /**\n" + " *

Performs vector to matrix multiplication:
\n" + " *
\n" + " * c = a * b
\n" + " *
\n" + " * cj = ∑k=1:n { bk * akj }\n" + " *

\n" + " *\n" + " * @param a The left vector in the multiplication operation. Not modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void mult( "+nameVector+" a , "+nameMatrix+" b , "+nameVector+" c) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" c.a"+y+" = "); for( int x = 1; x <= dimen; x++ ) { out.print("a.a"+x+"*b.a"+x+""+y); if( x < dimen ) out.print(" + "); else out.print(";\n"); } } out.print(" }\n\n"); } private void dot( int dimen ){ out.print(" /**\n" + " *

Performs the vector dot product:
\n" + " *
\n" + " * c = a * b
\n" + " *
\n" + " * c> = ∑k=1:n { bk * ak }\n" + " *

\n" + " *\n" + " * @param a The left vector in the multiplication operation. Not modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " * @return The dot product\n" + " */\n" + " public static double dot( "+nameVector+" a , "+nameVector+" b ) {\n"); out.print(" return "); for( int i = 1; i <= dimen; i++) { out.print("a.a"+i+"*b.a"+i); if( i < dimen ) out.print(" + "); else out.print(";\n"); } out.print(" }\n\n"); } private void setIdentity( int dimen ){ out.print(" /**\n" + " * Sets all the diagonal elements equal to one and everything else equal to zero.\n" + " * If this is a square matrix then it will be an identity matrix.\n" + " *\n" + " * @param a A matrix.\n" + " */\n" + " public static void setIdentity( "+nameMatrix+" a ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { int val = x==y?1:0; out.print("a.a"+x+""+y+" = "+val+";"); if( x < dimen ) out.print(" "); else out.print("\n"); } } out.print(" }\n\n"); } private void invert( int dimen ){ out.print(" /**\n" + " * Inverts matrix 'a' using minor matrices and stores the results in 'inv'. Scaling is applied to improve\n" + " * stability against overflow and underflow.\n" + " *\n" + " * WARNING: Potentially less stable than using LU decomposition.\n" + " *\n" + " * @param a Input matrix. Not modified.\n" + " * @param inv Inverted output matrix. Modified.\n" + " * @return true if it was successful or false if it failed. Not always reliable.\n" + " */\n" + " public static boolean invert( "+nameMatrix+" a , "+nameMatrix+" inv ) {\n" + "\n" + " double scale = 1.0/elementMaxAbs(a);\n" + "\n"); int matrix[] = new int[dimen*dimen]; int index = 0; for (int y = 1; y <= dimen; y++) { for (int x = 1; x <= dimen; x++, index++) { matrix[index] = index; String coor = y + "" + x; out.print(" double a" + coor + " = a.a" + coor + "*scale;\n"); } } out.println(); try { GenerateInverseFromMinor gen = new GenerateInverseFromMinor(false); gen.printMinors(matrix, dimen, out); } catch (FileNotFoundException e) { throw new RuntimeException(e); } out.println(); for (int y = 1; y <= dimen; y++) { for( int x = 1; x <= dimen; x++ ) { String coor0 = y+""+x; String coor1 = x+""+y; out.print(" inv.a"+coor0+" = m"+coor1+"/det;\n"); } } out.println(); out.print(" return !Double.isNaN(det) && !Double.isInfinite(det);\n"); out.print(" }\n\n"); } private void trace(int dimen) { out.print(" /**\n" + " *

\n" + " * This computes the trace of the matrix:
\n" + " *
\n" + " * trace = ∑i=1:n { aii }\n" + " *

\n" + " *

\n" + " * The trace is only defined for square matrices.\n" + " *

\n" + " *\n" + " * @param a A square matrix. Not modified.\n" + " */\n" + " public static double trace( "+nameMatrix+" a ) {\n"); out.print(" return "); for( int i = 1; i <= dimen; i++ ) { out.print("a.a"+i+""+1); if( i < dimen ) out.print(" + "); else out.println(";"); } out.print(" }\n\n"); } private void det( int dimen ){ out.print(" /**\n" + " * Computes the determinant using minor matrices.\n" + " *

\n" + " * WARNING: Potentially less stable than using LU decomposition.\n" + " *\n" + " * @param mat Input matrix. Not modified.\n" + " * @return The determinant.\n" + " */\n" + " public static double det( "+nameMatrix+" mat ) {\n" + "\n"); if( dimen == 2 ) { out.print(" return mat.a11*mat.a22 - mat.a12*mat.a21;\n"); } else if( dimen == 3 ) { out.print( " double a = mat.a11*(mat.a22*mat.a33 - mat.a23*mat.a32);\n" + " double b = mat.a12*(mat.a21*mat.a33 - mat.a23*mat.a31);\n" + " double c = mat.a13*(mat.a21*mat.a32 - mat.a31*mat.a22);\n" + "\n" + " return a-b+c;\n"); } else { GenerateDeterminantFromMinor helper = new GenerateDeterminantFromMinor(out) { @Override protected String getInputValue(int element) { int row = element/(N+1) + 1; int col = element%(N+1) + 1; return "mat.a"+row+""+col; } }; helper.printFunctionInner(dimen); out.print("\n return ret;\n"); } out.print(" }\n\n"); } private void diag( int dimen ) { out.print(" /**\n" + " *

\n" + " * Extracts all diagonal elements from 'input' and places them inside the 'out' vector. Elements\n" + " * are in sequential order.\n" + " *

\n" + " *\n" + " *\n" + " * @param input Matrix. Not modified.\n" + " * @param out Vector containing diagonal elements. Modified.\n" + " */\n" + " public static void diag( "+nameMatrix+" input , "+nameVector+" out ) {\n"); for( int i = 1; i <= dimen; i++ ) { out.print(" out.a" + i + " = input.a" + i + "" + i + ";\n"); } out.print(" }\n\n"); } private void elementMax( int dimen ) { out.print(" /**\n" + " *

\n" + " * Returns the value of the element in the matrix that has the largest value.
\n" + " *
\n" + " * Max{ aij } for all i and j
\n" + " *

\n" + " *\n" + " * @param a A matrix. Not modified.\n" + " * @return The max element value of the matrix.\n" + " */\n" + " public static double elementMax( "+nameMatrix+" a ) {\n"); out.print(" double max = a.a11;\n"); for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { if( y == 1 && x == 1 ) continue; out.print(" max = Math.max(max,a.a"+y+""+x+");\n"); } } out.print("\n" + " return max;\n" + " }\n\n"); } private void elementMax_vector( int dimen ) { out.print(" /**\n" + " *

\n" + " * Returns the value of the element in the vector that has the largest value.
\n" + " *
\n" + " * Max{ ai } for all i
\n" + " *

\n" + " *\n" + " * @param a A vector. Not modified.\n" + " * @return The max element value of the matrix.\n" + " */\n" + " public static double elementMax( "+nameVector+" a ) {\n"); out.print(" double max = a.a1;\n"); for( int y = 2; y <= dimen; y++ ) { out.print(" max = Math.max(max,a.a"+y+");\n"); } out.print("\n" + " return max;\n" + " }\n\n"); } private void elementMaxAbs( int dimen ) { out.print(" /**\n" + " *

\n" + " * Returns the absolute value of the element in the matrix that has the largest absolute value.
\n" + " *
\n" + " * Max{ |aij| } for all i and j
\n" + " *

\n" + " *\n" + " * @param a A matrix. Not modified.\n" + " * @return The max abs element value of the matrix.\n" + " */\n" + " public static double elementMaxAbs( "+nameMatrix+" a ) {\n"); out.print(" double max = a.a11;\n"); for (int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { if( y == 1 && x == 1 ) continue; out.print(" max = Math.max(max,Math.abs(a.a" + y + "" + x + "));\n"); } } out.print("\n" + " return max;\n" + " }\n\n"); } private void elementMaxAbs_vector( int dimen ) { out.print(" /**\n" + " *

\n" + " * Returns the absolute value of the element in the vector that has the largest absolute value.
\n" + " *
\n" + " * Max{ |ai| } for all i
\n" + " *

\n" + " *\n" + " * @param a A matrix. Not modified.\n" + " * @return The max abs element value of the vector.\n" + " */\n" + " public static double elementMaxAbs( "+nameVector+" a ) {\n"); out.print(" double max = a.a1;\n"); for( int y = 2; y <= dimen; y++ ) { out.print(" max = Math.max(max,Math.abs(a.a"+y+"));\n"); } out.print("\n" + " return max;\n" + " }\n\n"); } private void elementMin( int dimen ) { out.print(" /**\n" + " *

\n" + " * Returns the value of the element in the matrix that has the minimum value.
\n" + " *
\n" + " * Min{ aij } for all i and j
\n" + " *

\n" + " *\n" + " * @param a A matrix. Not modified.\n" + " * @return The value of element in the matrix with the minimum value.\n" + " */\n" + " public static double elementMin( "+nameMatrix+" a ) {\n"); out.print(" double min = a.a11;\n"); for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { if( y == 1 && x == 1 ) continue; out.print(" min = Math.min(min, a.a"+y+""+x+");\n"); } } out.print("\n" + " return min;\n" + " }\n\n"); } private void elementMin_vector( int dimen ) { out.print(" /**\n" + " *

\n" + " * Returns the value of the element in the vector that has the minimum value.
\n" + " *
\n" + " * Min{ ai } for all
\n" + " *

\n" + " *\n" + " * @param a A matrix. Not modified.\n" + " * @return The value of element in the vector with the minimum value.\n" + " */\n" + " public static double elementMin( "+nameVector+" a ) {\n"); out.print(" double min = a.a1;\n"); for( int y = 2; y <= dimen; y++ ) { out.print(" min = Math.min(min, a.a"+y+");\n"); } out.print("\n" + " return min;\n" + " }\n\n"); } private void elementMinAbs( int dimen ) { out.print(" /**\n" + " *

\n" + " * Returns the absolute value of the element in the matrix that has the smallest absolute value.
\n" + " *
\n" + " * Min{ |aij| } for all i and j
\n" + " *

\n" + " *\n" + " * @param a A matrix. Not modified.\n" + " * @return The max element value of the matrix.\n" + " */\n" + " public static double elementMinAbs( "+nameMatrix+" a ) {\n"); out.print(" double min = a.a11;\n"); for (int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { if( y == 1 && x == 1 ) continue; out.print(" min = Math.min(min,Math.abs(a.a"+y+""+x+"));\n"); } } out.print("\n" + " return min;\n" + " }\n\n"); } private void elementMinAbs_vector(int dimen) { out.print(" /**\n" + " *

\n" + " * Returns the absolute value of the element in the vector that has the smallest absolute value.
\n" + " *
\n" + " * Min{ |ai| } for all i
\n" + " *

\n" + " *\n" + " * @param a A matrix. Not modified.\n" + " * @return The max element value of the vector.\n" + " */\n" + " public static double elementMinAbs( "+nameVector+" a ) {\n"); out.print(" double min = a.a1;\n"); for( int y = 2; y <= dimen; y++ ) { out.print(" min = Math.min(min,Math.abs(a.a"+y+"));\n"); } out.print("\n" + " return min;\n" + " }\n\n"); } private void elementMult_two( int dimen ) { out.print(" /**\n" + " *

Performs an element by element multiplication operation:
\n" + " *
\n" + " * aij = aij * bij
\n" + " *

\n" + " * @param a The left matrix in the multiplication operation. Modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " */\n" + " public static void elementMult( " + nameMatrix + " a , " + nameMatrix + " b) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("a."+w+" *= b."+w+ ";"); if (x < dimen) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void elementMult_vector_two(int dimen) { out.print(" /**\n" + " *

Performs an element by element multiplication operation:
\n" + " *
\n" + " * ai = ai * bi
\n" + " *

\n" + " * @param a The left vector in the multiplication operation. Modified.\n" + " * @param b The right vector in the multiplication operation. Not modified.\n" + " */\n" + " public static void elementMult( "+nameVector+" a , "+nameVector+" b) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" a.a"+y+" *= b.a"+y+";\n"); } out.print(" }\n\n"); } private void elementMult_three( int dimen ) { out.print(" /**\n" + " *

Performs an element by element multiplication operation:
\n" + " *
\n" + " * cij = aij * bij
\n" + " *

\n" + " * @param a The left matrix in the multiplication operation. Not modified.\n" + " * @param b The right matrix in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void elementMult( "+nameMatrix+" a , "+nameMatrix+" b , "+nameMatrix+" c ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("c."+w+" = a."+w+"*b."+w+";"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void elementMult_vector_three( int dimen ) { out.print(" /**\n" + " *

Performs an element by element multiplication operation:
\n" + " *
\n" + " * ci = ai * bj
\n" + " *

\n" + " * @param a The left vector in the multiplication operation. Not modified.\n" + " * @param b The right vector in the multiplication operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void elementMult( "+nameVector+" a , "+nameVector+" b , "+nameVector+" c ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" c.a"+y+" = a.a"+y+"*b.a"+y+";\n"); } out.print(" }\n\n"); } private void elementDiv_two( int dimen ) { out.print(" /**\n" + " *

Performs an element by element division operation:
\n" + " *
\n" + " * aij = aij / bij
\n" + " *

\n" + " * @param a The left matrix in the division operation. Modified.\n" + " * @param b The right matrix in the division operation. Not modified.\n" + " */\n" + " public static void elementDiv( "+nameMatrix+" a , "+nameMatrix+" b) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("a."+w+" /= b."+w+";"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void elementDiv_vector_two( int dimen ) { out.print(" /**\n" + " *

Performs an element by element division operation:
\n" + " *
\n" + " * ai = ai / bi
\n" + " *

\n" + " * @param a The left vector in the division operation. Modified.\n" + " * @param b The right vector in the division operation. Not modified.\n" + " */\n" + " public static void elementDiv( "+nameVector+" a , "+nameVector+" b) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" a.a"+y+" /= b.a"+y+";\n"); } out.print(" }\n\n"); } private void elementDiv_three( int dimen ) { out.print(" /**\n" + " *

Performs an element by element division operation:
\n" + " *
\n" + " * cij = aij / bij
\n" + " *

\n" + " * @param a The left matrix in the division operation. Not modified.\n" + " * @param b The right matrix in the division operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void elementDiv( "+nameMatrix+" a , "+nameMatrix+" b , "+nameMatrix+" c ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("c."+w+" = a."+w+"/b."+w+";"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void elementDiv_vector_three( int dimen ) { out.print(" /**\n" + " *

Performs an element by element division operation:
\n" + " *
\n" + " * ci = ai / bi
\n" + " *

\n" + " * @param a The left vector in the division operation. Not modified.\n" + " * @param b The right vector in the division operation. Not modified.\n" + " * @param c Where the results of the operation are stored. Modified.\n" + " */\n" + " public static void elementDiv( "+nameVector+" a , "+nameVector+" b , "+nameVector+" c ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" c.a"+y+" = a.a"+y+"/b.a"+y+";\n"); } out.print(" }\n\n"); } private void scale_two( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an in-place element by element scalar multiplication.
\n" + " *
\n" + " * aij = α*aij\n" + " *

\n" + " *\n" + " * @param a The matrix that is to be scaled. Modified.\n" + " * @param alpha the amount each element is multiplied by.\n" + " */\n" + " public static void scale( double alpha , "+nameMatrix+" a ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("a."+w+" *= alpha;"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void scale_vector_two( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an in-place element by element scalar multiplication.
\n" + " *
\n" + " * aij = α*aij\n" + " *

\n" + " *\n" + " * @param a The vector that is to be scaled. Modified.\n" + " * @param alpha the amount each element is multiplied by.\n" + " */\n" + " public static void scale( double alpha , "+nameVector+" a ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" a.a"+y+" *= alpha;\n"); } out.print(" }\n\n"); } private void scale_three( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an element by element scalar multiplication.
\n" + " *
\n" + " * bij = α*aij\n" + " *

\n" + " *\n" + " * @param alpha the amount each element is multiplied by.\n" + " * @param a The matrix that is to be scaled. Not modified.\n" + " * @param b Where the scaled matrix is stored. Modified.\n" + " */\n" + " public static void scale( double alpha , "+nameMatrix+" a , "+nameMatrix+" b ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("b."+w+" = a."+w+"*alpha;"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void scale_vector_three( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an element by element scalar multiplication.
\n" + " *
\n" + " * bi = α*ai\n" + " *

\n" + " *\n" + " * @param alpha the amount each element is multiplied by.\n" + " * @param a The vector that is to be scaled. Not modified.\n" + " * @param b Where the scaled matrix is stored. Modified.\n" + " */\n" + " public static void scale( double alpha , "+nameVector+" a , "+nameVector+" b ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" b.a"+y+" = a.a"+y+"*alpha;\n"); } out.print(" }\n\n"); } private void divide_two( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an in-place element by element scalar division. Scalar denominator.
\n" + " *
\n" + " * aij = aij/α\n" + " *

\n" + " *\n" + " * @param a The matrix whose elements are to be divided. Modified.\n" + " * @param alpha the amount each element is divided by.\n" + " */\n" + " public static void divide( "+nameMatrix+" a , double alpha ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("a."+w+" /= alpha;"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void divide_vector_two( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an in-place element by element scalar division. Scalar denominator.
\n" + " *
\n" + " * ai = ai/α\n" + " *

\n" + " *\n" + " * @param a The vector whose elements are to be divided. Modified.\n" + " * @param alpha the amount each element is divided by.\n" + " */\n" + " public static void divide( "+nameVector+" a , double alpha ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" a.a"+y+" /= alpha;\n"); } out.print(" }\n\n"); } private void divide_three( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an element by element scalar division. Scalar denominator.
\n" + " *
\n" + " * bij = aij /α\n" + " *

\n" + " *\n" + " * @param alpha the amount each element is divided by.\n" + " * @param a The matrix whose elements are to be divided. Not modified.\n" + " * @param b Where the results are stored. Modified.\n" + " */\n" + " public static void divide( "+nameMatrix+" a , double alpha , "+nameMatrix+" b ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("b."+w+" = a."+w+"/alpha;"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void divide_vector_three( int dimen ) { out.print(" /**\n" + " *

\n" + " * Performs an element by element scalar division. Scalar denominator.
\n" + " *
\n" + " * bi = ai /α\n" + " *

\n" + " *\n" + " * @param alpha the amount each element is divided by.\n" + " * @param a The vector whose elements are to be divided. Not modified.\n" + " * @param b Where the results are stored. Modified.\n" + " */\n" + " public static void divide( "+nameVector+" a , double alpha , "+nameVector+" b ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" b.a"+y+" = a.a"+y+"/alpha;\n"); } out.print(" }\n\n"); } private void changeSign( int dimen ) { out.print(" /**\n" + " *

\n" + " * Changes the sign of every element in the matrix.
\n" + " *
\n" + " * aij = -aij\n" + " *

\n" + " *\n" + " * @param a A matrix. Modified.\n" + " */\n" + " public static void changeSign( "+nameMatrix+" a )\n" + " {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("a."+w+" = -a."+w+";"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void changeSign_vector( int dimen ) { out.print(" /**\n" + " *

\n" + " * Changes the sign of every element in the vector.
\n" + " *
\n" + " * ai = -ai\n" + " *

\n" + " *\n" + " * @param a A vector. Modified.\n" + " */\n" + " public static void changeSign( "+nameVector+" a )\n" + " {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" a.a"+y+" = -a.a"+y+";\n"); } out.print(" }\n\n"); } private void fill( int dimen ) { out.print(" /**\n" + " *

\n" + " * Sets every element in the matrix to the specified value.
\n" + " *
\n" + " * aij = value\n" + " *

\n" + " *\n" + " * @param a A matrix whose elements are about to be set. Modified.\n" + " * @param v The value each element will have.\n" + " */\n" + " public static void fill( "+nameMatrix+" a , double v ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" "); for( int x = 1; x <= dimen; x++ ) { String w = "a"+y+""+x; out.print("a."+w+" = v;"); if( x < dimen ) out.print(" "); else out.println(); } } out.print(" }\n\n"); } private void fill_vector( int dimen ) { out.print(" /**\n" + " *

\n" + " * Sets every element in the vector to the specified value.
\n" + " *
\n" + " * ai = value\n" + " *

\n" + " *\n" + " * @param a A vector whose elements are about to be set. Modified.\n" + " * @param v The value each element will have.\n" + " */\n" + " public static void fill( "+nameVector+" a , double v ) {\n"); for( int y = 1; y <= dimen; y++ ) { out.print(" a.a"+y+" = v;\n"); } out.print(" }\n\n"); } private void extract( int dimen ) { out.print(" /**\n" + " * Extracts the row from the matrix a.\n" + " * @param a Input matrix\n" + " * @param row Which row is to be extracted\n" + " * @param out output. Storage for the extracted row. If null then a new vector will be returned.\n" + " * @return The extracted row.\n" + " */\n" + " public static "+nameVector+" extractRow( "+nameMatrix+" a , int row , "+nameVector+" out ) {\n" + " if( out == null) out = new "+nameVector+"();\n" + " switch( row ) {\n"); for (int i = 0; i < dimen; i++) { out.print(" case "+i+":\n"); for (int j = 0; j < dimen; j++) { int n = j+1; out.print(" out.a"+n+" = a.a"+(i+1)+""+n+";\n"); } out.print(" break;\n"); } out.print(" default:\n" + " throw new IllegalArgumentException(\"Out of bounds row. row = \"+row);\n" + " }\n" + " return out;\n" + " }\n" + "\n" + " /**\n" + " * Extracts the column from the matrix a.\n" + " * @param a Input matrix\n" + " * @param column Which column is to be extracted\n" + " * @param out output. Storage for the extracted column. If null then a new vector will be returned.\n" + " * @return The extracted column.\n" + " */\n" + " public static "+nameVector+" extractColumn( "+nameMatrix+" a , int column , "+nameVector+" out ) {\n" + " if( out == null) out = new "+nameVector+"();\n" + " switch( column ) {\n"); for (int i = 0; i < dimen; i++) { out.print(" case "+i+":\n"); for (int j = 0; j < dimen; j++) { int n = j+1; out.print(" out.a"+n+" = a.a"+n+""+(i+1)+";\n"); } out.print(" break;\n"); } out.print(" default:\n" + " throw new IllegalArgumentException(\"Out of bounds column. column = \"+column);\n" + " }\n" + " return out;\n" + " }\n\n"); } public static void main( String args[] ) throws FileNotFoundException { GenerateFixedOps app = new GenerateFixedOps(); app.generate(); } }ejml-0.28/main/dense64/generate/org/ejml/data/000077500000000000000000000000001256171534400210175ustar00rootroot00000000000000ejml-0.28/main/dense64/generate/org/ejml/data/GenerateFixedMatrixN.java000066400000000000000000000164301256171534400257030ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.CodeGeneratorBase; import java.io.FileNotFoundException; /** * @author Peter Abeles */ public class GenerateFixedMatrixN extends CodeGeneratorBase{ String classPreamble = "FixedMatrix"; @Override public void generate() throws FileNotFoundException { for( int dimension = 2; dimension <= 6; dimension++ ){ print(dimension); } } public void print( int dimen ) throws FileNotFoundException { String className = classPreamble +dimen+"_64F"; setOutputFile(className); out.print("import org.ejml.ops.MatrixIO;\n" + "\n" + "/**\n" + " * Fixed sized vector with "+dimen+" elements. Can represent a "+dimen+" x 1 or 1 x "+dimen+" matrix, context dependent.\n" + " *

DO NOT MODIFY. Automatically generated code created by "+getClass().getSimpleName()+"

\n" + " *\n" + " * @author Peter Abeles\n" + " */\n" + "public class "+className+" implements FixedMatrix64F {\n"); printClassParam(dimen); out.print("\n" + " public "+className+"() {\n" + " }\n" + "\n" + " public "+className+"("); printFunctionParam(dimen); out.print(")\n" + " {\n"); printSetFromParam(dimen,""); out.print(" }\n" + "\n" + " public "+className+"("+className+" o) {\n"); printSetFromParam(dimen,"o."); out.print(" }\n" + "\n" + " @Override\n" + " public double get(int row, int col) {\n" + " return unsafe_get(row,col);\n" + " }\n" + "\n" + " @Override\n" + " public double unsafe_get(int row, int col) {\n" + " if( row != 0 && col != 0 )\n" + " throw new IllegalArgumentException(\"Row or column must be zero since this is a vector\");\n" + "\n" + " int w = Math.max(row,col);\n" + "\n"); setGetter(dimen); out.print(" } else {\n" + " throw new IllegalArgumentException(\"Out of range. \"+w);\n" + " }\n" + " }\n" + "\n" + " @Override\n" + " public void set(int row, int col, double val) {\n" + " unsafe_set(row,col,val);\n" + " }\n" + "\n" + " @Override\n" + " public void unsafe_set(int row, int col, double val) {\n" + " if( row != 0 && col != 0 )\n" + " throw new IllegalArgumentException(\"Row or column must be zero since this is a vector\");\n" + "\n" + " int w = Math.max(row,col);\n" + "\n"); setSetter(dimen); out.print(" } else {\n" + " throw new IllegalArgumentException(\"Out of range. \"+w);\n" + " }\n" + " }\n" + "\n"); printSetMatrix(dimen); out.print(" @Override\n" + " public int getNumRows() {\n" + " return "+dimen+";\n" + " }\n" + "\n" + " @Override\n" + " public int getNumCols() {\n" + " return 1;\n" + " }\n" + "\n" + " @Override\n" + " public int getNumElements() {\n" + " return "+dimen+";\n" + " }\n" + "\n" + " @Override\n" + " public T copy() {\n" + " return (T)new "+className+"(this);\n" + " }\n" + "\n" + " @Override\n" + " public void print() {\n" + " MatrixIO.print(System.out, this);\n" + " }\n" + "}\n\n"); } private void printClassParam( int dimen ) { out.print(" public double "); for( int i = 1; i <= dimen; i++ ) { out.print("a"+i); if( i < dimen ) out.print(","); else out.print(";\n"); } } private void printFunctionParam( int dimen ) { for( int i = 1; i <= dimen; i++ ) { out.print("double a"+i); if( i < dimen ) out.print(","); } } private void printSetFromParam(int dimen, String prefix) { for( int i = 1; i <= dimen; i++ ) { out.println(" this.a"+i+" = "+prefix+"a"+i+";"); } } private void printSetMatrix(int dimen) { out.print(" @Override\n" + " public void set(Matrix original) {\n" + " RealMatrix64F m = (RealMatrix64F)original;\n" + "\n" + " if( m.getNumCols() == 1 && m.getNumRows() == "+dimen+" ) {\n"); for (int i = 0; i < dimen; i++) { out.print(" a"+(i+1)+" = m.get("+i+",0);\n"); } out.print(" } else if( m.getNumRows() == 1 && m.getNumCols() == "+dimen+" ){\n"); for (int i = 0; i < dimen; i++) { out.print(" a"+(i+1)+" = m.get(0,"+i+");\n"); } out.print(" } else {\n" + " throw new IllegalArgumentException(\"Incompatible shape\");\n" + " }\n" + " }\n\n"); } private void setGetter(int dimen) { for( int i = 0; i < dimen; i++ ) { if( i == 0 ) out.print(" if( w == 0 ) {\n"); else out.print(" } else if( w == "+i+" ) {\n"); out.print(" return a"+(i+1)+";\n"); } } private void setSetter(int dimen ) { for( int i = 0; i < dimen; i++ ) { if( i == 0 ) out.print(" if( w == 0 ) {\n"); else out.print(" } else if( w == "+i+" ) {\n"); out.print(" a"+(i+1)+" = val;\n"); } } public static void main( String args[] ) throws FileNotFoundException { GenerateFixedMatrixN app = new GenerateFixedMatrixN(); app.generate(); } } ejml-0.28/main/dense64/generate/org/ejml/data/GenerateFixedMatrixNxN.java000066400000000000000000000173551256171534400262200ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.CodeGeneratorBase; import java.io.FileNotFoundException; /** * @author Peter Abeles */ public class GenerateFixedMatrixNxN extends CodeGeneratorBase{ String classPreamble = "FixedMatrix"; @Override public void generate() throws FileNotFoundException { for( int dimension = 2; dimension <= 6; dimension++ ){ print(dimension); } } public void print( int dimen ) throws FileNotFoundException { String className = classPreamble +dimen+"x"+dimen+"_64F"; setOutputFile(className); out.println("import org.ejml.ops.MatrixIO;\n\n"+ "/**\n" + " * Fixed sized "+dimen+" by "+className+" matrix. The matrix is stored as class variables for very fast read/write. aXY is the\n" + " * value of row = X and column = Y.\n" + " *

DO NOT MODIFY. Automatically generated code created by "+getClass().getSimpleName()+"

\n" + " *\n" + " * @author Peter Abeles\n" + " */\n" + "public class "+className+" implements FixedMatrix64F {\n"); printClassParam(dimen); out.print("\n" + " public "+className+"() {\n" + " }\n" + "\n" + " public "+className); printFunctionParam(dimen); out.print(" {\n"); printSetFromParam(dimen, ""); out.print(" }\n" + "\n" + " public " + className + "( " + className + " o ) {\n"); printSetFromParam(dimen, "o."); out.print(" }\n" + "\n" + " @Override\n" + " public double get(int row, int col) {\n" + " return unsafe_get(row,col);\n" + " }\n" + "\n" + " @Override\n" + " public double unsafe_get(int row, int col) {\n"); setGetter(dimen); out.print(" throw new IllegalArgumentException(\"Row and/or column out of range. \"+row+\" \"+col);\n" + " }\n" + "\n" + " @Override\n" + " public void set(int row, int col, double val) {\n" + " unsafe_set(row,col,val);\n" + " }\n" + "\n" + " @Override\n" + " public void unsafe_set(int row, int col, double val) {\n"); setSetter(dimen); out.print(" throw new IllegalArgumentException(\"Row and/or column out of range. \"+row+\" \"+col);\n" + " }\n" + "\n"); printSetMatrix(dimen); out.print(" @Override\n" + " public int getNumRows() {\n" + " return "+dimen+";\n" + " }\n" + "\n" + " @Override\n" + " public int getNumCols() {\n" + " return "+dimen+";\n" + " }\n" + "\n" + " @Override\n" + " public int getNumElements() {\n" + " return "+(dimen*dimen)+";\n" + " }\n" + "\n" + " @Override\n" + " public T copy() {\n" + " return (T)new "+className+"(this);\n" + " }\n" + "\n" + " @Override\n" + " public void print() {\n" + " MatrixIO.print(System.out, this);\n" + " }\n" + "}\n\n"); } private void printClassParam( int dimen ) { for( int y = 1; y <= dimen; y++ ) { out.print(" public double "); for( int x = 1; x <= dimen; x++ ) { out.print("a"+y+""+x); if( x != dimen ) out.print(","); else out.println(";"); } } } private void printFunctionParam( int dimen ) { for( int y = 1; y <= dimen; y++ ) { if( y == 1 ) out.print("( "); else out.print(" "); for( int x = 1; x <= dimen; x++ ) { out.print("double a"+y+""+x); if( x != dimen ) out.print(","); else if( y != dimen ) out.println(","); else out.println(")"); } } } private void printSetFromParam(int dimen, String prefix) { for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { out.println(" this.a"+y+""+x+" = "+prefix+"a"+y+""+x+";"); } } } private void setGetter(int dimen) { for( int y = 1; y <= dimen; y++ ) { if( y == 1 ) out.print(" if( row == 0 ) {\n"); else out.print(" } else if( row == "+(y-1)+" ) {\n"); for( int x = 1; x <= dimen; x++ ) { if( x == 1 ) out.print(" if( col == 0 ) {\n"); else out.print(" } else if( col == "+(x-1)+" ) {\n"); out.print(" return a"+y+""+x+";\n"); } out.print(" }\n"); } out.print(" }\n"); } private void setSetter(int dimen ) { for( int y = 1; y <= dimen; y++ ) { if( y == 1 ) out.print(" if( row == 0 ) {\n"); else out.print(" } else if( row == "+(y-1)+" ) {\n"); for( int x = 1; x <= dimen; x++ ) { if( x == 1 ) out.print(" if( col == 0 ) {\n"); else out.print(" } else if( col == "+(x-1)+" ) {\n"); out.print(" a"+y+""+x+" = val; return;\n"); } out.print(" }\n"); } out.print(" }\n"); } private void printSetMatrix( int dimen ) { out.print(" @Override\n" + " public void set(Matrix original) {\n" + " if( original.getNumCols() != "+dimen+" || original.getNumRows() != "+dimen+" )\n" + " throw new IllegalArgumentException(\"Rows and/or columns do not match\");\n" + " RealMatrix64F m = (RealMatrix64F)original;\n" + " \n"); for( int y = 1; y <= dimen; y++ ) { for( int x = 1; x <= dimen; x++ ) { out.print(" a"+y+""+x+" = m.get("+(y-1)+","+(x-1)+");\n"); } } out.print(" }\n\n"); } public static void main( String args[] ) throws FileNotFoundException { GenerateFixedMatrixNxN app = new GenerateFixedMatrixNxN(); app.generate(); } } ejml-0.28/main/dense64/src/000077500000000000000000000000001256171534400153655ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/000077500000000000000000000000001256171534400161545ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/000077500000000000000000000000001256171534400171035ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/000077500000000000000000000000001256171534400176465ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/000077500000000000000000000000001256171534400207405ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/BlockInnerMultiplication.java000066400000000000000000000462671256171534400265660ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; /** *

* Matrix multiplication for the inner row major blocks, typically inside of a {@link org.ejml.data.BlockMatrix64F}. *

* *

* This code was auto generated by {@link GeneratorBlockInnerMultiplication} and should not be modified directly. *

* * @author Peter Abeles */ public class BlockInnerMultiplication { /** *

* Performs the follow operation on individual inner blocks:
*
* C = C + A * B *

*/ public static void blockMultPlus( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < heightA; i++ ) { // for( int k = 0; k < widthA; k++ ) { // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB]; // } // } // } int a = indexA; int rowC = indexC; for( int i = 0; i < heightA; i++ , rowC += widthC ) { int b = indexB; final int endC = rowC + widthC; final int endA = a + widthA; while( a != endA ) {//for( int k = 0; k < widthA; k++ ) { double valA = dataA[a++]; int c = rowC; while( c != endC ) {//for( int j = 0; j < widthC; j++ ) { dataC[ c++ ] += valA * dataB[ b++ ]; } } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C + AT * B *

*/ public static void blockMultPlusTransA( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < widthA; i++ ) { // for( int k = 0; k < heightA; k++ ) { // double valA = dataA[k*widthA + i + indexA]; // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB]; // } // } // } int rowC = indexC; for( int i = 0; i < widthA; i++ , rowC += widthC) { int colA = i + indexA; int endA = colA + widthA*heightA; int b = indexB; // for( int k = 0; k < heightA; k++ ) { while(colA != endA ) { double valA = dataA[colA]; int c = rowC; final int endB = b + widthC; //for( int j = 0; j < widthC; j++ ) { while( b != endB ) { dataC[ c++ ] += valA * dataB[b++]; } colA += widthA; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C + A * BT *

*/ public static void blockMultPlusTransB( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { for( int i = 0; i < heightA; i++ ) { for( int j = 0; j < widthC; j++ ) { double val = 0; for( int k = 0; k < widthA; k++ ) { val += dataA[i*widthA + k + indexA] * dataB[j*widthA + k + indexB]; } dataC[ i*widthC + j + indexC ] += val; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C - A * B *

*/ public static void blockMultMinus( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < heightA; i++ ) { // for( int k = 0; k < widthA; k++ ) { // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB]; // } // } // } int a = indexA; int rowC = indexC; for( int i = 0; i < heightA; i++ , rowC += widthC ) { int b = indexB; final int endC = rowC + widthC; final int endA = a + widthA; while( a != endA ) {//for( int k = 0; k < widthA; k++ ) { double valA = dataA[a++]; int c = rowC; while( c != endC ) {//for( int j = 0; j < widthC; j++ ) { dataC[ c++ ] -= valA * dataB[ b++ ]; } } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C - AT * B *

*/ public static void blockMultMinusTransA( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < widthA; i++ ) { // for( int k = 0; k < heightA; k++ ) { // double valA = dataA[k*widthA + i + indexA]; // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB]; // } // } // } int rowC = indexC; for( int i = 0; i < widthA; i++ , rowC += widthC) { int colA = i + indexA; int endA = colA + widthA*heightA; int b = indexB; // for( int k = 0; k < heightA; k++ ) { while(colA != endA ) { double valA = dataA[colA]; int c = rowC; final int endB = b + widthC; //for( int j = 0; j < widthC; j++ ) { while( b != endB ) { dataC[ c++ ] -= valA * dataB[b++]; } colA += widthA; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C - A * BT *

*/ public static void blockMultMinusTransB( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { for( int i = 0; i < heightA; i++ ) { for( int j = 0; j < widthC; j++ ) { double val = 0; for( int k = 0; k < widthA; k++ ) { val += dataA[i*widthA + k + indexA] * dataB[j*widthA + k + indexB]; } dataC[ i*widthC + j + indexC ] -= val; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = A * B *

*/ public static void blockMultSet( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < heightA; i++ ) { // for( int k = 0; k < widthA; k++ ) { // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB]; // } // } // } int a = indexA; int rowC = indexC; for( int i = 0; i < heightA; i++ , rowC += widthC ) { int b = indexB; final int endC = rowC + widthC; final int endA = a + widthA; while( a != endA ) {//for( int k = 0; k < widthA; k++ ) { double valA = dataA[a++]; int c = rowC; if( b == indexB ) { while( c != endC ) {//for( int j = 0; j < widthC; j++ ) { dataC[ c++ ] = valA * dataB[ b++ ]; } } else { while( c != endC ) {//for( int j = 0; j < widthC; j++ ) { dataC[ c++ ] += valA * dataB[ b++ ]; } } } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = AT * B *

*/ public static void blockMultSetTransA( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < widthA; i++ ) { // for( int k = 0; k < heightA; k++ ) { // double valA = dataA[k*widthA + i + indexA]; // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB]; // } // } // } int rowC = indexC; for( int i = 0; i < widthA; i++ , rowC += widthC) { int colA = i + indexA; int endA = colA + widthA*heightA; int b = indexB; // for( int k = 0; k < heightA; k++ ) { while(colA != endA ) { double valA = dataA[colA]; int c = rowC; final int endB = b + widthC; //for( int j = 0; j < widthC; j++ ) { if( b == indexB ) { while( b != endB ) { dataC[ c++ ] = valA * dataB[b++]; } } else { while( b != endB ) { dataC[ c++ ] += valA * dataB[b++]; } } colA += widthA; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = A * BT *

*/ public static void blockMultSetTransB( final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { for( int i = 0; i < heightA; i++ ) { for( int j = 0; j < widthC; j++ ) { double val = 0; for( int k = 0; k < widthA; k++ ) { val += dataA[i*widthA + k + indexA] * dataB[j*widthA + k + indexB]; } dataC[ i*widthC + j + indexC ] = val; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C + α A * B *

*/ public static void blockMultPlus( double alpha , final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < heightA; i++ ) { // for( int k = 0; k < widthA; k++ ) { // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB]; // } // } // } int a = indexA; int rowC = indexC; for( int i = 0; i < heightA; i++ , rowC += widthC ) { int b = indexB; final int endC = rowC + widthC; final int endA = a + widthA; while( a != endA ) {//for( int k = 0; k < widthA; k++ ) { double valA = alpha*dataA[a++]; int c = rowC; while( c != endC ) {//for( int j = 0; j < widthC; j++ ) { dataC[ c++ ] += valA * dataB[ b++ ]; } } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C + α AT * B *

*/ public static void blockMultPlusTransA( double alpha , final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < widthA; i++ ) { // for( int k = 0; k < heightA; k++ ) { // double valA = dataA[k*widthA + i + indexA]; // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB]; // } // } // } int rowC = indexC; for( int i = 0; i < widthA; i++ , rowC += widthC) { int colA = i + indexA; int endA = colA + widthA*heightA; int b = indexB; // for( int k = 0; k < heightA; k++ ) { while(colA != endA ) { double valA = alpha*dataA[colA]; int c = rowC; final int endB = b + widthC; //for( int j = 0; j < widthC; j++ ) { while( b != endB ) { dataC[ c++ ] += valA * dataB[b++]; } colA += widthA; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = C + α A * BT *

*/ public static void blockMultPlusTransB( double alpha , final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { for( int i = 0; i < heightA; i++ ) { for( int j = 0; j < widthC; j++ ) { double val = 0; for( int k = 0; k < widthA; k++ ) { val += dataA[i*widthA + k + indexA] * dataB[j*widthA + k + indexB]; } dataC[ i*widthC + j + indexC ] += alpha * val; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = α A * B *

*/ public static void blockMultSet( double alpha , final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < heightA; i++ ) { // for( int k = 0; k < widthA; k++ ) { // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB]; // } // } // } int a = indexA; int rowC = indexC; for( int i = 0; i < heightA; i++ , rowC += widthC ) { int b = indexB; final int endC = rowC + widthC; final int endA = a + widthA; while( a != endA ) {//for( int k = 0; k < widthA; k++ ) { double valA = alpha*dataA[a++]; int c = rowC; if( b == indexB ) { while( c != endC ) {//for( int j = 0; j < widthC; j++ ) { dataC[ c++ ] = valA * dataB[ b++ ]; } } else { while( c != endC ) {//for( int j = 0; j < widthC; j++ ) { dataC[ c++ ] += valA * dataB[ b++ ]; } } } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = α AT * B *

*/ public static void blockMultSetTransA( double alpha , final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { // for( int i = 0; i < widthA; i++ ) { // for( int k = 0; k < heightA; k++ ) { // double valA = dataA[k*widthA + i + indexA]; // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB]; // } // } // } int rowC = indexC; for( int i = 0; i < widthA; i++ , rowC += widthC) { int colA = i + indexA; int endA = colA + widthA*heightA; int b = indexB; // for( int k = 0; k < heightA; k++ ) { while(colA != endA ) { double valA = alpha*dataA[colA]; int c = rowC; final int endB = b + widthC; //for( int j = 0; j < widthC; j++ ) { if( b == indexB ) { while( b != endB ) { dataC[ c++ ] = valA * dataB[b++]; } } else { while( b != endB ) { dataC[ c++ ] += valA * dataB[b++]; } } colA += widthA; } } } /** *

* Performs the follow operation on individual inner blocks:
*
* C = α A * BT *

*/ public static void blockMultSetTransB( double alpha , final double[] dataA, final double []dataB, final double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { for( int i = 0; i < heightA; i++ ) { for( int j = 0; j < widthC; j++ ) { double val = 0; for( int k = 0; k < widthA; k++ ) { val += dataA[i*widthA + k + indexA] * dataB[j*widthA + k + indexB]; } dataC[ i*widthC + j + indexC ] = alpha * val; } } } } ejml-0.28/main/dense64/src/org/ejml/alg/block/BlockInnerRankUpdate.java000066400000000000000000000276351256171534400256250ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.D1Submatrix64F; /** * Performs rank-n update operations on the inner blocks of a {@link org.ejml.data.BlockMatrix64F} * * It is assumed and not checked that the submatrices are aligned along the matrix's blocks. * * @author Peter Abeles */ public class BlockInnerRankUpdate { /** *

* Performs:
*
* A = A + α B TB *

* * @param blockLength Size of the block in the block matrix. * @param alpha scaling factor for right hand side. * @param A Block aligned submatrix. * @param B Block aligned submatrix. */ public static void rankNUpdate( int blockLength , double alpha , D1Submatrix64F A , D1Submatrix64F B ) { int heightB = B.row1-B.row0; if( heightB > blockLength ) throw new IllegalArgumentException("Height of B cannot be greater than the block length"); int N = B.col1-B.col0; if( A.col1-A.col0 != N ) throw new IllegalArgumentException("A does not have the expected number of columns based on B's width"); if( A.row1-A.row0 != N ) throw new IllegalArgumentException("A does not have the expected number of rows based on B's width"); for( int i = B.col0; i < B.col1; i += blockLength ) { int indexB_i = B.row0*B.original.numCols + i*heightB; int widthB_i = Math.min(blockLength,B.col1-i); int rowA = i-B.col0+A.row0; int heightA = Math.min( blockLength , A.row1 - rowA); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB_j = Math.min(blockLength,B.col1-j); int indexA = rowA * A.original.numCols + (j-B.col0+A.col0)*heightA; int indexB_j = B.row0*B.original.numCols + j*heightB; BlockInnerMultiplication.blockMultPlusTransA(alpha, B.original.data,B.original.data,A.original.data, indexB_i,indexB_j,indexA,heightB,widthB_i,widthB_j); } } } /** *

* Rank N update function for a symmetric inner submatrix and only operates on the upper * triangular portion of the submatrix.
*
* A = A - B TB *

*/ public static void symmRankNMinus_U( int blockLength , D1Submatrix64F A , D1Submatrix64F B ) { int heightB = B.row1-B.row0; if( heightB > blockLength ) throw new IllegalArgumentException("Height of B cannot be greater than the block length"); int N = B.col1-B.col0; if( A.col1-A.col0 != N ) throw new IllegalArgumentException("A does not have the expected number of columns based on B's width"); if( A.row1-A.row0 != N ) throw new IllegalArgumentException("A does not have the expected number of rows based on B's width"); for( int i = B.col0; i < B.col1; i += blockLength ) { int indexB_i = B.row0*B.original.numCols + i*heightB; int widthB_i = Math.min(blockLength,B.col1-i); int rowA = i-B.col0+A.row0; int heightA = Math.min( blockLength , A.row1 - rowA); for( int j = i; j < B.col1; j += blockLength ) { int widthB_j = Math.min(blockLength,B.col1-j); int indexA = rowA * A.original.numCols + (j-B.col0+A.col0)*heightA; int indexB_j = B.row0*B.original.numCols + j*heightB; if( i == j ) { // only the upper portion of this block needs to be modified since it is along a diagonal multTransABlockMinus_U( B.original.data,A.original.data, indexB_i,indexB_j,indexA,heightB,widthB_i,widthB_j); } else { multTransABlockMinus( B.original.data,A.original.data, indexB_i,indexB_j,indexA,heightB,widthB_i,widthB_j); } } } } /** *

* Rank N update function for a symmetric inner submatrix and only operates on the lower * triangular portion of the submatrix.
*
* A = A - B*BT
*

*/ public static void symmRankNMinus_L( int blockLength , D1Submatrix64F A , D1Submatrix64F B ) { int widthB = B.col1-B.col0; if( widthB > blockLength ) throw new IllegalArgumentException("Width of B cannot be greater than the block length"); int N = B.row1-B.row0; if( A.col1-A.col0 != N ) throw new IllegalArgumentException("A does not have the expected number of columns based on B's height"); if( A.row1-A.row0 != N ) throw new IllegalArgumentException("A does not have the expected number of rows based on B's height"); for( int i = B.row0; i < B.row1; i += blockLength ) { int heightB_i = Math.min(blockLength,B.row1-i); int indexB_i = i*B.original.numCols + heightB_i*B.col0; int rowA = i-B.row0+A.row0; int heightA = Math.min( blockLength , A.row1 - rowA); for( int j = B.row0; j <= i; j += blockLength ) { int widthB_j = Math.min(blockLength,B.row1-j); int indexA = rowA * A.original.numCols + (j-B.row0+A.col0)*heightA; int indexB_j = j*B.original.numCols + widthB_j*B.col0; if( i == j ) { multTransBBlockMinus_L( B.original.data,A.original.data, indexB_i,indexB_j,indexA,widthB,heightB_i,widthB_j); } else { multTransBBlockMinus( B.original.data,A.original.data, indexB_i,indexB_j,indexA,widthB,heightB_i,widthB_j); } } } } /** *

* Performs the following operation on a block:
*
* c = c - aTa
*

*/ protected static void multTransABlockMinus( double[] dataA, double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC ) { // for( int i = 0; i < widthA; i++ ) { // for( int k = 0; k < heightA; k++ ) { // // double valA = dataA[k*widthA + i + indexA]; // for( int j = 0; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] -= valA * dataA[k*widthC + j + indexB]; // } // } // } int rowB = indexB; int endLoopK = rowB + heightA*widthC; int startA = indexA; //for( int k = 0; k < heightA; k++ ) { for( ; rowB != endLoopK; rowB += widthC , startA += widthA ) { int a = startA; int c = indexC; int endA = a + widthA; int endB = rowB + widthC; while( a != endA ) { double valA = dataA[a++]; int b = rowB; while( b != endB ) { dataC[ c++ ] -= valA * dataA[b++]; } } } } /** *

* Performs the following operation on the upper triangular portion of a block:
*
* c = c - aTa
*

*/ protected static void multTransABlockMinus_U( double[] dataA, double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC ) { // for( int i = 0; i < widthA; i++ ) { // for( int k = 0; k < heightA; k++ ) { // // double valA = dataA[k*widthA + i + indexA]; // for( int j = i; j < widthC; j++ ) { // dataC[ i*widthC + j + indexC ] -= valA * dataA[k*widthC + j + indexB]; // } // } // } for( int i = 0; i < widthA; i++ ) { for( int k = 0; k < heightA; k++ ) { double valA = dataA[k*widthA + i + indexA]; int b = k*widthC + indexB + i; int c = i*widthC + indexC + i; int endC = (c-i)+widthC; while( c != endC ) { // for( int j = i; j < widthC; j++ ) { dataC[ c++ ] -= valA * dataA[b++]; } } } } /** *

* Performs the following operation on a block:
*
* c = c - a*aT
*

*/ protected static void multTransBBlockMinus( final double[] dataA, final double []dataC, final int indexA, final int indexB, final int indexC, final int widthA, final int heightA, final int widthC ) { // for( int i = 0; i < heightA; i++ ) { // for( int j = 0; j < widthC; j++ ) { // double sum = 0; // for( int k = 0; k < widthA; k++ ) { // sum += dataA[i*widthA + k + indexA] * dataA[j*widthA + k + indexB]; // } // dataC[ i*widthC + j + indexC ] -= sum; // } // } int rowA = indexA; int c = indexC; for( int i = 0; i < heightA; i++ , rowA += widthA ) { final int endA = rowA + widthA; int rowB = indexB; final int endLoopJ = c + widthC; // for( int j = 0; j < widthC; j++ ) { while( c != endLoopJ ) { int a = rowA; int b = rowB; double sum = 0; while( a != endA ) { sum += dataA[a++] * dataA[b++]; } dataC[ c++ ] -= sum; rowB += widthA; } } } /** *

* Performs the following operation on the lower triangular portion of a block:
*
* c = c - a*aT
*

*/ protected static void multTransBBlockMinus_L( double[] dataA, double []dataC, int indexA, int indexB, int indexC, final int widthA, final int heightA, final int widthC ) { // for( int i = 0; i < heightA; i++ ) { // for( int j = 0; j <= i; j++ ) { // double sum = 0; // for( int k = 0; k < widthA; k++ ) { // sum += dataA[i*widthA + k + indexA] * dataA[j*widthA + k + indexB]; // } // dataC[ i*widthC + j + indexC ] -= sum; // } // } for( int i = 0; i < heightA; i++ ) { int rowA = i*widthA+indexA; int endA = rowA + widthA; int rowB = indexB; int rowC = i*widthC + indexC; for( int j = 0; j <= i; j++ , rowB += widthA) { double sum = 0; int a = rowA; int b = rowB; while( a != endA ) { sum += dataA[a++] * dataA[b++]; } dataC[ rowC + j ] -= sum; } } } } ejml-0.28/main/dense64/src/org/ejml/alg/block/BlockInnerTriangularSolver.java000066400000000000000000000231521256171534400270600ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; /** *

* Contains triangular solvers for inner blocks of a {@link org.ejml.data.BlockMatrix64F}. *

* *

* Algorithm for lower triangular inverse:
* *

 * for i=1:m
 *     for j=1:i-1
 *         val = 0
 *         for k=j:i-1
 *             val = val - L(i,k) * X(k,j)
 *         end
 *         x(i,j) = val / L(i,i)
 *     end
 *     x(i,i) = 1 / L(i,i)
 * end
 * 
*

* * @author Peter Abeles */ public class BlockInnerTriangularSolver { /** *

* Inverts a square lower triangular matrix: L = L-1 *

* * @param L Lower triangular matrix being inverted. Not modified. * @oaran K_inv Where the inverse is stored. Can be the same as L. Modified. * @param m The number of rows and columns. * @param offsetL which index does the L matrix start at. * @param offsetL_inv which index does the L_inv matrix start at. * */ public static void invertLower( double L[] , double L_inv[] , int m , int offsetL , int offsetL_inv ) { for( int i = 0; i < m; i++ ) { double L_ii = L[ offsetL + i*m + i ]; for( int j = 0; j < i; j++ ) { double val = 0; for( int k = j; k < i; k++ ) { val += L[offsetL + i*m + k] * L_inv[ offsetL_inv + k*m + j ]; } L_inv[ offsetL_inv + i*m + j ] = -val / L_ii; } L_inv[ offsetL_inv + i*m + i ] = 1.0 / L_ii; } } /** *

* Inverts a square lower triangular matrix: L = L-1 *

* * @param L Lower triangular matrix being inverted. Over written with inverted matrix. Modified. * @param m The number of rows and columns. * @param offsetL which index does the L matrix start at. * */ public static void invertLower( double L[] , int m , int offsetL ) { for( int i = 0; i < m; i++ ) { double L_ii = L[ offsetL + i*m + i ]; for( int j = 0; j < i; j++ ) { double val = 0; for( int k = j; k < i; k++ ) { val += L[offsetL + i*m + k] * L[ offsetL + k*m + j ]; } L[ offsetL + i*m + j ] = -val / L_ii; } L[ offsetL + i*m + i ] = 1.0 / L_ii; } } /** *

* Solves for non-singular lower triangular matrices using forward substitution. *
* B = L-1B
*
* where B is a (m by n) matrix, L is a lower triangular (m by m) matrix. *

* * @param L An m by m non-singular lower triangular matrix. Not modified. * @param b An m by n matrix. Modified. * @param m size of the L matrix * @param n number of columns in the B matrix. * @param strideL number of elements that need to be added to go to the next row in L * @param offsetL initial index in L where the matrix starts * @param offsetB initial index in B where the matrix starts */ public static void solveL( double L[] , double []b , int m , int n , int strideL , int offsetL , int offsetB ) { for( int j = 0; j < n; j++ ) { for( int i = 0; i < m; i++ ) { double sum = b[offsetB + i*n+j]; for( int k=0; k * Solves for non-singular transposed lower triangular matrices using backwards substitution: *
* B = L-TB
*
* where B is a (m by n) matrix, L is a lower triangular (m by m) matrix. *

* * @param L An m by m non-singular lower triangular matrix. Not modified. * @param b An m by n matrix. Modified. * @param m size of the L matrix * @param n number of columns in the B matrix. * @param strideL number of elements that need to be added to go to the next row in L * @param offsetL initial index in L where the matrix starts * @param offsetB initial index in B where the matrix starts */ public static void solveTransL( double L[] , double []b , int m , int n , int strideL , int offsetL , int offsetB ) { for( int j = 0; j < n; j++ ) { for( int i = m-1; i >= 0; i-- ) { double sum = b[offsetB + i*n+j]; for( int k=i+1; k * Solves for non-singular lower triangular matrices using forward substitution. *
* BT = L-1BT
*
* where B is a (n by m) matrix, L is a lower triangular (m by m) matrix. *

* * @param L An m by m non-singular lower triangular matrix. Not modified. * @param b An n by m matrix. Modified. * @param m size of the L matrix * @param n number of columns in the B matrix. * @param offsetL initial index in L where the matrix starts * @param offsetB initial index in B where the matrix starts */ public static void solveLTransB( double L[] , double []b , int m , int n , int strideL , int offsetL , int offsetB ) { // for( int j = 0; j < n; j++ ) { // for( int i = 0; i < m; i++ ) { // double sum = b[offsetB + j*m+i]; // for( int k=0; k * Solves for non-singular upper triangular matrices using backwards substitution. *
* B = U-1B
*
* where B (m by n) is a matrix, U is a (m by m ) upper triangular matrix.
*

* * @param U An m by m non-singular upper triangular matrix. Not modified. * @param b An m by n matrix. Modified. * @param m size of the L matrix * @paramUn number of columns in the B matrix. * @param offsetU initial index in L where the matrix starts * @param offsetB initial index in B where the matrix starts */ public static void solveU( double U[] , double []b , int m , int n , int strideU , int offsetU , int offsetB ) { for( int j = 0; j < n; j++ ) { for( int i = m-1; i >= 0; i-- ) { double sum = b[offsetB + i*n+j]; for( int k=i+1; k * Solves for non-singular upper triangular matrices using forward substitution. *
* B = U-TB
*
* where B (m by n) is a matrix, U is a (m by m ) upper triangular matrix.
*

* * @param U An m by m non-singular upper triangular matrix. Not modified. * @param b An m by n matrix. Modified. * @param m size of the L matrix * @paramUn number of columns in the B matrix. * @param offsetU initial index in L where the matrix starts * @param offsetB initial index in B where the matrix starts */ public static void solveTransU( double U[] , double []b , int m , int n , int strideU , int offsetU , int offsetB ) { for( int j = 0; j < n; j++ ) { for( int i = 0; i < m; i++ ) { double sum = b[offsetB + i*n+j]; for( int k=0; k * Converts matrix data stored is a row major format into a block row major format in place. *

* * @param numRows number of rows in the matrix. * @param numCols number of columns in the matrix. * @param blockLength Block size in the converted matrix. * @param data Matrix data in a row-major format. Modified. * @param tmp Temporary data structure that is to be the size of a block row. */ public static void convertRowToBlock( int numRows , int numCols , int blockLength , double[] data, double[] tmp ) { int minLength = Math.min( blockLength , numRows ) * numCols; if( tmp.length < minLength ) { throw new IllegalArgumentException("tmp must be at least "+minLength+" long "); } for( int i = 0; i < numRows; i += blockLength ) { int blockHeight = Math.min( blockLength , numRows - i); System.arraycopy(data,i*numCols,tmp,0,blockHeight*numCols); for( int j = 0; j < numCols; j += blockLength ) { int blockWidth = Math.min( blockLength , numCols - j); int indexDst = i*numCols + blockHeight*j; int indexSrcRow = j; for( int k = 0; k < blockHeight; k++ ) { System.arraycopy(tmp,indexSrcRow,data,indexDst,blockWidth); indexDst += blockWidth; indexSrcRow += numCols; } } } } /** * Converts a row major block matrix into a row major matrix. * * @param src Original BlockMatrix64F.. Not modified. * @param dst Equivalent DenseMatrix64F. Modified. */ public static DenseMatrix64F convert( BlockMatrix64F src , DenseMatrix64F dst ) { return ConvertMatrixType.convert(src,dst); } /** *

* Converts matrix data stored is a block row major format into a row major format in place. *

* * @param numRows number of rows in the matrix. * @param numCols number of columns in the matrix. * @param blockLength Block size in the converted matrix. * @param data Matrix data in a block row-major format. Modified. * @param tmp Temporary data structure that is to be the size of a block row. */ public static void convertBlockToRow( int numRows , int numCols , int blockLength , double[] data, double[] tmp ) { int minLength = Math.min( blockLength , numRows ) * numCols; if( tmp.length < minLength ) { throw new IllegalArgumentException("tmp must be at least "+minLength+" long and not "+tmp.length); } for( int i = 0; i < numRows; i += blockLength ) { int blockHeight = Math.min( blockLength , numRows - i); System.arraycopy(data,i*numCols,tmp,0,blockHeight*numCols); for( int j = 0; j < numCols; j += blockLength ) { int blockWidth = Math.min( blockLength , numCols - j); int indexSrc = blockHeight*j; int indexDstRow = i*numCols + j; for( int k = 0; k < blockHeight; k++ ) { System.arraycopy(tmp,indexSrc,data,indexDstRow,blockWidth); indexSrc += blockWidth; indexDstRow += numCols; } } } } /** * Converts the transpose of a row major matrix into a row major block matrix. * * @param src Original DenseMatrix64F. Not modified. * @param dst Equivalent BlockMatrix64F. Modified. */ public static void convertTranSrc( DenseMatrix64F src , BlockMatrix64F dst ) { if( src.numRows != dst.numCols || src.numCols != dst.numRows ) throw new IllegalArgumentException("Incompatible matrix shapes."); for( int i = 0; i < dst.numRows; i += dst.blockLength ) { int blockHeight = Math.min( dst.blockLength , dst.numRows - i); for( int j = 0; j < dst.numCols; j += dst.blockLength ) { int blockWidth = Math.min( dst.blockLength , dst.numCols - j); int indexDst = i*dst.numCols + blockHeight*j; int indexSrc = j*src.numCols + i; for( int l = 0; l < blockWidth; l++ ) { int rowSrc = indexSrc + l*src.numCols; int rowDst = indexDst + l; for( int k = 0; k < blockHeight; k++ , rowDst += blockWidth ) { dst.data[ rowDst ] = src.data[rowSrc++]; } } } } } // This can be speed up by inlining the multBlock* calls, reducing number of multiplications // and other stuff. doesn't seem to have any speed advantage over mult_reorder() public static void mult( BlockMatrix64F A , BlockMatrix64F B , BlockMatrix64F C ) { if( A.numCols != B.numRows ) throw new IllegalArgumentException("Columns in A are incompatible with rows in B"); if( A.numRows != C.numRows ) throw new IllegalArgumentException("Rows in A are incompatible with rows in C"); if( B.numCols != C.numCols ) throw new IllegalArgumentException("Columns in B are incompatible with columns in C"); if( A.blockLength != B.blockLength || A.blockLength != C.blockLength ) throw new IllegalArgumentException("Block lengths are not all the same."); final int blockLength = A.blockLength; D1Submatrix64F Asub = new D1Submatrix64F(A,0, A.numRows, 0, A.numCols); D1Submatrix64F Bsub = new D1Submatrix64F(B,0, B.numRows, 0, B.numCols); D1Submatrix64F Csub = new D1Submatrix64F(C,0, C.numRows, 0, C.numCols); BlockMultiplication.mult(blockLength,Asub,Bsub,Csub); } public static void multTransA( BlockMatrix64F A , BlockMatrix64F B , BlockMatrix64F C ) { if( A.numRows != B.numRows ) throw new IllegalArgumentException("Rows in A are incompatible with rows in B"); if( A.numCols != C.numRows ) throw new IllegalArgumentException("Columns in A are incompatible with rows in C"); if( B.numCols != C.numCols ) throw new IllegalArgumentException("Columns in B are incompatible with columns in C"); if( A.blockLength != B.blockLength || A.blockLength != C.blockLength ) throw new IllegalArgumentException("Block lengths are not all the same."); final int blockLength = A.blockLength; D1Submatrix64F Asub = new D1Submatrix64F(A,0, A.numRows, 0, A.numCols); D1Submatrix64F Bsub = new D1Submatrix64F(B,0, B.numRows, 0, B.numCols); D1Submatrix64F Csub = new D1Submatrix64F(C,0, C.numRows, 0, C.numCols); BlockMultiplication.multTransA(blockLength,Asub,Bsub,Csub); } public static void multTransB( BlockMatrix64F A , BlockMatrix64F B , BlockMatrix64F C ) { if( A.numCols != B.numCols ) throw new IllegalArgumentException("Columns in A are incompatible with columns in B"); if( A.numRows != C.numRows ) throw new IllegalArgumentException("Rows in A are incompatible with rows in C"); if( B.numRows != C.numCols ) throw new IllegalArgumentException("Rows in B are incompatible with columns in C"); if( A.blockLength != B.blockLength || A.blockLength != C.blockLength ) throw new IllegalArgumentException("Block lengths are not all the same."); final int blockLength = A.blockLength; D1Submatrix64F Asub = new D1Submatrix64F(A,0, A.numRows, 0, A.numCols); D1Submatrix64F Bsub = new D1Submatrix64F(B,0, B.numRows, 0, B.numCols); D1Submatrix64F Csub = new D1Submatrix64F(C,0, C.numRows, 0, C.numCols); BlockMultiplication.multTransB(blockLength,Asub,Bsub,Csub); } /** * Transposes a block matrix. * * @param A Original matrix. Not modified. * @param A_tran Transposed matrix. Modified. */ public static BlockMatrix64F transpose( BlockMatrix64F A , BlockMatrix64F A_tran ) { if( A_tran != null ) { if( A.numRows != A_tran.numCols || A.numCols != A_tran.numRows ) throw new IllegalArgumentException("Incompatible dimensions."); if( A.blockLength != A_tran.blockLength ) throw new IllegalArgumentException("Incompatible block size."); } else { A_tran = new BlockMatrix64F(A.numCols,A.numRows,A.blockLength); } for( int i = 0; i < A.numRows; i += A.blockLength ) { int blockHeight = Math.min( A.blockLength , A.numRows - i); for( int j = 0; j < A.numCols; j += A.blockLength ) { int blockWidth = Math.min( A.blockLength , A.numCols - j); int indexA = i*A.numCols + blockHeight*j; int indexC = j*A_tran.numCols + blockWidth*i; transposeBlock( A , A_tran , indexA , indexC , blockWidth , blockHeight ); } } return A_tran; } /** * Transposes an individual block inside a block matrix. */ private static void transposeBlock( BlockMatrix64F A , BlockMatrix64F A_tran, int indexA , int indexC , int width , int height ) { for( int i = 0; i < height; i++ ) { int rowIndexC = indexC + i; int rowIndexA = indexA + width*i; int end = rowIndexA + width; for( ; rowIndexA < end; rowIndexC += height, rowIndexA++ ) { A_tran.data[ rowIndexC ] = A.data[ rowIndexA ]; } } } public static BlockMatrix64F createRandom( int numRows , int numCols , double min , double max , Random rand ) { BlockMatrix64F ret = new BlockMatrix64F(numRows,numCols); RandomMatrices.setRandom(ret,min,max,rand); return ret; } public static BlockMatrix64F createRandom( int numRows , int numCols , double min , double max , Random rand , int blockLength ) { BlockMatrix64F ret = new BlockMatrix64F(numRows,numCols,blockLength); RandomMatrices.setRandom(ret,min,max,rand); return ret; } public static BlockMatrix64F convert(DenseMatrix64F A , int blockLength ) { BlockMatrix64F ret = new BlockMatrix64F(A.numRows,A.numCols,blockLength); convert(A,ret); return ret; } public static BlockMatrix64F convert(DenseMatrix64F A ) { BlockMatrix64F ret = new BlockMatrix64F(A.numRows,A.numCols); convert(A,ret); return ret; } public static boolean isEquals( BlockMatrix64F A , BlockMatrix64F B ) { if( A.blockLength != B.blockLength ) return false; return MatrixFeatures.isEquals(A,B); } public static boolean isEquals( BlockMatrix64F A , BlockMatrix64F B , double tol ) { if( A.blockLength != B.blockLength ) return false; return MatrixFeatures.isEquals(A,B,tol); } /** * Sets either the upper or low triangle of a matrix to zero */ public static void zeroTriangle( boolean upper , BlockMatrix64F A ) { int blockLength = A.blockLength; if( upper ) { for( int i = 0; i < A.numRows; i += blockLength ) { int h = Math.min(blockLength,A.numRows-i); for( int j = i; j < A.numCols; j += blockLength ) { int w = Math.min(blockLength,A.numCols-j); int index = i*A.numCols + h*j; if( j == i ) { for( int k = 0; k < h; k++ ) { for( int l = k+1; l < w; l++ ) { A.data[index + w*k+l ] = 0; } } } else { for( int k = 0; k < h; k++ ) { for( int l = 0; l < w; l++ ) { A.data[index + w*k+l ] = 0; } } } } } } else { for( int i = 0; i < A.numRows; i += blockLength ) { int h = Math.min(blockLength,A.numRows-i); for( int j = 0; j <= i; j += blockLength ) { int w = Math.min(blockLength,A.numCols-j); int index = i*A.numCols + h*j; if( j == i ) { for( int k = 0; k < h; k++ ) { int z = Math.min(k,w); for( int l = 0; l < z; l++ ) { A.data[index + w*k+l ] = 0; } } } else { for( int k = 0; k < h; k++ ) { for( int l = 0; l < w; l++ ) { A.data[index + w*k+l ] = 0; } } } } } } } /** * Copies either the upper or lower triangular portion of src into dst. Dst can be smaller * than src. * * @param upper If the upper or lower triangle is copied. * @param src The source matrix. Not modified. * @param dst The destination matrix. Modified. */ public static void copyTriangle( boolean upper , BlockMatrix64F src , BlockMatrix64F dst ) { if( src.blockLength != dst.blockLength ) throw new IllegalArgumentException("Block size is different"); if( src.numRows < dst.numRows ) throw new IllegalArgumentException("The src has fewer rows than dst"); if( src.numCols < dst.numCols ) throw new IllegalArgumentException("The src has fewer columns than dst"); int blockLength = src.blockLength; int numRows = Math.min(src.numRows,dst.numRows); int numCols = Math.min(src.numCols,dst.numCols); if( upper ) { for( int i = 0; i < numRows; i += blockLength ) { int heightSrc = Math.min(blockLength,src.numRows-i); int heightDst = Math.min(blockLength,dst.numRows-i); for( int j = i; j < numCols; j += blockLength ) { int widthSrc = Math.min(blockLength,src.numCols-j); int widthDst = Math.min(blockLength,dst.numCols-j); int indexSrc = i*src.numCols + heightSrc*j; int indexDst = i*dst.numCols + heightDst*j; if( j == i ) { for( int k = 0; k < heightDst; k++ ) { for( int l = k; l < widthDst; l++ ) { dst.data[indexDst + widthDst*k+l ] = src.data[indexSrc + widthSrc*k+l ]; } } } else { for( int k = 0; k < heightDst; k++ ) { System.arraycopy(src.data, indexSrc + widthSrc * k, dst.data, indexDst + widthDst * k, widthDst); } } } } } else { for( int i = 0; i < numRows; i += blockLength ) { int heightSrc = Math.min(blockLength,src.numRows-i); int heightDst = Math.min(blockLength,dst.numRows-i); for( int j = 0; j <= i; j += blockLength ) { int widthSrc = Math.min(blockLength,src.numCols-j); int widthDst = Math.min(blockLength,dst.numCols-j); int indexSrc = i*src.numCols + heightSrc*j; int indexDst = i*dst.numCols + heightDst*j; if( j == i ) { for( int k = 0; k < heightDst; k++ ) { int z = Math.min(k+1,widthDst); for( int l = 0; l < z; l++ ) { dst.data[indexDst + widthDst*k+l ] = src.data[indexSrc + widthSrc*k+l ]; } } } else { for( int k = 0; k < heightDst; k++ ) { System.arraycopy(src.data, indexSrc + widthSrc * k, dst.data, indexDst + widthDst * k, widthDst); } } } } } } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param A A matrix whose elements are about to be set. Modified. * @param value The value each element will have. */ public static void set( BlockMatrix64F A , double value ) { CommonOps.fill(A, value); } /** *

Sets the value of A to all zeros except along the diagonal.

* * @param A Block matrix. */ public static void setIdentity( BlockMatrix64F A ) { int minLength = Math.min(A.numRows,A.numCols); CommonOps.fill(A, 0); int blockLength = A.blockLength; for( int i = 0; i < minLength; i += blockLength ) { int h = Math.min(blockLength,A.numRows-i); int w = Math.min(blockLength,A.numCols-i); int index = i*A.numCols + h*i; int m = Math.min(h,w); for( int k = 0; k < m; k++ ) { A.data[index + k*w + k ] = 1; } } } /** *

* Returns a new matrix with ones along the diagonal and zeros everywhere else. *

* * @param numRows Number of rows. * @param numCols NUmber of columns. * @param blockLength Block length. * @return An identify matrix. */ public static BlockMatrix64F identity(int numRows, int numCols, int blockLength ) { BlockMatrix64F A = new BlockMatrix64F(numRows,numCols,blockLength); int minLength = Math.min(numRows,numCols); for( int i = 0; i < minLength; i += blockLength ) { int h = Math.min(blockLength,A.numRows-i); int w = Math.min(blockLength,A.numCols-i); int index = i*A.numCols + h*i; int m = Math.min(h,w); for( int k = 0; k < m; k++ ) { A.data[index + k*w + k ] = 1; } } return A; } /** *

* Checks to see if the two matrices have an identical shape an block size. *

* * @param A Matrix. * @param B Matrix. */ public static void checkIdenticalShape( BlockMatrix64F A , BlockMatrix64F B ) { if( A.blockLength != B.blockLength ) throw new IllegalArgumentException("Block size is different"); if( A.numRows != B.numRows ) throw new IllegalArgumentException("Number of rows is different"); if( A.numCols != B.numCols ) throw new IllegalArgumentException("NUmber of columns is different"); } /** *

* Extracts a matrix from src into dst. The submatrix which is copied has its initial coordinate * at (0,0) and ends at (dst.numRows,dst.numCols). The end rows/columns must be aligned along blocks * or else it will silently screw things up. *

* * @param src Matrix which a submatrix is being extracted from. Not modified. * @param dst Where the submatrix is written to. Its rows and columns be less than or equal to 'src'. Modified. */ public static void extractAligned(BlockMatrix64F src, BlockMatrix64F dst) { if( src.blockLength != dst.blockLength ) throw new IllegalArgumentException("Block size is different"); if( src.numRows < dst.numRows ) throw new IllegalArgumentException("The src has fewer rows than dst"); if( src.numCols < dst.numCols ) throw new IllegalArgumentException("The src has fewer columns than dst"); int blockLength = src.blockLength; int numRows = Math.min(src.numRows,dst.numRows); int numCols = Math.min(src.numCols,dst.numCols); for( int i = 0; i < numRows; i += blockLength ) { int heightSrc = Math.min(blockLength,src.numRows-i); int heightDst = Math.min(blockLength,dst.numRows-i); for( int j = 0; j < numCols; j += blockLength ) { int widthSrc = Math.min(blockLength,src.numCols-j); int widthDst = Math.min(blockLength,dst.numCols-j); int indexSrc = i*src.numCols + heightSrc*j; int indexDst = i*dst.numCols + heightDst*j; for( int k = 0; k < heightDst; k++ ) { System.arraycopy(src.data, indexSrc + widthSrc * k, dst.data, indexDst + widthDst * k, widthDst); } } } } /** * Checks to see if the submatrix has its boundaries along inner blocks. * * @param blockLength Size of an inner block. * @param A Submatrix. * @return If it is block aligned or not. */ public static boolean blockAligned( int blockLength , D1Submatrix64F A ) { if( A.col0 % blockLength != 0 ) return false; if( A.row0 % blockLength != 0 ) return false; if( A.col1 % blockLength != 0 && A.col1 != A.original.numCols ) { return false; } if( A.row1 % blockLength != 0 && A.row1 != A.original.numRows) { return false; } return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/BlockMultiplication.java000066400000000000000000000311341256171534400255550ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.D1Submatrix64F; import static org.ejml.alg.block.BlockInnerMultiplication.*; /** *

* Matrix multiplication for {@link org.ejml.data.BlockMatrix64F}. All sub-matrices must be * block aligned. *

* * @author Peter Abeles */ public class BlockMultiplication { /** *

* Performs a matrix multiplication on {@link org.ejml.data.BlockMatrix64F} submatrices.
*
* c = a * b
*
*

* *

* It is assumed that all submatrices start at the beginning of a block and end at the end of a block. *

* * @param blockLength Size of the blocks in the submatrix. * @param A A submatrix. Not modified. * @param B A submatrix. Not modified. * @param C Result of the operation. Modified, */ public static void mult( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { for( int i = A.row0; i < A.row1; i += blockLength ) { int heightA = Math.min( blockLength , A.row1 - i ); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = (i-A.row0+C.row0)*C.original.numCols + (j-B.col0+C.col0)*heightA; for( int k = A.col0; k < A.col1; k += blockLength ) { int widthA = Math.min( blockLength , A.col1 - k ); int indexA = i*A.original.numCols + k*heightA; int indexB = (k-A.col0+B.row0)*B.original.numCols + j*widthA; if( k == A.col0 ) blockMultSet(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); else blockMultPlus(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); } } } } /** *

* Performs a matrix multiplication on {@link org.ejml.data.BlockMatrix64F} submatrices.
*
* c = c + a * b
*
*

* *

* It is assumed that all submatrices start at the beginning of a block and end at the end of a block. *

* * @param blockLength Size of the blocks in the submatrix. * @param A A submatrix. Not modified. * @param B A submatrix. Not modified. * @param C Result of the operation. Modified, */ public static void multPlus( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { // checkInput( blockLength,A,B,C); for( int i = A.row0; i < A.row1; i += blockLength ) { int heightA = Math.min( blockLength , A.row1 - i ); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = (i-A.row0+C.row0)*C.original.numCols + (j-B.col0+C.col0)*heightA; for( int k = A.col0; k < A.col1; k += blockLength ) { int widthA = Math.min( blockLength , A.col1 - k ); int indexA = i*A.original.numCols + k*heightA; int indexB = (k-A.col0+B.row0)*B.original.numCols + j*widthA; blockMultPlus(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); } } } } /** *

* Performs a matrix multiplication on {@link org.ejml.data.BlockMatrix64F} submatrices.
*
* c = c - a * b
*
*

* *

* It is assumed that all submatrices start at the beginning of a block and end at the end of a block. *

* * @param blockLength Size of the blocks in the submatrix. * @param A A submatrix. Not modified. * @param B A submatrix. Not modified. * @param C Result of the operation. Modified, */ public static void multMinus( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { checkInput( blockLength,A,B,C); for( int i = A.row0; i < A.row1; i += blockLength ) { int heightA = Math.min( blockLength , A.row1 - i ); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = (i-A.row0+C.row0)*C.original.numCols + (j-B.col0+C.col0)*heightA; for( int k = A.col0; k < A.col1; k += blockLength ) { int widthA = Math.min( blockLength , A.col1 - k ); int indexA = i*A.original.numCols + k*heightA; int indexB = (k-A.col0+B.row0)*B.original.numCols + j*widthA; blockMultMinus(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); } } } } private static void checkInput( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { int Arow = A.getRows();int Acol = A.getCols(); int Brow = B.getRows();int Bcol = B.getCols(); int Crow = C.getRows();int Ccol = C.getCols(); if( Arow != Crow ) throw new RuntimeException("Mismatch A and C rows"); if( Bcol != Ccol ) throw new RuntimeException("Mismatch B and C columns"); if( Acol != Brow ) throw new RuntimeException("Mismatch A columns and B rows"); if( !BlockMatrixOps.blockAligned(blockLength,A)) throw new RuntimeException("Sub-Matrix A is not block aligned"); if( !BlockMatrixOps.blockAligned(blockLength,B)) throw new RuntimeException("Sub-Matrix B is not block aligned"); if( !BlockMatrixOps.blockAligned(blockLength,C)) throw new RuntimeException("Sub-Matrix C is not block aligned"); } /** *

* Performs a matrix multiplication with a transpose on {@link org.ejml.data.BlockMatrix64F} submatrices.
*
* c = aT * b
*
*

* *

* It is assumed that all submatrices start at the beginning of a block and end at the end of a block. *

* * @param blockLength Size of the blocks in the submatrix. * @param A A submatrix. Not modified. * @param B A submatrix. Not modified. * @param C Result of the operation. Modified, */ public static void multTransA( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { for( int i = A.col0; i < A.col1; i += blockLength ) { int widthA = Math.min( blockLength , A.col1 - i ); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = (i-A.col0+C.row0)*C.original.numCols + (j-B.col0+C.col0)*widthA; for( int k = A.row0; k < A.row1; k += blockLength ) { int heightA = Math.min( blockLength , A.row1 - k ); int indexA = k*A.original.numCols + i*heightA; int indexB = (k-A.row0+B.row0)*B.original.numCols + j*heightA; if( k == A.row0 ) blockMultSetTransA(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); else blockMultPlusTransA(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); } } } } public static void multPlusTransA( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { for( int i = A.col0; i < A.col1; i += blockLength ) { int widthA = Math.min( blockLength , A.col1 - i ); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = (i-A.col0+C.row0)*C.original.numCols + (j-B.col0+C.col0)*widthA; for( int k = A.row0; k < A.row1; k += blockLength ) { int heightA = Math.min( blockLength , A.row1 - k ); int indexA = k*A.original.numCols + i*heightA; int indexB = (k-A.row0+B.row0)*B.original.numCols + j*heightA; blockMultPlusTransA(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); } } } } public static void multMinusTransA( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { for( int i = A.col0; i < A.col1; i += blockLength ) { int widthA = Math.min( blockLength , A.col1 - i ); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = (i-A.col0+C.row0)*C.original.numCols + (j-B.col0+C.col0)*widthA; for( int k = A.row0; k < A.row1; k += blockLength ) { int heightA = Math.min( blockLength , A.row1 - k ); int indexA = k*A.original.numCols + i*heightA; int indexB = (k-A.row0+B.row0)*B.original.numCols + j*heightA; blockMultMinusTransA(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); } } } } /** *

* Performs a matrix multiplication with a transpose on {@link org.ejml.data.BlockMatrix64F} submatrices.
*
* c = a * b T
*
*

* *

* It is assumed that all submatrices start at the beginning of a block and end at the end of a block. *

* * @param blockLength Length of the blocks in the submatrix. * @param A A submatrix. Not modified. * @param B A submatrix. Not modified. * @param C Result of the operation. Modified, */ public static void multTransB( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { for( int i = A.row0; i < A.row1; i += blockLength ) { int heightA = Math.min( blockLength , A.row1 - i ); for( int j = B.row0; j < B.row1; j += blockLength ) { int widthC = Math.min( blockLength , B.row1 - j ); int indexC = (i-A.row0+C.row0)*C.original.numCols + (j-B.row0+C.col0)*heightA; for( int k = A.col0; k < A.col1; k += blockLength ) { int widthA = Math.min( blockLength , A.col1 - k ); int indexA = i*A.original.numCols + k*heightA; int indexB = j*B.original.numCols + (k-A.col0+B.col0)*widthC; if( k == A.col0 ) blockMultSetTransB(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthC); else blockMultPlusTransB(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthC); } } } } } ejml-0.28/main/dense64/src/org/ejml/alg/block/BlockTriangularSolver.java000066400000000000000000000466671256171534400261040ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.D1Submatrix64F; import static org.ejml.alg.block.BlockInnerMultiplication.blockMultMinus; /** *

* Contains triangular solvers for {@link org.ejml.data.BlockMatrix64F} block aligned sub-matrices. *

* *

* For a more detailed description of a similar algorithm see: * Page 30 in "Fundamentals of Matrix Computations" 2nd Ed. by David S. Watkins * or any description of a block triangular solver in any other computational linear algebra book. *

* * @author Peter Abeles */ public class BlockTriangularSolver { /** * Inverts an upper or lower triangular block submatrix. * * @param blockLength * @param upper Is it upper or lower triangular. * @param T Triangular matrix that is to be inverted. Must be block aligned. Not Modified. * @param T_inv Where the inverse is stored. This can be the same as T. Modified. * @param temp Work space variable that is size blockLength*blockLength. */ public static void invert( final int blockLength , final boolean upper , final D1Submatrix64F T , final D1Submatrix64F T_inv , final double temp[] ) { if( upper ) throw new IllegalArgumentException("Upper triangular matrices not supported yet"); if( temp.length < blockLength*blockLength ) throw new IllegalArgumentException("Temp must be at least blockLength*blockLength long."); if( T.row0 != T_inv.row0 || T.row1 != T_inv.row1 || T.col0 != T_inv.col0 || T.col1 != T_inv.col1) throw new IllegalArgumentException("T and T_inv must be at the same elements in the matrix"); final int M = T.row1-T.row0; final double dataT[] = T.original.data; final double dataX[] = T_inv.original.data; final int offsetT = T.row0*T.original.numCols+M*T.col0; for( int i = 0; i < M; i += blockLength ) { int heightT = Math.min(T.row1-(i+T.row0),blockLength); int indexII = offsetT + T.original.numCols*(i+T.row0) + heightT*(i+T.col0); for( int j = 0; j < i; j += blockLength ) { int widthX = Math.min(T.col1-(j+T.col0),blockLength); for( int w = 0; w < temp.length; w++ ) { temp[w] = 0; } for( int k = j; k < i; k += blockLength ) { int widthT = Math.min(T.col1-(k+T.col0),blockLength); int indexL = offsetT + T.original.numCols*(i+T.row0) + heightT*(k+T.col0); int indexX = offsetT + T.original.numCols*(k+T.row0) + widthT*(j+T.col0); blockMultMinus(dataT,dataX,temp,indexL,indexX,0,heightT,widthT,widthX); } int indexX = offsetT + T.original.numCols*(i+T.row0) + heightT*(j+T.col0); BlockInnerTriangularSolver.solveL(dataT,temp,heightT,widthX,heightT,indexII,0); System.arraycopy(temp,0,dataX,indexX,widthX*heightT); } BlockInnerTriangularSolver.invertLower(dataT,dataX,heightT,indexII,indexII); } } /** * Inverts an upper or lower triangular block submatrix. * * @param blockLength * @param upper Is it upper or lower triangular. * @param T Triangular matrix that is to be inverted. Overwritten with solution. Modified. * @param temp Work space variable that is size blockLength*blockLength. */ public static void invert( final int blockLength , final boolean upper , final D1Submatrix64F T , final double temp[] ) { if( upper ) throw new IllegalArgumentException("Upper triangular matrices not supported yet"); if( temp.length < blockLength*blockLength ) throw new IllegalArgumentException("Temp must be at least blockLength*blockLength long."); final int M = T.row1-T.row0; final double dataT[] = T.original.data; final int offsetT = T.row0*T.original.numCols+M*T.col0; for( int i = 0; i < M; i += blockLength ) { int heightT = Math.min(T.row1-(i+T.row0),blockLength); int indexII = offsetT + T.original.numCols*(i+T.row0) + heightT*(i+T.col0); for( int j = 0; j < i; j += blockLength ) { int widthX = Math.min(T.col1-(j+T.col0),blockLength); for( int w = 0; w < temp.length; w++ ) { temp[w] = 0; } for( int k = j; k < i; k += blockLength ) { int widthT = Math.min(T.col1-(k+T.col0),blockLength); int indexL = offsetT + T.original.numCols*(i+T.row0) + heightT*(k+T.col0); int indexX = offsetT + T.original.numCols*(k+T.row0) + widthT*(j+T.col0); blockMultMinus(dataT,dataT,temp,indexL,indexX,0,heightT,widthT,widthX); } int indexX = offsetT + T.original.numCols*(i+T.row0) + heightT*(j+T.col0); BlockInnerTriangularSolver.solveL(dataT,temp,heightT,widthX,heightT,indexII,0); System.arraycopy(temp,0,dataT,indexX,widthX*heightT); } BlockInnerTriangularSolver.invertLower(dataT,heightT,indexII); } } /** *

* Performs an in-place solve operation on the provided block aligned sub-matrices.
*
* B = T-1 B
*
* where T is a triangular matrix. T or B can be transposed. T is a square matrix of arbitrary * size and B has the same number of rows as T and an arbitrary number of columns. *

* * @param blockLength Size of the inner blocks. * @param upper If T is upper or lower triangular. * @param T An upper or lower triangular matrix. Not modified. * @param B A matrix whose height is the same as T's width. Solution is written here. Modified. */ public static void solve( final int blockLength , final boolean upper , final D1Submatrix64F T , final D1Submatrix64F B , final boolean transT ) { if( upper ) { solveR(blockLength,T,B,transT); } else { solveL(blockLength,T,B,transT); } } /** *

* Performs an in-place solve operation where T is contained in a single block.
*
* B = T-1 B
*
* where T is a triangular matrix contained in an inner block. T or B can be transposed. T must be a single complete inner block * and B is either a column block vector or row block vector. *

* * @param blockLength Size of the inner blocks in the block matrix. * @param upper If T is upper or lower triangular. * @param T An upper or lower triangular matrix that is contained in an inner block. Not modified. * @param B A block aligned row or column submatrix. Modified. * @param transT If T is transposed or not. * @param transB If B is transposed or not. */ public static void solveBlock( final int blockLength , final boolean upper , final D1Submatrix64F T , final D1Submatrix64F B , final boolean transT ,final boolean transB ) { int Trows = T.row1-T.row0; if( Trows > blockLength ) throw new IllegalArgumentException("T can be at most the size of a block"); // number of rows in a block. The submatrix can be smaller than a block final int blockT_rows = Math.min(blockLength,T.original.numRows-T.row0); final int blockT_cols = Math.min(blockLength,T.original.numCols-T.col0); int offsetT = T.row0*T.original.numCols+blockT_rows*T.col0; final double dataT[] = T.original.data; final double dataB[] = B.original.data; if( transB ) { if( upper ) { if ( transT ) { throw new IllegalArgumentException("Operation not yet supported"); } else { throw new IllegalArgumentException("Operation not yet supported"); } } else { if ( transT ) { throw new IllegalArgumentException("Operation not yet supported"); } else { for( int i = B.row0; i < B.row1; i += blockLength ) { int N = Math.min(B.row1 , i + blockLength ) - i; int offsetB = i*B.original.numCols + N*B.col0; BlockInnerTriangularSolver.solveLTransB(dataT,dataB,blockT_rows,N,blockT_rows,offsetT,offsetB); } } } } else { if( Trows != B.row1-B.row0 ) throw new IllegalArgumentException("T and B must have the same number of rows."); if( upper ) { if ( transT ) { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveTransU(dataT,dataB,Trows,N,Trows,offsetT,offsetB); } } else { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveU(dataT,dataB,Trows,N,Trows,offsetT,offsetB); } } } else { if ( transT ) { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveTransL(dataT,dataB,Trows,N,blockT_cols,offsetT,offsetB); } } else { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveL(dataT,dataB,Trows,N,blockT_cols,offsetT,offsetB); } } } } } /** *

* Solves lower triangular systems:
*
* B = L-1 B
*
*

* *

Reverse or forward substitution is used depending upon L being transposed or not.

* * @param blockLength * @param L Lower triangular with dimensions m by m. Not modified. * @param B A matrix with dimensions m by n. Solution is written into here. Modified. * @param transL Is the triangular matrix transposed? */ public static void solveL( final int blockLength , final D1Submatrix64F L, final D1Submatrix64F B , boolean transL ) { D1Submatrix64F Y = new D1Submatrix64F(B.original); D1Submatrix64F Linner = new D1Submatrix64F(L.original); D1Submatrix64F Binner = new D1Submatrix64F(B.original); int lengthL = B.row1 - B.row0; int startI,stepI; if( transL ) { startI = lengthL - lengthL % blockLength; if( startI == lengthL && lengthL >= blockLength ) startI -= blockLength; stepI = -blockLength; } else { startI = 0; stepI = blockLength; } for( int i = startI; ; i += stepI ) { if( transL ) { if( i < 0 ) break; } else { if( i >= lengthL ) break; } // width and height of the inner T(i,i) block int widthT = Math.min(blockLength, lengthL-i); Linner.col0 = L.col0 + i; Linner.col1 = Linner.col0 + widthT; Linner.row0 = L.row0 + i; Linner.row1 = Linner.row0 + widthT; Binner.col0 = B.col0; Binner.col1 = B.col1; Binner.row0 = B.row0 + i; Binner.row1 = Binner.row0 + widthT; // solve the top row block // B(i,:) = T(i,i)^-1 Y(i,:) solveBlock(blockLength,false, Linner,Binner,transL,false); boolean updateY; if( transL ) { updateY = Linner.row0 > 0; } else { updateY = Linner.row1 < L.row1; } if( updateY ) { // Y[i,:] = Y[i,:] - sum j=1:i-1 { T[i,j] B[j,i] } // where i is the next block down // The summation is a block inner product if( transL ) { Linner.col1 = Linner.col0; Linner.col0 = Linner.col1 - blockLength; Linner.row1 = L.row1; //Tinner.col1 = Tinner.col1; // Binner.row0 = Binner.row0; Binner.row1 = B.row1; Y.row0 = Binner.row0-blockLength; Y.row1 = Binner.row0; } else { Linner.row0 = Linner.row1; Linner.row1 = Math.min(Linner.row0+blockLength, L.row1); Linner.col0 = L.col0; //Tinner.col1 = Tinner.col1; Binner.row0 = B.row0; //Binner.row1 = Binner.row1; Y.row0 = Binner.row1; Y.row1 = Math.min(Y.row0+blockLength,B.row1); } // step through each block column for( int k = B.col0; k < B.col1; k += blockLength ) { Binner.col0 = k; Binner.col1 = Math.min(k+blockLength,B.col1); Y.col0 = Binner.col0; Y.col1 = Binner.col1; if( transL ) { // Y = Y - T^T * B BlockMultiplication.multMinusTransA(blockLength, Linner,Binner,Y); } else { // Y = Y - T * B BlockMultiplication.multMinus(blockLength, Linner,Binner,Y); } } } } } /** *

* Solves upper triangular systems:
*
* B = R-1 B
*
*

* *

Only the first B.numRows rows in R will be processed. Lower triangular elements are ignored.

* *

Reverse or forward substitution is used depending upon L being transposed or not.

* * @param blockLength * @param R Upper triangular with dimensions m by m. Not modified. * @param B A matrix with dimensions m by n. Solution is written into here. Modified. * @param transR Is the triangular matrix transposed? */ public static void solveR( final int blockLength , final D1Submatrix64F R, final D1Submatrix64F B , boolean transR ) { int lengthR = B.row1 - B.row0; if( R.getCols() != lengthR ) { throw new IllegalArgumentException("Number of columns in R must be equal to the number of rows in B"); } else if( R.getRows() != lengthR ) { throw new IllegalArgumentException("Number of rows in R must be equal to the number of rows in B"); } D1Submatrix64F Y = new D1Submatrix64F(B.original); D1Submatrix64F Rinner = new D1Submatrix64F(R.original); D1Submatrix64F Binner = new D1Submatrix64F(B.original); int startI,stepI; if( transR ) { startI = 0; stepI = blockLength; } else { startI = lengthR - lengthR % blockLength; if( startI == lengthR && lengthR >= blockLength ) startI -= blockLength; stepI = -blockLength; } for( int i = startI; ; i += stepI ) { if( transR ) { if( i >= lengthR ) break; } else { if( i < 0 ) break; } // width and height of the inner T(i,i) block int widthT = Math.min(blockLength, lengthR-i); Rinner.col0 = R.col0 + i; Rinner.col1 = Rinner.col0 + widthT; Rinner.row0 = R.row0 + i; Rinner.row1 = Rinner.row0 + widthT; Binner.col0 = B.col0; Binner.col1 = B.col1; Binner.row0 = B.row0 + i; Binner.row1 = Binner.row0 + widthT; // solve the top row block // B(i,:) = T(i,i)^-1 Y(i,:) solveBlock(blockLength,true, Rinner,Binner,transR,false); boolean updateY; if( transR ) { updateY = Rinner.row1 < R.row1; } else { updateY = Rinner.row0 > 0; } if( updateY ) { // Y[i,:] = Y[i,:] - sum j=1:i-1 { T[i,j] B[j,i] } // where i is the next block down // The summation is a block inner product if( transR ) { Rinner.col0 = Rinner.col1; Rinner.col1 = Math.min(Rinner.col0+blockLength, R.col1); Rinner.row0 = R.row0; //Rinner.row1 = Rinner.row1; Binner.row0 = B.row0; //Binner.row1 = Binner.row1; Y.row0 = Binner.row1; Y.row1 = Math.min(Y.row0+blockLength,B.row1); } else { Rinner.row1 = Rinner.row0; Rinner.row0 = Rinner.row1 - blockLength; Rinner.col1 = R.col1; // Binner.row0 = Binner.row0; Binner.row1 = B.row1; Y.row0 = Binner.row0-blockLength; Y.row1 = Binner.row0; } // step through each block column for( int k = B.col0; k < B.col1; k += blockLength ) { Binner.col0 = k; Binner.col1 = Math.min(k+blockLength,B.col1); Y.col0 = Binner.col0; Y.col1 = Binner.col1; if( transR ) { // Y = Y - T^T * B BlockMultiplication.multMinusTransA(blockLength, Rinner,Binner,Y); } else { // Y = Y - T * B BlockMultiplication.multMinus(blockLength, Rinner,Binner,Y); } } } } } } ejml-0.28/main/dense64/src/org/ejml/alg/block/BlockVectorOps.java000066400000000000000000000322721256171534400245100ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.D1Submatrix64F; /** *

* Math operations for inner vectors (row and column) inside of block matrices:
*
* scale: bi = α*ai
* div: i = ai
* add: ci = α*ai + βBi
* dot: c = sum ai*bi
*

* *

* All submatrices must be block aligned. All offsets and end indexes are relative to the beginning of each * submatrix. *

* * @author Peter Abeles */ public class BlockVectorOps { /** *

* Row vector scale:
* scale: bi = α*ai
* where 'a' and 'b' are row vectors within the row block vector A and B. *

* * @param A submatrix. Not modified. * @param rowA which row in A the vector is contained in. * @param alpha scale factor. * @param B submatrix that the results are written to. Modified. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. */ public static void scale_row(final int blockLength, D1Submatrix64F A, int rowA, double alpha, D1Submatrix64F B, int rowB, int offset, int end) { final double dataA[] = A.original.data; final double dataB[] = B.original.data; // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; // handle rows in any block int rowBlockA = A.row0 + rowA - rowA % blockLength; rowA = rowA % blockLength; int rowBlockB = B.row0 + rowB - rowB % blockLength; rowB = rowB % blockLength; final int heightA = Math.min(blockLength,A.row1-rowBlockA); final int heightB = Math.min(blockLength,B.row1-rowBlockB); for( int i = startI; i < end; i += blockLength ) { int segment = Math.min(blockLength,end-i); int widthA = Math.min(blockLength,A.col1-A.col0-i); int widthB = Math.min(blockLength,B.col1-B.col0-i); int indexA = rowBlockA*A.original.numCols + (A.col0+i)*heightA + rowA*widthA; int indexB = rowBlockB*B.original.numCols + (B.col0+i)*heightB + rowB*widthB; if( i == startI ) { indexA += offset; indexB += offset; for( int j = offset; j < segment; j++ ) { dataB[indexB++] = alpha*dataA[indexA++]; } } else { for( int j = 0; j < segment; j++ ) { dataB[indexB++] = alpha*dataA[indexA++]; } } } } /** *

* Row vector divide:
* div: bi = ai
* where 'a' and 'b' are row vectors within the row block vector A and B. *

* * @param A submatrix. Not modified. * @param rowA which row in A the vector is contained in. * @param alpha scale factor. * @param B submatrix that the results are written to. Modified. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. */ public static void div_row(final int blockLength, D1Submatrix64F A, int rowA, double alpha, D1Submatrix64F B, int rowB, int offset, int end) { final double dataA[] = A.original.data; final double dataB[] = B.original.data; // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; // handle rows in any block int rowBlockA = A.row0 + rowA - rowA % blockLength; rowA = rowA % blockLength; int rowBlockB = B.row0 + rowB - rowB % blockLength; rowB = rowB % blockLength; final int heightA = Math.min(blockLength,A.row1-rowBlockA); final int heightB = Math.min(blockLength,B.row1-rowBlockB); for( int i = startI; i < end; i += blockLength ) { int segment = Math.min(blockLength,end-i); int widthA = Math.min(blockLength,A.col1-A.col0-i); int widthB = Math.min(blockLength,B.col1-B.col0-i); int indexA = rowBlockA*A.original.numCols + (A.col0+i)*heightA + rowA*widthA; int indexB = rowBlockB*B.original.numCols + (B.col0+i)*heightB + rowB*widthB; if( i == startI ) { indexA += offset; indexB += offset; for( int j = offset; j < segment; j++ ) { dataB[indexB++] = dataA[indexA++]/alpha; } } else { for( int j = 0; j < segment; j++ ) { dataB[indexB++] = dataA[indexA++]/alpha; } } } } /** *

* Row vector add:
* add: ci = α*ai + βBi
* where 'a', 'b', and 'c' are row vectors within the row block vectors of A, B, and C respectively. *

* * @param blockLength Length of each inner matrix block. * @param A submatrix. Not modified. * @param rowA which row in A the vector is contained in. * @param alpha scale factor of A * @param B submatrix. Not modified. * @param rowB which row in B the vector is contained in. * @param beta scale factor of B * @param C submatrix where the results are written to. Modified. * @param rowC which row in C is the vector contained. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. */ public static void add_row( final int blockLength , D1Submatrix64F A , int rowA , double alpha , D1Submatrix64F B , int rowB , double beta , D1Submatrix64F C , int rowC , int offset , int end ) { final int heightA = Math.min(blockLength,A.row1-A.row0); final int heightB = Math.min(blockLength,B.row1-B.row0); final int heightC = Math.min(blockLength,C.row1-C.row0); // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; final double dataA[] = A.original.data; final double dataB[] = B.original.data; final double dataC[] = C.original.data; for( int i = startI; i < end; i += blockLength ) { int segment = Math.min(blockLength,end-i); int widthA = Math.min(blockLength,A.col1-A.col0-i); int widthB = Math.min(blockLength,B.col1-B.col0-i); int widthC = Math.min(blockLength,C.col1-C.col0-i); int indexA = A.row0*A.original.numCols + (A.col0+i)*heightA + rowA*widthA; int indexB = B.row0*B.original.numCols + (B.col0+i)*heightB + rowB*widthB; int indexC = C.row0*C.original.numCols + (C.col0+i)*heightC + rowC*widthC; if( i == startI ) { indexA += offset; indexB += offset; indexC += offset; for( int j = offset; j < segment; j++ ) { dataC[indexC++] = alpha*dataA[indexA++] + beta*dataB[indexB++]; } } else { for( int j = 0; j < segment; j++ ) { dataC[indexC++] = alpha*dataA[indexA++] + beta*dataB[indexB++]; } } } } /** *

* Row vector dot/inner product:
* dot: c = sum ai*bi
* where 'a' and 'b' are row vectors within the row block vector A and B, and 'c' is a scalar. *

* * @param A submatrix. Not modified. * @param rowA which row in A the vector is contained in. * @param B submatrix. Not modified. * @param rowB which row in B the vector is contained in. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. * @return Results of the dot product. */ public static double dot_row(final int blockLength, D1Submatrix64F A, int rowA, D1Submatrix64F B, int rowB, int offset, int end) { // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; final double dataA[] = A.original.data; final double dataB[] = B.original.data; double total = 0; // handle rows in any block int rowBlockA = A.row0 + rowA - rowA % blockLength; rowA = rowA % blockLength; int rowBlockB = B.row0 + rowB - rowB % blockLength; rowB = rowB % blockLength; final int heightA = Math.min(blockLength,A.row1-rowBlockA); final int heightB = Math.min(blockLength,B.row1-rowBlockB); if( A.col1 - A.col0 != B.col1 - B.col0 ) throw new RuntimeException(); for( int i = startI; i < end; i += blockLength ) { int segment = Math.min(blockLength,end-i); int widthA = Math.min(blockLength,A.col1-A.col0-i); int widthB = Math.min(blockLength,B.col1-B.col0-i); int indexA = rowBlockA*A.original.numCols + (A.col0+i)*heightA + rowA*widthA; int indexB = rowBlockB*B.original.numCols + (B.col0+i)*heightB + rowB*widthB; if( i == startI ) { indexA += offset; indexB += offset; for( int j = offset; j < segment; j++ ) { total += dataB[indexB++]*dataA[indexA++]; } } else { for( int j = 0; j < segment; j++ ) { total += dataB[indexB++]*dataA[indexA++]; } } } return total; } /** *

* vector dot/inner product from one row vector and one column vector:
* dot: c = sum ai*bi
* where 'a' is a row vector 'b' is a column vectors within the row block vector A and B, and 'c' is a scalar. *

* * @param A block row vector. Not modified. * @param rowA which row in A the vector is contained in. * @param B block column vector. Not modified. * @param colB which column in B is the vector contained in. * @param offset Index at which the vectors start at. * @param end Index at which the vectors end at. * @return Results of the dot product. */ public static double dot_row_col(final int blockLength, D1Submatrix64F A, int rowA, D1Submatrix64F B, int colB, int offset, int end) { // handle the case where offset is more than a block int startI = offset - offset % blockLength; offset = offset % blockLength; final double dataA[] = A.original.data; final double dataB[] = B.original.data; double total = 0; // handle rows in any block int rowBlockA = A.row0 + rowA - rowA % blockLength; rowA = rowA % blockLength; int colBlockB = B.col0 + colB - colB % blockLength; colB = colB % blockLength; final int heightA = Math.min(blockLength,A.row1-rowBlockA); final int widthB = Math.min(blockLength,B.col1-colBlockB); if( A.col1 - A.col0 != B.col1 - B.col0 ) throw new RuntimeException(); for( int i = startI; i < end; i += blockLength ) { int segment = Math.min(blockLength,end-i); int widthA = Math.min(blockLength,A.col1-A.col0-i); int heightB = Math.min(blockLength,B.row1-B.row0-i); int indexA = rowBlockA*A.original.numCols + (A.col0+i)*heightA + rowA*widthA; int indexB = (B.row0+i)*B.original.numCols + colBlockB*heightB + colB; if( i == startI ) { indexA += offset; indexB += offset*widthB; for( int j = offset; j < segment; j++ , indexB += widthB) { total += dataB[indexB]*dataA[indexA++]; } } else { for( int j = 0; j < segment; j++ , indexB += widthB) { total += dataB[indexB]*dataA[indexA++]; } } } return total; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/GeneratorBlockInnerMultiplication.java000066400000000000000000000261111256171534400304170ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.alg.generic.CodeGeneratorMisc; import java.io.FileNotFoundException; import java.io.PrintStream; /** * @author Peter Abeles */ public class GeneratorBlockInnerMultiplication { String className; PrintStream stream; public GeneratorBlockInnerMultiplication( String className ) throws FileNotFoundException { this.className = className; stream = new PrintStream(className+".java"); } public void createClass() { printTop(); for( int i = 0; i < 2; i++ ) { boolean hasAlpha = i==1; for( Operation o : Operation.values()) { if( hasAlpha && o == Operation.MINUS ) continue; print_mult(hasAlpha,o); print_multTransA(hasAlpha,o); print_multTransB(hasAlpha,o); } } stream.print("}\n"); } private void printTop() { String foo = CodeGeneratorMisc.COPYRIGHT + "\n" + "package org.ejml.alg.block;\n" + "\n" + "/**\n" + " *

\n" + " * Matrix multiplication for the inner row major blocks, typically inside of a {@link org.ejml.data.BlockMatrix64F}.\n" + " *

\n" + " *\n" + " *

\n" + " * This code was auto generated by {@link GeneratorBlockInnerMultiplication} and should not be modified directly.\n" + " *

\n" + " *\n" + " * @author Peter Abeles\n" + " */\n" + "public class "+className+" {\n"; stream.print(foo); } private void print_mult( boolean hasAlpha , Operation opType ) { createHeader(hasAlpha,opType,false,false); stream.print( "// for( int i = 0; i < heightA; i++ ) {\n" + "// for( int k = 0; k < widthA; k++ ) {\n" + "// for( int j = 0; j < widthC; j++ ) {\n" + "// dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB];\n" + "// }\n" + "// }\n" + "// }\n"); stream.println(); String o = ( opType == Operation.MINUS ) ? "-=" : "+="; String m = hasAlpha ? "alpha*" : ""; stream.print( " int a = indexA;\n"+ " int rowC = indexC;\n"+ " for( int i = 0; i < heightA; i++ , rowC += widthC ) {\n" + " int b = indexB;\n" + "\n" + " final int endC = rowC + widthC;\n" + " final int endA = a + widthA;"+ "\n"+ " while( a != endA ) {//for( int k = 0; k < widthA; k++ ) {\n" + " double valA = "+m+"dataA[a++];\n" + "\n" + " int c = rowC;\n" + "\n"); if( opType == Operation.SET ) { stream.print( " if( b == indexB ) {\n" + " while( c != endC ) {//for( int j = 0; j < widthC; j++ ) {\n" + " dataC[ c++ ] = valA * dataB[ b++ ];\n" + " }\n" + " } else {\n" + " while( c != endC ) {//for( int j = 0; j < widthC; j++ ) {\n" + " dataC[ c++ ] "+o+" valA * dataB[ b++ ];\n" + " }\n" + " }\n"); } else { stream.print( " while( c != endC ) {//for( int j = 0; j < widthC; j++ ) {\n" + " dataC[ c++ ] "+o+" valA * dataB[ b++ ];\n" + " }\n"); } stream.println( " }\n" + " }"); stream.println(" }"); } private String createOpString(boolean hasAlpha, Operation opType) { String o = opString(opType); if( hasAlpha ) o += " alpha * "; return o; } private void print_multTransA( boolean hasAlpha , Operation opType ) { createHeader(hasAlpha,opType,true,false); String o = ( opType == Operation.MINUS ) ? "-=" : "+="; String m = hasAlpha ? "alpha*" : ""; stream.print( "// for( int i = 0; i < widthA; i++ ) {\n" + "// for( int k = 0; k < heightA; k++ ) {\n" + "// double valA = dataA[k*widthA + i + indexA];\n" + "// for( int j = 0; j < widthC; j++ ) {\n" + "// dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB];\n" + "// }\n" + "// }\n" + "// }\n"); stream.println(); stream.print( " int rowC = indexC;\n"+ " for( int i = 0; i < widthA; i++ , rowC += widthC) {\n" + " int colA = i + indexA;\n" + " int endA = colA + widthA*heightA;\n" + " int b = indexB;\n" + "\n" + " // for( int k = 0; k < heightA; k++ ) {\n" + " while(colA != endA ) {\n" + " double valA = "+m+"dataA[colA];\n" + "\n" + " int c = rowC;\n" + " final int endB = b + widthC;\n" + "\n" + " //for( int j = 0; j < widthC; j++ ) {\n"); if( opType == Operation.SET ) { stream.print( " if( b == indexB ) {\n" + " while( b != endB ) {\n" + " dataC[ c++ ] = valA * dataB[b++];\n" + " } \n" + " } else {\n" + " while( b != endB ) {\n" + " dataC[ c++ ] "+o+" valA * dataB[b++];\n" + " }\n" + " }\n"); } else { stream.print( " while( b != endB ) {\n" + " dataC[ c++ ] "+o+" valA * dataB[b++];\n" + " }\n"); } stream.print( " colA += widthA;\n"+ " }\n" + " }\n"); stream.println(" }"); } private void print_multTransB( boolean hasAlpha , Operation opType ) { createHeader(hasAlpha,opType,false,true); String o = createOpString(hasAlpha, opType); stream.println( " for( int i = 0; i < heightA; i++ ) {\n" + " for( int j = 0; j < widthC; j++ ) {\n" + " double val = 0;\n" + "\n" + " for( int k = 0; k < widthA; k++ ) {\n" + " val += dataA[i*widthA + k + indexA] * dataB[j*widthA + k + indexB];\n" + " }\n" + "\n" + " dataC[ i*widthC + j + indexC ] "+o+" val;\n" + " }\n" + " }"); stream.println(" }"); } private void createHeader( boolean hasAlpha , Operation opType , boolean transA , boolean transB ) { String alphaString = hasAlpha ? " α " : ""; String alphaParam = hasAlpha ? " double alpha ," : ""; String transAString = transA ? "T" : ""; String transBString = transB ? "T" : ""; String opTypeString; switch( opType ) { case MINUS: opTypeString = "C - "; break; case PLUS: opTypeString = "C + "; break; case SET: opTypeString = ""; break; default: throw new RuntimeException("Unknown optype"); } String funcName = "blockMult"+opName(opType); if( transA && transB ) funcName += "TransAB"; else if( transA ) funcName += "TransA"; else if( transB ) funcName += "TransB"; stream.println(); stream.print( " /**\n" + " *

\n" + " * Performs the follow operation on individual inner blocks:
\n" + " *
\n"); stream.print( " * C = "+opTypeString+alphaString+"A"+transAString+" * B"+transBString+"\n"); stream.print( " *

\n" + " */\n" + " public static void "+funcName+"("+alphaParam+" final double[] dataA, final double []dataB, final double []dataC,\n" + " int indexA, int indexB, int indexC,\n" + " final int heightA, final int widthA, final int widthC) {\n"); } private String opString( Operation opType ) { switch( opType ) { case MINUS: return "-="; case PLUS: return "+="; case SET: return "="; default: throw new RuntimeException("Unknown opType "+opType); } } private String opName( Operation opType ) { switch( opType ) { case MINUS: return "Minus"; case PLUS: return "Plus"; case SET: return "Set"; default: throw new RuntimeException("Unknown opType "+opType); } } private static enum Operation { /** Add results to output matrix */ PLUS, /** Subtract results from output matrix */ MINUS, /** set output matrix to results */ SET } public static void main( String args[] ) throws FileNotFoundException { GeneratorBlockInnerMultiplication app = new GeneratorBlockInnerMultiplication("BlockInnerMultiplication"); app.createClass(); System.out.println("Done generating class"); } } ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/000077500000000000000000000000001256171534400236145ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/bidiagonal/000077500000000000000000000000001256171534400257055ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/bidiagonal/BidiagonalHelper.java000066400000000000000000000056451256171534400317530ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.bidiagonal; import org.ejml.data.D1Submatrix64F; import static org.ejml.alg.block.decomposition.qr.BlockHouseHolder.*; /** * @author Peter Abeles */ public class BidiagonalHelper { /** * Performs a standard bidiagonal decomposition just on the outer blocks of the provided matrix * * @param blockLength * @param A * @param gammasU */ public static boolean bidiagOuterBlocks( final int blockLength , final D1Submatrix64F A , final double gammasU[], final double gammasV[]) { // System.out.println("---------- Orig"); // A.original.print(); int width = Math.min(blockLength,A.col1-A.col0); int height = Math.min(blockLength,A.row1-A.row0); int min = Math.min(width,height); for( int i = 0; i < min; i++ ) { //--- Apply reflector to the column // compute the householder vector if (!computeHouseHolderCol(blockLength, A, gammasU, i)) return false; // apply to rest of the columns in the column block rank1UpdateMultR_Col(blockLength,A,i,gammasU[A.col0+i]); // apply to the top row block rank1UpdateMultR_TopRow(blockLength,A,i,gammasU[A.col0+i]); System.out.println("After column stuff"); A.original.print(); //-- Apply reflector to the row if(!computeHouseHolderRow(blockLength,A,gammasV,i)) return false; // apply to rest of the rows in the row block rank1UpdateMultL_Row(blockLength,A,i,i+1,gammasV[A.row0+i]); System.out.println("After update row"); A.original.print(); // apply to the left column block // TODO THIS WON'T WORK!!!!!!!!!!!!! // Needs the whole matrix to have been updated by the left reflector to compute the correct solution // rank1UpdateMultL_LeftCol(blockLength,A,i,i+1,gammasV[A.row0+i]); System.out.println("After row stuff"); A.original.print(); } return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/chol/000077500000000000000000000000001256171534400245415ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/chol/CholeskyOuterForm_B64.java000066400000000000000000000135121256171534400314450ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.chol; import org.ejml.alg.block.BlockInnerRankUpdate; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.BlockTriangularSolver; import org.ejml.data.BlockMatrix64F; import org.ejml.data.Complex64F; import org.ejml.data.D1Submatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; /** *

* Block Cholesky using outer product form. The original matrix is stored and modified. *

* *

* Based on the description provided in "Fundamentals of Matrix Computations" 2nd Ed. by David S. Watkins. *

* * @author Peter Abeles */ public class CholeskyOuterForm_B64 implements CholeskyDecomposition { // if it should compute an upper or lower triangular matrix private boolean lower = false; // The decomposed matrix. private BlockMatrix64F T; // predeclare local work space private D1Submatrix64F subA = new D1Submatrix64F(); private D1Submatrix64F subB = new D1Submatrix64F(); private D1Submatrix64F subC = new D1Submatrix64F(); // storage for the determinant private Complex64F det = new Complex64F(); /** * Creates a new BlockCholeskyOuterForm * * @param lower Should it decompose it into a lower triangular matrix or not. */ public CholeskyOuterForm_B64(boolean lower) { this.lower = lower; } /** * Decomposes the provided matrix and stores the result in the same matrix. * * @param A Matrix that is to be decomposed. Modified. * @return If it succeeded or not. */ @Override public boolean decompose(BlockMatrix64F A) { if( A.numCols != A.numRows ) throw new IllegalArgumentException("A must be square"); this.T = A; if( lower ) return decomposeLower(); else return decomposeUpper(); } private boolean decomposeLower() { int blockLength = T.blockLength; subA.set(T); subB.set(T); subC.set(T); for( int i = 0; i < T.numCols; i += blockLength ) { int widthA = Math.min(blockLength, T.numCols-i); subA.col0 = i; subA.col1 = i+widthA; subA.row0 = subA.col0; subA.row1 = subA.col1; subB.col0 = i; subB.col1 = i+widthA; subB.row0 = i+widthA; subB.row1 = T.numRows; subC.col0 = i+widthA; subC.col1 = T.numRows; subC.row0 = i+widthA; subC.row1 = T.numRows; // cholesky on inner block A if( !InnerCholesky_B64.lower(subA)) return false; // on the last block these operations are not needed. if( widthA == blockLength ) { // B = L^-1 B BlockTriangularSolver.solveBlock(blockLength,false,subA,subB,false,true); // C = C - B * B^T BlockInnerRankUpdate.symmRankNMinus_L(blockLength,subC,subB); } } BlockMatrixOps.zeroTriangle(true,T); return true; } private boolean decomposeUpper() { int blockLength = T.blockLength; subA.set(T); subB.set(T); subC.set(T); for( int i = 0; i < T.numCols; i += blockLength ) { int widthA = Math.min(blockLength, T.numCols-i); subA.col0 = i; subA.col1 = i+widthA; subA.row0 = subA.col0; subA.row1 = subA.col1; subB.col0 = i+widthA; subB.col1 = T.numCols; subB.row0 = i; subB.row1 = i+widthA; subC.col0 = i+widthA; subC.col1 = T.numCols; subC.row0 = i+widthA; subC.row1 = T.numCols; // cholesky on inner block A if( !InnerCholesky_B64.upper(subA)) return false; // on the last block these operations are not needed. if( widthA == blockLength ) { // B = U^-1 B BlockTriangularSolver.solveBlock(blockLength,true,subA,subB,true,false); // C = C - B^T * B BlockInnerRankUpdate.symmRankNMinus_U(blockLength,subC,subB); } } BlockMatrixOps.zeroTriangle(false,T); return true; } @Override public boolean isLower() { return lower; } @Override public BlockMatrix64F getT(BlockMatrix64F T) { if( T == null ) return this.T; T.set(this.T); return T; } @Override public Complex64F computeDeterminant() { double prod = 1.0; int blockLength = T.blockLength; for( int i = 0; i < T.numCols; i += blockLength ) { // width of the submatrix int widthA = Math.min(blockLength, T.numCols-i); // index of the first element in the block int indexT = i*T.numCols + i*widthA; // product along the diagonal for (int j = 0; j < widthA; j++) { prod *= T.data[indexT]; indexT += widthA+1; } } det.real = prod*prod; det.imaginary = 0; return det; } @Override public boolean inputModified() { return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/chol/InnerCholesky_B64.java000066400000000000000000000075471256171534400306110ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.chol; import org.ejml.data.D1Submatrix64F; /** * Performs a cholesky decomposition on an individual inner block. * * @author Peter Abeles */ // TODO merge with CholeskyBlockHelper public class InnerCholesky_B64 { public static boolean upper( D1Submatrix64F T ) { int n = T.row1-T.row0; int indexT = T.row0* T.original.numCols + T.col0*n; return upper(T.original.data,indexT,n); } public static boolean lower( D1Submatrix64F T ) { int n = T.row1-T.row0; int indexT = T.row0* T.original.numCols + T.col0*n; return lower(T.original.data,indexT,n); } /** * Performs an inline upper Cholesky decomposition on an inner row-major matrix. Only * the upper triangular portion of the matrix is read or written to. * * @param T Array containing an inner row-major matrix. Modified. * @param indexT First index of the inner row-major matrix. * @param n Number of rows and columns of the matrix. * @return If the decomposition succeeded. */ public static boolean upper( double[]T , int indexT , int n ) { double el_ii; double div_el_ii=0; for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { double sum = T[ indexT + i*n+j]; // todo optimize for( int k = 0; k < i; k++ ) { sum -= T[ indexT + k*n+i] * T[ indexT + k*n+j]; } if( i == j ) { // is it positive-definite? if( sum <= 0.0 ) return false; el_ii = Math.sqrt(sum); T[ indexT + i*n+i] = el_ii; div_el_ii = 1.0/el_ii; } else { T[ indexT + i*n+j] = sum*div_el_ii; } } } return true; } /** * Performs an inline lower Cholesky decomposition on an inner row-major matrix. Only * the lower triangular portion of the matrix is read or written to. * * @param T Array containing an inner row-major matrix. Modified. * @param indexT First index of the inner row-major matrix. * @param n Number of rows and columns of the matrix. * @return If the decomposition succeeded. */ public static boolean lower( double[]T , int indexT , int n ) { double el_ii; double div_el_ii=0; for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { double sum = T[ indexT + j*n+i]; // todo optimize for( int k = 0; k < i; k++ ) { sum -= T[ indexT + i*n+k] * T[ indexT + j*n+k]; } if( i == j ) { // is it positive-definite? if( sum <= 0.0 ) return false; el_ii = Math.sqrt(sum); T[ indexT + i*n+i] = el_ii; div_el_ii = 1.0/el_ii; } else { T[ indexT + j*n+i] = sum*div_el_ii; } } } return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/hessenberg/000077500000000000000000000000001256171534400257415ustar00rootroot00000000000000TridiagonalDecompositionHouseholder_B64.java000066400000000000000000000235511256171534400363420ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.hessenberg; import org.ejml.alg.block.BlockMultiplication; import org.ejml.alg.block.decomposition.qr.QRDecompositionHouseholder_B64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.CommonOps; import static org.ejml.alg.block.BlockInnerMultiplication.blockMultPlusTransA; /** *

* Tridiagonal similar decomposition for block matrices. Orthogonal matrices are computed using * householder vectors. *

* *

* Based off algorithm in section 2 of J. J. Dongarra, D. C. Sorensen, S. J. Hammarling, * "Block Reduction of Matrices to Condensed Forms for Eigenvalue Computations" Journal of * Computations and Applied Mathematics 27 (1989) 215-227 *
* Computations of Householder reflectors has been modified from what is presented in that paper to how * it is performed in "Fundamentals of Matrix Computations" 2nd ed. by David S. Watkins. *

* * @author Peter Abeles */ public class TridiagonalDecompositionHouseholder_B64 implements TridiagonalSimilarDecomposition { // matrix which is being decomposed // householder vectors are stored along the upper triangle rows protected BlockMatrix64F A; // temporary storage for block computations protected BlockMatrix64F V = new BlockMatrix64F(1,1); // stores intermediate results in matrix multiplication protected BlockMatrix64F tmp = new BlockMatrix64F(1,1); protected double gammas[] = new double[1]; // temporary storage for zeros and ones in U protected DenseMatrix64F zerosM = new DenseMatrix64F(1,1); @Override public BlockMatrix64F getT(BlockMatrix64F T) { if( T == null ) { T = new BlockMatrix64F(A.numRows,A.numCols,A.blockLength); } else { if( T.numRows != A.numRows || T.numCols != A.numCols ) throw new IllegalArgumentException("T must have the same dimensions as the input matrix"); CommonOps.fill(T, 0); } T.set(0,0,A.data[0]); for( int i = 1; i < A.numRows; i++ ) { double d = A.get(i-1,i); T.set(i,i,A.get(i,i)); T.set(i-1,i,d); T.set(i,i-1,d); } return T; } @Override public BlockMatrix64F getQ(BlockMatrix64F Q, boolean transposed) { Q = QRDecompositionHouseholder_B64.initializeQ(Q, A.numRows, A.numCols, A.blockLength, false); int height = Math.min(A.blockLength,A.numRows); V.reshape(height,A.numCols,false); tmp.reshape(height,A.numCols,false); D1Submatrix64F subQ = new D1Submatrix64F(Q); D1Submatrix64F subU = new D1Submatrix64F(A); D1Submatrix64F subW = new D1Submatrix64F(V); D1Submatrix64F tmp = new D1Submatrix64F(this.tmp); int N = A.numRows; int start = N - N % A.blockLength; if( start == N ) start -= A.blockLength; if( start < 0 ) start = 0; // (Q1^T * (Q2^T * (Q3^t * A))) for( int i = start; i >= 0; i -= A.blockLength ) { int blockSize = Math.min(A.blockLength,N-i); subW.col0 = i; subW.row1 = blockSize; subW.original.reshape(subW.row1,subW.col1,false); if( transposed ) { tmp.row0 = i; tmp.row1 = A.numCols; tmp.col0 = 0; tmp.col1 = blockSize; } else { tmp.col0 = i; tmp.row1 = blockSize; } tmp.original.reshape(tmp.row1,tmp.col1,false); subU.col0 = i; subU.row0 = i; subU.row1 = subU.row0+blockSize; // zeros and ones are saved and overwritten in U so that standard matrix multiplication can be used copyZeros(subU); // compute W for Q(i) = ( I + W*Y^T) TridiagonalHelper_B64.computeW_row(A.blockLength, subU, subW, gammas, i); subQ.col0 = i; subQ.row0 = i; // Apply the Qi to Q // Qi = I + W*U^T // Note that U and V are really row vectors. but standard notation assumed they are column vectors. // which is why the functions called don't match the math above // (I + W*U^T)*Q // F=U^T*Q(i) if( transposed ) BlockMultiplication.multTransB(A.blockLength,subQ,subU,tmp); else BlockMultiplication.mult(A.blockLength,subU,subQ,tmp); // Q(i+1) = Q(i) + W*F if( transposed ) BlockMultiplication.multPlus(A.blockLength,tmp,subW,subQ); else BlockMultiplication.multPlusTransA(A.blockLength,subW,tmp,subQ); replaceZeros(subU); } return Q; } private void copyZeros( D1Submatrix64F subU ) { int N = Math.min(A.blockLength,subU.col1-subU.col0); for( int i = 0; i < N; i++ ) { // save the zeros for( int j = 0; j <= i; j++ ) { zerosM.unsafe_set(i,j,subU.get(i,j)); subU.set(i,j,0); } // save the one if( subU.col0 + i + 1 < subU.original.numCols ) { zerosM.unsafe_set(i,i+1,subU.get(i,i+1)); subU.set(i,i+1,1); } } } private void replaceZeros( D1Submatrix64F subU ) { int N = Math.min(A.blockLength,subU.col1-subU.col0); for( int i = 0; i < N; i++ ) { // save the zeros for( int j = 0; j <= i; j++ ) { subU.set(i,j,zerosM.get(i,j)); } // save the one if( subU.col0 + i + 1 < subU.original.numCols ) { subU.set(i,i+1,zerosM.get(i,i+1)); } } } @Override public void getDiagonal(double[] diag, double[] off) { diag[0] = A.data[0]; for( int i = 1; i < A.numRows; i++ ) { diag[i] = A.get(i,i); off[i-1] = A.get(i-1,i); } } @Override public boolean decompose(BlockMatrix64F orig) { if( orig.numCols != orig.numRows ) throw new IllegalArgumentException("Input matrix must be square."); init(orig); D1Submatrix64F subA = new D1Submatrix64F(A); D1Submatrix64F subV = new D1Submatrix64F(V); D1Submatrix64F subU = new D1Submatrix64F(A); int N = orig.numCols; for( int i = 0; i < N; i += A.blockLength ) { // System.out.println("-------- triag i "+i); int height = Math.min(A.blockLength,A.numRows-i); subA.col0 = subU.col0 = i; subA.row0 = subU.row0 = i; subU.row1 = subU.row0 + height; subV.col0 = i; subV.row1 = height; subV.original.reshape(subV.row1,subV.col1,false); // bidiagonalize the top row TridiagonalHelper_B64.tridiagUpperRow(A.blockLength, subA, gammas, subV); // apply Householder reflectors to the lower portion using block multiplication if( subU.row1 < orig.numCols) { // take in account the 1 in the last row. The others are skipped over. double before = subU.get(A.blockLength-1,A.blockLength); subU.set(A.blockLength-1,A.blockLength,1); // A = A + U*V^T + V*U^T multPlusTransA(A.blockLength,subU,subV,subA); multPlusTransA(A.blockLength,subV,subU,subA); subU.set(A.blockLength-1,A.blockLength,before); } } return true; } /** * C = C + A^T*B * * @param blockLength * @param A row block vector * @param B row block vector * @param C */ public static void multPlusTransA( int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { int heightA = Math.min( blockLength , A.row1 - A.row0 ); for( int i = C.row0+blockLength; i < C.row1; i += blockLength ) { int heightC = Math.min( blockLength , C.row1 - i ); int indexA = A.row0*A.original.numCols + (i-C.row0+A.col0)*heightA; for( int j = i; j < C.col1; j += blockLength ) { int widthC = Math.min( blockLength , C.col1 - j ); int indexC = i*C.original.numCols + j*heightC; int indexB = B.row0*B.original.numCols + (j-C.col0+B.col0)*heightA; blockMultPlusTransA(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,heightC,widthC); } } } private void init( BlockMatrix64F orig ) { this.A = orig; int height = Math.min(A.blockLength,A.numRows); V.reshape(height,A.numCols,A.blockLength,false); tmp.reshape(height,A.numCols,A.blockLength,false); if( gammas.length < A.numCols ) gammas = new double[ A.numCols ]; zerosM.reshape(A.blockLength,A.blockLength+1,false); } @Override public boolean inputModified() { return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/hessenberg/TridiagonalHelper_B64.java000066400000000000000000000266461256171534400326320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.hessenberg; import org.ejml.alg.block.BlockVectorOps; import org.ejml.alg.block.decomposition.qr.BlockHouseHolder; import org.ejml.data.D1Submatrix64F; import org.ejml.ops.CommonOps; import static org.ejml.alg.block.decomposition.qr.BlockHouseHolder.computeHouseHolderRow; /** * @author Peter Abeles */ public class TridiagonalHelper_B64 { /** *

* Performs a tridiagonal decomposition on the upper row only. *

* *

* For each row 'a' in 'A': * Compute 'u' the householder reflector. * y(:) = A*u * v(i) = y - (1/2)*(y^T*u)*u * a(i+1) = a(i) - u*γ*v^T - v*u^t *

* * @param blockLength Size of a block * @param A is the row block being decomposed. Modified. * @param gammas Householder gammas. * @param V Where computed 'v' are stored in a row block. Modified. */ public static void tridiagUpperRow( final int blockLength , final D1Submatrix64F A , final double gammas[] , final D1Submatrix64F V ) { int blockHeight = Math.min(blockLength,A.row1-A.row0); if( blockHeight <= 1 ) return; int width = A.col1-A.col0; int num = Math.min(width-1,blockHeight); int applyIndex = Math.min(width,blockHeight); // step through rows in the block for( int i = 0; i < num; i++ ) { // compute the new reflector and save it in a row in 'A' computeHouseHolderRow(blockLength,A,gammas,i); double gamma = gammas[A.row0+i]; // compute y computeY(blockLength,A,V,i,gamma); // compute v from y computeRowOfV(blockLength,A,V,i,gamma); // Apply the reflectors to the next row in 'A' only if( i+1 < applyIndex ) { applyReflectorsToRow( blockLength , A , V , i+1 ); } } } /** *

* Computes W from the householder reflectors stored in the columns of the row block * submatrix Y. *

* *

* Y = v(1)
* W = -β1v(1)
* for j=2:r
*   z = -β(I +WYT)v(j)
*   W = [W z]
*   Y = [Y v(j)]
* end
*
* where v(.) are the house holder vectors, and r is the block length. Note that * Y already contains the householder vectors so it does not need to be modified. *

* *

* Y and W are assumed to have the same number of rows and columns. *

*/ public static void computeW_row( final int blockLength , final D1Submatrix64F Y , final D1Submatrix64F W , final double beta[] , int betaIndex ) { final int heightY = Y.row1-Y.row0; CommonOps.fill(W.original, 0); // W = -beta*v(1) BlockHouseHolder.scale_row(blockLength,Y,W,0,1,-beta[betaIndex++]); final int min = Math.min(heightY,W.col1-W.col0); // set up rest of the rows for( int i = 1; i < min; i++ ) { // w=-beta*(I + W*Y^T)*u double b = -beta[betaIndex++]; // w = w -beta*W*(Y^T*u) for( int j = 0; j < i; j++ ) { double yv = BlockHouseHolder.innerProdRow(blockLength,Y,i,Y,j,1); BlockVectorOps.add_row(blockLength,W,i,1,W,j,b*yv,W,i,1,Y.col1-Y.col0); } //w=w -beta*u + stuff above BlockHouseHolder.add_row(blockLength,Y,i,b,W,i,1,W,i,1,Y.col1-Y.col0); } } /** *

* Given an already computed tridiagonal decomposition, compute the V row block vector.
*
* y(:) = A*u
* v(i) = y - (1/2)*γ*(y^T*u)*u *

*/ public static void computeV_blockVector( final int blockLength , final D1Submatrix64F A , final double gammas[] , final D1Submatrix64F V ) { int blockHeight = Math.min(blockLength,A.row1-A.row0); if( blockHeight <= 1 ) return; int width = A.col1-A.col0; int num = Math.min(width-1,blockHeight); for( int i = 0; i < num; i++ ) { double gamma = gammas[A.row0+i]; // compute y computeY(blockLength,A,V,i,gamma); // compute v from y computeRowOfV(blockLength,A,V,i,gamma); } } /** *

* Applies the reflectors that have been computed previously to the specified row. *
* A = A + u*v^T + v*u^T only along the specified row in A. *

* * @param blockLength * @param A Contains the reflectors and the row being updated. * @param V Contains previously computed 'v' vectors. * @param row The row of 'A' that is to be updated. */ public static void applyReflectorsToRow( final int blockLength , final D1Submatrix64F A , final D1Submatrix64F V , int row ) { int height = Math.min(blockLength, A.row1 - A.row0); double dataA[] = A.original.data; double dataV[] = V.original.data; int indexU,indexV; // for each previously computed reflector for( int i = 0; i < row; i++ ) { int width = Math.min(blockLength,A.col1 - A.col0); indexU = A.original.numCols*A.row0 + height*A.col0 + i*width + row; indexV = V.original.numCols*V.row0 + height*V.col0 + i*width + row; double u_row = (i+1 == row) ? 1.0 : dataA[ indexU ]; double v_row = dataV[ indexV ]; // take in account the leading one double before = A.get(i,i+1); A.set(i,i+1,1); // grab only the relevant row from A = A + u*v^T + v*u^T BlockVectorOps.add_row(blockLength,A,row,1,V,i,u_row,A,row,row,A.col1-A.col0); BlockVectorOps.add_row(blockLength,A,row,1,A,i,v_row,A,row,row,A.col1-A.col0); A.set(i,i+1,before); } } /** *

* Computes the 'y' vector and stores the result in 'v'
*
* y = -γ(A + U*V^T + V*U^T)u *

* * @param blockLength * @param A Contains the reflectors and the row being updated. * @param V Contains previously computed 'v' vectors. * @param row The row of 'A' that is to be updated. */ public static void computeY( final int blockLength , final D1Submatrix64F A , final D1Submatrix64F V , int row , double gamma ) { // Elements in 'y' before 'row' are known to be zero and the element at 'row' // is not used. Thus only elements after row and after are computed. // y = A*u multA_u(blockLength,A,V,row); for( int i = 0; i < row; i++ ) { // y = y + u_i*v_i^t*u + v_i*u_i^t*u // v_i^t*u double dot_v_u = BlockHouseHolder.innerProdRow(blockLength,A,row,V,i,1); // u_i^t*u double dot_u_u = BlockHouseHolder.innerProdRow(blockLength,A,row,A,i,1); // y = y + u_i*(v_i^t*u) // the ones in these 'u' are skipped over since the next submatrix of A // is only updated BlockVectorOps.add_row(blockLength,V,row,1,A,i,dot_v_u,V,row,row+1,A.col1-A.col0); // y = y + v_i*(u_i^t*u) // the 1 in U is taken account above BlockVectorOps.add_row(blockLength,V,row,1,V,i,dot_u_u,V,row,row+1,A.col1-A.col0); } // y = -gamma*y BlockVectorOps.scale_row(blockLength,V,row,-gamma,V,row,row+1,V.col1-V.col0); } /** *

* Multiples the appropriate submatrix of A by the specified reflector and stores * the result ('y') in V.
*
* y = A*u
*

* * @param blockLength * @param A Contains the 'A' matrix and 'u' vector. * @param V Where resulting 'y' row vectors are stored. * @param row row in matrix 'A' that 'u' vector and the row in 'V' that 'y' is stored in. */ public static void multA_u( final int blockLength , final D1Submatrix64F A , final D1Submatrix64F V , int row ) { int heightMatA = A.row1-A.row0; for( int i = row+1; i < heightMatA; i++ ) { double val = innerProdRowSymm(blockLength,A,row,A,i,1); V.set(row,i,val); } } public static double innerProdRowSymm(int blockLength, D1Submatrix64F A, int rowA, D1Submatrix64F B, int rowB, int zeroOffset ) { int offset = rowA + zeroOffset; if( offset + B.col0 >= B.col1 ) return 0; if( offset < rowB ) { // take in account the one in 'A' double total = B.get(offset,rowB); total += BlockVectorOps.dot_row_col(blockLength,A,rowA,B,rowB,offset+1,rowB); total += BlockVectorOps.dot_row(blockLength,A,rowA,B,rowB,rowB,A.col1-A.col0); return total; } else { // take in account the one in 'A' double total = B.get(rowB,offset); total += BlockVectorOps.dot_row(blockLength,A,rowA,B,rowB,offset+1,A.col1-A.col0); return total; } } /** *

* Final computation for a single row of 'v':
*
* v = y -(1/2)γ(y^T*u)*u *

* * @param blockLength * @param A * @param V * @param row * @param gamma */ public static void computeRowOfV( final int blockLength , final D1Submatrix64F A , final D1Submatrix64F V , int row , double gamma ) { // val=(y^T*u) double val = BlockHouseHolder.innerProdRow(blockLength,A,row,V,row,1); // take in account the one double before = A.get(row,row+1); A.set(row,row+1,1); // v = y - (1/2)gamma*val * u BlockVectorOps.add_row(blockLength,V,row,1,A,row,-0.5*gamma*val,V,row,row+1,A.col1-A.col0); A.set(row,row+1,before); } } ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/qr/000077500000000000000000000000001256171534400242365ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/qr/BlockHouseHolder.java000066400000000000000000001077541256171534400303130ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.qr; import org.ejml.alg.block.BlockInnerMultiplication; import org.ejml.alg.block.BlockVectorOps; import org.ejml.data.D1Submatrix64F; /** * *

* Contains various helper functions for performing a block matrix QR decomposition. *

* *

* Assumptions: *

    * All submatrices are aligned along the inner blocks of the {@link org.ejml.data.BlockMatrix64F}. * Some times vectors are assumed to have leading zeros and a one. *
* * @author Peter Abeles */ public class BlockHouseHolder { /** * Performs a standard QR decomposition on the specified submatrix that is one block wide. * * @param blockLength * @param Y * @param gamma */ public static boolean decomposeQR_block_col( final int blockLength , final D1Submatrix64F Y , final double gamma[] ) { int width = Y.col1-Y.col0; int height = Y.row1-Y.row0; int min = Math.min(width,height); for( int i = 0; i < min; i++ ) { // compute the householder vector if (!computeHouseHolderCol(blockLength, Y, gamma, i)) return false; // apply to rest of the columns in the block rank1UpdateMultR_Col(blockLength,Y,i,gamma[Y.col0+i]); } return true; } /** *

* Computes the householder vector that is used to create reflector for the column. * The results are stored in the original matrix. *

* *

* The householder vector 'u' is computed as follows:
*
* u(1) = 1
* u(i) = x(i)/(τ + x(1))
*

* * The first element is implicitly assumed to be one and not written. * * @return If there was any problems or not. true = no problem. */ public static boolean computeHouseHolderCol( final int blockLength, final D1Submatrix64F Y, final double[] gamma, final int i) { double max = BlockHouseHolder.findMaxCol(blockLength,Y,i); if( max == 0.0 ) { return false; } else { // computes tau and normalizes u by max double tau = computeTauAndDivideCol(blockLength, Y, i, max); // divide u by u_0 double u_0 = Y.get(i,i) + tau; divideElementsCol(blockLength,Y,i, u_0 ); gamma[Y.col0+i] = u_0/tau; tau *= max; // after the reflector is applied the column would be all zeros but be -tau in the first element Y.set(i,i,-tau); } return true; } /** *

* Computes the householder vector from the specified row *

* *

* The householder vector 'u' is computed as follows:
*
* u(1) = 1
* u(i) = x(i)/(τ + x(1))
*

* * The first element is implicitly assumed to be one and not written. * * @return If there was any problems or not. true = no problem. */ public static boolean computeHouseHolderRow( final int blockLength, final D1Submatrix64F Y, final double[] gamma, final int i) { double max = BlockHouseHolder.findMaxRow(blockLength,Y,i,i+1); if( max == 0.0 ) { return false; } else { // computes tau and normalizes u by max double tau = computeTauAndDivideRow(blockLength, Y, i,i+1, max); // divide u by u_0 double u_0 = Y.get(i,i+1) + tau; BlockVectorOps.div_row(blockLength,Y,i,u_0,Y,i,i+1,Y.col1-Y.col0); gamma[Y.row0+i] = u_0/tau; // after the reflector is applied the column would be all zeros but be -tau in the first element Y.set(i,i+1,-tau*max); } return true; } /** *

* Applies a householder reflector stored in column 'col' to the remainder of the columns * in the block after it. Takes in account leading zeros and one.
*
* A = (I - γ*u*uT)*A
*

* * @param A submatrix that is at most one block wide and aligned along inner blocks * @param col The column in A containing 'u' * */ public static void rank1UpdateMultR_Col( final int blockLength , final D1Submatrix64F A , final int col , final double gamma ) { final int width = Math.min(blockLength,A.col1 - A.col0); final double dataA[] = A.original.data; for( int j = col+1; j < width; j++ ) { // total = U^T * A(:,j) double total = innerProdCol(blockLength, A, col, width, j, width); total *= gamma; // A(:,j) - gamma*U*total for( int i = A.row0; i < A.row1; i += blockLength ) { int height = Math.min( blockLength , A.row1 - i ); int indexU = i*A.original.numCols + height*A.col0 + col; int indexA = i*A.original.numCols + height*A.col0 + j; if( i == A.row0 ) { indexU += width*(col+1); indexA += width*col; dataA[ indexA ] -= total; indexA += width; for( int k = col+1; k < height; k++ , indexU += width, indexA += width ) { dataA[ indexA ] -= total*dataA[ indexU ]; } } else { int endU = indexU + width*height; // for( int k = 0; k < height; k++ for( ; indexU != endU; indexU += width, indexA += width ) { dataA[ indexA ] -= total*dataA[ indexU ]; } } } } } /** *

* Applies a householder reflector stored in column 'col' to the top block row (excluding * the first column) of A. Takes in account leading zeros and one.
*
* A = (I - γ*u*uT)*A
*

* * @param A submatrix that is at most one block wide and aligned along inner blocks * @param col The column in A containing 'u' * */ public static void rank1UpdateMultR_TopRow( final int blockLength , final D1Submatrix64F A , final int col , final double gamma ) { final double dataA[] = A.original.data; final int widthCol = Math.min( blockLength , A.col1 - col ); // step through columns in top block, skipping over the first block for( int colStartJ = A.col0 + blockLength; colStartJ < A.col1; colStartJ += blockLength ) { final int widthJ = Math.min( blockLength , A.col1 - colStartJ); for( int j = 0; j < widthJ; j++ ) { // total = U^T * A(:,j) * gamma double total = innerProdCol(blockLength, A, col, widthCol, (colStartJ-A.col0)+j, widthJ)*gamma; // A(:,j) - gamma*U*total // just update the top most block int i = A.row0; int height = Math.min( blockLength , A.row1 - i ); int indexU = i*A.original.numCols + height*A.col0 + col; int indexA = i*A.original.numCols + height*colStartJ + j; // take in account zeros and one indexU += widthCol*(col+1); indexA += widthJ*col; dataA[ indexA ] -= total; indexA += widthJ; for( int k = col+1; k < height; k++ , indexU += widthCol, indexA += widthJ ) { dataA[ indexA ] -= total*dataA[ indexU ]; } } } } /** *

* Applies a householder reflector stored in row 'row' to the remainder of the row * in the block after it. Takes in account leading zeros and one.
*
* A = A*(I - γ*u*uT)
*

* * @param A submatrix that is block aligned * @param row The row in A containing 'u' * @param colStart First index in 'u' that the reflector starts at * */ public static void rank1UpdateMultL_Row( final int blockLength , final D1Submatrix64F A , final int row , final int colStart , final double gamma ) { final int height = Math.min(blockLength,A.row1 - A.row0); final double dataA[] = A.original.data; int zeroOffset = colStart-row; for( int i = row+1; i < height; i++ ) { // total = U^T * A(i,:) double total = innerProdRow(blockLength, A, row, A , i, zeroOffset ); total *= gamma; // A(i,:) - gamma*U*total for( int j = A.col0; j < A.col1; j += blockLength ) { int width = Math.min( blockLength , A.col1 - j ); int indexU = A.row0*A.original.numCols + height*j + row*width; int indexA = A.row0*A.original.numCols + height*j + i*width; if( j == A.col0 ) { indexU += colStart+1; indexA += colStart; dataA[indexA++] -= total; for( int k = colStart+1; k < width; k++ ) { dataA[ indexA++ ] -= total*dataA[ indexU++ ]; } } else { for( int k = 0; k < width; k++ ) { dataA[ indexA++ ] -= total*dataA[ indexU++ ]; } } } } } /** *

* Applies a householder reflector stored in row 'row' to the left column block. * Takes in account leading zeros and one.
*
* A = A*(I - γ*u*uT)
*

* * @param A submatrix that is block aligned * @param row The row in A containing 'u' * @param zeroOffset How far off the diagonal is the first element in 'u' * */ public static void rank1UpdateMultL_LeftCol( final int blockLength , final D1Submatrix64F A , final int row , final double gamma , int zeroOffset ) { final int heightU = Math.min(blockLength,A.row1 - A.row0); final int width = Math.min(blockLength,A.col1-A.col0); final double data[] = A.original.data; for( int blockStart = A.row0+blockLength; blockStart < A.row1; blockStart += blockLength) { final int heightA = Math.min(blockLength,A.row1 - blockStart); for( int i = 0; i < heightA; i++ ) { // total = U^T * A(i,:) double total = innerProdRow(blockLength, A, row, A, i+(blockStart-A.row0), zeroOffset); total *= gamma; // A(i,:) - gamma*U*total // plusScale_row(blockLength,); int indexU = A.row0*A.original.numCols + heightU*A.col0 + row*width; int indexA = blockStart*A.original.numCols + heightA*A.col0 + i*width; // skip over zeros and assume first element in U is 1 indexU += zeroOffset+1; indexA += zeroOffset; data[indexA++] -= total; for( int k = zeroOffset+1; k < width; k++ ) { data[ indexA++ ] -= total*data[ indexU++ ]; } } } } /** *

* Computes the inner product of column vector 'colA' against column vector 'colB' while taking account leading zeros and one.
*
* ret = aT*b *

* *

* Column A is assumed to be a householder vector. Element at 'colA' is one and previous ones are zero. *

* * @param blockLength * @param A block aligned submatrix. * @param colA Column inside the block of first column vector. * @param widthA how wide the column block that colA is inside of. * @param colB Column inside the block of second column vector. * @param widthB how wide the column block that colB is inside of. * @return dot product of the two vectors. */ public static double innerProdCol( int blockLength, D1Submatrix64F A, int colA, int widthA, int colB, int widthB ) { double total = 0; final double data[] = A.original.data; // first column in the blocks final int colBlockA = A.col0 + colA - colA % blockLength; final int colBlockB = A.col0 + colB - colB % blockLength; colA = colA % blockLength; colB = colB % blockLength; // compute dot product down column vectors for( int i = A.row0; i < A.row1; i += blockLength ) { int height = Math.min( blockLength , A.row1 - i ); int indexA = i*A.original.numCols + height*colBlockA + colA; int indexB = i*A.original.numCols + height*colBlockB + colB; if( i == A.row0 ) { // handle leading zeros indexA += widthA*(colA + 1); indexB += widthB*colA; // handle leading one total = data[indexB]; indexB += widthB; // standard vector dot product int endA = indexA + (height - colA - 1)*widthA; for( ; indexA != endA; indexA += widthA, indexB += widthB ) { // for( int k = col+1; k < height; k++ , indexU += width, indexA += width ) { total += data[indexA] * data[indexB]; } } else { // standard vector dot product int endA = indexA + widthA*height; // for( int k = 0; k < height; k++ ) { for( ; indexA != endA; indexA += widthA, indexB += widthB ) { total += data[indexA] * data[indexB]; } } } return total; } /** *

* Computes the inner product of row vector 'rowA' against row vector 'rowB' while taking account leading zeros and one.
*
* ret = aT*b *

* *

* Row A is assumed to be a householder vector. Element at 'colStartA' is one and previous elements are zero. *

* * @param blockLength * @param A block aligned submatrix. * @param rowA Row index inside the sub-matrix of first row vector has zeros and ones.. * @param rowB Row index inside the sub-matrix of second row vector. * @return dot product of the two vectors. */ public static double innerProdRow(int blockLength, D1Submatrix64F A, int rowA, D1Submatrix64F B, int rowB, int zeroOffset ) { int offset = rowA + zeroOffset; if( offset + B.col0 >= B.col1 ) return 0; // take in account the one in 'A' double total = B.get(rowB,offset); total += BlockVectorOps.dot_row(blockLength,A,rowA,B,rowB,offset+1,A.col1-A.col0); return total; } public static void add_row( final int blockLength , D1Submatrix64F A , int rowA , double alpha , D1Submatrix64F B , int rowB , double beta , D1Submatrix64F C , int rowC , int zeroOffset , int end ) { int offset = rowA+zeroOffset; if( C.col0 + offset >= C.col1 ) return; // handle leading one C.set(rowC,offset,alpha+B.get(rowB,offset)*beta); BlockVectorOps.add_row(blockLength,A,rowA,alpha,B,rowB,beta,C,rowC,offset+1,end); } /** * Divides the elements at the specified column by 'val'. Takes in account * leading zeros and one. */ public static void divideElementsCol( final int blockLength , final D1Submatrix64F Y , final int col , final double val ) { final int width = Math.min(blockLength,Y.col1-Y.col0); final double dataY[] = Y.original.data; for( int i = Y.row0; i < Y.row1; i += blockLength ) { int height = Math.min( blockLength , Y.row1 - i ); int index = i*Y.original.numCols + height*Y.col0 + col; if( i == Y.row0 ) { index += width*(col+1); for( int k = col+1; k < height; k++ , index += width ) { dataY[index] /= val; } } else { int endIndex = index + width*height; //for( int k = 0; k < height; k++ for( ; index != endIndex; index += width ) { dataY[index] /= val; } } } } /** * Scales the elements in the specified row starting at element colStart by 'val'.
* W = val*Y * * Takes in account zeros and leading one automatically. * * @param zeroOffset How far off the diagonal is the first element in the vector. */ public static void scale_row( final int blockLength , final D1Submatrix64F Y , final D1Submatrix64F W , final int row , final int zeroOffset, final double val ) { int offset = row+zeroOffset; if( offset >= W.col1-W.col0 ) return; // handle the one W.set(row,offset,val); // scale rest of the vector BlockVectorOps.scale_row(blockLength,Y,row,val,W,row,offset+1,Y.col1-Y.col0); } /** *

* From the specified column of Y tau is computed and each element is divided by 'max'. * See code below: *

* *
     * for i=col:Y.numRows
     *   Y[i][col] = u[i][col] / max
     *   tau = tau + u[i][col]*u[i][col]
     * end
     * tau = sqrt(tau)
     * if( Y[col][col] < 0 )
     *    tau = -tau;
     * 
* */ public static double computeTauAndDivideCol( final int blockLength , final D1Submatrix64F Y , final int col , final double max ) { final int width = Math.min(blockLength,Y.col1-Y.col0); final double dataY[] = Y.original.data; double top=0; double norm2 = 0; for( int i = Y.row0; i < Y.row1; i += blockLength ) { int height = Math.min( blockLength , Y.row1 - i ); int index = i*Y.original.numCols + height*Y.col0 + col; if( i == Y.row0 ) { index += width*col; // save this value so that the sign can be determined later on top = dataY[index] /= max; norm2 += top*top; index += width; for( int k = col+1; k < height; k++ , index += width ) { double val = dataY[index] /= max; norm2 += val*val; } } else { for( int k = 0; k < height; k++ , index += width ) { double val = dataY[index] /= max; norm2 += val*val; } } } norm2 = Math.sqrt(norm2); if( top < 0 ) norm2 = -norm2; return norm2; } /** *

* From the specified row of Y tau is computed and each element is divided by 'max'. * See code below: *

* *
     * for j=row:Y.numCols
     *   Y[row][j] = u[row][j] / max
     *   tau = tau + u[row][j]*u[row][j]
     * end
     * tau = sqrt(tau)
     * if( Y[row][row] < 0 )
     *    tau = -tau;
     * 
* * @param row Which row in the block will be processed * @param colStart The first column that computation of tau will start at * @param max used to normalize and prevent buffer over flow * */ public static double computeTauAndDivideRow( final int blockLength , final D1Submatrix64F Y , final int row , int colStart , final double max ) { final int height = Math.min(blockLength , Y.row1-Y.row0); final double dataY[] = Y.original.data; double top=0; double norm2 = 0; int startJ = Y.col0 + colStart - colStart%blockLength; colStart = colStart%blockLength; for( int j = startJ; j < Y.col1; j += blockLength ) { int width = Math.min( blockLength , Y.col1 - j ); int index = Y.row0*Y.original.numCols + height*j + row*width; if( j == startJ ) { index += colStart; // save this value so that the sign can be determined later on top = dataY[index] /= max; norm2 += top*top; index++; for( int k = colStart+1; k < width; k++ ) { double val = dataY[index++] /= max; norm2 += val*val; } } else { for( int k = 0; k < width; k++ ) { double val = dataY[index++] /= max; norm2 += val*val; } } } norm2 = Math.sqrt(norm2); if( top < 0 ) norm2 = -norm2; return norm2; } /** * Finds the element in the column with the largest absolute value. The offset * from zero is automatically taken in account based on the column. */ public static double findMaxCol( final int blockLength , final D1Submatrix64F Y , final int col ) { final int width = Math.min(blockLength,Y.col1-Y.col0); final double dataY[] = Y.original.data; double max = 0; for( int i = Y.row0; i < Y.row1; i += blockLength ) { int height = Math.min( blockLength , Y.row1 - i ); int index = i*Y.original.numCols + height*Y.col0 + col; if( i == Y.row0 ) { index += width*col; for( int k = col; k < height; k++ , index += width ) { double v = Math.abs(dataY[index]); if( v > max ) { max = v; } } } else { for( int k = 0; k < height; k++ , index += width ) { double v = Math.abs(dataY[index]); if( v > max ) { max = v; } } } } return max; } /** * Finds the element in the column with the largest absolute value. The offset * from zero is automatically taken in account based on the column. */ public static double findMaxRow( final int blockLength , final D1Submatrix64F Y , final int row , final int colStart ) { final int height = Math.min(blockLength , Y.row1-Y.row0); final double dataY[] = Y.original.data; double max = 0; for( int j = Y.col0; j < Y.col1; j += blockLength ) { int width = Math.min( blockLength , Y.col1 - j ); int index = Y.row0*Y.original.numCols + height*j + row*width; if( j == Y.col0 ) { index += colStart; for( int k = colStart; k < width; k++ ) { double v = Math.abs(dataY[index++]); if( v > max ) { max = v; } } } else { for( int k = 0; k < width; k++ ) { double v = Math.abs(dataY[index++]); if( v > max ) { max = v; } } } } return max; } /** *

* Computes W from the householder reflectors stored in the columns of the column block * submatrix Y. *

* *

* Y = v(1)
* W = -β1v(1)
* for j=2:r
*   z = -β(I +WYT)v(j)
*   W = [W z]
*   Y = [Y v(j)]
* end
*
* where v(.) are the house holder vectors, and r is the block length. Note that * Y already contains the householder vectors so it does not need to be modified. *

* *

* Y and W are assumed to have the same number of rows and columns. *

* * @param Y Input matrix containing householder vectors. Not modified. * @param W Resulting W matrix. Modified. * @param temp Used internally. Must have W.numCols elements. * @param beta Beta's for householder vectors. * @param betaIndex Index of first relevant beta. */ public static void computeW_Column( final int blockLength , final D1Submatrix64F Y , final D1Submatrix64F W , final double temp[], final double beta[] , int betaIndex ) { final int widthB = W.col1-W.col0; // set the first column in W initializeW(blockLength, W, Y, widthB, beta[betaIndex++]); final int min = Math.min(widthB,W.row1-W.row0); // set up rest of the columns for( int j = 1; j < min; j++ ) { //compute the z vector and insert it into W computeY_t_V(blockLength,Y,j,temp); computeZ(blockLength,Y,W,j,temp,beta[betaIndex++]); } } /** *

* Sets W to its initial value using the first column of 'y' and the value of 'b': *
* W = -βv
*
* where v = Y(:,0). *

* * @param blockLength size of the inner block * @param W Submatrix being initialized. * @param Y Contains householder vector * @param widthB How wide the W block matrix is. * @param b beta */ public static void initializeW( final int blockLength, final D1Submatrix64F W, final D1Submatrix64F Y, final int widthB, final double b) { final double dataW[] = W.original.data; final double dataY[] = Y.original.data; for( int i = W.row0; i < W.row1; i += blockLength ) { int heightW = Math.min( blockLength , W.row1 - i ); int indexW = i*W.original.numCols + heightW*W.col0; int indexY = i*Y.original.numCols + heightW*Y.col0; // take in account the first element in V being 1 if( i == W.row0 ) { dataW[indexW] = -b; indexW += widthB; indexY += widthB; for( int k = 1; k < heightW; k++ , indexW += widthB , indexY += widthB ) { dataW[indexW] = -b* dataY[indexY]; } } else { for( int k = 0; k < heightW; k++ , indexW += widthB , indexY += widthB ) { dataW[indexW] = -b* dataY[indexY]; } } } } /** * Computes the vector z and inserts it into 'W':
*
* z = - βj*(Vj + W*h)
*
* where h is a vector of length 'col' and was computed using {@link #computeY_t_V}. * V is a column in the Y matrix. Z is a column in the W matrix. Both Z and V are * column 'col'. */ public static void computeZ( final int blockLength , final D1Submatrix64F Y , final D1Submatrix64F W, final int col , final double []temp , final double beta ) { final int width = Y.col1-Y.col0; final double dataW[] = W.original.data; final double dataY[] = Y.original.data; final int colsW = W.original.numCols; final double beta_neg = -beta; for( int i = Y.row0; i < Y.row1; i += blockLength ) { int heightW = Math.min( blockLength , Y.row1 - i ); int indexW = i*colsW + heightW*W.col0; int indexZ = i*colsW + heightW*W.col0 + col; int indexV = i*Y.original.numCols + heightW*Y.col0 + col; if( i == Y.row0 ) { // handle the triangular portion with the leading zeros and the one for( int k = 0; k < heightW; k++ , indexZ += width, indexW += width , indexV += width ) { // compute the rows of W * h double total = 0; for( int j = 0; j < col; j++ ) { total += dataW[indexW+j] * temp[j]; } // add the two vectors together and multiply by -beta if( k < col ) { // zeros dataW[indexZ] = -beta*total; } else if( k == col ) { // one dataW[indexZ] = beta_neg*(1.0 + total); } else { // normal data dataW[indexZ] = beta_neg*(dataY[indexV] + total); } } } else { int endZ = indexZ + width*heightW; // for( int k = 0; k < heightW; k++ , while( indexZ != endZ ) { // compute the rows of W * h double total = 0; for( int j = 0; j < col; j++ ) { total += dataW[indexW+j] * temp[j]; } // add the two vectors together and multiply by -beta dataW[indexZ] = beta_neg*(dataY[indexV] + total); indexZ += width; indexW += width; indexV += width; } } } } /** * Computes YTv(j). Where Y are the columns before 'col' and v is the column * at 'col'. The zeros and ones are taken in account. The solution is a vector with 'col' elements. * * width of Y must be along the block of original matrix A * * @param temp Temporary storage of least length 'col' */ public static void computeY_t_V( final int blockLength , final D1Submatrix64F Y , final int col , final double []temp ) { final int widthB = Y.col1-Y.col0; for( int j = 0; j < col; j++ ) { temp[j] = innerProdCol(blockLength,Y,col,widthB,j,widthB); } } /** * Special multiplication that takes in account the zeros and one in Y, which * is the matrix that stores the householder vectors. * */ public static void multAdd_zeros( final int blockLength , final D1Submatrix64F Y , final D1Submatrix64F B , final D1Submatrix64F C ) { int widthY = Y.col1 - Y.col0; for( int i = Y.row0; i < Y.row1; i += blockLength ) { int heightY = Math.min( blockLength , Y.row1 - i ); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = (i-Y.row0+C.row0)*C.original.numCols + (j-B.col0+C.col0)*heightY; for( int k = Y.col0; k < Y.col1; k += blockLength ) { int indexY = i*Y.original.numCols + k*heightY; int indexB = (k-Y.col0+B.row0)*B.original.numCols + j*widthY; if( i == Y.row0 ) { multBlockAdd_zerosone(Y.original.data,B.original.data,C.original.data, indexY,indexB,indexC,heightY,widthY,widthB); } else { BlockInnerMultiplication.blockMultPlus(Y.original.data,B.original.data,C.original.data, indexY,indexB,indexC,heightY,widthY,widthB); } } } } } /** *

* Inner block mult add operation that takes in account the zeros and on in dataA, * which is the top part of the Y block vector that has the householder vectors.
*
* C = C + A * B *

*/ public static void multBlockAdd_zerosone( double[] dataA, double []dataB, double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { for( int i = 0; i < heightA; i++ ) { for( int j = 0; j < widthC; j++ ) { double val = i < widthA ? dataB[i*widthC+j+indexB] : 0; int end = Math.min(i,widthA); for( int k = 0; k < end; k++ ) { val += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB]; } dataC[ i*widthC + j + indexC ] += val; } } } /** *

* Performs a matrix multiplication on the block aligned submatrices. A is * assumed to be block column vector that is lower triangular with diagonal elements set to 1.
*
* C = A^T * B *

*/ public static void multTransA_vecCol( final int blockLength , D1Submatrix64F A , D1Submatrix64F B , D1Submatrix64F C ) { int widthA = A.col1 - A.col0; if( widthA > blockLength ) throw new IllegalArgumentException("A is expected to be at most one block wide."); for( int j = B.col0; j < B.col1; j += blockLength ) { int widthB = Math.min( blockLength , B.col1 - j ); int indexC = C.row0*C.original.numCols + (j-B.col0+C.col0)*widthA; for( int k = A.row0; k < A.row1; k += blockLength ) { int heightA = Math.min( blockLength , A.row1 - k ); int indexA = k*A.original.numCols + A.col0*heightA; int indexB = (k-A.row0+B.row0)*B.original.numCols + j*heightA; if( k == A.row0 ) multTransABlockSet_lowerTriag(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); else BlockInnerMultiplication.blockMultPlusTransA(A.original.data,B.original.data,C.original.data, indexA,indexB,indexC,heightA,widthA,widthB); } } } /** * Performs a matrix multiplication on an single inner block where A is assumed to be lower triangular with diagonal * elements equal to 1.
*
* C = A^T * B */ protected static void multTransABlockSet_lowerTriag( double[] dataA, double []dataB, double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthC) { for( int i = 0; i < widthA; i++ ) { for( int j = 0; j < widthC; j++ ) { double val = i < heightA ? dataB[i*widthC + j + indexB] : 0; for( int k = i+1; k < heightA; k++ ) { val += dataA[k*widthA + i + indexA] * dataB[k*widthC + j + indexB]; } dataC[ i*widthC + j + indexC ] = val; } } } } ejml-0.28/main/dense64/src/org/ejml/alg/block/decomposition/qr/QRDecompositionHouseholder_B64.java000066400000000000000000000323311256171534400327770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.qr; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.BlockMultiplication; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; /** *

* QR decomposition for {@link BlockMatrix64F} using householder reflectors. The decomposition is * performed by computing a QR decomposition for each block column as is normally done, see {@link org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholder_D64}. * The reflectors are then combined and applied to the remainder of the matrix. This process is repeated * until all the block columns have been processed *

* *

* The input matrix is modified and used to store the decomposition. Reflectors are stored in the lower triangle * columns. The first element of the reflector is implicitly assumed to be one. *

* *

* Each iteration can be sketched as follows: *

 * QR_Decomposition( A(:,i-r to i) )
 * W=computeW( A(:,i-r to i) )
 * A(:,i:n) = (I + W*YT)TA(:,i:n)
 * 
* Where r is the block size, i is the submatrix being considered, A is the input matrix, * Y is a matrix containing the reflectors just computed, * and W is computed using {@link BlockHouseHolder#computeW_Column}. *

* *

* Based upon "Block Householder QR Factorization" pg 255 in "Matrix Computations" * 3rd Ed. 1996 by Gene H. Golub and Charles F. Van Loan. *

* * @author Peter Abeles */ public class QRDecompositionHouseholder_B64 implements QRDecomposition { // the input matrix which is overwritten with the decomposition. // Reflectors are stored in the lower triangular portion. The R matrix is stored // in the upper triangle portion private BlockMatrix64F dataA; // where the computed W matrix is stored private BlockMatrix64F dataW = new BlockMatrix64F(1,1); // Matrix used to store an intermediate calculation private BlockMatrix64F dataWTA = new BlockMatrix64F(1,1); // size of the inner matrix block. private int blockLength; // The submatrices which are being manipulated in each iteration private D1Submatrix64F A = new D1Submatrix64F(); private D1Submatrix64F Y = new D1Submatrix64F(); private D1Submatrix64F W = new D1Submatrix64F(dataW); private D1Submatrix64F WTA = new D1Submatrix64F(dataWTA); private double temp[] = new double[1]; // stores the computed gammas private double gammas[] = new double[1]; // save the W matrix the first time it is computed in the decomposition private boolean saveW = false; /** * This is the input matrix after it has been overwritten with the decomposition. * * @return Internal matrix used to store decomposition. */ public BlockMatrix64F getQR() { return dataA; } /** *

* Sets if it should internally save the W matrix before performing the decomposition. Must * be set before decomposition the matrix. *

* *

* Saving W can result in about a 5% savings when solving systems around a height of 5k. The * price is that it needs to save a matrix the size of the input matrix. *

* * @param saveW If the W matrix should be saved or not. */ public void setSaveW(boolean saveW) { this.saveW = saveW; } /** * @inheritDoc */ @Override public BlockMatrix64F getQ(BlockMatrix64F Q, boolean compact) { Q = initializeQ(Q, dataA.numRows , dataA.numCols , blockLength , compact); applyQ(Q,true); return Q; } /** * Sanity checks the input or declares a new matrix. Return matrix is an identity matrix. */ public static BlockMatrix64F initializeQ(BlockMatrix64F Q, int numRows , int numCols , int blockLength , boolean compact) { int minLength = Math.min(numRows,numCols); if( compact ) { if( Q == null ) { Q = new BlockMatrix64F(numRows,minLength,blockLength); BlockMatrixOps.setIdentity(Q); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension. Found "+Q.numRows+" "+Q.numCols); } else { BlockMatrixOps.setIdentity(Q); } } } else { if( Q == null ) { Q = new BlockMatrix64F(numRows,numRows,blockLength); BlockMatrixOps.setIdentity(Q); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension. Found "+Q.numRows+" "+Q.numCols); } else { BlockMatrixOps.setIdentity(Q); } } } return Q; } /** *

* Multiplies the provided matrix by Q using householder reflectors. This is more * efficient that computing Q then applying it to the matrix. *

* *

* B = Q * B *

* * @param B Matrix which Q is applied to. Modified. */ public void applyQ( BlockMatrix64F B ) { applyQ(B,false); } /** * Specialized version of applyQ() that allows the zeros in an identity matrix * to be taken advantage of depending on if isIdentity is true or not. * * @param B * @param isIdentity If B is an identity matrix. */ public void applyQ( BlockMatrix64F B , boolean isIdentity ) { int minDimen = Math.min(dataA.numCols,dataA.numRows); D1Submatrix64F subB = new D1Submatrix64F(B); W.col0 = W.row0 = 0; Y.row1 = W.row1 = dataA.numRows; WTA.row0 = WTA.col0 = 0; int start = minDimen - minDimen % blockLength; if( start == minDimen ) start -= blockLength; if( start < 0 ) start = 0; // (Q1^T * (Q2^T * (Q3^t * A))) for( int i = start; i >= 0; i -= blockLength ) { Y.col0 = i; Y.col1 = Math.min(Y.col0+blockLength,dataA.numCols); Y.row0 = i; if( isIdentity ) subB.col0 = i; subB.row0 = i; setW(); WTA.row1 = Y.col1-Y.col0; WTA.col1 = subB.col1-subB.col0; WTA.original.reshape(WTA.row1,WTA.col1,false); // Compute W matrix from reflectors stored in Y if( !saveW ) BlockHouseHolder.computeW_Column(blockLength,Y,W,temp, gammas,Y.col0); // Apply the Qi to Q BlockHouseHolder.multTransA_vecCol(blockLength,Y,subB,WTA); BlockMultiplication.multPlus(blockLength,W,WTA,subB); } } /** *

* Multiplies the provided matrix by QT using householder reflectors. This is more * efficient that computing Q then applying it to the matrix. *

* *

* Q = Q*(I - γ W*Y^T)
* QR = A => R = Q^T*A = (Q3^T * (Q2^T * (Q1^t * A))) *

* * @param B Matrix which Q is applied to. Modified. */ public void applyQTran( BlockMatrix64F B ) { int minDimen = Math.min(dataA.numCols,dataA.numRows); D1Submatrix64F subB = new D1Submatrix64F(B); W.col0 = W.row0 = 0; Y.row1 = W.row1 = dataA.numRows; WTA.row0 = WTA.col0 = 0; // (Q3^T * (Q2^T * (Q1^t * A))) for( int i = 0; i < minDimen; i += blockLength ) { Y.col0 = i; Y.col1 = Math.min(Y.col0+blockLength,dataA.numCols); Y.row0 = i; subB.row0 = i; // subB.row1 = B.numRows; // subB.col0 = 0; // subB.col1 = B.numCols; setW(); // W.original.reshape(W.row1,W.col1,false); WTA.row0 = 0; WTA.col0 = 0; WTA.row1 = W.col1-W.col0; WTA.col1 = subB.col1-subB.col0; WTA.original.reshape(WTA.row1,WTA.col1,false); // Compute W matrix from reflectors stored in Y if( !saveW ) BlockHouseHolder.computeW_Column(blockLength,Y,W,temp, gammas,Y.col0); // Apply the Qi to Q BlockMultiplication.multTransA(blockLength,W,subB,WTA); BlockHouseHolder.multAdd_zeros(blockLength,Y,WTA,subB); } } /** * @inheritDoc */ @Override public BlockMatrix64F getR(BlockMatrix64F R, boolean compact) { int min = Math.min(dataA.numRows,dataA.numCols); if( R == null ) { if( compact ) { R = new BlockMatrix64F(min,dataA.numCols,blockLength); } else { R = new BlockMatrix64F(dataA.numRows,dataA.numCols,blockLength); } } else { if( compact ) { if( R.numCols != dataA.numCols || R.numRows != min ) { throw new IllegalArgumentException("Unexpected dimension."); } } else if( R.numCols != dataA.numCols || R.numRows != dataA.numRows ) { throw new IllegalArgumentException("Unexpected dimension."); } } BlockMatrixOps.zeroTriangle(false,R); BlockMatrixOps.copyTriangle(true,dataA,R); return R; } /** * @inheritDoc */ @Override public boolean decompose(BlockMatrix64F orig) { setup(orig); int m = Math.min(orig.numCols,orig.numRows); // process the matrix one column block at a time and overwrite the input matrix for( int j = 0; j < m; j += blockLength ) { Y.col0 = j; Y.col1 = Math.min( orig.numCols , Y.col0 + blockLength ); Y.row0 = j; // compute the QR decomposition of the left most block column // this overwrites the original input matrix if( !BlockHouseHolder.decomposeQR_block_col(blockLength,Y,gammas) ) { return false; } // Update the remainder of the matrix using the reflectors just computed updateA(A); } return true; } /** * Adjust submatrices and helper data structures for the input matrix. Must be called * before the decomposition can be computed. * * @param orig */ private void setup(BlockMatrix64F orig) { blockLength = orig.blockLength; dataW.blockLength = blockLength; dataWTA.blockLength = blockLength; this.dataA = orig; A.original = dataA; int l = Math.min(blockLength,orig.numCols); dataW.reshape(orig.numRows,l,false); dataWTA.reshape(l,orig.numRows,false); Y.original = orig; Y.row1 = W.row1 = orig.numRows; if( temp.length < blockLength ) temp = new double[blockLength]; if( gammas.length < orig.numCols ) gammas = new double[ orig.numCols ]; if( saveW ) { dataW.reshape(orig.numRows,orig.numCols,false); } } /** *

* A = (I + W YT)TA
* A = A + Y (WTA)
*
* where A is a submatrix of the input matrix. *

*/ protected void updateA( D1Submatrix64F A ) { setW(); A.row0 = Y.row0; A.row1 = Y.row1; A.col0 = Y.col1; A.col1 = Y.original.numCols; WTA.row0 = 0; WTA.col0 = 0; WTA.row1 = W.col1-W.col0; WTA.col1 = A.col1-A.col0; WTA.original.reshape(WTA.row1,WTA.col1,false); if( A.col1 > A.col0 ) { BlockHouseHolder.computeW_Column(blockLength,Y,W,temp, gammas,Y.col0); BlockMultiplication.multTransA(blockLength,W,A,WTA); BlockHouseHolder.multAdd_zeros(blockLength,Y,WTA,A); } else if( saveW ) { BlockHouseHolder.computeW_Column(blockLength,Y,W,temp, gammas,Y.col0); } } /** * Sets the submatrix of W up give Y is already configured and if it is being cached or not. */ private void setW() { if( saveW ) { W.col0 = Y.col0; W.col1 = Y.col1; W.row0 = Y.row0; W.row1 = Y.row1; } else { W.col1 = Y.col1 - Y.col0; W.row0 = Y.row0; } } /** * The input matrix is always modified. * * @return Returns true since the input matrix is modified. */ @Override public boolean inputModified() { return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/linsol/000077500000000000000000000000001256171534400222405ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/linsol/chol/000077500000000000000000000000001256171534400231655ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/linsol/chol/BlockCholeskyOuterSolver.java000066400000000000000000000115731256171534400310050ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.linsol.chol; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.BlockTriangularSolver; import org.ejml.alg.block.decomposition.chol.CholeskyOuterForm_B64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.SpecializedOps; /** *

Linear solver that uses a block cholesky decomposition.

* *

* Solver works by using the standard Cholesky solving strategy:
* A=L*LT
* A*x=b
* L*LT*x = b
* L*y = b
* LT*x = y
* x = L-Ty *

* *

* It is also possible to use the upper triangular cholesky decomposition. *

* * @author Peter Abeles */ public class BlockCholeskyOuterSolver implements LinearSolver { // cholesky decomposition private CholeskyOuterForm_B64 decomposer = new CholeskyOuterForm_B64(true); // size of a block take from input matrix private int blockLength; // temporary data structure used in some calculation. private double temp[]; /** * Decomposes and overwrites the input matrix. * * @param A Semi-Positive Definite (SPD) system matrix. Modified. Reference saved. * @return If the matrix can be decomposed. Will always return false of not SPD. */ @Override public boolean setA(BlockMatrix64F A) { // Extract a lower triangular solution if( !decomposer.decompose(A) ) return false; blockLength = A.blockLength; return true; } @Override public double quality() { return SpecializedOps.qualityTriangular(decomposer.getT(null)); } /** * If X == null then the solution is written into B. Otherwise the solution is copied * from B into X. */ @Override public void solve(BlockMatrix64F B, BlockMatrix64F X) { if( B.blockLength != blockLength ) throw new IllegalArgumentException("Unexpected blocklength in B."); D1Submatrix64F L = new D1Submatrix64F(decomposer.getT(null)); if( X != null ) { if( X.blockLength != blockLength ) throw new IllegalArgumentException("Unexpected blocklength in X."); if( X.numRows != L.col1 ) throw new IllegalArgumentException("Not enough rows in X"); } if( B.numRows != L.col1 ) throw new IllegalArgumentException("Not enough rows in B"); // L * L^T*X = B // Solve for Y: L*Y = B BlockTriangularSolver.solve(blockLength,false,L,new D1Submatrix64F(B),false); // L^T * X = Y BlockTriangularSolver.solve(blockLength,false,L,new D1Submatrix64F(B),true); if( X != null ) { // copy the solution from B into X BlockMatrixOps.extractAligned(B,X); } } @Override public void invert(BlockMatrix64F A_inv) { BlockMatrix64F T = decomposer.getT(null); if( A_inv.numRows != T.numRows || A_inv.numCols != T.numCols ) throw new IllegalArgumentException("Unexpected number or rows and/or columns"); if( temp == null || temp.length < blockLength*blockLength ) temp = new double[ blockLength* blockLength ]; // zero the upper triangular portion of A_inv BlockMatrixOps.zeroTriangle(true,A_inv); D1Submatrix64F L = new D1Submatrix64F(T); D1Submatrix64F B = new D1Submatrix64F(A_inv); // invert L from cholesky decomposition and write the solution into the lower // triangular portion of A_inv // B = inv(L) BlockTriangularSolver.invert(blockLength,false,L,B,temp); // B = L^-T * B // todo could speed up by taking advantage of B being lower triangular // todo take advantage of symmetry BlockTriangularSolver.solveL(blockLength,L,B,true); } @Override public boolean modifiesA() { return decomposer.inputModified(); } @Override public boolean modifiesB() { return true; } @Override public CholeskyDecomposition getDecomposition() { return decomposer; } } ejml-0.28/main/dense64/src/org/ejml/alg/block/linsol/qr/000077500000000000000000000000001256171534400226625ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/block/linsol/qr/BlockQrHouseHolderSolver.java000066400000000000000000000121751256171534400304250ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.linsol.qr; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.BlockTriangularSolver; import org.ejml.alg.block.decomposition.qr.QRDecompositionHouseholder_B64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.SpecializedOps; /** *

* A solver for {@link org.ejml.alg.block.decomposition.qr.QRDecompositionHouseholder_B64}. Systems are solved for using the standard * QR decomposition method, sketched below. *

* *

* A = Q*R
* A*x = b
* Q*R*x = b
* R*x = y = QTb
* x = R-1y
*
* Where A is the m by n matrix being decomposed. Q is an orthogonal matrix. R is upper triangular matrix. *

* * @author Peter Abeles */ public class BlockQrHouseHolderSolver implements LinearSolver { // QR decomposition algorithm protected QRDecompositionHouseholder_B64 decomposer = new QRDecompositionHouseholder_B64(); // the input matrix which has been decomposed protected BlockMatrix64F QR; public BlockQrHouseHolderSolver() { decomposer.setSaveW(false); } /** * Computes the QR decomposition of A and store the results in A. * * @param A The A matrix in the linear equation. Modified. Reference saved. * @return true if the decomposition was successful. */ @Override public boolean setA(BlockMatrix64F A) { if( A.numRows < A.numCols ) throw new IllegalArgumentException("Number of rows must be more than or equal to the number of columns. " + "Can't solve an underdetermined system."); if( !decomposer.decompose(A)) return false; this.QR = decomposer.getQR(); return true; } /** * Computes the quality using diagonal elements the triangular R matrix in the QR decomposition. * * @return Solutions quality. */ @Override public double quality() { return SpecializedOps.qualityTriangular(decomposer.getQR()); } @Override public void solve(BlockMatrix64F B, BlockMatrix64F X) { if( B.numCols != X.numCols ) throw new IllegalArgumentException("Columns of B and X do not match"); if( QR.numCols != X.numRows ) throw new IllegalArgumentException("Rows in X do not match the columns in A"); if( QR.numRows != B.numRows ) throw new IllegalArgumentException("Rows in B do not match the rows in A."); if( B.blockLength != QR.blockLength || X.blockLength != QR.blockLength ) throw new IllegalArgumentException("All matrices must have the same block length."); // The system being solved for can be described as: // Q*R*X = B // First apply householder reflectors to B // Y = Q^T*B decomposer.applyQTran(B); // Second solve for Y using the upper triangle matrix R and the just computed Y // X = R^-1 * Y BlockMatrixOps.extractAligned(B,X); // extract a block aligned matrix int M = Math.min(QR.numRows,QR.numCols); BlockTriangularSolver.solve(QR.blockLength,true, new D1Submatrix64F(QR,0,M,0,M),new D1Submatrix64F(X),false); } /** * Invert by solving for against an identity matrix. * * @param A_inv Where the inverted matrix saved. Modified. */ @Override public void invert(BlockMatrix64F A_inv) { int M = Math.min(QR.numRows,QR.numCols); if( A_inv.numRows != M || A_inv.numCols != M ) throw new IllegalArgumentException("A_inv must be square an have dimension "+M); // Solve for A^-1 // Q*R*A^-1 = I // Apply householder reflectors to the identity matrix // y = Q^T*I = Q^T BlockMatrixOps.setIdentity(A_inv); decomposer.applyQTran(A_inv); // Solve using upper triangular R matrix // R*A^-1 = y // A^-1 = R^-1*y BlockTriangularSolver.solve(QR.blockLength,true, new D1Submatrix64F(QR,0,M,0,M),new D1Submatrix64F(A_inv),false); } @Override public boolean modifiesA() { return decomposer.inputModified(); } @Override public boolean modifiesB() { return true; } @Override public QRDecomposition getDecomposition() { return decomposer; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/000077500000000000000000000000001256171534400207445ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/000077500000000000000000000000001256171534400236205ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/BaseDecomposition_B64_to_D64.java000066400000000000000000000056061256171534400316330ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.DecompositionInterface; /** * Generic interface for wrapping a {@link BlockMatrix64F} decomposition for * processing of {@link org.ejml.data.DenseMatrix64F}. * * @author Peter Abeles */ public class BaseDecomposition_B64_to_D64 implements DecompositionInterface { protected DecompositionInterface alg; protected double[]tmp; protected BlockMatrix64F Ablock = new BlockMatrix64F(); protected int blockLength; public BaseDecomposition_B64_to_D64(DecompositionInterface alg, int blockLength) { this.alg = alg; this.blockLength = blockLength; } @Override public boolean decompose(DenseMatrix64F A) { Ablock.numRows = A.numRows; Ablock.numCols = A.numCols; Ablock.blockLength = blockLength; Ablock.data = A.data; int tmpLength = Math.min( Ablock.blockLength , A.numRows ) * A.numCols; if( tmp == null || tmp.length < tmpLength ) tmp = new double[ tmpLength ]; // doing an in-place convert is much more memory efficient at the cost of a little // but of CPU BlockMatrixOps.convertRowToBlock(A.numRows,A.numCols,Ablock.blockLength,A.data,tmp); boolean ret = alg.decompose(Ablock); // convert it back to the normal format if it wouldn't have been modified if( !alg.inputModified() ) { BlockMatrixOps.convertBlockToRow(A.numRows,A.numCols,Ablock.blockLength,A.data,tmp); } return ret; } public void convertBlockToRow(int numRows , int numCols , int blockLength , double[] data) { int tmpLength = Math.min( blockLength , numRows ) * numCols; if( tmp == null || tmp.length < tmpLength ) tmp = new double[ tmpLength ]; BlockMatrixOps.convertBlockToRow(numRows,numCols,Ablock.blockLength,data,tmp); } @Override public boolean inputModified() { return alg.inputModified(); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/TriangularSolver.java000066400000000000000000000171301256171534400277700ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition; /** *

* This contains algorithms for solving systems of equations where T is a * non-singular triangular matrix:
*
* T*x = b
*
* where x and b are vectors, and T is an n by n matrix. T can either be a lower or upper triangular matrix.
*

*

* These functions are designed for use inside of other algorithms. To use them directly * is dangerous since no sanity checks are performed. *

* * @author Peter Abeles */ public class TriangularSolver { /** *

* Inverts a square lower triangular matrix: L = L-1 *

* * * @param L * @param m */ public static void invertLower( double L[] , int m ) { for( int i = 0; i < m; i++ ) { double L_ii = L[ i*m + i ]; for( int j = 0; j < i; j++ ) { double val = 0; for( int k = j; k < i; k++ ) { val += L[ i*m + k] * L[ k*m + j ]; } L[ i*m + j ] = -val / L_ii; } L[ i*m + i ] = 1.0 / L_ii; } } public static void invertLower( double L[] , double L_inv[] , int m ) { for( int i = 0; i < m; i++ ) { double L_ii = L[ i*m + i ]; for( int j = 0; j < i; j++ ) { double val = 0; for( int k = j; k < i; k++ ) { val -= L[ i*m + k] * L_inv[ k*m + j ]; } L_inv[ i*m + j ] = val / L_ii; } L_inv[ i*m + i ] = 1.0 / L_ii; } } /** *

* Solves for non-singular lower triangular matrices using forward substitution. *
* b = L-1b
*
* where b is a vector, L is an n by n matrix.
*

* * @param L An n by n non-singular lower triangular matrix. Not modified. * @param b A vector of length n. Modified. * @param n The size of the matrices. */ public static void solveL( double L[] , double []b , int n ) { // for( int i = 0; i < n; i++ ) { // double sum = b[i]; // for( int k=0; k * This is a forward substitution solver for non-singular lower triangular matrices. *
* b = (LT)-1b
*
* where b is a vector, L is an n by n matrix.
*

*

* L is a lower triangular matrix, but it comes up with a solution as if it was * an upper triangular matrix that was computed by transposing L. *

* * @param L An n by n non-singular lower triangular matrix. Not modified. * @param b A vector of length n. Modified. * @param n The size of the matrices. */ public static void solveTranL( double L[] , double []b , int n ) { for( int i =n-1; i>=0; i-- ) { double sum = b[i]; for( int k = i+1; k * This is a forward substitution solver for non-singular upper triangular matrices. *
* b = U-1b
*
* where b is a vector, U is an n by n matrix.
*

* * @param U An n by n non-singular upper triangular matrix. Not modified. * @param b A vector of length n. Modified. * @param n The size of the matrices. */ public static void solveU( double U[] , double []b , int n ) { // for( int i =n-1; i>=0; i-- ) { // double sum = b[i]; // for( int j = i+1; j =0; i-- ) { double sum = b[i]; int indexU = i*n+i+1; for( int j = i+1; j =minRow; i-- ) { // double sum = b[i]; // for( int j = i+1; j =minRow; i-- ) { double sum = b[i]; int indexU = i*sideLength+i+1; for( int j = i+1; j * This is a forward substitution solver for non-singular upper triangular matrices which are * a sub-matrix inside a larger. The columns of 'b' are solved for individually *
* b = U-1b
*
* where b is a matrix, U is an n by n matrix.
*

* * @param U Matrix containing the upper triangle system * @param startU Index of the first element in U * @param strideU stride between rows * @param widthU How wide the square matrix is * @param b Matrix containing the solution to the system. Overwritten with the solution. * @param startB Index of the first element in B * @param strideB stride between rows * @param widthB How wide the matrix is. Length is the same as U's width */ public static void solveU( double []U , int startU , int strideU , int widthU , double []b , int startB , int strideB , int widthB ) { for( int colB = 0; colB < widthB; colB++ ) { for( int i =widthU-1; i>=0; i-- ) { double sum = b[startB + i*strideB + colB]; for( int j = i+1; j * Performs a {@link org.ejml.interfaces.decomposition.BidiagonalDecomposition} using * householder reflectors. This is efficient on wide or square matrices. *

* * @author Peter Abeles */ public class BidiagonalDecompositionRow_D64 implements BidiagonalDecomposition { // A combined matrix that stores te upper Hessenberg matrix and the orthogonal matrix. private DenseMatrix64F UBV; // number of rows private int m; // number of columns private int n; // the smaller of m or n private int min; // the first element in the orthogonal vectors private double gammasU[]; private double gammasV[]; // temporary storage private double b[]; private double u[]; /** * Creates a decompose that defines the specified amount of memory. * * @param numElements number of elements in the matrix. */ public BidiagonalDecompositionRow_D64(int numElements) { UBV = new DenseMatrix64F(numElements); gammasU = new double[ numElements ]; gammasV = new double[ numElements ]; b = new double[ numElements ]; u = new double[ numElements ]; } public BidiagonalDecompositionRow_D64() { this(1); } /** * Computes the decomposition of the provided matrix. If no errors are detected then true is returned, * false otherwise. * * @param A The matrix that is being decomposed. Not modified. * @return If it detects any errors or not. */ @Override public boolean decompose( DenseMatrix64F A ) { init(A); return _decompose(); } /** * Sets up internal data structures and creates a copy of the input matrix. * * @param A The input matrix. Not modified. */ protected void init(DenseMatrix64F A ) { UBV = A; m = UBV.numRows; n = UBV.numCols; min = Math.min(m,n); int max = Math.max(m,n); if( b.length < max+1 ) { b = new double[ max+1 ]; u = new double[ max+1 ]; } if( gammasU.length < m ) { gammasU = new double[ m ]; } if( gammasV.length < n ) { gammasV = new double[ n ]; } } /** * The raw UBV matrix that is stored internally. * * @return UBV matrix. */ public DenseMatrix64F getUBV() { return UBV; } @Override public void getDiagonal(double[] diag, double[] off) { diag[0] = UBV.get(0); for( int i = 1; i < n; i++ ) { diag[i] = UBV.unsafe_get(i,i); off[i-1] = UBV.unsafe_get(i-1,i); } } /** * Returns the bidiagonal matrix. * * @param B If not null the results are stored here, if null a new matrix is created. * @return The bidiagonal matrix. */ @Override public DenseMatrix64F getB( DenseMatrix64F B , boolean compact ) { B = handleB(B, compact,m,n,min); //System.arraycopy(UBV.data, 0, B.data, 0, UBV.getNumElements()); B.set(0,0,UBV.get(0,0)); for( int i = 1; i < min; i++ ) { B.set(i,i, UBV.get(i,i)); B.set(i-1,i, UBV.get(i-1,i)); } if( n > m ) B.set(min-1,min,UBV.get(min-1,min)); return B; } public static DenseMatrix64F handleB(DenseMatrix64F B, boolean compact, int m , int n , int min ) { int w = n > m ? min + 1 : min; if( compact ) { if( B == null ) { B = new DenseMatrix64F(min,w); } else { B.reshape(min,w, false); B.zero(); } } else { if( B == null ) { B = new DenseMatrix64F(m,n); } else { B.reshape(m,n, false); B.zero(); } } return B; } /** * Returns the orthogonal U matrix. * * @param U If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ @Override public DenseMatrix64F getU( DenseMatrix64F U , boolean transpose , boolean compact ) { U = handleU(U, transpose, compact,m,n,min); CommonOps.setIdentity(U); for( int i = 0; i < m; i++ ) u[i] = 0; for( int j = min-1; j >= 0; j-- ) { u[j] = 1; for( int i = j+1; i < m; i++ ) { u[i] = UBV.get(i,j); } if( transpose ) QrHelperFunctions_D64.rank1UpdateMultL(U, u, gammasU[j], j, j, m); else QrHelperFunctions_D64.rank1UpdateMultR(U, u, gammasU[j], j, j, m, this.b); } return U; } public static DenseMatrix64F handleU(DenseMatrix64F U, boolean transpose, boolean compact, int m, int n , int min ) { if( compact ){ if( transpose ) { if( U == null ) U = new DenseMatrix64F(min,m); else { U.reshape(min,m, false); } } else { if( U == null ) U = new DenseMatrix64F(m,min); else U.reshape(m,min, false); } } else { if( U == null ) U = new DenseMatrix64F(m,m); else U.reshape(m,m, false); } return U; } /** * Returns the orthogonal V matrix. * * @param V If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ @Override public DenseMatrix64F getV( DenseMatrix64F V , boolean transpose , boolean compact ) { V = handleV(V, transpose, compact,m,n,min); CommonOps.setIdentity(V); // UBV.print(); // todo the very first multiplication can be avoided by setting to the rank1update output for( int j = min-1; j >= 0; j-- ) { u[j+1] = 1; for( int i = j+2; i < n; i++ ) { u[i] = UBV.get(j,i); } if( transpose ) QrHelperFunctions_D64.rank1UpdateMultL(V, u, gammasV[j], j + 1, j + 1, n); else QrHelperFunctions_D64.rank1UpdateMultR(V, u, gammasV[j], j + 1, j + 1, n, this.b); } return V; } public static DenseMatrix64F handleV(DenseMatrix64F V, boolean transpose, boolean compact, int m , int n , int min ) { int w = n > m ? min + 1 : min; if( compact ) { if( transpose ) { if( V == null ) { V = new DenseMatrix64F(w,n); } else V.reshape(w,n, false); } else { if( V == null ) { V = new DenseMatrix64F(n,w); } else V.reshape(n,w, false); } } else { if( V == null ) { V = new DenseMatrix64F(n,n); } else V.reshape(n,n, false); } return V; } /** * Internal function for computing the decomposition. */ private boolean _decompose() { for( int k = 0; k < min; k++ ) { // UBV.print(); computeU(k); // System.out.println("--- after U"); // UBV.print(); computeV(k); // System.out.println("--- after V"); // UBV.print(); } return true; } protected void computeU( int k) { double b[] = UBV.data; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = 0; for( int i = k; i < m; i++ ) { // copy the householder vector to vector outside of the matrix to reduce caching issues // big improvement on larger matrices and a relatively small performance hit on small matrices. double val = u[i] = b[i*n+k]; val = Math.abs(val); if( val > max ) max = val; } if( max > 0 ) { // -------- set up the reflector Q_k double tau = QrHelperFunctions_D64.computeTauAndDivide(k, m, u, max); // write the reflector into the lower left column of the matrix // while dividing u by nu double nu = u[k] + tau; QrHelperFunctions_D64.divideElements_Bcol(k + 1, m, n, u, b, k, nu); u[k] = 1.0; double gamma = nu/tau; gammasU[k] = gamma; // ---------- multiply on the left by Q_k QrHelperFunctions_D64.rank1UpdateMultR(UBV, u, gamma, k + 1, k, m, this.b); b[k*n+k] = -tau*max; } else { gammasU[k] = 0; } } protected void computeV(int k) { double b[] = UBV.data; int row = k*n; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = QrHelperFunctions_D64.findMax(b, row + k + 1, n - k - 1); if( max > 0 ) { // -------- set up the reflector Q_k double tau = QrHelperFunctions_D64.computeTauAndDivide(k + 1, n, b, row, max); // write the reflector into the lower left column of the matrix double nu = b[row+k+1] + tau; QrHelperFunctions_D64.divideElements_Brow(k + 2, n, u, b, row, nu); u[k+1] = 1.0; double gamma = nu/tau; gammasV[k] = gamma; // writing to u could be avoided by working directly with b. // requires writing a custom rank1Update function // ---------- multiply on the left by Q_k QrHelperFunctions_D64.rank1UpdateMultL(UBV, u, gamma, k + 1, k + 1, n); b[row+k+1] = -tau*max; } else { gammasV[k] = 0; } } /** * Returns gammas from the householder operations for the U matrix. * * @return gammas for householder operations */ public double[] getGammasU() { return gammasU; } /** * Returns gammas from the householder operations for the V matrix. * * @return gammas for householder operations */ public double[] getGammasV() { return gammasV; } @Override public boolean inputModified() { return true; } }BidiagonalDecompositionTall_D64.java000066400000000000000000000115721256171534400345230ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/bidiagonal/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.bidiagonal; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.BidiagonalDecomposition; import org.ejml.interfaces.decomposition.QRPDecomposition; import org.ejml.ops.CommonOps; /** *

* {@link org.ejml.interfaces.decomposition.BidiagonalDecomposition} specifically designed for tall matrices. * First step is to perform QR decomposition on the input matrix. Then R is decomposed using * a bidiagonal decomposition. By performing the bidiagonal decomposition on the smaller matrix * computations can be saved if m/n > 5/3 and if U is NOT needed. *

* *

* A = [Q1 Q2][U1 0; 0 I] [B1;0] VT
* U=[Q1*U1 Q2]
* B=[B1;0]
* A = U*B*VT *

* *

* A QRP decomposition is used internally. That decomposition relies an a fixed threshold for selecting singular * values and is known to be less stable than SVD. There is the potential for a degregation of stability * by using BidiagonalDecompositionTall instead of BidiagonalDecomposition. A few simple tests have shown * that loss in stability to be insignificant. *

* *

* See page 404 in "Fundamentals of Matrix Computations", 2nd by David S. Watkins. *

* * * @author Peter Abeles */ // TODO optimize this code public class BidiagonalDecompositionTall_D64 implements BidiagonalDecomposition { QRPDecomposition decompQRP = DecompositionFactory.qrp(500, 100); // todo this should be passed in BidiagonalDecomposition decompBi = new BidiagonalDecompositionRow_D64(); DenseMatrix64F B = new DenseMatrix64F(1,1); // number of rows int m; // number of column int n; // min(m,n) int min; @Override public void getDiagonal(double[] diag, double[] off) { diag[0] = B.get(0); for( int i = 1; i < n; i++ ) { diag[i] = B.unsafe_get(i,i); off[i-1] = B.unsafe_get(i-1,i); } } @Override public DenseMatrix64F getB(DenseMatrix64F B, boolean compact) { B = BidiagonalDecompositionRow_D64.handleB(B, compact, m, n, min); B.set(0,0,this.B.get(0,0)); for( int i = 1; i < min; i++ ) { B.set(i,i, this.B.get(i,i)); B.set(i-1,i, this.B.get(i-1,i)); } if( n > m) B.set(min-1,min,this.B.get(min-1,min)); return B; } @Override public DenseMatrix64F getU(DenseMatrix64F U, boolean transpose, boolean compact) { U = BidiagonalDecompositionRow_D64.handleU(U, false, compact, m, n, min); if( compact ) { // U = Q*U1 DenseMatrix64F Q1 = decompQRP.getQ(null,true); DenseMatrix64F U1 = decompBi.getU(null,false,true); CommonOps.mult(Q1,U1,U); } else { // U = [Q1*U1 Q2] DenseMatrix64F Q = decompQRP.getQ(U,false); DenseMatrix64F U1 = decompBi.getU(null,false,true); DenseMatrix64F Q1 = CommonOps.extract(Q,0,Q.numRows,0,min); DenseMatrix64F tmp = new DenseMatrix64F(Q1.numRows,U1.numCols); CommonOps.mult(Q1,U1,tmp); CommonOps.insert(tmp,Q,0,0); } if( transpose ) CommonOps.transpose(U); return U; } @Override public DenseMatrix64F getV(DenseMatrix64F V, boolean transpose, boolean compact) { return decompBi.getV(V,transpose,compact); } @Override public boolean decompose(DenseMatrix64F orig) { if( !decompQRP.decompose(orig) ) { return false; } m = orig.numRows; n = orig.numCols; min = Math.min(m, n); B.reshape(min, n,false); decompQRP.getR(B,true); // apply the column pivots. // TODO this is horribly inefficient DenseMatrix64F result = new DenseMatrix64F(min,n); DenseMatrix64F P = decompQRP.getPivotMatrix(null); CommonOps.multTransB(B, P, result); B.set(result); return decompBi.decompose(B); } @Override public boolean inputModified() { return decompQRP.inputModified(); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/chol/000077500000000000000000000000001256171534400245455ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/chol/CholeskyBlockHelper_D64.java000066400000000000000000000063741256171534400317330ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.data.DenseMatrix64F; /** * A specialized Cholesky decomposition algorithm that is designed to help out * {@link CholeskyDecompositionBlock_D64} perform its calculations. While decomposing * the matrix it will modify its internal lower triangular matrix and the original * that is being modified. * * @author Peter Abeles */ class CholeskyBlockHelper_D64 { // the decomposed matrix private DenseMatrix64F L; private double[] el; /** * Creates a CholeksyDecomposition capable of decomposing a matrix that is * n by n, where n is the width. * * @param widthMax The maximum width of a matrix that can be processed. */ public CholeskyBlockHelper_D64(int widthMax) { this.L = new DenseMatrix64F(widthMax,widthMax); this.el = L.data; } /** * Decomposes a submatrix. The results are written to the submatrix * and to its internal matrix L. * * @param mat A matrix which has a submatrix that needs to be inverted * @param indexStart the first index of the submatrix * @param n The width of the submatrix that is to be inverted. * @return True if it was able to finish the decomposition. */ public boolean decompose( DenseMatrix64F mat , int indexStart , int n ) { double m[] = mat.data; double el_ii; double div_el_ii=0; for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { double sum = m[indexStart+i*mat.numCols+j]; int iEl = i*n; int jEl = j*n; int end = iEl+i; // k = 0:i-1 for( ; iEl * L*LT=A * * @return A lower triangular matrix. */ public DenseMatrix64F getL() { return L; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/chol/CholeskyDecompositionBlock_D64.java000066400000000000000000000174331256171534400333260ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.data.DenseMatrix64F; /** * This is an implementation of Cholesky that processes internal submatrices as blocks. This is * done to reduce the number of cache issues. * * @author Peter Abeles */ public class CholeskyDecompositionBlock_D64 extends CholeskyDecompositionCommon_D64 { private int blockWidth; // how wide the blocks should be private DenseMatrix64F B; // row rectangular matrix private CholeskyBlockHelper_D64 chol; /** * Creates a CholeksyDecomposition capable of decomposing a matrix that is * n by n, where n is the width. * * @param blockWidth The width of a block. */ public CholeskyDecompositionBlock_D64(int blockWidth) { super(true); this.blockWidth = blockWidth; } /** * Declares additional internal data structures. */ @Override public void setExpectedMaxSize( int numRows , int numCols ) { super.setExpectedMaxSize(numRows,numCols); // if the matrix that is being decomposed is smaller than the block we really don't // see the B matrix. if( numRows < blockWidth) B = new DenseMatrix64F(0,0); else B = new DenseMatrix64F(blockWidth,maxWidth); chol = new CholeskyBlockHelper_D64(blockWidth); } /** *

* Performs Choleksy decomposition on the provided matrix. *

* *

* If the matrix is not positive definite then this function will return * false since it can't complete its computations. Not all errors will be * found. *

* @return True if it was able to finish the decomposition. */ @Override protected boolean decomposeLower() { if( n < blockWidth) B.reshape(0,0, false); else B.reshape(blockWidth,n-blockWidth, false); int numBlocks = n / blockWidth; int remainder = n % blockWidth; if( remainder > 0 ) { numBlocks++; } B.numCols = n; for( int i = 0; i < numBlocks; i++ ) { B.numCols -= blockWidth; if( B.numCols > 0 ) { // apply cholesky to the current block if( !chol.decompose(T,(i*blockWidth)* T.numCols + i*blockWidth,blockWidth) ) return false; int indexSrc = i*blockWidth* T.numCols + (i+1)*blockWidth; int indexDst = (i+1)*blockWidth* T.numCols + i*blockWidth; // B = L^(-1) * B solveL_special(chol.getL().data, T,indexSrc,indexDst,B); int indexL = (i+1)*blockWidth*n + (i+1)*blockWidth; // c = c - a^T*a symmRankTranA_sub(B, T,indexL); } else { int width = remainder > 0 ? remainder : blockWidth; if( !chol.decompose(T,(i*blockWidth)* T.numCols + i*blockWidth,width) ) return false; } } // zero the top right corner. for( int i = 0; i < n; i++ ) { for( int j = i+1; j < n; j++ ) { t[i*n+j] = 0.0; } } return true; } @Override protected boolean decomposeUpper() { throw new RuntimeException("Not implemented. Do a lower decomposition and transpose it..."); } /** * This is a variation on the {@link org.ejml.alg.dense.decomposition.TriangularSolver#solveL} function. * It grabs the input from the top right row rectangle of the source matrix then writes the results * to the lower bottom column rectangle. The rectangle matrices just matrices are submatrices * of the matrix that is being decomposed. The results are also written to B. * * @param L A lower triangular matrix. * @param b_src matrix with the vectors that are to be solved for * @param indexSrc First index of the submatrix where the inputs are coming from. * @param indexDst First index of the submatrix where the results are going to. * @param B */ public static void solveL_special( final double L[] , final DenseMatrix64F b_src, final int indexSrc , final int indexDst , final DenseMatrix64F B ) { final double dataSrc[] = b_src.data; final double b[]= B.data; final int m = B.numRows; final int n = B.numCols; final int widthL = m; // for( int j = 0; j < n; j++ ) { // for( int i = 0; i < widthL; i++ ) { // double sum = dataSrc[indexSrc+i*b_src.numCols+j]; // for( int k=0; k * Performs this operation:
*
* c = c - aTa
* where c is a submatrix. *

* * Only the upper triangle is updated. * * @param a A matrix. * @param c A matrix. * @param startIndexC start of the submatrix in c. */ public static void symmRankTranA_sub( DenseMatrix64F a , DenseMatrix64F c , int startIndexC ) { // TODO update so that it doesn't modify/read parts that it shouldn't final double dataA[] = a.data; final double dataC[] = c.data; // for( int i = 0; i < a.numCols; i++ ) { // for( int k = 0; k < a.numRows; k++ ) { // double valA = dataA[k*a.numCols+i]; // // for( int j = i; j < a.numCols; j++ ) { // dataC[startIndexC+i*c.numCols+j] -= valA * dataA[k*a.numCols+j]; // } // } // } final int strideC = c.numCols + 1; for( int i = 0; i < a.numCols; i++ ) { int indexA = i; int endR = a.numCols; for( int k = 0; k < a.numRows; k++ , indexA += a.numCols , endR += a.numCols) { int indexC = startIndexC; final double valA = dataA[indexA]; int indexR = indexA; while( indexR < endR ) { dataC[indexC++] -= valA * dataA[indexR++]; } } startIndexC += strideC; } } }CholeskyDecompositionCommon_D64.java000066400000000000000000000124471256171534400334450ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.ops.CommonOps; /** * *

* This is an abstract class for a Cholesky decomposition. It provides the solvers, but the actual * decomposition is provided in other classes. *

* * @see org.ejml.interfaces.decomposition.CholeskyDecomposition * @author Peter Abeles */ public abstract class CholeskyDecompositionCommon_D64 implements CholeskyDecomposition { // it can decompose a matrix up to this width protected int maxWidth=-1; // width and height of the matrix protected int n; // the decomposed matrix protected DenseMatrix64F T; protected double[] t; // tempoary variable used by various functions protected double vv[]; // is it a lower triangular matrix or an upper triangular matrix protected boolean lower; // storage for computed determinant protected Complex64F det = new Complex64F(); /** * Specifies if a lower or upper variant should be constructed. * * @param lower should a lower or upper triangular matrix be used. */ public CholeskyDecompositionCommon_D64(boolean lower) { this.lower = lower; } public void setExpectedMaxSize( int numRows , int numCols ) { if( numRows != numCols ) { throw new IllegalArgumentException("Can only decompose square matrices"); } this.maxWidth = numCols; this.vv = new double[maxWidth]; } /** * If true the decomposition was for a lower triangular matrix. * If false it was for an upper triangular matrix. * * @return True if lower, false if upper. */ @Override public boolean isLower() { return lower; } /** *

* Performs Choleksy decomposition on the provided matrix. *

* *

* If the matrix is not positive definite then this function will return * false since it can't complete its computations. Not all errors will be * found. This is an efficient way to check for positive definiteness. *

* @param mat A symmetric positive definite matrix with n <= widthMax. * @return True if it was able to finish the decomposition. */ @Override public boolean decompose( DenseMatrix64F mat ) { if( mat.numRows > maxWidth ) { setExpectedMaxSize(mat.numRows,mat.numCols); } else if( mat.numRows != mat.numCols ) { throw new IllegalArgumentException("Must be a square matrix."); } n = mat.numRows; T = mat; t = T.data; if(lower) { return decomposeLower(); } else { return decomposeUpper(); } } @Override public boolean inputModified() { return true; } /** * Performs an lower triangular decomposition. * * @return true if the matrix was decomposed. */ protected abstract boolean decomposeLower(); /** * Performs an upper triangular decomposition. * * @return true if the matrix was decomposed. */ protected abstract boolean decomposeUpper(); @Override public DenseMatrix64F getT( DenseMatrix64F T ) { // see if it needs to declare a new matrix or not if( T == null ) { T = new DenseMatrix64F(n,n); } else { if( T.numRows != n || T.numCols != n ) throw new IllegalArgumentException("Unexpected matrix dimension for T."); CommonOps.fill(T, 0); } // write the values to T if( lower ) { for( int i = 0; i < n; i++ ) { for( int j = 0; j <= i; j++ ) { T.unsafe_set(i,j,this.T.unsafe_get(i,j)); } } } else { for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { T.unsafe_set(i,j,this.T.unsafe_get(i,j)); } } } return T; } /** * Returns the triangular matrix from the decomposition. * * @return A lower or upper triangular matrix. */ public DenseMatrix64F getT() { return T; } public double[] _getVV() { return vv; } @Override public Complex64F computeDeterminant() { double prod = 1; int total = n*n; for( int i = 0; i < total; i += n + 1 ) { prod *= t[i]; } det.real = prod*prod; det.imaginary = 0; return det; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/chol/CholeskyDecompositionInner_D64.java000066400000000000000000000066741256171534400333540ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; /** *

* This implementation of a Cholesky decomposition using the inner-product form. * For large matrices a block implementation is better. On larger matrices the lower triangular * decomposition is significantly faster. This is faster on smaller matrices than {@link CholeskyDecompositionBlock_D64} * but much slower on larger matrices. *

* * @author Peter Abeles */ public class CholeskyDecompositionInner_D64 extends CholeskyDecompositionCommon_D64 { public CholeskyDecompositionInner_D64() { super(true); } public CholeskyDecompositionInner_D64(boolean lower) { super(lower); } @Override protected boolean decomposeLower() { double el_ii; double div_el_ii=0; for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { double sum = t[i*n+j]; int iEl = i*n; int jEl = j*n; int end = iEl+i; // k = 0:i-1 for( ; iEl * This variant on the Cholesky decomposition avoid the need to take the square root * by performing the following decomposition:
*
* L*D*LT=A
*
* where L is a lower triangular matrix with zeros on the diagonal. D is a diagonal matrix. * The diagonal elements of L are equal to one. *

*

* Unfortunately the speed advantage of not computing the square root is washed out by the * increased number of array accesses. There only appears to be a slight speed boost for * very small matrices. *

* * @author Peter Abeles */ public class CholeskyDecompositionLDL_D64 implements CholeskyLDLDecomposition { // it can decompose a matrix up to this width private int maxWidth; // width and height of the matrix private int n; // the decomposed matrix private DenseMatrix64F L; private double[] el; // the D vector private double[] d; // tempoary variable used by various functions double vv[]; public void setExpectedMaxSize( int numRows , int numCols ) { if( numRows != numCols ) { throw new IllegalArgumentException("Can only decompose square matrices"); } this.maxWidth = numRows; this.L = new DenseMatrix64F(maxWidth,maxWidth); this.el = L.data; this.vv = new double[maxWidth]; this.d = new double[maxWidth]; } /** *

* Performs Choleksy decomposition on the provided matrix. *

* *

* If the matrix is not positive definite then this function will return * false since it can't complete its computations. Not all errors will be * found. *

* @param mat A symetric n by n positive definite matrix. * @return True if it was able to finish the decomposition. */ public boolean decompose( DenseMatrix64F mat ) { if( mat.numRows > maxWidth ) { setExpectedMaxSize(mat.numRows,mat.numCols); } else if( mat.numRows != mat.numCols ) { throw new RuntimeException("Can only decompose square matrices"); } n = mat.numRows; L.set(mat); double d_inv=0; for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { double sum = el[i*n+j]; for( int k = 0; k < i; k++ ) { sum -= el[i*n+k]*el[j*n+k]*d[k]; } if( i == j ) { // is it positive-definate? if( sum <= 0.0 ) return false; d[i] = sum; d_inv = 1.0/sum; el[i*n+i] = 1; } else { el[j*n+i] = sum*d_inv; } } } // zero the top right corner. for( int i = 0; i < n; i++ ) { for( int j = i+1; j < n; j++ ) { el[i*n+j] = 0.0; } } return true; } @Override public boolean inputModified() { return false; } /** * Diagonal elements of the diagonal D matrix. * * @return diagonal elements of D */ @Override public double[] getDiagonal() { return d; } /** * Returns L matrix from the decomposition.
* L*D*LT=A * * @return A lower triangular matrix. */ public DenseMatrix64F getL() { return L; } public double[] _getVV() { return vv; } @Override public DenseMatrix64F getL(DenseMatrix64F L) { if( L == null ) { L = this.L.copy(); } else { L.set(this.L); } return L; } @Override public DenseMatrix64F getD(DenseMatrix64F D) { return CommonOps.diag(D,L.numCols,d); } }CholeskyDecomposition_B64_to_D64.java000066400000000000000000000041571256171534400334100ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.EjmlParameters; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.decomposition.chol.CholeskyOuterForm_B64; import org.ejml.alg.dense.decomposition.BaseDecomposition_B64_to_D64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; /** * Wrapper around {@link org.ejml.alg.block.decomposition.chol.CholeskyOuterForm_B64} that allows * it to process DenseMatrix64F. * * @author Peter Abeles */ public class CholeskyDecomposition_B64_to_D64 extends BaseDecomposition_B64_to_D64 implements CholeskyDecomposition { public CholeskyDecomposition_B64_to_D64(boolean lower) { super(new CholeskyOuterForm_B64(lower), EjmlParameters.BLOCK_WIDTH); } @Override public boolean isLower() { return ((CholeskyOuterForm_B64)alg).isLower(); } @Override public DenseMatrix64F getT(DenseMatrix64F T) { BlockMatrix64F T_block = ((CholeskyOuterForm_B64)alg).getT(null); if( T == null ) { T = new DenseMatrix64F(T_block.numRows,T_block.numCols); } BlockMatrixOps.convert(T_block,T); // todo set zeros return T; } @Override public Complex64F computeDeterminant() { return ((CholeskyOuterForm_B64)alg).computeDeterminant(); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/000077500000000000000000000000001256171534400243645ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/EigenPowerMethod.java000066400000000000000000000147261256171534400304460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.NormOps; import org.ejml.ops.SpecializedOps; /** *

* The power method is an iterative method that can be used to find dominant eigen vector in * a matrix. Computing Anq for larger and larger values of n, where q is a vector. Eventually the * dominant (if there is any) eigen vector will "win". *

* *

* Shift implementations find the eigen value of the matrix B=A-pI instead. This matrix has the * same eigen vectors, but can converge much faster if p is chosen wisely. *

* *

* See section 5.3 in "Fundamentals of Matrix Computations" Second Edition, David S. Watkins. *

* *

* WARNING: These functions have well known conditions where they will not converge or converge * very slowly and are only used in special situations in practice. I have also seen it converge * to none dominant eigen vectors. *

* * * @author Peter Abeles */ public class EigenPowerMethod { // used to determine convergence private double tol = 1e-10; private DenseMatrix64F q0,q1,q2; private int maxIterations = 20; private DenseMatrix64F B; private DenseMatrix64F seed; /** * * @param size The size of the matrix which can be processed. */ public EigenPowerMethod( int size ) { q0 = new DenseMatrix64F(size,1); q1 = new DenseMatrix64F(size,1); q2 = new DenseMatrix64F(size,1); B = new DenseMatrix64F(size,size); } /** * Sets the value of the vector to use in the start of the iterations. * * @param seed The initial seed vector in the iteration. */ public void setSeed(DenseMatrix64F seed) { this.seed = seed; } /** * * @param maxIterations * @param tolerance */ public void setOptions(int maxIterations, double tolerance) { this.maxIterations = maxIterations; this.tol = tolerance; } /** * This method computes the eigen vector with the largest eigen value by using the * direct power method. This technique is the easiest to implement, but the slowest to converge. * Works only if all the eigenvalues are real. * * @param A The matrix. Not modified. * @return If it converged or not. */ public boolean computeDirect( DenseMatrix64F A ) { initPower(A); boolean converged = false; for( int i = 0; i < maxIterations && !converged; i++ ) { // q0.print(); CommonOps.mult(A,q0,q1); double s = NormOps.normPInf(q1); CommonOps.divide(q1,s,q2); converged = checkConverged(A); } return converged; } private void initPower(DenseMatrix64F A ) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("A must be a square matrix."); if( seed != null ) { q0.set(seed); } else { for( int i = 0; i < A.numRows; i++ ) { q0.data[i] = 1; } } } /** * Test for convergence by seeing if the element with the largest change * is smaller than the tolerance. In some test cases it alternated between * the + and - values of the eigen vector. When this happens it seems to have "converged" * to a non-dominant eigen vector. At least in the case I looked at. I haven't devoted * a lot of time into this issue... */ private boolean checkConverged(DenseMatrix64F A) { double worst = 0; double worst2 = 0; for( int j = 0; j < A.numRows; j++ ) { double val = Math.abs(q2.data[j] - q0.data[j]); if( val > worst ) worst = val; val = Math.abs(q2.data[j] + q0.data[j]); if( val > worst2 ) worst2 = val; } // swap vectors DenseMatrix64F temp = q0; q0 = q2; q2 = temp; if( worst < tol ) return true; else if( worst2 < tol ) return true; else return false; } /** * Computes the most dominant eigen vector of A using a shifted matrix. * The shifted matrix is defined as B = A - αI and can converge faster * if α is chosen wisely. In general it is easier to choose a value for α * that will converge faster with the shift-invert strategy than this one. * * @param A The matrix. * @param alpha Shifting factor. * @return If it converged or not. */ public boolean computeShiftDirect( DenseMatrix64F A ,double alpha) { SpecializedOps.addIdentity(A,B,-alpha); return computeDirect(B); } /** * Computes the most dominant eigen vector of A using an inverted shifted matrix. * The inverted shifted matrix is defined as B = (A - αI)-1 and * can converge faster if α is chosen wisely. * * @param A An invertible square matrix matrix. * @param alpha Shifting factor. * @return If it converged or not. */ public boolean computeShiftInvert( DenseMatrix64F A , double alpha ) { initPower(A); LinearSolver solver = LinearSolverFactory.linear(A.numCols); SpecializedOps.addIdentity(A,B,-alpha); solver.setA(B); boolean converged = false; for( int i = 0; i < maxIterations && !converged; i++ ) { solver.solve(q0,q1); double s = NormOps.normPInf(q1); CommonOps.divide(q1,s,q2); converged = checkConverged(A); } return converged; } public DenseMatrix64F getEigenVector() { return q0; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/EigenvalueExtractor.java000066400000000000000000000017721256171534400312160ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; /** * @author Peter Abeles */ public interface EigenvalueExtractor { public boolean process( DenseMatrix64F A ); public int getNumberOfEigenvalues(); public Complex64F[] getEigenvalues(); } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/EigenvalueSmall.java000066400000000000000000000100161256171534400303020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.data.Complex64F; /** * @author Peter Abeles */ public class EigenvalueSmall { public Complex64F value0 = new Complex64F(); public Complex64F value1 = new Complex64F(); // if |a11-a22| >> |a12+a21| there might be a better way. see pg371 public void value2x2( double a11 , double a12, double a21 , double a22 ) { // apply a rotators such that th a11 and a22 elements are the same double c,s; if( a12 + a21 == 0 ) { // is this pointless since c = s = 1.0/Math.sqrt(2); } else { double aa = (a11-a22); double bb = (a12+a21); double t_hat = aa/bb; double t = t_hat/(1.0+Math.sqrt(1.0+t_hat*t_hat)); c = 1.0/Math.sqrt(1.0+t*t); s = c*t; } double c2 = c*c; double s2 = s*s; double cs = c*s; double b11 = c2*a11 + s2*a22 - cs*(a12+a21); double b12 = c2*a12 - s2*a21 + cs*(a11-a22); double b21 = c2*a21 - s2*a12 + cs*(a11-a22); // double b22 = c2*a22 + s2*a11 + cs*(a12+a21); // apply second rotator to make A upper triangular if real eigenvalues if( b21*b12 >= 0 ) { if( b12 == 0 ) { c = 0; s = 1; } else { s = Math.sqrt(b21/(b12+b21)); c = Math.sqrt(b12/(b12+b21)); } // c2 = b12;//c*c; // s2 = b21;//s*s; cs = c*s; a11 = b11 - cs*(b12 + b21); // a12 = c2*b12 - s2*b21; // a21 = c2*b21 - s2*b12; a22 = b11 + cs*(b12 + b21); value0.real = a11; value1.real = a22; value0.imaginary = value1.imaginary = 0; } else { value0.real = value1.real = b11; value0.imaginary = Math.sqrt(-b21*b12); value1.imaginary = -value0.imaginary; } } /** * Computes the eigenvalues of a 2 by 2 matrix using a faster but more prone to errors method. This * is the typical method. */ public void value2x2_fast( double a11 , double a12, double a21 , double a22 ) { double left = (a11+a22)/2.0; double inside = 4.0*a12*a21 + (a11-a22)*(a11-a22); if( inside < 0 ) { value0.real = value1.real = left; value0.imaginary = Math.sqrt(-inside)/2.0; value1.imaginary = -value0.imaginary; } else { double right = Math.sqrt(inside)/2.0; value0.real = (left+right); value1.real = (left-right); value0.imaginary = value1.imaginary = 0.0; } } /** * Compute the symmetric eigenvalue using a slightly safer technique */ // See page 385 of Fundamentals of Matrix Computations 2nd public void symm2x2_fast( double a11 , double a12, double a22 ) { // double p = (a11 - a22)*0.5; // double r = Math.sqrt(p*p + a12*a12); // // value0.real = a22 + a12*a12/(r-p); // value1.real = a22 - a12*a12/(r+p); // } // // public void symm2x2_std( double a11 , double a12, double a22 ) // { double left = (a11+a22)*0.5; double b = (a11-a22)*0.5; double right = Math.sqrt(b*b+a12*a12); value0.real = left + right; value1.real = left - right; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/SwitchingEigenDecomposition.java000066400000000000000000000064201256171534400326750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.ops.MatrixFeatures; /** * Checks to see what type of matrix is being decomposed and calls different eigenvalue decomposition * algorithms depending on the results. This primarily checks to see if the matrix is symmetric or not. * * * @author Peter Abeles */ public class SwitchingEigenDecomposition implements EigenDecomposition { // tolerance used in deciding if a matrix is symmetric or not private double tol; EigenDecomposition symmetricAlg; EigenDecomposition generalAlg; boolean symmetric; // should it compute eigenvectors or just eigenvalues? boolean computeVectors; DenseMatrix64F A = new DenseMatrix64F(1,1); /** * * @param computeVectors * @param tol Tolerance for a matrix being symmetric */ public SwitchingEigenDecomposition( int matrixSize , boolean computeVectors , double tol ) { symmetricAlg = DecompositionFactory.eig(matrixSize,computeVectors,true); generalAlg = DecompositionFactory.eig(matrixSize,computeVectors,false); this.computeVectors = computeVectors; this.tol = tol; } public SwitchingEigenDecomposition( int matrixSize ) { this(matrixSize,true,1e-8); } @Override public int getNumberOfEigenvalues() { return symmetric ? symmetricAlg.getNumberOfEigenvalues() : generalAlg.getNumberOfEigenvalues(); } @Override public Complex64F getEigenvalue(int index) { return symmetric ? symmetricAlg.getEigenvalue(index) : generalAlg.getEigenvalue(index); } @Override public DenseMatrix64F getEigenVector(int index) { if( !computeVectors ) throw new IllegalArgumentException("Configured to not compute eignevectors"); return symmetric ? symmetricAlg.getEigenVector(index) : generalAlg.getEigenVector(index); } @Override public boolean decompose(DenseMatrix64F orig) { A.set(orig); symmetric = MatrixFeatures.isSymmetric(A,tol); return symmetric ? symmetricAlg.decompose(A) : generalAlg.decompose(A); } @Override public boolean inputModified() { // since it doesn't know which algorithm will be used until a matrix is provided make a copy // of all inputs return false; } } SymmetricQRAlgorithmDecomposition_D64.java000066400000000000000000000174601256171534400344200ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.alg.dense.decomposition.eig.symm.SymmetricQREigenHelper; import org.ejml.alg.dense.decomposition.eig.symm.SymmetricQrAlgorithm; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.CommonOps; /** *

* Computes the eigenvalues and eigenvectors of a real symmetric matrix using the symmetric implicit QR algorithm. * Inside each iteration a QR decomposition of Ai-piI is implicitly computed. *

*

* This implementation is based on the algorithm is sketched out in:
* David S. Watkins, "Fundamentals of Matrix Computations," Second Edition. page 377-385 *

* * @see org.ejml.alg.dense.decomposition.eig.symm.SymmetricQrAlgorithm * @see org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecompositionHouseholder_D64 * * @author Peter Abeles */ public class SymmetricQRAlgorithmDecomposition_D64 implements EigenDecomposition { // computes a tridiagonal matrix whose eigenvalues are the same as the original // matrix and can be easily computed. private TridiagonalSimilarDecomposition decomp; // helper class for eigenvalue and eigenvector algorithms private SymmetricQREigenHelper helper; // computes the eigenvectors private SymmetricQrAlgorithm vector; // should it compute eigenvectors at the same time as the eigenvalues? private boolean computeVectorsWithValues = false; // where the found eigenvalues are stored private double values[]; // where the tridiagonal matrix is stored private double diag[]; private double off[]; private double diagSaved[]; private double offSaved[]; // temporary variable used to store/compute eigenvectors private DenseMatrix64F V; // the extracted eigenvectors private DenseMatrix64F eigenvectors[]; // should it compute eigenvectors or just eigenvalues boolean computeVectors; public SymmetricQRAlgorithmDecomposition_D64(TridiagonalSimilarDecomposition decomp, boolean computeVectors) { this.decomp = decomp; this.computeVectors = computeVectors; helper = new SymmetricQREigenHelper(); vector = new SymmetricQrAlgorithm(helper); } public SymmetricQRAlgorithmDecomposition_D64(boolean computeVectors) { this(DecompositionFactory.tridiagonal(0),computeVectors); } public void setComputeVectorsWithValues(boolean computeVectorsWithValues) { if( !computeVectors ) throw new IllegalArgumentException("Compute eigenvalues has been set to false"); this.computeVectorsWithValues = computeVectorsWithValues; } /** * Used to limit the number of internal QR iterations that the QR algorithm performs. 20 * should be enough for most applications. * * @param max The maximum number of QR iterations it will perform. */ public void setMaxIterations( int max ) { vector.setMaxIterations(max); } @Override public int getNumberOfEigenvalues() { return helper.getMatrixSize(); } @Override public Complex64F getEigenvalue(int index) { return new Complex64F(values[index],0); } @Override public DenseMatrix64F getEigenVector(int index) { return eigenvectors[index]; } /** * Decomposes the matrix using the QR algorithm. Care was taken to minimize unnecessary memory copying * and cache skipping. * * @param orig The matrix which is being decomposed. Not modified. * @return true if it decomposed the matrix or false if an error was detected. This will not catch all errors. */ @Override public boolean decompose(DenseMatrix64F orig) { if( orig.numCols != orig.numRows ) throw new IllegalArgumentException("Matrix must be square."); if( orig.numCols <= 0 ) return false; int N = orig.numRows; // compute a similar tridiagonal matrix if( !decomp.decompose(orig) ) return false; if( diag == null || diag.length < N) { diag = new double[N]; off = new double[N-1]; } decomp.getDiagonal(diag,off); // Tell the helper to work with this matrix helper.init(diag,off,N); if( computeVectors ) { if( computeVectorsWithValues ) { return extractTogether(); } else { return extractSeparate(N); } } else { return computeEigenValues(); } } @Override public boolean inputModified() { return decomp.inputModified(); } private boolean extractTogether() { // extract the orthogonal from the similar transform V = decomp.getQ(V,true); // tell eigenvector algorithm to update this matrix as it computes the rotators helper.setQ(V); vector.setFastEigenvalues(false); // extract the eigenvalues if( !vector.process(-1,null,null) ) return false; // the V matrix contains the eigenvectors. Convert those into column vectors eigenvectors = CommonOps.rowsToVector(V,eigenvectors); // save a copy of them since this data structure will be recycled next values = helper.copyEigenvalues(values); return true; } private boolean extractSeparate(int numCols) { if (!computeEigenValues()) return false; // ---- set up the helper to decompose the same tridiagonal matrix // swap arrays instead of copying them to make it slightly faster helper.reset(numCols); diagSaved = helper.swapDiag(diagSaved); offSaved = helper.swapOff(offSaved); // extract the orthogonal from the similar transform V = decomp.getQ(V,true); // tell eigenvector algorithm to update this matrix as it computes the rotators vector.setQ(V); // extract eigenvectors if( !vector.process(-1,null,null, values) ) return false; // the ordering of the eigenvalues might have changed values = helper.copyEigenvalues(values); // the V matrix contains the eigenvectors. Convert those into column vectors eigenvectors = CommonOps.rowsToVector(V,eigenvectors); return true; } /** * Computes eigenvalues only * * @return */ private boolean computeEigenValues() { // make a copy of the internal tridiagonal matrix data for later use diagSaved = helper.copyDiag(diagSaved); offSaved = helper.copyOff(offSaved); vector.setQ(null); vector.setFastEigenvalues(true); // extract the eigenvalues if( !vector.process(-1,null,null) ) return false; // save a copy of them since this data structure will be recycled next values = helper.copyEigenvalues(values); return true; } } WatchedDoubleStepQRDecomposition_D64.java000066400000000000000000000066301256171534400341400ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.alg.dense.decomposition.eig.watched.WatchedDoubleStepQREigenvalue; import org.ejml.alg.dense.decomposition.eig.watched.WatchedDoubleStepQREigenvector; import org.ejml.alg.dense.decomposition.hessenberg.HessenbergSimilarDecomposition_D64; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.EigenDecomposition; /** *

* Finds the eigenvalue decomposition of an arbitrary square matrix using the implicit double-step QR algorithm. * Watched is included in its name because it is designed to print out internal debugging information. This * class is still underdevelopment and has yet to be optimized. *

* *

* Based off the description found in:
* David S. Watkins, "Fundamentals of Matrix Computations." Second Edition. *

* * @author Peter Abeles */ //TODO looks like there might be some pointless copying of arrays going on public class WatchedDoubleStepQRDecomposition_D64 implements EigenDecomposition { HessenbergSimilarDecomposition_D64 hessenberg; WatchedDoubleStepQREigenvalue algValue; WatchedDoubleStepQREigenvector algVector; DenseMatrix64F H; // should it compute eigenvectors or just eigenvalues boolean computeVectors; public WatchedDoubleStepQRDecomposition_D64(boolean computeVectors) { hessenberg = new HessenbergSimilarDecomposition_D64(10); algValue = new WatchedDoubleStepQREigenvalue(); algVector = new WatchedDoubleStepQREigenvector(); this.computeVectors = computeVectors; } @Override public boolean decompose(DenseMatrix64F A) { if( !hessenberg.decompose(A) ) return false; H = hessenberg.getH(null); algValue.getImplicitQR().createR = false; // algValue.getImplicitQR().setChecks(true,true,true); if( !algValue.process(H) ) return false; // for( int i = 0; i < A.numRows; i++ ) { // System.out.println(algValue.getEigenvalues()[i]); // } algValue.getImplicitQR().createR = true; if( computeVectors ) return algVector.process(algValue.getImplicitQR(), H, hessenberg.getQ(null)); else return true; } @Override public boolean inputModified() { return hessenberg.inputModified(); } @Override public int getNumberOfEigenvalues() { return algValue.getEigenvalues().length; } @Override public Complex64F getEigenvalue(int index) { return algValue.getEigenvalues()[index]; } @Override public DenseMatrix64F getEigenVector(int index) { return algVector.getEigenvectors()[index]; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/symm/000077500000000000000000000000001256171534400253515ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/symm/SymmetricQREigenHelper.java000066400000000000000000000313251256171534400325470ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.symm; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.eig.EigenvalueSmall; import org.ejml.data.DenseMatrix64F; import java.util.Random; /** * A helper class for the symmetric matrix implicit QR algorithm for eigenvalue decomposition. * Performs most of the basic operations needed to extract eigenvalues and eigenvectors. * * @author Peter Abeles */ public class SymmetricQREigenHelper { // used in exceptional shifts protected Random rand = new Random(0x34671e); // how many steps has it taken protected int steps; // how many exception shifts has it performed protected int numExceptional; // the step number of the last exception shift protected int lastExceptional; // used to compute eigenvalues directly protected EigenvalueSmall eigenSmall = new EigenvalueSmall(); // orthogonal matrix used in similar transform. optional protected DenseMatrix64F Q; // size of the matrix being processed protected int N; // diagonal elements in the matrix protected double diag[]; // the off diagonal elements protected double off[]; // which submatrix is being processed protected int x1; protected int x2; // where splits are performed protected int splits[]; protected int numSplits; // current value of the bulge private double bulge; // local helper functions private double c,s,c2,s2,cs; public SymmetricQREigenHelper() { splits = new int[1]; } public void printMatrix() { System.out.print("Off Diag[ "); for( int j = 0; j < N-1; j++ ) { System.out.printf("%5.2f ",off[j]); } System.out.println(); System.out.print(" Diag[ "); for( int j = 0; j < N; j++ ) { System.out.printf("%5.2f ",diag[j]); } System.out.println(); } public void setQ(DenseMatrix64F q) { Q = q; } public void incrementSteps() { steps++; } /** * Sets up and declares internal data structures. * * @param diag Diagonal elements from tridiagonal matrix. Modified. * @param off Off diagonal elements from tridiagonal matrix. Modified. * @param numCols number of columns (and rows) in the matrix. */ public void init( double diag[] , double off[], int numCols ) { reset(numCols); this.diag = diag; this.off = off; } /** * Exchanges the internal array of the diagonal elements for the provided one. */ public double[] swapDiag( double diag[] ) { double[] ret = this.diag; this.diag = diag; return ret; } /** * Exchanges the internal array of the off diagonal elements for the provided one. */ public double[] swapOff( double off[] ) { double[] ret = this.off; this.off = off; return ret; } /** * Sets the size of the matrix being decomposed, declares new memory if needed, * and sets all helper functions to their initial value. */ public void reset( int N ) { this.N = N; this.diag = null; this.off = null; if( splits.length < N ) { splits = new int[N]; } numSplits = 0; x1 = 0; x2 = N-1; steps = numExceptional = lastExceptional = 0; this.Q = null; } public double[] copyDiag( double []ret ) { if( ret == null || ret.length < N ) { ret = new double[N]; } System.arraycopy(diag,0,ret,0,N); return ret; } public double[] copyOff( double []ret ) { if( ret == null || ret.length < N-1 ) { ret = new double[N-1]; } System.arraycopy(off,0,ret,0,N-1); return ret; } public double[] copyEigenvalues( double []ret ) { if( ret == null || ret.length < N ) { ret = new double[N]; } System.arraycopy(diag,0,ret,0,N); return ret; } /** * Sets which submatrix is being processed. * @param x1 Lower bound, inclusive. * @param x2 Upper bound, inclusive. */ public void setSubmatrix( int x1 , int x2 ) { this.x1 = x1; this.x2 = x2; } /** * Checks to see if the specified off diagonal element is zero using a relative metric. */ protected boolean isZero( int index ) { double bottom = Math.abs(diag[index])+Math.abs(diag[index+1]); return( Math.abs(off[index]) <= bottom*UtilEjml.EPS); } protected void performImplicitSingleStep( double lambda , boolean byAngle ) { if( x2-x1 == 1 ) { createBulge2by2(x1,lambda,byAngle); } else { createBulge(x1,lambda,byAngle); for( int i = x1; i < x2-2 && bulge != 0.0; i++ ) { removeBulge(i); } if( bulge != 0.0 ) removeBulgeEnd(x2-2); } } protected void updateQ( int m , int n , double c , double s ) { int rowA = m*N; int rowB = n*N; // for( int i = 0; i < N; i++ ) { // double a = Q.data[rowA+i]; // double b = Q.data[rowB+i]; // Q.data[rowA+i] = c*a + s*b; // Q.data[rowB+i] = -s*a + c*b; // } int endA = rowA + N; while( rowA < endA ) { double a = Q.data[rowA]; double b = Q.data[rowB]; Q.data[rowA++] = c*a + s*b; Q.data[rowB++] = -s*a + c*b; } } /** * Performs a similar transform on A-pI */ protected void createBulge( int x1 , double p , boolean byAngle ) { double a11 = diag[x1]; double a22 = diag[x1+1]; double a12 = off[x1]; double a23 = off[x1+1]; if( byAngle ) { c = Math.cos(p); s = Math.sin(p); c2 = c*c; s2 = s*s; cs = c*s; } else { computeRotation(a11-p, a12); } // multiply the rotator on the top left. diag[x1] = c2*a11 + 2.0*cs*a12 + s2*a22; diag[x1+1] = c2*a22 - 2.0*cs*a12 + s2*a11; off[x1] = a12*(c2-s2) + cs*(a22 - a11); off[x1+1] = c*a23; bulge = s*a23; if( Q != null ) updateQ(x1,x1+1,c,s); } protected void createBulge2by2( int x1 , double p , boolean byAngle ) { double a11 = diag[x1]; double a22 = diag[x1+1]; double a12 = off[x1]; if( byAngle ) { c = Math.cos(p); s = Math.sin(p); c2 = c*c; s2 = s*s; cs = c*s; } else { computeRotation(a11-p, a12); } // multiply the rotator on the top left. diag[x1] = c2*a11 + 2.0*cs*a12 + s2*a22; diag[x1+1] = c2*a22 - 2.0*cs*a12 + s2*a11; off[x1] = a12*(c2-s2) + cs*(a22 - a11); if( Q != null ) updateQ(x1,x1+1,c,s); } /** * Computes the rotation and stores it in (c,s) */ private void computeRotation(double run, double rise) { // double alpha = Math.sqrt(run*run + rise*rise); // c = run/alpha; // s = rise/alpha; if( Math.abs(rise) > Math.abs(run)) { double k = run/rise; double bottom = 1.0 + k*k; double bottom_sq = Math.sqrt(bottom); s2 = 1.0/bottom; c2 = k*k/bottom; cs = k/bottom; s = 1.0/bottom_sq; c = k/bottom_sq; } else { double t = rise/run; double bottom = 1.0 + t*t; double bottom_sq = Math.sqrt(bottom); c2 = 1.0/bottom; s2 = t*t/bottom; cs = t/bottom; c = 1.0/bottom_sq; s = t/bottom_sq; } } protected void removeBulge( int x1 ) { double a22 = diag[x1+1]; double a33 = diag[x1+2]; double a12 = off[x1]; double a23 = off[x1+1]; double a34 = off[x1+2]; computeRotation(a12, bulge); // multiply the rotator on the top left. diag[x1+1] = c2*a22 + 2.0*cs*a23 + s2*a33; diag[x1+2] = c2*a33 - 2.0*cs*a23 + s2*a22; off[x1] = c*a12 + s*bulge; off[x1+1] = a23*(c2-s2) + cs*(a33 - a22); off[x1+2] = c*a34; bulge = s*a34; if( Q != null ) updateQ(x1+1,x1+2,c,s); } /** * Rotator to remove the bulge */ protected void removeBulgeEnd( int x1 ) { double a22 = diag[x1+1]; double a12 = off[x1]; double a23 = off[x1+1]; double a33 = diag[x1+2]; computeRotation(a12, bulge); // multiply the rotator on the top left. diag[x1+1] = c2*a22 + 2.0*cs*a23 + s2*a33; diag[x1+2] = c2*a33 - 2.0*cs*a23 + s2*a22; off[x1] = c*a12 + s*bulge; off[x1+1] = a23*(c2-s2) + cs*(a33 - a22); if( Q != null ) updateQ(x1+1,x1+2,c,s); } /** * Computes the eigenvalue of the 2 by 2 matrix. */ protected void eigenvalue2by2( int x1 ) { double a = diag[x1]; double b = off[x1]; double c = diag[x1+1]; // normalize to reduce overflow double absA = Math.abs(a); double absB = Math.abs(b); double absC = Math.abs(c); double scale = absA > absB ? absA : absB; if( absC > scale ) scale = absC; // see if it is a pathological case. the diagonal must already be zero // and the eigenvalues are all zero. so just return if( scale == 0 ) { off[x1] = 0; diag[x1] = 0; diag[x1+1] = 0; return; } a /= scale; b /= scale; c /= scale; eigenSmall.symm2x2_fast(a,b,c); off[x1] = 0; diag[x1] = scale*eigenSmall.value0.real; diag[x1+1] = scale*eigenSmall.value1.real; } /** * Perform a shift in a random direction that is of the same magnitude as the elements in the matrix. */ public void exceptionalShift() { // rotating by a random angle handles at least one case using a random lambda // does not handle well: // - two identical eigenvalues are next to each other and a very small diagonal element numExceptional++; double mag = 0.05*numExceptional; if( mag > 1.0 ) mag = 1.0; double theta = 2.0*(rand.nextDouble()-0.5)*mag; performImplicitSingleStep(theta,true); lastExceptional = steps; } /** * Tells it to process the submatrix at the next split. Should be called after the * current submatrix has been processed. */ public boolean nextSplit() { if( numSplits == 0 ) return false; x2 = splits[--numSplits]; if( numSplits > 0 ) x1 = splits[numSplits-1]+1; else x1 = 0; return true; } public double computeShift() { if( x2-x1 >= 1 ) return computeWilkinsonShift(); else return diag[x2]; } public double computeWilkinsonShift() { double a = diag[x2-1]; double b = off[x2-1]; double c = diag[x2]; // normalize to reduce overflow double absA = Math.abs(a); double absB = Math.abs(b); double absC = Math.abs(c); double scale = absA > absB ? absA : absB; if( absC > scale ) scale = absC; if( scale == 0 ) { throw new RuntimeException("this should never happen"); } a /= scale; b /= scale; c /= scale; // TODO see 385 eigenSmall.symm2x2_fast(a,b,c); // return the eigenvalue closest to c double diff0 = Math.abs(eigenSmall.value0.real-c); double diff1 = Math.abs(eigenSmall.value1.real-c); if( diff0 < diff1 ) return scale*eigenSmall.value0.real; else return scale*eigenSmall.value1.real; } public int getMatrixSize() { return N; } public void resetSteps() { steps = 0; lastExceptional = 0; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/symm/SymmetricQrAlgorithm.java000066400000000000000000000145331256171534400323500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.symm; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; /** *

* Computes the eigenvalues and eigenvectors of a symmetric tridiagonal matrix using the symmetric QR algorithm. *

*

* This implementation is based on the algorithm is sketched out in:
* David S. Watkins, "Fundamentals of Matrix Computations," Second Edition. page 377-385 *

* @author Peter Abeles */ public class SymmetricQrAlgorithm { // performs many of the low level calculations private SymmetricQREigenHelper helper; // transpose of the orthogonal matrix private DenseMatrix64F Q; // the eigenvalues previously computed private double eigenvalues[]; private int exceptionalThresh = 15; private int maxIterations = exceptionalThresh*15; // should it ever analytically compute eigenvalues // if this is true then it can't compute eigenvalues at the same time private boolean fastEigenvalues; // is it following a script or not private boolean followingScript; public SymmetricQrAlgorithm(SymmetricQREigenHelper helper ) { this.helper = helper; } /** * Creates a new SymmetricQREigenvalue class that declares its own SymmetricQREigenHelper. */ public SymmetricQrAlgorithm() { this.helper = new SymmetricQREigenHelper(); } public void setMaxIterations(int maxIterations) { this.maxIterations = maxIterations; } public DenseMatrix64F getQ() { return Q; } public void setQ(DenseMatrix64F q) { Q = q; } public void setFastEigenvalues(boolean fastEigenvalues) { this.fastEigenvalues = fastEigenvalues; } /** * Returns the eigenvalue at the specified index. * * @param index Which eigenvalue. * @return The eigenvalue. */ public double getEigenvalue( int index ) { return helper.diag[index]; } /** * Returns the number of eigenvalues available. * * @return How many eigenvalues there are. */ public int getNumberOfEigenvalues() { return helper.N; } /** * Computes the eigenvalue of the provided tridiagonal matrix. Note that only the upper portion * needs to be tridiagonal. The bottom diagonal is assumed to be the same as the top. * * @param sideLength Number of rows and columns in the input matrix. * @param diag Diagonal elements from tridiagonal matrix. Modified. * @param off Off diagonal elements from tridiagonal matrix. Modified. * @return true if it succeeds and false if it fails. */ public boolean process( int sideLength, double diag[] , double off[] , double eigenvalues[] ) { if( diag != null ) helper.init(diag,off,sideLength); if( Q == null ) Q = CommonOps.identity(helper.N); helper.setQ(Q); this.followingScript = true; this.eigenvalues = eigenvalues; this.fastEigenvalues = false; return _process(); } public boolean process( int sideLength, double diag[] , double off[] ) { if( diag != null ) helper.init(diag,off,sideLength); this.followingScript = false; this.eigenvalues = null; return _process(); } private boolean _process() { while( helper.x2 >= 0 ) { // if it has cycled too many times give up if( helper.steps > maxIterations ) { return false; } if( helper.x1 == helper.x2 ) { // System.out.println("Steps = "+helper.steps); // see if it is done processing this submatrix helper.resetSteps(); if( !helper.nextSplit() ) break; } else if( fastEigenvalues && helper.x2-helper.x1 == 1 ) { // There are analytical solutions to this case. Just compute them directly. // TODO might be able to speed this up by doing the 3 by 3 case also helper.resetSteps(); helper.eigenvalue2by2(helper.x1); helper.setSubmatrix(helper.x2,helper.x2); } else if( helper.steps-helper.lastExceptional > exceptionalThresh ){ // it isn't a good sign if exceptional shifts are being done here helper.exceptionalShift(); } else { performStep(); } helper.incrementSteps(); // helper.printMatrix(); } // helper.printMatrix(); return true; } /** * First looks for zeros and then performs the implicit single step in the QR Algorithm. */ public void performStep() { // check for zeros for( int i = helper.x2-1; i >= helper.x1; i-- ) { if( helper.isZero(i) ) { helper.splits[helper.numSplits++] = i; helper.x1 = i+1; return; } } double lambda; if( followingScript ) { if( helper.steps > 10 ) { followingScript = false; return; } else { // Using the true eigenvalues will in general lead to the fastest convergence // typically takes 1 or 2 steps lambda = eigenvalues[helper.x2]; } } else { // the current eigenvalue isn't working so try something else lambda = helper.computeShift(); } // similar transforms helper.performImplicitSingleStep(lambda,false); } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/watched/000077500000000000000000000000001256171534400260035ustar00rootroot00000000000000WatchedDoubleStepQREigen.java000066400000000000000000000452571256171534400333650ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/watched/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.watched; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.eig.EigenvalueSmall; import org.ejml.alg.dense.decomposition.qr.QrHelperFunctions_D64; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.MatrixFeatures; import java.util.Random; /** *

* The double step implicit Eigenvalue decomposition algorithm is fairly complicated and needs to be designed so that * it can handle several special cases. To aid in development and debugging this class was created. It allows * individual components to be tested and to print out their results. This shows how each step is performed. *

* *

* Do not use this class to compute the eigenvalues since it is much slower than a non-debug implementation. *

* */ // TODO make rank1UpdateMultR efficient once again by setting 0 to x1 and creating a new one that updates all the rows // TODO option of modifying original matrix public class WatchedDoubleStepQREigen { private Random rand = new Random(0x2342); private int N; DenseMatrix64F A; private DenseMatrix64F u; private double gamma; private DenseMatrix64F _temp; // how many steps did it take to find the eigenvalue int numStepsFind[]; int steps; Complex64F eigenvalues[]; int numEigen; // computes eigenvalues for 2 by 2 submatrices private EigenvalueSmall valueSmall = new EigenvalueSmall(); private double temp[] = new double[9]; private boolean printHumps = false; boolean checkHessenberg = false; private boolean checkOrthogonal = false; private boolean checkUncountable = false; private boolean useStandardEq = false; private boolean useCareful2x2 = true; private boolean normalize = true; int lastExceptional; int numExceptional; int exceptionalThreshold = 20; int maxIterations = exceptionalThreshold*20; public boolean createR = true; public DenseMatrix64F Q; public void incrementSteps() { steps++; } public void setQ( DenseMatrix64F Q ) { this.Q = Q; } private void addEigenvalue( double v ) { numStepsFind[numEigen] = steps; eigenvalues[numEigen].set(v,0); numEigen++; steps = 0; lastExceptional = 0; } private void addEigenvalue( double v , double i ) { numStepsFind[numEigen] = steps; eigenvalues[numEigen].set(v,i); numEigen++; steps = 0; lastExceptional = 0; } public void setChecks( boolean hessenberg , boolean orthogonal , boolean uncountable ) { this.checkHessenberg = hessenberg; this.checkOrthogonal = orthogonal; this.checkUncountable = uncountable; } public boolean isZero( int x1 , int x2 ) { // this provides a relative threshold for when dealing with very large/small numbers double target = Math.abs(A.get(x1,x2)); double above = Math.abs(A.get(x1-1,x2)); // according to Matrix Computations page 352 this is what is done in Eispack double right = Math.abs(A.get(x1,x2+1)); return target <= 0.5*UtilEjml.EPS*(above+right); } public void setup( DenseMatrix64F A ) { if( A.numRows != A.numCols ) throw new RuntimeException("Must be square") ; if( N != A.numRows ) { N = A.numRows; this.A = A.copy(); u = new DenseMatrix64F(A.numRows,1); _temp = new DenseMatrix64F(A.numRows,1); numStepsFind = new int[ A.numRows ]; } else { this.A.set(A); UtilEjml.memset(numStepsFind,0,numStepsFind.length); } // zero all the off numbers that should be zero for a hessenberg matrix for( int i = 2; i < N; i++ ) { for( int j = 0; j < i-1; j++ ) { this.A.set(i,j,0); } } eigenvalues = new Complex64F[ A.numRows ]; for( int i = 0; i < eigenvalues.length; i++ ) { eigenvalues[i] = new Complex64F(); } numEigen = 0; lastExceptional = 0; numExceptional = 0; steps = 0; } /** * Perform a shift in a random direction that is of the same magnitude as the elements in the matrix. */ public void exceptionalShift( int x1 , int x2) { if( printHumps ) System.out.println("Performing exceptional implicit double step"); // perform a random shift that is of the same magnitude as the matrix double val = Math.abs(A.get(x2,x2)); if( val == 0 ) val = 1; numExceptional++; // the closer the value is the better it handles identical eigenvalues cases double p = 1-Math.pow(0.1,numExceptional); val *= p+2.0*(1.0-p)*(rand.nextDouble()-0.5); if( rand.nextBoolean() ) val = -val; performImplicitSingleStep(x1,x2,val); lastExceptional = steps; } /** * Performs an implicit double step using the values contained in the lower right hand side * of the submatrix for the estimated eigenvector values. * @param x1 * @param x2 */ public void implicitDoubleStep( int x1 , int x2 ) { if( printHumps ) System.out.println("Performing implicit double step"); // compute the wilkinson shift double z11 = A.get(x2 - 1, x2 - 1); double z12 = A.get(x2 - 1, x2); double z21 = A.get(x2, x2 - 1); double z22 = A.get(x2, x2); double a11 = A.get(x1,x1); double a21 = A.get(x1+1,x1); double a12 = A.get(x1,x1+1); double a22 = A.get(x1+1,x1+1); double a32 = A.get(x1+2,x1+1); if( normalize ) { temp[0] = a11;temp[1] = a21;temp[2] = a12;temp[3] = a22;temp[4] = a32; temp[5] = z11;temp[6] = z22;temp[7] = z12;temp[8] = z21; double max = Math.abs(temp[0]); for( int j = 1; j < temp.length; j++ ) { if( Math.abs(temp[j]) > max ) max = Math.abs(temp[j]); } a11 /= max;a21 /= max;a12 /= max;a22 /= max;a32 /= max; z11 /= max;z22 /= max;z12 /= max;z21 /= max; } // these equations are derived when the eigenvalues are extracted from the lower right // 2 by 2 matrix. See page 388 of Fundamentals of Matrix Computations 2nd ed for details. double b11,b21,b31; if( useStandardEq ) { b11 = ((a11- z11)*(a11- z22)- z21 * z12)/a21 + a12; b21 = a11 + a22 - z11 - z22; b31 = a32; } else { // this is different from the version in the book and seems in my testing to be more resilient to // over flow issues b11 = ((a11- z11)*(a11- z22)- z21 * z12) + a12*a21; b21 = (a11 + a22 - z11 - z22)*a21; b31 = a32*a21; } performImplicitDoubleStep(x1, x2, b11 , b21 , b31 ); } /** * Performs an implicit double step given the set of two imaginary eigenvalues provided. * Since one eigenvalue is the complex conjugate of the other only one set of real and imaginary * numbers is needed. * * @param x1 upper index of submatrix. * @param x2 lower index of submatrix. * @param real Real component of each of the eigenvalues. * @param img Imaginary component of one of the eigenvalues. */ public void performImplicitDoubleStep(int x1, int x2 , double real , double img ) { double a11 = A.get(x1,x1); double a21 = A.get(x1+1,x1); double a12 = A.get(x1,x1+1); double a22 = A.get(x1+1,x1+1); double a32 = A.get(x1+2,x1+1); double p_plus_t = 2.0*real; double p_times_t = real*real + img*img; double b11,b21,b31; if( useStandardEq ) { b11 = (a11*a11 - p_plus_t*a11+p_times_t)/a21 + a12; b21 = a11+a22-p_plus_t; b31 = a32; } else { // this is different from the version in the book and seems in my testing to be more resilient to // over flow issues b11 = (a11*a11 - p_plus_t*a11+p_times_t) + a12*a21; b21 = (a11+a22-p_plus_t)*a21; b31 = a32*a21; } performImplicitDoubleStep(x1, x2, b11, b21, b31); } private void performImplicitDoubleStep(int x1, int x2, double b11 , double b21 , double b31 ) { if( !bulgeDoubleStepQn(x1,b11,b21,b31,0,false) ) return; // get rid of the bump if( Q != null ) { QrHelperFunctions_D64.rank1UpdateMultR(Q, u.data, gamma, 0, x1, x1 + 3, _temp.data); if( checkOrthogonal && !MatrixFeatures.isOrthogonal(Q,1e-8) ) { u.print(); Q.print(); throw new RuntimeException("Bad"); } } if( printHumps ) { System.out.println("Applied first Q matrix, it should be humped now. A = "); A.print("%12.3e"); System.out.println("Pushing the hump off the matrix."); } // perform double steps for( int i = x1; i < x2-2; i++ ) { if( bulgeDoubleStepQn(i) && Q != null ) { QrHelperFunctions_D64.rank1UpdateMultR(Q, u.data, gamma, 0, i + 1, i + 4, _temp.data); if( checkOrthogonal && !MatrixFeatures.isOrthogonal(Q,1e-8) ) throw new RuntimeException("Bad"); } if( printHumps ) { System.out.println("i = "+i+" A = "); A.print("%12.3e"); } } if( printHumps ) System.out.println("removing last bump"); // the last one has to be a single step if( x2-2 >= 0 && bulgeSingleStepQn(x2-2) && Q != null ) { QrHelperFunctions_D64.rank1UpdateMultR(Q, u.data, gamma, 0, x2 - 1, x2 + 1, _temp.data); if( checkOrthogonal && !MatrixFeatures.isOrthogonal(Q,1e-8) ) throw new RuntimeException("Bad"); } if( printHumps ) { System.out.println(" A = "); A.print("%12.3e"); } // A.print("%12.3e"); if( checkHessenberg && !MatrixFeatures.isUpperTriangle(A,1,1e-12)) { A.print("%12.3e"); throw new RuntimeException("Bad matrix"); } } public void performImplicitSingleStep(int x1, int x2 , double eigenvalue ) { if( !createBulgeSingleStep(x1,eigenvalue) ) return; // get rid of the bump if( Q != null ) { QrHelperFunctions_D64.rank1UpdateMultR(Q, u.data, gamma, 0, x1, x1 + 2, _temp.data); if( checkOrthogonal && !MatrixFeatures.isOrthogonal(Q,1e-8) ) throw new RuntimeException("Bad"); } if( printHumps ) { System.out.println("Applied first Q matrix, it should be humped now. A = "); A.print("%12.3e"); System.out.println("Pushing the hump off the matrix."); } // perform simple steps for( int i = x1; i < x2-1; i++ ) { if( bulgeSingleStepQn(i) && Q != null ) { QrHelperFunctions_D64.rank1UpdateMultR(Q, u.data, gamma, 0, i + 1, i + 3, _temp.data); if( checkOrthogonal && !MatrixFeatures.isOrthogonal(Q,1e-8) ) throw new RuntimeException("Bad"); } if( printHumps ) { System.out.println("i = "+i+" A = "); A.print("%12.3e"); } } if( checkHessenberg && !MatrixFeatures.isUpperTriangle(A,1,1e-12)) { A.print("%12.3e"); throw new RuntimeException("Bad matrix"); } } public boolean createBulgeSingleStep( int x1 , double eigenvalue ) { double b11 = A.get(x1,x1) - eigenvalue; double b21 = A.get(x1+1,x1); double threshold = Math.abs(A.get(x1,x1))*UtilEjml.EPS; return bulgeSingleStepQn(x1,b11,b21,threshold,false); } public boolean bulgeDoubleStepQn( int i ) { double a11 = A.get(i+1,i); double a21 = A.get(i+2,i); double a31 = A.get(i+3,i); double threshold = Math.abs(A.get(i,i))*UtilEjml.EPS; return bulgeDoubleStepQn(i+1,a11,a21,a31,threshold,true); } public boolean bulgeDoubleStepQn( int i , double a11, double a21 , double a31, double threshold , boolean set ) { double max; if( normalize ) { double absA11 = Math.abs(a11); double absA21 = Math.abs(a21); double absA31 = Math.abs(a31); max = absA11 > absA21 ? absA11 : absA21; if( absA31 > max ) max = absA31; // if( max <= Math.abs(A.get(i,i))*UtilEjml.EPS ) { if( max <= threshold ) { if( set ) { A.set(i,i-1,0); A.set(i+1,i-1,0); A.set(i+2,i-1,0); } return false; } a11 /= max; a21 /= max; a31 /= max; } else { max = 1; } // compute the reflector using the b's above double tau = Math.sqrt(a11*a11 + a21*a21 + a31*a31); if( a11 < 0 ) tau = -tau; double div = a11+tau; u.set(i,0,1); u.set(i+1,0,a21/div); u.set(i+2,0,a31/div); gamma = div/tau; // compute A_1 = Q_1^T * A * Q_1 // apply Q*A - just do the 3 rows QrHelperFunctions_D64.rank1UpdateMultR(A, u.data, gamma, 0, i, i + 3, _temp.data); if( set ) { A.set(i,i-1,-max*tau); A.set(i+1,i-1,0); A.set(i+2,i-1,0); } if( printHumps ) { System.out.println(" After Q. A ="); A.print(); } // apply A*Q - just the three things QrHelperFunctions_D64.rank1UpdateMultL(A, u.data, gamma, 0, i, i + 3); // System.out.println(" after Q*A*Q "); // A.print(); if(checkUncountable && MatrixFeatures.hasUncountable(A)) { throw new RuntimeException("bad matrix"); } return true; } public boolean bulgeSingleStepQn( int i ) { double a11 = A.get(i+1,i); double a21 = A.get(i+2,i); double threshold = Math.abs(A.get(i,i))*UtilEjml.EPS; return bulgeSingleStepQn(i+1,a11,a21,threshold,true); } public boolean bulgeSingleStepQn( int i , double a11 , double a21 , double threshold , boolean set) { double max; if( normalize ) { max = Math.abs(a11); if( max < Math.abs(a21)) max = Math.abs(a21); // if( max <= Math.abs(A.get(i,i))*UtilEjml.EPS ) { if( max <= threshold ) { // System.out.println("i = "+i); // A.print(); if( set ) { A.set(i,i-1,0); A.set(i+1,i-1,0); } return false; } a11 /= max; a21 /= max; } else { max = 1; } // compute the reflector using the b's above double tau = Math.sqrt(a11*a11 + a21*a21); if( a11 < 0 ) tau = -tau; double div = a11+tau; u.set(i,0,1); u.set(i+1,0,a21/div); gamma = div/tau; // compute A_1 = Q_1^T * A * Q_1 // apply Q*A - just do the 3 rows QrHelperFunctions_D64.rank1UpdateMultR(A, u.data, gamma, 0, i, i + 2, _temp.data); if( set ) { A.set(i,i-1,-max*tau); A.set(i+1,i-1,0); } // apply A*Q - just the three things QrHelperFunctions_D64.rank1UpdateMultL(A, u.data, gamma, 0, i, i + 2); if(checkUncountable && MatrixFeatures.hasUncountable(A)) { throw new RuntimeException("bad matrix"); } return true; } public void eigen2by2_scale( double a11 , double a12 , double a21 , double a22 ) { double abs11 = Math.abs(a11); double abs22 = Math.abs(a22); double abs12 = Math.abs(a12); double abs21 = Math.abs(a21); double max = abs11 > abs22 ? abs11 : abs22; if( max < abs12 ) max = abs12; if( max < abs21 ) max = abs21; if( max == 0 ) { valueSmall.value0.real = 0; valueSmall.value0.imaginary = 0; valueSmall.value1.real = 0; valueSmall.value1.imaginary = 0; } else { a12 /= max; a21 /= max; a11/=max;a22/=max; if( useCareful2x2 ) { valueSmall.value2x2(a11,a12,a21,a22); } else { valueSmall.value2x2_fast(a11,a12,a21,a22); } valueSmall.value0.real *= max; valueSmall.value0.imaginary *= max; valueSmall.value1.real *= max; valueSmall.value1.imaginary *= max; } // System.out.printf("eigen (%6.3f , %6.3f) (%6.3f , %6.3f)\n",p0_real,p0_img,p1_real,p1_img); } public int getNumberOfEigenvalues() { return numEigen; } public Complex64F[] getEigenvalues() { return eigenvalues; } public void addComputedEigen2x2(int x1,int x2) { eigen2by2_scale(A.get(x1,x1),A.get(x1,x2),A.get(x2,x1),A.get(x2,x2)); if( checkUncountable && (Double.isNaN(valueSmall.value0.real) || Double.isNaN(valueSmall.value1.real)) ) { throw new RuntimeException("Uncountable"); } addEigenvalue(valueSmall.value0.real,valueSmall.value0.imaginary); addEigenvalue(valueSmall.value1.real,valueSmall.value1.imaginary); } public boolean isReal2x2( int x1 , int x2 ) { eigen2by2_scale(A.get(x1,x1),A.get(x1,x2),A.get(x2,x1),A.get(x2,x2)); return valueSmall.value0.isReal(); } public void addEigenAt( int x1 ) { addEigenvalue(A.get(x1,x1)); } public void printSteps() { for( int i = 0; i < N; i++ ) { System.out.println("Step["+i+"] = "+numStepsFind[i]); } } } WatchedDoubleStepQREigenvalue.java000066400000000000000000000072101256171534400344050ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/watched/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.watched; import org.ejml.alg.dense.decomposition.eig.EigenvalueExtractor; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; /** * @author Peter Abeles */ public class WatchedDoubleStepQREigenvalue implements EigenvalueExtractor { WatchedDoubleStepQREigen implicitQR; int splits[]; int numSplits; int x1; int x2; public WatchedDoubleStepQREigenvalue() { implicitQR = new WatchedDoubleStepQREigen(); } public void setup( DenseMatrix64F A ) { implicitQR.setup(A); implicitQR.setQ(null); splits = new int[ A.numRows ]; numSplits = 0; } @Override public boolean process(DenseMatrix64F origA) { setup(origA); x1 = 0; x2 = origA.numRows-1; while( implicitQR.numEigen < origA.numRows ) { if( implicitQR.steps > implicitQR.maxIterations ) return false; implicitQR.incrementSteps(); if( x2 < x1 ) { moveToNextSplit(); } else if( x2-x1 == 0 ) { // implicitQR.A.print(); implicitQR.addEigenAt(x1); x2--; } else if( x2-x1 == 1 ) { // implicitQR.A.print(); implicitQR.addComputedEigen2x2(x1,x2); x2 -= 2; } else if( implicitQR.steps-implicitQR.lastExceptional > implicitQR.exceptionalThreshold ) { // see if the matrix blew up if( Double.isNaN(implicitQR.A.get(x2,x2))) { return false; } implicitQR.exceptionalShift(x1,x2); } else if( implicitQR.isZero(x2,x2-1) ) { // implicitQR.A.print(); implicitQR.addEigenAt(x2); x2--; }else { performIteration(); } } return true; } private void moveToNextSplit() { if( numSplits <= 0 ) throw new RuntimeException("bad"); x2 = splits[--numSplits]; if( numSplits > 0 ) { x1 = splits[numSplits-1]+1; } else { x1 = 0; } } private void performIteration() { boolean changed = false; // see if it can perform a split for( int i = x2; i > x1; i-- ) { if( implicitQR.isZero(i,i-1)) { x1 = i; splits[numSplits++] = i-1; changed = true; // reduce the scope of what it is looking at break; } } if( !changed ) implicitQR.implicitDoubleStep(x1,x2); } @Override public int getNumberOfEigenvalues() { return implicitQR.getNumberOfEigenvalues(); } @Override public Complex64F[] getEigenvalues() { return implicitQR.getEigenvalues(); } public WatchedDoubleStepQREigen getImplicitQR() { return implicitQR; } }WatchedDoubleStepQREigenvector.java000066400000000000000000000222101256171534400345700ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/eig/watched/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.watched; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.NormOps; import org.ejml.ops.SpecializedOps; /** * @author Peter Abeles */ public class WatchedDoubleStepQREigenvector { WatchedDoubleStepQREigen implicit; // Q matrix from double step QR DenseMatrix64F Q; DenseMatrix64F eigenvectors[]; DenseMatrix64F eigenvectorTemp; LinearSolver solver; Complex64F origEigenvalues[]; int N; int splits[]; int numSplits; int x1,x2; int indexVal; boolean onscript; public boolean process( WatchedDoubleStepQREigen implicit , DenseMatrix64F A , DenseMatrix64F Q_h ) { this.implicit = implicit; if( N != A.numRows ) { N = A.numRows; Q = new DenseMatrix64F(N,N); splits = new int[N]; origEigenvalues = new Complex64F[N]; eigenvectors = new DenseMatrix64F[N]; eigenvectorTemp = new DenseMatrix64F(N,1); solver = LinearSolverFactory.linear(0); } else { // UtilEjml.setnull(eigenvectors); eigenvectors = new DenseMatrix64F[N]; } System.arraycopy(implicit.eigenvalues,0,origEigenvalues,0,N); implicit.setup(A); implicit.setQ(Q); numSplits = 0; onscript = true; // System.out.println("Orig A"); // A.print("%12.10f"); if( !findQandR() ) return false; return extractVectors(Q_h); } public boolean extractVectors( DenseMatrix64F Q_h ) { UtilEjml.memset(eigenvectorTemp.data,0); // extract eigenvectors from the shur matrix // start at the top left corner of the matrix boolean triangular = true; for( int i = 0; i < N; i++ ) { Complex64F c = implicit.eigenvalues[N-i-1]; if( triangular && !c.isReal() ) triangular = false; if( c.isReal() && eigenvectors[N-i-1] == null) { solveEigenvectorDuplicateEigenvalue(c.real,i,triangular); } } // translate the eigenvectors into the frame of the original matrix if( Q_h != null ) { DenseMatrix64F temp = new DenseMatrix64F(N,1); for( int i = 0; i < N; i++ ) { DenseMatrix64F v = eigenvectors[i]; if( v != null ) { CommonOps.mult(Q_h,v,temp); eigenvectors[i] = temp; temp = v; } } } return true; } private void solveEigenvectorDuplicateEigenvalue( double real , int first , boolean isTriangle ) { double scale = Math.abs(real); if( scale == 0 ) scale = 1; eigenvectorTemp.reshape(N,1, false); eigenvectorTemp.zero(); if( first > 0 ) { if( isTriangle ) { solveUsingTriangle(real, first , eigenvectorTemp); } else { solveWithLU(real, first , eigenvectorTemp); } } eigenvectorTemp.reshape(N,1, false); for( int i = first; i < N; i++ ) { Complex64F c = implicit.eigenvalues[N-i-1]; if( c.isReal() && Math.abs(c.real-real)/scale < 100.0*UtilEjml.EPS ) { eigenvectorTemp.data[i] = 1; DenseMatrix64F v = new DenseMatrix64F(N,1); CommonOps.multTransA(Q,eigenvectorTemp,v); eigenvectors[N-i-1] = v; NormOps.normalizeF(v); eigenvectorTemp.data[i] = 0; } } } private void solveUsingTriangle(double real, int index, DenseMatrix64F r ) { for( int i = 0; i < index; i++ ) { implicit.A.add(i,i,-real); } SpecializedOps.subvector(implicit.A,0,index,index,false,0,r); CommonOps.changeSign(r); TriangularSolver.solveU(implicit.A.data,r.data,implicit.A.numRows,0,index); for( int i = 0; i < index; i++ ) { implicit.A.add(i,i,real); } } private void solveWithLU(double real, int index, DenseMatrix64F r ) { DenseMatrix64F A = new DenseMatrix64F(index,index); CommonOps.extract(implicit.A,0,index,0,index,A,0,0); for( int i = 0; i < index; i++ ) { A.add(i,i,-real); } r.reshape(index,1, false); SpecializedOps.subvector(implicit.A,0,index,index,false,0,r); CommonOps.changeSign(r); // TODO this must be very inefficient if( !solver.setA(A)) throw new RuntimeException("Solve failed"); solver.solve(r,r); } public boolean findQandR() { CommonOps.setIdentity(Q); x1 = 0; x2 = N-1; // use the already computed eigenvalues to recompute the Q and R matrices indexVal = 0; while( indexVal < N ) { if (!findNextEigenvalue()) { return false; } } // Q.print("%1.10f"); // // implicit.A.print("%1.10f"); return true; } private boolean findNextEigenvalue() { boolean foundEigen = false; while( !foundEigen && implicit.steps < implicit.maxIterations ) { // implicit.A.print(); implicit.incrementSteps(); if( x2 < x1 ) { moveToNextSplit(); } else if( x2-x1 == 0 ) { implicit.addEigenAt(x1); x2--; indexVal++; foundEigen = true; } else if( x2-x1 == 1 && !implicit.isReal2x2(x1,x2)) { implicit.addComputedEigen2x2(x1,x2); x2 -= 2; indexVal += 2; foundEigen = true; } else if( implicit.steps-implicit.lastExceptional > implicit.exceptionalThreshold ) { // implicit.A.print("%e"); //System.err.println("If it needs to do an exceptional shift then something went very bad."); // return false; implicit.exceptionalShift(x1,x2); implicit.lastExceptional = implicit.steps; } else if( implicit.isZero(x2,x2-1)) { // check for convergence implicit.addEigenAt(x2); foundEigen = true; x2--; indexVal++; } else { checkSplitPerformImplicit(); } } return foundEigen; } private void checkSplitPerformImplicit() { // check for splits for( int i = x2; i > x1; i-- ) { if( implicit.isZero(i,i-1)) { x1 = i; splits[numSplits++] = i-1; // reduce the scope of what it is looking at return; } } // first try using known eigenvalues in the same order they were originally found if( onscript) { if( implicit.steps > implicit.exceptionalThreshold/2 ) { onscript = false; } else { Complex64F a = origEigenvalues[indexVal]; // if no splits are found perform an implicit step if( a.isReal() ) { implicit.performImplicitSingleStep(x1,x2, a.getReal()); } else if( x2 < N-2 ) { implicit.performImplicitDoubleStep(x1,x2, a.real,a.imaginary); } else { onscript = false; } } } else { // that didn't work so try a modified order if( x2-x1 >= 1 && x2 < N-2 ) implicit.implicitDoubleStep(x1,x2); else implicit.performImplicitSingleStep(x1,x2,implicit.A.get(x2,x2)); } } private void moveToNextSplit() { if( numSplits <= 0 ) throw new RuntimeException("bad"); x2 = splits[--numSplits]; if( numSplits > 0 ) { x1 = splits[numSplits-1]+1; } else { x1 = 0; } } public DenseMatrix64F getQ() { return Q; } public WatchedDoubleStepQREigen getImplicit() { return implicit; } public DenseMatrix64F[] getEigenvectors() { return eigenvectors; } public Complex64F[] getEigenvalues() { return implicit.eigenvalues; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/hessenberg/000077500000000000000000000000001256171534400257455ustar00rootroot00000000000000HessenbergSimilarDecomposition_D64.java000066400000000000000000000166701256171534400353230ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.alg.dense.decomposition.qr.QrHelperFunctions_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.ejml.ops.CommonOps; /** *

* Finds the decomposition of a matrix in the form of:
*
* A = OHOT
*
* where A is an m by m matrix, O is an orthogonal matrix, and H is an upper Hessenberg matrix. *

* *

* A matrix is upper Hessenberg if aij = 0 for all i > j+1. For example, the following matrix * is upper Hessenberg.
*
* WRITE IT OUT USING A TABLE *

* *

* This decomposition is primarily used as a step for computing the eigenvalue decomposition of a matrix. * The basic algorithm comes from David S. Watkins, "Fundamentals of MatrixComputations" Second Edition. *

*/ // TODO create a column based one similar to what was done for QR decomposition? public class HessenbergSimilarDecomposition_D64 implements DecompositionInterface { // A combined matrix that stores te upper Hessenberg matrix and the orthogonal matrix. private DenseMatrix64F QH; // number of rows and columns of the matrix being decompose private int N; // the first element in the orthogonal vectors private double gammas[]; // temporary storage private double b[]; private double u[]; /** * Creates a decomposition that won't need to allocate new memory if it is passed matrices up to * the specified size. * * @param initialSize Expected size of the matrices it will decompose. */ public HessenbergSimilarDecomposition_D64(int initialSize) { gammas = new double[ initialSize ]; b = new double[ initialSize ]; u = new double[ initialSize ]; } public HessenbergSimilarDecomposition_D64() { this(5); } /** * Computes the decomposition of the provided matrix. If no errors are detected then true is returned, * false otherwise. * @param A The matrix that is being decomposed. Not modified. * @return If it detects any errors or not. */ @Override public boolean decompose( DenseMatrix64F A ) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("A must be square."); if( A.numRows <= 0 ) return false; QH = A; N = A.numCols; if( b.length < N ) { b = new double[ N ]; gammas = new double[ N ]; u = new double[ N ]; } return _decompose(); } @Override public boolean inputModified() { return true; } /** * The raw QH matrix that is stored internally. * * @return QH matrix. */ public DenseMatrix64F getQH() { return QH; } /** * An upper Hessenberg matrix from the decompostion. * * @param H If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted H matrix. */ public DenseMatrix64F getH( DenseMatrix64F H ) { if( H == null ) { H = new DenseMatrix64F(N,N); } else if( N != H.numRows || N != H.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else H.zero(); // copy the first row System.arraycopy(QH.data, 0, H.data, 0, N); for( int i = 1; i < N; i++ ) { for( int j = i-1; j < N; j++ ) { H.set(i,j, QH.get(i,j)); } } return H; } /** * An orthogonal matrix that has the following property: H = QTAQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public DenseMatrix64F getQ( DenseMatrix64F Q ) { if( Q == null ) { Q = new DenseMatrix64F(N,N); for( int i = 0; i < N; i++ ) { Q.data[i*N+i] = 1; } } else if( N != Q.numRows || N != Q.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else CommonOps.setIdentity(Q); for( int j = N-2; j >= 0; j-- ) { u[j+1] = 1; for( int i = j+2; i < N; i++ ) { u[i] = QH.get(i,j); } QrHelperFunctions_D64.rank1UpdateMultR(Q, u, gammas[j], j + 1, j + 1, N, b); } return Q; } /** * Internal function for computing the decomposition. */ private boolean _decompose() { double h[] = QH.data; for( int k = 0; k < N-2; k++ ) { // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = 0; for( int i = k+1; i < N; i++ ) { // copy the householder vector to vector outside of the matrix to reduce caching issues // big improvement on larger matrices and a relatively small performance hit on small matrices. double val = u[i] = h[i*N+k]; val = Math.abs(val); if( val > max ) max = val; } if( max > 0 ) { // -------- set up the reflector Q_k double tau = 0; // normalize to reduce overflow/underflow // and compute tau for the reflector for( int i = k+1; i < N; i++ ) { double val = u[i] /= max; tau += val*val; } tau = Math.sqrt(tau); if( u[k+1] < 0 ) tau = -tau; // write the reflector into the lower left column of the matrix double nu = u[k+1] + tau; u[k+1] = 1.0; for( int i = k+2; i < N; i++ ) { h[i*N+k] = u[i] /= nu; } double gamma = nu/tau; gammas[k] = gamma; // ---------- multiply on the left by Q_k QrHelperFunctions_D64.rank1UpdateMultR(QH, u, gamma, k + 1, k + 1, N, b); // ---------- multiply on the right by Q_k QrHelperFunctions_D64.rank1UpdateMultL(QH, u, gamma, 0, k + 1, N); // since the first element in the householder vector is known to be 1 // store the full upper hessenberg h[(k+1)*N+k] = -tau*max; } else { gammas[k] = 0; } } return true; } public double[] getGammas() { return gammas; } } TridiagonalDecompositionHouseholderOrig_D64.java000066400000000000000000000174671256171534400372020ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.alg.dense.decomposition.qr.QrHelperFunctions_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; /** *

* A straight forward implementation from "Fundamentals of Matrix Computations," Second Edition.
*
* This is only saved to provide a point of reference in benchmarks. *

* * @author Peter Abeles */ public class TridiagonalDecompositionHouseholderOrig_D64 { /** * Internal storage of decomposed matrix. The tridiagonal matrix is stored in the * upper tridiagonal portion of the matrix. The householder vectors are stored * in the upper rows. */ DenseMatrix64F QT; // The size of the matrix int N; // temporary storage double w[]; // gammas for the householder operations double gammas[]; // temporary storage double b[]; public TridiagonalDecompositionHouseholderOrig_D64() { N = 1; QT = new DenseMatrix64F(N,N); w = new double[N]; b = new double[N]; gammas = new double[N]; } /** * Returns the interal matrix where the decomposed results are stored. * @return */ public DenseMatrix64F getQT() { return QT; } /** * Extracts the tridiagonal matrix found in the decomposition. * * @param T If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted T matrix. */ public DenseMatrix64F getT( DenseMatrix64F T) { if( T == null ) { T = new DenseMatrix64F(N,N); } else if( N != T.numRows || N != T.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else T.zero(); T.data[0] = QT.data[0]; T.data[1] = QT.data[1]; for( int i = 1; i < N-1; i++ ) { T.set(i,i, QT.get(i,i)); T.set(i,i+1,QT.get(i,i+1)); T.set(i,i-1,QT.get(i-1,i)); } T.data[(N-1)*N+N-1] = QT.data[(N-1)*N+N-1]; T.data[(N-1)*N+N-2] = QT.data[(N-2)*N+N-1]; return T; } /** * An orthogonal matrix that has the following property: T = QTAQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public DenseMatrix64F getQ( DenseMatrix64F Q ) { if( Q == null ) { Q = new DenseMatrix64F(N,N); for( int i = 0; i < N; i++ ) { Q.data[i*N+i] = 1; } } else if( N != Q.numRows || N != Q.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else CommonOps.setIdentity(Q); for( int i = 0; i < N; i++ ) w[i] = 0; for( int j = N-2; j >= 0; j-- ) { w[j+1] = 1; for( int i = j+2; i < N; i++ ) { w[i] = QT.get(j,i); } QrHelperFunctions_D64.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b); // Q.print(); } return Q; } /** * Decomposes the provided symmetric matrix. * * @param A Symmetric matrix that is going to be decomposed. Not modified. */ public void decompose( DenseMatrix64F A ) { init(A); for( int k = 1; k < N; k++ ) { similarTransform(k); // System.out.println("k=="+k); // QT.print(); } } /** * Computes and performs the similar a transform for submatrix k. */ private void similarTransform( int k) { double t[] = QT.data; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = 0; int rowU = (k-1)*N; for( int i = k; i < N; i++ ) { double val = Math.abs(t[rowU+i]); if( val > max ) max = val; } if( max > 0 ) { // -------- set up the reflector Q_k double tau = 0; // normalize to reduce overflow/underflow // and compute tau for the reflector for( int i = k; i < N; i++ ) { double val = t[rowU+i] /= max; tau += val*val; } tau = Math.sqrt(tau); if( t[rowU+k] < 0 ) tau = -tau; // write the reflector into the lower left column of the matrix double nu = t[rowU+k] + tau; t[rowU+k] = 1.0; for( int i = k+1; i < N; i++ ) { t[rowU+i] /= nu; } double gamma = nu/tau; gammas[k] = gamma; // ---------- Specialized householder that takes advantage of the symmetry householderSymmetric(k,gamma); // since the first element in the householder vector is known to be 1 // store the full upper hessenberg t[rowU+k] = -tau*max; } else { gammas[k] = 0; } } /** * Performs the householder operations on left and right and side of the matrix. QTAQ * @param row Specifies the submatrix. * * @param gamma The gamma for the householder operation */ public void householderSymmetric( int row , double gamma ) { int startU = (row-1)*N; // compute v = -gamma*A*u for( int i = row; i < N; i++ ) { double total = 0; for( int j = row; j < N; j++ ) { total += QT.data[i*N+j]*QT.data[startU+j]; } w[i] = -gamma*total; // System.out.println("y["+i+"] = "+w[i]); } // alpha = -0.5*gamma*u^T*v double alpha = 0; for( int i = row; i < N; i++ ) { alpha += QT.data[startU+i]*w[i]; } alpha *= -0.5*gamma; // w = v + alpha*u for( int i = row; i < N; i++ ) { w[i] += alpha*QT.data[startU+i]; // System.out.println("w["+i+"] = "+w[i]); } // A = A + w*u^T + u*w^T for( int i = row; i < N; i++ ) { double ww = w[i]; double uu = QT.data[startU+i]; // System.out.println("u["+i+"] = "+uu); for( int j = i; j < N; j++ ) { QT.data[j*N+i] = QT.data[i*N+j] += ww*QT.data[startU+j] + w[j]*uu; } } } /** * If needed declares and sets up internal data structures. * * @param A Matrix being decomposed. */ public void init( DenseMatrix64F A ) { if( A.numRows != A.numCols) throw new IllegalArgumentException("Must be square"); if( A.numCols != N ) { N = A.numCols; QT.reshape(N,N, false); if( w.length < N ) { w = new double[ N ]; gammas = new double[N]; b = new double[N]; } } // just copy the top right triangle QT.set(A); } public double getGamma( int index ) { return gammas[index]; } }TridiagonalDecompositionHouseholder_D64.java000066400000000000000000000215501256171534400363450ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.alg.dense.decomposition.qr.QrHelperFunctions_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.CommonOps; /** *

* Performs a {@link org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition similar tridiagonal decomposition} on a square symmetric input matrix. * Householder vectors perform the similar operation and the symmetry is taken advantage * of for good performance. *

*

* Finds the decomposition of a matrix in the form of:
*
* A = O*T*OT
*
* where A is a symmetric m by m matrix, O is an orthogonal matrix, and T is a tridiagonal matrix. *

*

* This implementation is based off of the algorithm described in:
*
* David S. Watkins, "Fundamentals of Matrix Computations," Second Edition. Page 349-355 *

* * @author Peter Abeles */ public class TridiagonalDecompositionHouseholder_D64 implements TridiagonalSimilarDecomposition { /** * Only the upper right triangle is used. The Tridiagonal portion stores * the tridiagonal matrix. The rows store householder vectors. */ private DenseMatrix64F QT; // The size of the matrix private int N; // temporary storage private double w[]; // gammas for the householder operations private double gammas[]; // temporary storage private double b[]; public TridiagonalDecompositionHouseholder_D64() { N = 1; w = new double[N]; b = new double[N]; gammas = new double[N]; } /** * Returns the internal matrix where the decomposed results are stored. * @return */ public DenseMatrix64F getQT() { return QT; } @Override public void getDiagonal(double[] diag, double[] off) { for( int i = 0; i < N; i++ ) { diag[i] = QT.data[i*N+i]; if( i+1 < N ) { off[i] = QT.data[i*N+i+1]; } } } /** * Extracts the tridiagonal matrix found in the decomposition. * * @param T If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted T matrix. */ @Override public DenseMatrix64F getT( DenseMatrix64F T ) { if( T == null ) { T = new DenseMatrix64F(N,N); } else if( N != T.numRows || N != T.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else T.zero(); T.data[0] = QT.data[0]; for( int i = 1; i < N; i++ ) { T.set(i,i, QT.get(i,i)); double a = QT.get(i-1,i); T.set(i-1,i,a); T.set(i,i-1,a); } if( N > 1 ) { T.data[(N-1)*N+N-1] = QT.data[(N-1)*N+N-1]; T.data[(N-1)*N+N-2] = QT.data[(N-2)*N+N-1]; } return T; } /** * An orthogonal matrix that has the following property: T = QTAQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ @Override public DenseMatrix64F getQ( DenseMatrix64F Q , boolean transposed ) { if( Q == null ) { Q = CommonOps.identity(N); } else if( N != Q.numRows || N != Q.numCols ) throw new IllegalArgumentException("The provided H must have the same dimensions as the decomposed matrix."); else CommonOps.setIdentity(Q); for( int i = 0; i < N; i++ ) w[i] = 0; if( transposed ) { for( int j = N-2; j >= 0; j-- ) { w[j+1] = 1; for( int i = j+2; i < N; i++ ) { w[i] = QT.data[j*N+i]; } QrHelperFunctions_D64.rank1UpdateMultL(Q, w, gammas[j + 1], j + 1, j + 1, N); } } else { for( int j = N-2; j >= 0; j-- ) { w[j+1] = 1; for( int i = j+2; i < N; i++ ) { w[i] = QT.get(j,i); } QrHelperFunctions_D64.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b); } } return Q; } /** * Decomposes the provided symmetric matrix. * * @param A Symmetric matrix that is going to be decomposed. Not modified. */ @Override public boolean decompose( DenseMatrix64F A ) { init(A); for( int k = 1; k < N; k++ ) { similarTransform(k); } return true; } /** * Computes and performs the similar a transform for submatrix k. */ private void similarTransform( int k) { double t[] = QT.data; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = 0; int rowU = (k-1)*N; for( int i = k; i < N; i++ ) { double val = Math.abs(t[rowU+i]); if( val > max ) max = val; } if( max > 0 ) { // -------- set up the reflector Q_k double tau = QrHelperFunctions_D64.computeTauAndDivide(k, N, t, rowU, max); // write the reflector into the lower left column of the matrix double nu = t[rowU+k] + tau; QrHelperFunctions_D64.divideElements(k + 1, N, t, rowU, nu); t[rowU+k] = 1.0; double gamma = nu/tau; gammas[k] = gamma; // ---------- Specialized householder that takes advantage of the symmetry householderSymmetric(k,gamma); // since the first element in the householder vector is known to be 1 // store the full upper hessenberg t[rowU+k] = -tau*max; } else { gammas[k] = 0; } } /** * Performs the householder operations on left and right and side of the matrix. QTAQ * @param row Specifies the submatrix. * * @param gamma The gamma for the householder operation */ public void householderSymmetric( int row , double gamma ) { int startU = (row-1)*N; // compute v = -gamma*A*u for( int i = row; i < N; i++ ) { double total = 0; // the lower triangle is not written to so it needs to traverse upwards // to get the information. Reduces the number of matrix writes need // improving large matrix performance for( int j = row; j < i; j++ ) { total += QT.data[j*N+i]*QT.data[startU+j]; } for( int j = i; j < N; j++ ) { total += QT.data[i*N+j]*QT.data[startU+j]; } w[i] = -gamma*total; } // alpha = -0.5*gamma*u^T*v double alpha = 0; for( int i = row; i < N; i++ ) { alpha += QT.data[startU+i]*w[i]; } alpha *= -0.5*gamma; // w = v + alpha*u for( int i = row; i < N; i++ ) { w[i] += alpha*QT.data[startU+i]; } // A = A + w*u^T + u*w^T for( int i = row; i < N; i++ ) { double ww = w[i]; double uu = QT.data[startU+i]; int rowA = i*N; for( int j = i; j < N; j++ ) { // only write to the upper portion of the matrix // this reduces the number of cache misses QT.data[rowA+j] += ww*QT.data[startU+j] + w[j]*uu; } } } /** * If needed declares and sets up internal data structures. * * @param A Matrix being decomposed. */ public void init( DenseMatrix64F A ) { if( A.numRows != A.numCols) throw new IllegalArgumentException("Must be square"); if( A.numCols != N ) { N = A.numCols; if( w.length < N ) { w = new double[ N ]; gammas = new double[N]; b = new double[N]; } } QT = A; } @Override public boolean inputModified() { return true; } } TridiagonalDecomposition_B64_to_D64.java000066400000000000000000000056571256171534400352720ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.EjmlParameters; import org.ejml.alg.block.decomposition.hessenberg.TridiagonalDecompositionHouseholder_B64; import org.ejml.alg.dense.decomposition.BaseDecomposition_B64_to_D64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.CommonOps; /** * Wrapper around a block implementation of TridiagonalSimilarDecomposition * * @author Peter Abeles */ public class TridiagonalDecomposition_B64_to_D64 extends BaseDecomposition_B64_to_D64 implements TridiagonalSimilarDecomposition { public TridiagonalDecomposition_B64_to_D64() { this(EjmlParameters.BLOCK_WIDTH); } public TridiagonalDecomposition_B64_to_D64(int blockSize) { super(new TridiagonalDecompositionHouseholder_B64(),blockSize); } @Override public DenseMatrix64F getT(DenseMatrix64F T) { int N = Ablock.numRows; if( T == null ) { T = new DenseMatrix64F(N,N); } else { CommonOps.fill(T, 0); } double[] diag = new double[ N ]; double[] off = new double[ N ]; ((TridiagonalDecompositionHouseholder_B64)alg).getDiagonal(diag,off); T.unsafe_set(0,0,diag[0]); for( int i = 1; i < N; i++ ) { T.unsafe_set(i,i,diag[i]); T.unsafe_set(i,i-1,off[i-1]); T.unsafe_set(i-1,i,off[i-1]); } return T; } @Override public DenseMatrix64F getQ(DenseMatrix64F Q, boolean transposed) { if( Q == null ) { Q = new DenseMatrix64F(Ablock.numRows,Ablock.numCols); } BlockMatrix64F Qblock = new BlockMatrix64F(); Qblock.numRows = Q.numRows; Qblock.numCols = Q.numCols; Qblock.blockLength = blockLength; Qblock.data = Q.data; ((TridiagonalDecompositionHouseholder_B64)alg).getQ(Qblock,transposed); convertBlockToRow(Q.numRows,Q.numCols,Ablock.blockLength,Q.data); return Q; } @Override public void getDiagonal(double[] diag, double[] off) { ((TridiagonalDecompositionHouseholder_B64)alg).getDiagonal(diag,off); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/lu/000077500000000000000000000000001256171534400242405ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/lu/LUDecompositionAlt_D64.java000066400000000000000000000070471256171534400312460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.lu; import org.ejml.data.DenseMatrix64F; /** *

* An LU decomposition algorithm that originally came from Jama. In general this is faster than * what is in NR since it creates a cache of a column, which makes a big difference in larger * matrices. *

* * @author Peter Abeles */ public class LUDecompositionAlt_D64 extends LUDecompositionBase_D64 { /** * This is a modified version of what was found in the JAMA package. The order that it * performs its permutations in is the primary difference from NR * * @param a The matrix that is to be decomposed. Not modified. * @return true If the matrix can be decomposed and false if it can not. */ public boolean decompose( DenseMatrix64F a ) { decomposeCommonInit(a); double LUcolj[] = vv; for( int j = 0; j < n; j++ ) { // make a copy of the column to avoid cache jumping issues for( int i = 0; i < m; i++) { LUcolj[i] = dataLU[i*n + j]; } // Apply previous transformations. for( int i = 0; i < m; i++ ) { int rowIndex = i*n; // Most of the time is spent in the following dot product. int kmax = i < j ? i : j; double s = 0.0; for (int k = 0; k < kmax; k++) { s += dataLU[rowIndex+k]*LUcolj[k]; } dataLU[rowIndex+j] = LUcolj[i] -= s; } // Find pivot and exchange if necessary. int p = j; double max = Math.abs(LUcolj[p]); for (int i = j+1; i < m; i++) { double v = Math.abs(LUcolj[i]); if ( v > max) { p = i; max = v; } } if (p != j) { // swap the rows // for (int k = 0; k < n; k++) { // double t = dataLU[p*n + k]; // dataLU[p*n + k] = dataLU[j*n + k]; // dataLU[j*n + k] = t; // } int rowP = p*n; int rowJ = j*n; int endP = rowP+n; for (;rowP < endP; rowP++,rowJ++) { double t = dataLU[rowP]; dataLU[rowP] = dataLU[rowJ]; dataLU[rowJ] = t; } int k = pivot[p]; pivot[p] = pivot[j]; pivot[j] = k; pivsign = -pivsign; } indx[j] = p; // Compute multipliers. if (j < m ) { double lujj = dataLU[j*n+j]; if( lujj != 0 ) { for (int i = j+1; i < m; i++) { dataLU[i*n+j] /= lujj; } } } } return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/lu/LUDecompositionBase_D64.java000066400000000000000000000147741256171534400314050ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.lu; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.SpecializedOps; /** *

* Contains common data structures and operations for LU decomposition algorithms. *

* @author Peter Abeles */ public abstract class LUDecompositionBase_D64 implements LUDecomposition { // the decomposed matrix protected DenseMatrix64F LU; // it can decompose a matrix up to this size protected int maxWidth=-1; // the shape of the matrix protected int m,n; // data in the matrix protected double dataLU[]; // used in set, solve, invert protected double vv[]; // used in set protected int indx[]; protected int pivot[]; // used by determinant protected double pivsign; Complex64F det = new Complex64F(); public void setExpectedMaxSize( int numRows , int numCols ) { LU = new DenseMatrix64F(numRows,numCols); this.dataLU = LU.data; maxWidth = Math.max(numRows,numCols); vv = new double[ maxWidth ]; indx = new int[ maxWidth ]; pivot = new int[ maxWidth ]; } public DenseMatrix64F getLU() { return LU; } public int[] getIndx() { return indx; } public int[] getPivot() { return pivot; } @Override public boolean inputModified() { return false; } /** * Writes the lower triangular matrix into the specified matrix. * * @param lower Where the lower triangular matrix is writen to. */ @Override public DenseMatrix64F getLower( DenseMatrix64F lower ) { int numRows = LU.numRows; int numCols = LU.numRows < LU.numCols ? LU.numRows : LU.numCols; if( lower == null ) { lower = new DenseMatrix64F(numRows,numCols); } else { if( lower.numCols != numCols || lower.numRows != numRows ) throw new IllegalArgumentException("Unexpected matrix dimension"); CommonOps.fill(lower, 0); } for( int i = 0; i < numCols; i++ ) { lower.set(i,i,1.0); for( int j = 0; j < i; j++ ) { lower.set(i,j, LU.get(i,j)); } } if( numRows > numCols ) { for( int i = numCols; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { lower.set(i,j, LU.get(i,j)); } } } return lower; } /** * Writes the upper triangular matrix into the specified matrix. * * @param upper Where the upper triangular matrix is writen to. */ @Override public DenseMatrix64F getUpper( DenseMatrix64F upper ) { int numRows = LU.numRows < LU.numCols ? LU.numRows : LU.numCols; int numCols = LU.numCols; if( upper == null ) { upper = new DenseMatrix64F(numRows, numCols); } else { if( upper.numCols != numCols || upper.numRows != numRows ) throw new IllegalArgumentException("Unexpected matrix dimension"); CommonOps.fill(upper, 0); } for( int i = 0; i < numRows; i++ ) { for( int j = i; j < numCols; j++ ) { upper.set(i,j, LU.get(i,j)); } } return upper; } public DenseMatrix64F getPivot( DenseMatrix64F pivot ) { return SpecializedOps.pivotMatrix(pivot, this.pivot, LU.numRows, false); } protected void decomposeCommonInit(DenseMatrix64F a) { if( a.numRows > maxWidth || a.numCols > maxWidth ) { setExpectedMaxSize(a.numRows,a.numCols); } m = a.numRows; n = a.numCols; LU.set(a); for (int i = 0; i < m; i++) { pivot[i] = i; } pivsign = 1; } /** * Determines if the decomposed matrix is singular. This function can return * false and the matrix be almost singular, which is still bad. * * @return true if singular false otherwise. */ @Override public boolean isSingular() { for( int i = 0; i < m; i++ ) { if( Math.abs(dataLU[i* n +i]) < UtilEjml.EPS ) return true; } return false; } /** * Computes the determinant from the LU decomposition. * * @return The matrix's determinant. */ @Override public Complex64F computeDeterminant() { if( m != n ) throw new IllegalArgumentException("Must be a square matrix."); double ret = pivsign; int total = m*n; for( int i = 0; i < total; i += n + 1 ) { ret *= dataLU[i]; } det.real = ret; det.imaginary = 0; return det; } public double quality() { return SpecializedOps.qualityTriangular(LU); } /** * a specialized version of solve that avoid additional checks that are not needed. */ public void _solveVectorInternal( double []vv ) { // Solve L*Y = B int ii = 0; for( int i = 0; i < n; i++ ) { int ip = indx[i]; double sum = vv[ip]; vv[ip] = vv[i]; if( ii != 0 ) { // for( int j = ii-1; j < i; j++ ) // sum -= dataLU[i* n +j]*vv[j]; int index = i*n + ii-1; for( int j = ii-1; j < i; j++ ) sum -= dataLU[index++]*vv[j]; } else if( sum != 0.0 ) { ii=i+1; } vv[i] = sum; } // Solve U*X = Y; TriangularSolver.solveU(dataLU,vv,n); } public double[] _getVV() { return vv; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/000077500000000000000000000000001256171534400242425ustar00rootroot00000000000000QRColPivDecompositionHouseholderColumn_D64.java000066400000000000000000000227671256171534400352350ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRPDecomposition; import org.ejml.ops.CommonOps; /** *

* Performs QR decomposition with column pivoting. To prevent overflow/underflow the whole matrix * is normalized by the max value, but columns are not normalized individually any more. To enable * code reuse it extends {@link QRDecompositionHouseholderColumn_D64} and functions from that class * are used whenever possible. Columns are transposed into single arrays, which allow for * fast pivots. *

* *

* Decomposition: A*P = Q*R *

* *

* Based off the description in "Fundamentals of Matrix Computations", 2nd by David S. Watkins. *

* * @author Peter Abeles */ public class QRColPivDecompositionHouseholderColumn_D64 extends QRDecompositionHouseholderColumn_D64 implements QRPDecomposition { // the ordering of each column, the current column i is the original column pivots[i] protected int pivots[]; // F-norm squared for each column protected double normsCol[]; // value of the maximum abs element protected double maxAbs; // threshold used to determine when a column is considered to be singular // Threshold is relative to the maxAbs protected double singularThreshold = UtilEjml.EPS; // the matrix's rank protected int rank; /** * Configure parameters. * * @param singularThreshold The singular threshold. */ public QRColPivDecompositionHouseholderColumn_D64(double singularThreshold) { this.singularThreshold = singularThreshold; } public QRColPivDecompositionHouseholderColumn_D64() { } @Override public void setSingularThreshold( double threshold ) { this.singularThreshold = threshold; } @Override public void setExpectedMaxSize( int numRows , int numCols ) { super.setExpectedMaxSize(numRows,numCols); if( pivots == null || pivots.length < numCols ) { pivots = new int[numCols]; normsCol = new double[numCols]; } } /** * Computes the Q matrix from the information stored in the QR matrix. This * operation requires about 4(m2n-mn2+n3/3) flops. * * @param Q The orthogonal Q matrix. */ @Override public DenseMatrix64F getQ( DenseMatrix64F Q , boolean compact ) { if( compact ) { if( Q == null ) { Q = CommonOps.identity(numRows,minLength); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } else { if( Q == null ) { Q = CommonOps.identity(numRows); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } for( int j = rank-1; j >= 0; j-- ) { double u[] = dataQR[j]; double vv = u[j]; u[j] = 1; QrHelperFunctions_D64.rank1UpdateMultR(Q, u, gammas[j], j, j, numRows, v); u[j] = vv; } return Q; } /** *

* To decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m2-2m2/3 flops. *

* *

* The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. *

*/ @Override public boolean decompose( DenseMatrix64F A ) { setExpectedMaxSize(A.numRows, A.numCols); convertToColumnMajor(A); maxAbs = CommonOps.elementMaxAbs(A); // initialize pivot variables setupPivotInfo(); // go through each column and perform the decomposition for( int j = 0; j < minLength; j++ ) { if( j > 0 ) updateNorms(j); swapColumns(j); // if its degenerate stop processing if( !householderPivot(j) ) break; updateA(j); rank = j+1; } return true; } /** * Sets the initial pivot ordering and compute the F-norm squared for each column */ private void setupPivotInfo() { for( int col = 0; col < numCols; col++ ) { pivots[col] = col; double c[] = dataQR[col]; double norm = 0; for( int row = 0; row < numRows; row++ ) { double element = c[row]; norm += element*element; } normsCol[col] = norm; } } /** * Performs an efficient update of each columns' norm */ private void updateNorms( int j ) { boolean foundNegative = false; for( int col = j; col < numCols; col++ ) { double e = dataQR[col][j-1]; normsCol[col] -= e*e; if( normsCol[col] < 0 ) { foundNegative = true; break; } } // if a negative sum has been found then clearly too much precision has been last // and it should recompute the column norms from scratch if( foundNegative ) { for( int col = j; col < numCols; col++ ) { double u[] = dataQR[col]; double actual = 0; for( int i=j; i < numRows; i++ ) { double v = u[i]; actual += v*v; } normsCol[col] = actual; } } } /** * Finds the column with the largest normal and makes that the first column * * @param j Current column being inspected */ private void swapColumns( int j ) { // find the column with the largest norm int largestIndex = j; double largestNorm = normsCol[j]; for( int col = j+1; col < numCols; col++ ) { double n = normsCol[col]; if( n > largestNorm ) { largestNorm = n; largestIndex = col; } } // swap the columns double []tempC = dataQR[j]; dataQR[j] = dataQR[largestIndex]; dataQR[largestIndex] = tempC; double tempN = normsCol[j]; normsCol[j] = normsCol[largestIndex]; normsCol[largestIndex] = tempN; int tempP = pivots[j]; pivots[j] = pivots[largestIndex]; pivots[largestIndex] = tempP; } /** *

* Computes the householder vector "u" for the first column of submatrix j. The already computed * norm is used and checks to see if the matrix is singular at this point. *

*

* Q = I - γuuT *

*

* This function finds the values of 'u' and 'γ'. *

* * @param j Which submatrix to work off of. * @return false if it is degenerate */ protected boolean householderPivot(int j) { final double u[] = dataQR[j]; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow final double max = QrHelperFunctions_D64.findMax(u, j, numRows - j); if( max <= 0 ) { return false; } else { // computes tau and normalizes u by max tau = QrHelperFunctions_D64.computeTauAndDivide(j, numRows, u, max); // divide u by u_0 double u_0 = u[j] + tau; QrHelperFunctions_D64.divideElements(j + 1, numRows, u, u_0); gamma = u_0/tau; tau *= max; u[j] = -tau; if( Math.abs(tau) <= singularThreshold ) { return false; } } gammas[j] = gamma; return true; } @Override public int getRank() { return rank; } @Override public int[] getPivots() { return pivots; } @Override public DenseMatrix64F getPivotMatrix(DenseMatrix64F P) { if( P == null ) P = new DenseMatrix64F(numCols,numCols); else if( P.numRows != numCols ) throw new IllegalArgumentException("Number of rows must be "+numCols); else if( P.numCols != numCols ) throw new IllegalArgumentException("Number of columns must be "+numCols); else { P.zero(); } for( int i = 0; i < numCols; i++ ) { P.set(pivots[i],i,1); } return P; } } QRDecompositionHouseholderColumn_D64.java000066400000000000000000000217661256171534400341160ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CommonOps; /** *

* Householder QR decomposition is rich in operations along the columns of the matrix. This can be * taken advantage of by solving for the Q matrix in a column major format to reduce the number * of CPU cache misses and the number of copies that are performed. *

* * @see QRDecompositionHouseholder_D64 * * @author Peter Abeles */ public class QRDecompositionHouseholderColumn_D64 implements QRDecomposition { /** * Where the Q and R matrices are stored. R is stored in the * upper triangular portion and Q on the lower bit. Lower columns * are where u is stored. Q_k = (I - gamma_k*u_k*u_k^T). */ protected double dataQR[][]; // [ column][ row ] // used internally to store temporary data protected double v[]; // dimension of the decomposed matrices protected int numCols; // this is 'n' protected int numRows; // this is 'm' protected int minLength; // the computed gamma for Q_k matrix protected double gammas[]; // local variables protected double gamma; protected double tau; // did it encounter an error? protected boolean error; public void setExpectedMaxSize( int numRows , int numCols ) { this.numCols = numCols; this.numRows = numRows; minLength = Math.min(numCols,numRows); int maxLength = Math.max(numCols,numRows); if( dataQR == null || dataQR.length < numCols || dataQR[0].length < numRows ) { dataQR = new double[ numCols ][ numRows ]; v = new double[ maxLength ]; gammas = new double[ minLength ]; } if( v.length < maxLength ) { v = new double[ maxLength ]; } if( gammas.length < minLength ) { gammas = new double[ minLength ]; } } /** * Returns the combined QR matrix in a 2D array format that is column major. * * @return The QR matrix in a 2D matrix column major format. [ column ][ row ] */ public double[][] getQR() { return dataQR; } /** * Computes the Q matrix from the imformation stored in the QR matrix. This * operation requires about 4(m2n-mn2+n3/3) flops. * * @param Q The orthogonal Q matrix. */ @Override public DenseMatrix64F getQ( DenseMatrix64F Q , boolean compact ) { if( compact ) { if( Q == null ) { Q = CommonOps.identity(numRows,minLength); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } else { if( Q == null ) { Q = CommonOps.identity(numRows); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } for( int j = minLength-1; j >= 0; j-- ) { double u[] = dataQR[j]; double vv = u[j]; u[j] = 1; QrHelperFunctions_D64.rank1UpdateMultR(Q, u, gammas[j], j, j, numRows, v); u[j] = vv; } return Q; } /** * Returns an upper triangular matrix which is the R in the QR decomposition. If compact then the input * expected to be size = [min(rows,cols) , numCols] otherwise size = [numRows,numCols]. * * @param R Storage for upper triangular matrix. * @param compact If true then a compact matrix is expected. */ @Override public DenseMatrix64F getR(DenseMatrix64F R, boolean compact) { if( R == null ) { if( compact ) { R = new DenseMatrix64F(minLength,numCols); } else R = new DenseMatrix64F(numRows,numCols); } else { if( compact ) { if( R.numCols != numCols || R.numRows != minLength ) throw new IllegalArgumentException( "Unexpected dimensions: found( "+R.numRows+" "+R.numCols+" ) expected( "+minLength+" "+numCols+" )"); } else { if( R.numCols != numCols || R.numRows != numRows ) throw new IllegalArgumentException("Unexpected dimensions"); } for( int i = 0; i < R.numRows; i++ ) { int min = Math.min(i,R.numCols); for( int j = 0; j < min; j++ ) { R.set(i,j,0); } } } for( int j = 0; j < numCols; j++ ) { double colR[] = dataQR[j]; int l = Math.min(j,numRows-1); for( int i = 0; i <= l; i++ ) { double val = colR[i]; R.set(i,j,val); } } return R; } /** *

* To decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m2-2m2/3 flops. *

* *

* The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. *

*/ @Override public boolean decompose( DenseMatrix64F A ) { setExpectedMaxSize(A.numRows, A.numCols); convertToColumnMajor(A); error = false; for( int j = 0; j < minLength; j++ ) { householder(j); updateA(j); } return !error; } @Override public boolean inputModified() { return false; } /** * Converts the standard row-major matrix into a column-major vector * that is advantageous for this problem. * * @param A original matrix that is to be decomposed. */ protected void convertToColumnMajor(DenseMatrix64F A) { for( int x = 0; x < numCols; x++ ) { double colQ[] = dataQR[x]; for( int y = 0; y < numRows; y++ ) { colQ[y] = A.data[y*numCols+x]; } } } /** *

* Computes the householder vector "u" for the first column of submatrix j. Note this is * a specialized householder for this problem. There is some protection against * overfloaw and underflow. *

*

* Q = I - γuuT *

*

* This function finds the values of 'u' and 'γ'. *

* * @param j Which submatrix to work off of. */ protected void householder( int j ) { final double u[] = dataQR[j]; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow final double max = QrHelperFunctions_D64.findMax(u, j, numRows - j); if( max == 0.0 ) { gamma = 0; error = true; } else { // computes tau and normalizes u by max tau = QrHelperFunctions_D64.computeTauAndDivide(j, numRows, u, max); // divide u by u_0 double u_0 = u[j] + tau; QrHelperFunctions_D64.divideElements(j + 1, numRows, u, u_0); gamma = u_0/tau; tau *= max; u[j] = -tau; } gammas[j] = gamma; } /** *

* Takes the results from the householder computation and updates the 'A' matrix.
*
* A = (I - γ*u*uT)A *

* * @param w The submatrix. */ protected void updateA( int w ) { final double u[] = dataQR[w]; for( int j = w+1; j < numCols; j++ ) { final double colQ[] = dataQR[j]; double val = colQ[w]; for( int k = w+1; k < numRows; k++ ) { val += u[k]*colQ[k]; } val *= gamma; colQ[w] -= val; for( int i = w+1; i < numRows; i++ ) { colQ[i] -= u[i]*val; } } } public double[] getGammas() { return gammas; } }QRDecompositionHouseholderTran_D64.java000066400000000000000000000244101256171534400335520ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CommonOps; /** *

* Householder QR decomposition is rich in operations along the columns of the matrix. This can be * taken advantage of by solving for the Q matrix in a column major format to reduce the number * of CPU cache misses and the number of copies that are performed. *

* * @see QRDecompositionHouseholder_D64 * * @author Peter Abeles */ // TODO remove QR Col and replace with this one? // -- On small matrices col seems to be about 10% faster public class QRDecompositionHouseholderTran_D64 implements QRDecomposition { /** * Where the Q and R matrices are stored. For speed reasons * this is transposed */ protected DenseMatrix64F QR; // used internally to store temporary data protected double v[]; // dimension of the decomposed matrices protected int numCols; // this is 'n' protected int numRows; // this is 'm' protected int minLength; // the computed gamma for Q_k matrix protected double gammas[]; // local variables protected double gamma; protected double tau; // did it encounter an error? protected boolean error; public void setExpectedMaxSize( int numRows , int numCols ) { this.numCols = numCols; this.numRows = numRows; minLength = Math.min(numCols,numRows); int maxLength = Math.max(numCols,numRows); if( QR == null ) { QR = new DenseMatrix64F(numCols,numRows); v = new double[ maxLength ]; gammas = new double[ minLength ]; } else { QR.reshape(numCols,numRows,false); } if( v.length < maxLength ) { v = new double[ maxLength ]; } if( gammas.length < minLength ) { gammas = new double[ minLength ]; } } /** * Inner matrix that stores the decomposition */ public DenseMatrix64F getQR() { return QR; } /** * Computes the Q matrix from the information stored in the QR matrix. This * operation requires about 4(mn-mn2+n3/3) flops. * * @param Q The orthogonal Q matrix. */ @Override public DenseMatrix64F getQ( DenseMatrix64F Q , boolean compact ) { if( compact ) { if( Q == null ) { Q = CommonOps.identity(numRows,minLength); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } else { if( Q == null ) { Q = CommonOps.identity(numRows); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } // Unlike applyQ() this takes advantage of zeros in the identity matrix // by not multiplying across all rows. for( int j = minLength-1; j >= 0; j-- ) { int diagIndex = j*numRows+j; double before = QR.data[diagIndex]; QR.data[diagIndex] = 1; QrHelperFunctions_D64.rank1UpdateMultR(Q, QR.data, j * numRows, gammas[j], j, j, numRows, v); QR.data[diagIndex] = before; } return Q; } /** * A = Q*A * * @param A Matrix that is being multiplied by Q. Is modified. */ public void applyQ( DenseMatrix64F A ) { if( A.numRows != numRows ) throw new IllegalArgumentException("A must have at least "+numRows+" rows."); for( int j = minLength-1; j >= 0; j-- ) { int diagIndex = j*numRows+j; double before = QR.data[diagIndex]; QR.data[diagIndex] = 1; QrHelperFunctions_D64.rank1UpdateMultR(A, QR.data, j * numRows, gammas[j], 0, j, numRows, v); QR.data[diagIndex] = before; } } /** * A = QT*A * * @param A Matrix that is being multiplied by QT. Is modified. */ public void applyTranQ( DenseMatrix64F A ) { for( int j = 0; j < minLength; j++ ) { int diagIndex = j*numRows+j; double before = QR.data[diagIndex]; QR.data[diagIndex] = 1; QrHelperFunctions_D64.rank1UpdateMultR(A, QR.data, j * numRows, gammas[j], 0, j, numRows, v); QR.data[diagIndex] = before; } } /** * Returns an upper triangular matrix which is the R in the QR decomposition. * * @param R An upper triangular matrix. * @param compact */ @Override public DenseMatrix64F getR(DenseMatrix64F R, boolean compact) { if( R == null ) { if( compact ) { R = new DenseMatrix64F(minLength,numCols); } else R = new DenseMatrix64F(numRows,numCols); } else { if( compact ) { if( R.numCols != numCols || R.numRows != minLength ) throw new IllegalArgumentException("Unexpected dimensions"); } else { if( R.numCols != numCols || R.numRows != numRows ) throw new IllegalArgumentException("Unexpected dimensions"); } for( int i = 0; i < R.numRows; i++ ) { int min = Math.min(i,R.numCols); for( int j = 0; j < min; j++ ) { R.unsafe_set(i,j,0); } } } for( int i = 0; i < R.numRows; i++ ) { for( int j = i; j < R.numCols; j++ ) { R.unsafe_set(i,j,QR.unsafe_get(j,i)); } } return R; } /** *

* To decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m2-2m2/3 flops. *

* *

* The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. *

*/ @Override public boolean decompose( DenseMatrix64F A ) { setExpectedMaxSize(A.numRows, A.numCols); CommonOps.transpose(A,QR); error = false; for( int j = 0; j < minLength; j++ ) { householder(j); updateA(j); } return !error; } @Override public boolean inputModified() { return false; } /** *

* Computes the householder vector "u" for the first column of submatrix j. Note this is * a specialized householder for this problem. There is some protection against * overflow and underflow. *

*

* Q = I - γuuT *

*

* This function finds the values of 'u' and 'γ'. *

* * @param j Which submatrix to work off of. */ protected void householder( final int j ) { int startQR = j*numRows; int endQR = startQR+numRows; startQR += j; final double max = QrHelperFunctions_D64.findMax(QR.data, startQR, numRows - j); if( max == 0.0 ) { gamma = 0; error = true; } else { // computes tau and normalizes u by max tau = QrHelperFunctions_D64.computeTauAndDivide(startQR, endQR, QR.data, max); // divide u by u_0 double u_0 = QR.data[startQR] + tau; QrHelperFunctions_D64.divideElements(startQR + 1, endQR, QR.data, u_0); gamma = u_0/tau; tau *= max; QR.data[startQR] = -tau; } gammas[j] = gamma; } /** *

* Takes the results from the householder computation and updates the 'A' matrix.
*
* A = (I - γ*u*uT)A *

* * @param w The submatrix. */ protected void updateA( final int w ) { // int rowW = w*numRows; // int rowJ = rowW + numRows; // // for( int j = w+1; j < numCols; j++ , rowJ += numRows) { // double val = QR.data[rowJ + w]; // // // val = gamma*u^T * A // for( int k = w+1; k < numRows; k++ ) { // val += QR.data[rowW + k]*QR.data[rowJ + k]; // } // val *= gamma; // // // A - val*u // QR.data[rowJ + w] -= val; // for( int i = w+1; i < numRows; i++ ) { // QR.data[rowJ + i] -= QR.data[rowW + i]*val; // } // } final double data[] = QR.data; final int rowW = w*numRows + w + 1; int rowJ = rowW + numRows; final int rowJEnd = rowJ + (numCols-w-1)*numRows; final int indexWEnd = rowW + numRows - w - 1; for( ; rowJEnd != rowJ; rowJ += numRows) { // assume the first element in u is 1 double val = data[rowJ - 1]; int indexW = rowW; int indexJ = rowJ; while( indexW != indexWEnd ) { val += data[indexW++]*data[indexJ++]; } val *= gamma; data[rowJ - 1] -= val; indexW = rowW; indexJ = rowJ; while( indexW != indexWEnd ) { data[indexJ++] -= data[indexW++]*val; } } } public double[] getGammas() { return gammas; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/QRDecompositionHouseholder_D64.java000066400000000000000000000256071256171534400330150ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CommonOps; /** *

* This variation of QR decomposition uses reflections to compute the Q matrix. * Each reflection uses a householder operations, hence its name. To provide a meaningful solution * the original matrix must have full rank. This is intended for processing of small to medium matrices. *

*

* Both Q and R are stored in the same m by n matrix. Q is not stored directly, instead the u from * Qk=(I-γ*u*uT) is stored. Decomposition requires about 2n*m2-2m2/3 flops. *

* *

* See the QR reflections algorithm described in:
* David S. Watkins, "Fundamentals of Matrix Computations" 2nd Edition, 2002 *

* *

* For the most part this is a straight forward implementation. To improve performance on large matrices a column is writen to an array and the order * of some of the loops has been changed. This will degrade performance noticeably on small matrices. Since * it is unlikely that the QR decomposition would be a bottle neck when small matrices are involved only * one implementation is provided. *

* * @author Peter Abeles */ public class QRDecompositionHouseholder_D64 implements QRDecomposition { /** * Where the Q and R matrices are stored. R is stored in the * upper triangular portion and Q on the lower bit. Lower columns * are where u is stored. Q_k = (I - gamma_k*u_k*u_k^T). */ protected DenseMatrix64F QR; // used internally to store temporary data protected double u[],v[]; // dimension of the decomposed matrices protected int numCols; // this is 'n' protected int numRows; // this is 'm' protected int minLength; protected double dataQR[]; // the computed gamma for Q_k matrix protected double gammas[]; // local variables protected double gamma; protected double tau; // did it encounter an error? protected boolean error; public void setExpectedMaxSize( int numRows , int numCols ) { error = false; this.numCols = numCols; this.numRows = numRows; minLength = Math.min(numRows,numCols); int maxLength = Math.max(numRows,numCols); if( QR == null ) { QR = new DenseMatrix64F(numRows,numCols); u = new double[ maxLength ]; v = new double[ maxLength ]; gammas = new double[ minLength ]; } else { QR.reshape(numRows,numCols,false); } dataQR = QR.data; if( u.length < maxLength ) { u = new double[ maxLength ]; v = new double[ maxLength ]; } if( gammas.length < minLength ) { gammas = new double[ minLength ]; } } /** * Returns a single matrix which contains the combined values of Q and R. This * is possible since Q is symmetric and R is upper triangular. * * @return The combined Q R matrix. */ public DenseMatrix64F getQR() { return QR; } /** * Computes the Q matrix from the imformation stored in the QR matrix. This * operation requires about 4(m2n-mn2+n3/3) flops. * * @param Q The orthogonal Q matrix. */ @Override public DenseMatrix64F getQ( DenseMatrix64F Q , boolean compact ) { if( compact ) { if( Q == null ) { Q = CommonOps.identity(numRows,minLength); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } else { if( Q == null ) { Q = CommonOps.identity(numRows); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CommonOps.setIdentity(Q); } } } for( int j = minLength-1; j >= 0; j-- ) { u[j] = 1; for( int i = j+1; i < numRows; i++ ) { u[i] = QR.get(i,j); } QrHelperFunctions_D64.rank1UpdateMultR(Q, u, gammas[j], j, j, numRows, v); } return Q; } /** * Returns an upper triangular matrix which is the R in the QR decomposition. * * @param R An upper triangular matrix. * @param compact */ @Override public DenseMatrix64F getR(DenseMatrix64F R, boolean compact) { if( R == null ) { if( compact ) { R = new DenseMatrix64F(minLength,numCols); } else R = new DenseMatrix64F(numRows,numCols); } else { if( compact ) { if( R.numCols != numCols || R.numRows != minLength ) throw new IllegalArgumentException("Unexpected dimensions"); } else { if( R.numCols != numCols || R.numRows != numRows ) throw new IllegalArgumentException("Unexpected dimensions"); } for( int i = 0; i < R.numRows; i++ ) { int min = Math.min(i,R.numCols); for( int j = 0; j < min; j++ ) { R.set(i,j,0); } } } for( int i = 0; i < minLength; i++ ) { for( int j = i; j < numCols; j++ ) { double val = QR.get(i,j); R.set(i,j,val); } } return R; } /** *

* In order to decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m2-2m2/3 flops. *

* *

* The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. *

*/ @Override public boolean decompose( DenseMatrix64F A ) { commonSetup(A); for( int j = 0; j < minLength; j++ ) { householder(j); updateA(j); } return !error; } @Override public boolean inputModified() { return false; } /** *

* Computes the householder vector "u" for the first column of submatrix j. Note this is * a specialized householder for this problem. There is some protection against * overflow and underflow. *

*

* Q = I - γuuT *

*

* This function finds the values of 'u' and 'γ'. *

* * @param j Which submatrix to work off of. */ protected void householder( int j ) { // find the element with the largest absolute value in the column and make a copy int index = j+j*numCols; double max = 0; for( int i = j; i < numRows; i++ ) { double d = u[i] = dataQR[index]; // absolute value of d if( d < 0 ) d = -d; if( max < d ) { max = d; } index += numCols; } if( max == 0.0 ) { gamma = 0; error = true; } else { // compute the norm2 of the matrix, with each element // normalized by the max value to avoid overflow problems tau = 0; for( int i = j; i < numRows; i++ ) { u[i] /= max; double d = u[i]; tau += d*d; } tau = Math.sqrt(tau); if( u[j] < 0 ) tau = -tau; double u_0 = u[j] + tau; gamma = u_0/tau; for( int i = j+1; i < numRows; i++ ) { u[i] /= u_0; } u[j] = 1; tau *= max; } gammas[j] = gamma; } /** *

* Takes the results from the householder computation and updates the 'A' matrix.
*
* A = (I - γ*u*uT)A *

* * @param w The submatrix. */ protected void updateA( int w ) { // much of the code below is equivalent to the rank1Update function // however, since τ has already been computed there is no need to // recompute it, saving a few multiplication operations // for( int i = w+1; i < numCols; i++ ) { // double val = 0; // // for( int k = w; k < numRows; k++ ) { // val += u[k]*dataQR[k*numCols +i]; // } // v[i] = gamma*val; // } // This is functionally the same as the above code but the order has been changed // to avoid jumping the cpu cache for( int i = w+1; i < numCols; i++ ) { v[i] = u[w]*dataQR[w*numCols +i]; } for( int k = w+1; k < numRows; k++ ) { int indexQR = k*numCols+w+1; for( int i = w+1; i < numCols; i++ ) { // v[i] += u[k]*dataQR[k*numCols +i]; v[i] += u[k]*dataQR[indexQR++]; } } for( int i = w+1; i < numCols; i++ ) { v[i] *= gamma; } // end of reordered code for( int i = w; i < numRows; i++ ) { double valU = u[i]; int indexQR = i*numCols+w+1; for( int j = w+1; j < numCols; j++ ) { // dataQR[i*numCols+j] -= valU*v[j]; dataQR[indexQR++] -= valU*v[j]; } } if( w < numCols ) { dataQR[w+w*numCols] = -tau; } // save the Q matrix in the lower portion of QR for( int i = w+1; i < numRows; i++ ) { dataQR[w+i*numCols] = u[i]; } } /** * This function performs sanity check on the input for decompose and sets up the QR matrix. * * @param A */ protected void commonSetup(DenseMatrix64F A) { setExpectedMaxSize(A.numRows,A.numCols); QR.set(A); } public double[] getGammas() { return gammas; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/QRDecomposition_B64_to_D64.java000066400000000000000000000052711256171534400317230ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.EjmlParameters; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.decomposition.qr.QRDecompositionHouseholder_B64; import org.ejml.alg.dense.decomposition.BaseDecomposition_B64_to_D64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CommonOps; /** * Wrapper that allows {@link QRDecomposition}(BlockMatrix64F) to be used * as a {@link QRDecomposition}(DenseMatrix64F). * * @author Peter Abeles */ public class QRDecomposition_B64_to_D64 extends BaseDecomposition_B64_to_D64 implements QRDecomposition { public QRDecomposition_B64_to_D64() { super(new QRDecompositionHouseholder_B64(), EjmlParameters.BLOCK_WIDTH); } @Override public DenseMatrix64F getQ(DenseMatrix64F Q, boolean compact) { int minLength = Math.min(Ablock.numRows,Ablock.numCols); if( Q == null ) { if( compact ) { Q = new DenseMatrix64F(Ablock.numRows,minLength); CommonOps.setIdentity(Q); } else { Q = new DenseMatrix64F(Ablock.numRows,Ablock.numRows); CommonOps.setIdentity(Q); } } BlockMatrix64F Qblock = new BlockMatrix64F(); Qblock.numRows = Q.numRows; Qblock.numCols = Q.numCols; Qblock.blockLength = blockLength; Qblock.data = Q.data; ((QRDecompositionHouseholder_B64)alg).getQ(Qblock,compact); convertBlockToRow(Q.numRows,Q.numCols,Ablock.blockLength,Q.data); return Q; } @Override public DenseMatrix64F getR(DenseMatrix64F R, boolean compact) { BlockMatrix64F Rblock; Rblock = ((QRDecompositionHouseholder_B64)alg).getR(null,compact); if( R == null ) { R = new DenseMatrix64F(Rblock.numRows,Rblock.numCols); } BlockMatrixOps.convert(Rblock,R); return R; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/QrHelperFunctions_D64.java000066400000000000000000000251441256171534400311430ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; /** *

* Contains different functions that are useful for computing the QR decomposition of a matrix. *

* *

* Two different families of functions are provided for help in computing reflectors. Internally * both of these functions switch between normalization by division or multiplication. Multiplication * is most often significantly faster than division (2 or 3 times) but produces less accurate results * on very small numbers. It checks to see if round off error is significant and decides which * one it should do. *

* *

* Tests were done using the stability benchmark in jmatbench and there doesn't seem to be * any advantage to always dividing by the max instead of checking and deciding. The most * noticeable difference between the two methods is with very small numbers. *

* * @author Peter Abeles */ public class QrHelperFunctions_D64 { public static double findMax( double[] u, int startU , int length ) { double max = -1; int index = startU; int stopIndex = startU + length; for( ; index < stopIndex; index++ ) { double val = u[index]; val = (val < 0.0D) ? -val : val; if( val > max ) max = val; } return max; } public static void divideElements(final int j, final int numRows , final double[] u, final double u_0 ) { // double div_u = 1.0/u_0; // // if( Double.isInfinite(div_u)) { for( int i = j; i < numRows; i++ ) { u[i] /= u_0; } // } else { // for( int i = j; i < numRows; i++ ) { // u[i] *= div_u; // } // } } public static void divideElements(int j, int numRows , double[] u, int startU , double u_0 ) { // double div_u = 1.0/u_0; // // if( Double.isInfinite(div_u)) { for( int i = j; i < numRows; i++ ) { u[i+startU] /= u_0; } // } else { // for( int i = j; i < numRows; i++ ) { // u[i+startU] *= div_u; // } // } } public static void divideElements_Brow(int j, int numRows , double[] u, double b[] , int startB , double u_0 ) { // double div_u = 1.0/u_0; // // if( Double.isInfinite(div_u)) { for( int i = j; i < numRows; i++ ) { u[i] = b[i+startB] /= u_0; } // } else { // for( int i = j; i < numRows; i++ ) { // u[i] = b[i+startB] *= div_u; // } // } } public static void divideElements_Bcol(int j, int numRows , int numCols , double[] u, double b[] , int startB , double u_0 ) { // double div_u = 1.0/u_0; // // if( Double.isInfinite(div_u)) { int indexB = j*numCols+startB; for( int i = j; i < numRows; i++ , indexB += numCols ) { b[indexB] = u[i] /= u_0; } // } else { // int indexB = j*numCols+startB; // for( int i = j; i < numRows; i++ , indexB += numCols ) { // b[indexB] = u[i] *= div_u; // } // } } public static double computeTauAndDivide(int j, int numRows , double[] u, int startU , double max) { // compute the norm2 of the matrix, with each element // normalized by the max value to avoid overflow problems double tau = 0; // double div_max = 1.0/max; // if( Double.isInfinite(div_max)) { // more accurate for( int i = j; i < numRows; i++ ) { double d = u[startU+i] /= max; tau += d*d; } // } else { // // faster // for( int i = j; i < numRows; i++ ) { // double d = u[startU+i] *= div_max; // tau += d*d; // } // } tau = Math.sqrt(tau); if( u[startU+j] < 0 ) tau = -tau; return tau; } /** * Normalizes elements in 'u' by dividing by max and computes the norm2 of the normalized * array u. Adjust the sign of the returned value depending on the size of the first * element in 'u'. Normalization is done to avoid overflow. * *
     * for i=j:numRows
     *   u[i] = u[i] / max
     *   tau = tau + u[i]*u[i]
     * end
     * tau = sqrt(tau)
     * if( u[j] < 0 )
     *    tau = -tau;
     * 
* * @param j Element in 'u' that it starts at. * @param numRows Element in 'u' that it stops at. * @param u Array * @param max Max value in 'u' that is used to normalize it. * @return norm2 of 'u' */ public static double computeTauAndDivide(final int j, final int numRows , final double[] u , final double max) { double tau = 0; // double div_max = 1.0/max; // if( Double.isInfinite(div_max)) { for( int i = j; i < numRows; i++ ) { double d = u[i] /= max; tau += d*d; } // } else { // for( int i = j; i < numRows; i++ ) { // double d = u[i] *= div_max; // tau += d*d; // } // } tau = Math.sqrt(tau); if( u[j] < 0 ) tau = -tau; return tau; } /** *

* Performs a rank-1 update operation on the submatrix specified by w with the multiply on the right.
*
* A = (I - γ*u*uT)*A
*

*

* The order that matrix multiplies are performed has been carefully selected * to minimize the number of operations. *

* *

* Before this can become a truly generic operation the submatrix specification needs * to be made more generic. *

*/ public static void rank1UpdateMultR( DenseMatrix64F A , double u[] , double gamma , int colA0, int w0, int w1 , double _temp[] ) { // for( int i = colA0; i < A.numCols; i++ ) { // double val = 0; // // for( int k = w0; k < w1; k++ ) { // val += u[k]*A.data[k*A.numCols +i]; // } // _temp[i] = gamma*val; // } // reordered to reduce cpu cache issues for( int i = colA0; i < A.numCols; i++ ) { _temp[i] = u[w0]*A.data[w0 *A.numCols +i]; } for( int k = w0+1; k < w1; k++ ) { int indexA = k*A.numCols + colA0; double valU = u[k]; for( int i = colA0; i < A.numCols; i++ ) { _temp[i] += valU*A.data[indexA++]; } } for( int i = colA0; i < A.numCols; i++ ) { _temp[i] *= gamma; } // end of reorder for( int i = w0; i < w1; i++ ) { double valU = u[i]; int indexA = i*A.numCols + colA0; for( int j = colA0; j < A.numCols; j++ ) { A.data[indexA++] -= valU*_temp[j]; } } } public static void rank1UpdateMultR(DenseMatrix64F A, double u[], int offsetU, double gamma, int colA0, int w0, int w1, double _temp[]) { // for( int i = colA0; i < A.numCols; i++ ) { // double val = 0; // // for( int k = w0; k < w1; k++ ) { // val += u[k+offsetU]*A.data[k*A.numCols +i]; // } // _temp[i] = gamma*val; // } // reordered to reduce cpu cache issues for( int i = colA0; i < A.numCols; i++ ) { _temp[i] = u[w0+offsetU]*A.data[w0 *A.numCols +i]; } for( int k = w0+1; k < w1; k++ ) { int indexA = k*A.numCols + colA0; double valU = u[k+offsetU]; for( int i = colA0; i < A.numCols; i++ ) { _temp[i] += valU*A.data[indexA++]; } } for( int i = colA0; i < A.numCols; i++ ) { _temp[i] *= gamma; } // end of reorder for( int i = w0; i < w1; i++ ) { double valU = u[i+offsetU]; int indexA = i*A.numCols + colA0; for( int j = colA0; j < A.numCols; j++ ) { A.data[indexA++] -= valU*_temp[j]; } } } /** *

* Performs a rank-1 update operation on the submatrix specified by w with the multiply on the left.
*
* A = A(I - γ*u*uT)
*

*

* The order that matrix multiplies are performed has been carefully selected * to minimize the number of operations. *

* *

* Before this can become a truly generic operation the submatrix specification needs * to be made more generic. *

*/ public static void rank1UpdateMultL( DenseMatrix64F A , double u[] , double gamma , int colA0, int w0 , int w1 ) { for( int i = colA0; i < A.numRows; i++ ) { int startIndex = i*A.numCols+w0; double sum = 0; int rowIndex = startIndex; for( int j = w0; j < w1; j++ ) { sum += A.data[rowIndex++]*u[j]; } sum = -gamma*sum; rowIndex = startIndex; for( int j = w0; j < w1; j++ ) { A.data[rowIndex++] += sum*u[j]; } } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/qr/QrUpdate.java000066400000000000000000000321751256171534400266420ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; /** *

* The effects of adding and removing rows from the A matrix in a QR decomposition can * be computed much faster than simply recomputing the whole decomposition. There are many real * world situations where this is useful. For example, when computing a rolling solution to * the most recent N measurements. *

* *

* Definitions: A ∈ ℜ m × n, m ≥ n, rank(A) = n and that A = QR, where * Q ∈ ℜ m × m is orthogonal, and R ∈ ℜ m × n is * upper triangular. *

* *

* ** IMPORTANT USAGE NOTE ** If auto grow is set to true then the internal data structures will grow automatically * to accommodate the matrices passed in. When adding elements to the decomposition the matrices must have enough * data elements to grow before hand. *

* *

* For more information see David S. Watkins, "Fundamentals of Matrix Computations" 2nd edition, pages 249-259. * It is also possible to add and remove columns efficiently, but this is less common and is not supported at * this time. *

* @author Peter Abeles */ public class QrUpdate { // the decomposition that is being adjusted private DenseMatrix64F Q,R; // product of planar multiplications private DenseMatrix64F U_tran; // using transpose of U reduces cache misses private DenseMatrix64F Qm; // used to temporarially store data private double r_row[]; // it can process matrices up to this size private int maxCols; private int maxRows; // number of rows and columns in the original A matrix that was decomposed private int m,n; // number of rows in the adjusted matrices private int m_m; // should it declare new internal data when what currently exists is too small or throw // and exception. private boolean autoGrow; /** * Creates an update which can decompose matrices up to the specified size. Autogrow * is set to false. * * @param maxRows * @param maxCols */ public QrUpdate( int maxRows , int maxCols ) { autoGrow = false; declareInternalData(maxRows, maxCols); } /** * Creates an update which can decompose matrices up to the specified size. Autogrow * is configurable. * * @param maxRows * @param maxCols * @param autoGrow */ public QrUpdate( int maxRows , int maxCols , boolean autoGrow ) { this.autoGrow = autoGrow; declareInternalData(maxRows, maxCols); } /** * Does not predeclare data and it will autogrow. */ public QrUpdate(){ autoGrow = true; } /** * Declares the internal data structures so that it can process matrices up to the specified size. * * @param maxRows * @param maxCols */ public void declareInternalData(int maxRows, int maxCols) { this.maxRows = maxRows; this.maxCols = maxCols; U_tran = new DenseMatrix64F(maxRows,maxRows); Qm = new DenseMatrix64F(maxRows,maxRows); r_row = new double[ maxCols ]; } /** *

* Adjusts the values of the Q and R matrices to take in account the effects of inserting * a row to the 'A' matrix at the specified location. This operation requires about 6mn + O(n) flops. *

* *

* If Q and/or R does not have enough data elements to grow then an exception is thrown. *

* *

* The adjustment done is by computing a series of planar Givens rotations that make the adjusted R * matrix upper triangular again. This is then used to modify the Q matrix. *

* * @param Q The Q matrix which is to be modified, must be big enough to grow. Must be n by n.. Is modified. * @param R The R matrix which is to be modified, must be big enough to grow. Must be m by n. Is modified. * @param row The row being inserted. Not modified. * @param rowIndex Which row index it is to be inserted at. * @param resizeR Should the number of rows in R be changed? The additional rows are all zero. */ public void addRow( DenseMatrix64F Q , DenseMatrix64F R , double []row , int rowIndex , boolean resizeR ) { // memory management and check precoditions setQR(Q,R,1); m_m = m+1; if( Q.data.length < m_m*m_m ) throw new IllegalArgumentException("Q matrix does not have enough data to grow"); if( resizeR && R.data.length < m_m*n ) throw new IllegalArgumentException("R matrix does not have enough data to grow"); if( resizeR ) R.reshape(m_m,n, false); U_tran.reshape(m_m,m_m, false); // apply givens rotation to the first two rows of the augmented R matrix applyFirstGivens(row); applyLaterGivens(); // compute new Q matrix updateInsertQ(rowIndex); // discard the reference since it is no longer needed this.Q = this.R = null; } /** *

* Adjusts the values of the Q and R matrices to take in account the effects of removing * a row from the 'A' matrix at the specified location. This operation requires about 6mn + O(n) flops. *

* *

* The adjustment is done by computing a series of planar Givens rotations that make the removed row in Q * equal to [1 0 ... 0]. *

* * @param Q The Q matrix. Is modified. * @param R The R matrix. Is modified. * @param rowIndex Which index of the row that is being removed. * @param resizeR should the shape of R be adjusted? */ public void deleteRow( DenseMatrix64F Q , DenseMatrix64F R , int rowIndex , boolean resizeR ) { setQR(Q,R,0); if( m - 1 < n ) { throw new IllegalArgumentException("Removing any row would make the system under determined."); } m_m = m - 1; U_tran.reshape(m,m, false); if( resizeR ) R.reshape(m_m,n, false); computeRemoveGivens(rowIndex); updateRemoveQ(rowIndex); updateRemoveR(); // discard the reference since it is no longer needed this.Q = this.R = null; } /** * Provides the results of a QR decomposition. These will be modified by adding or removing * rows from the original 'A' matrix. * * @param Q The Q matrix which is to be modified. Is modified later and reference saved. * @param R The R matrix which is to be modified. Is modified later and reference saved. */ private void setQR( DenseMatrix64F Q , DenseMatrix64F R , int growRows ) { if( Q.numRows != Q.numCols ) { throw new IllegalArgumentException("Q should be square."); } this.Q = Q; this.R = R; m = Q.numRows; n = R.numCols; if( m+growRows > maxRows || n > maxCols ) { if( autoGrow ) { declareInternalData(m+growRows,n); } else { throw new IllegalArgumentException("Autogrow has been set to false and the maximum number of rows" + " or columns has been exceeded."); } } } /** * Updates the Q matrix to take in account the inserted matrix. * * @param rowIndex where the matrix has been inserted. */ private void updateInsertQ( int rowIndex ) { Qm.set(Q); Q.reshape(m_m,m_m, false); for( int i = 0; i < rowIndex; i++ ) { for( int j = 0; j < m_m; j++ ) { double sum = 0; for( int k = 0; k < m; k++ ) { sum += Qm.data[i*m+k]* U_tran.data[j*m_m+k+1]; } Q.data[i*m_m+j] = sum; } } for( int j = 0; j < m_m; j++ ) { Q.data[rowIndex*m_m+j] = U_tran.data[j*m_m]; } for( int i = rowIndex+1; i < m_m; i++ ) { for( int j = 0; j < m_m; j++ ) { double sum = 0; for( int k = 0; k < m; k++ ) { sum += Qm.data[(i-1)*m+k]* U_tran.data[j*m_m+k+1]; } Q.data[i*m_m+j] = sum; } } } /** * Updates the Q matrix to take inaccount the row that was removed by only multiplying e * lements that need to be. There is still some room for improvement here... * @param rowIndex */ private void updateRemoveQ( int rowIndex ) { Qm.set(Q); Q.reshape(m_m,m_m, false); for( int i = 0; i < rowIndex; i++ ) { for( int j = 1; j < m; j++ ) { double sum = 0; for( int k = 0; k < m; k++ ) { sum += Qm.data[i*m+k]* U_tran.data[j*m+k]; } Q.data[i*m_m+j-1] = sum; } } for( int i = rowIndex+1; i < m; i++ ) { for( int j = 1; j < m; j++ ) { double sum = 0; for( int k = 0; k < m; k++ ) { sum += Qm.data[i*m+k]* U_tran.data[j*m+k]; } Q.data[(i-1)*m_m+j-1] = sum; } } } /** * Updates the R matrix to take in account the removed row. */ private void updateRemoveR() { for( int i = 1; i < n+1; i++ ) { for( int j = 0; j < n; j++ ) { double sum = 0; for( int k = i-1; k <= j; k++ ) { sum += U_tran.data[i*m+k] * R.data[k*n+j]; } R.data[(i-1)*n+j] = sum; } } } private void applyFirstGivens(double[] row) { double c,s; double xi = row[0]; double xj = R.data[0]; double r = xi*xi + xj*xj; if( r != 0 ) { r = Math.sqrt(r); c = xi/r; s = xj/r; } else { c = 1; s = 0; } R.data[0] = r; for( int col = 1; col < n; col++ ) { double vali = row[col]; double valj = R.data[col]; R.data[col] = c*vali + s*valj; r_row[col] = c*valj - s*vali; } // set U to its initial values CommonOps.setIdentity(U_tran); U_tran.data[0] = c; U_tran.data[1] = s; U_tran.data[m_m] = -s; U_tran.data[m_m+1] = c; } private void applyLaterGivens() { for( int row = 1; row < n; row++ ) { // first compute the rotation double c,s; double xi = r_row[row]; double xj = R.data[n*row+row]; double r = xi*xi + xj*xj; if( r != 0 ) { r = Math.sqrt(r); c = xi/r; s = xj/r; } else { c = 1; s = 0; } // update R matrix R.data[n*row+row] = r; for( int col = row+1; col < n; col++ ) { double vali = r_row[col]; double valj = R.data[n*row+col]; R.data[n*row+col] = c*vali + s*valj; r_row[col] = c*valj - s*vali; } // compute U^T = U^T_(x+1) * U^T_x for( int col = 0; col <= row+1; col++ ) { double q1 = U_tran.data[row*m_m+col]; double q2 = U_tran.data[(row+1)*m_m+col]; U_tran.data[row*m_m+col] = c*q1 + s*q2; U_tran.data[(row+1)*m_m+col] = c*q2 - s*q1; } } } private void computeRemoveGivens( int selectedRow ) { CommonOps.setIdentity(U_tran); double xj = Q.data[selectedRow*m+m-1]; for( int j = m-2; j >= 0; j-- ) { // first compute the rotation double c,s; double xi = Q.data[selectedRow*m+j]; double r = xi*xi + xj*xj; if( r != 0 ) { r = Math.sqrt(r); c = xi/r; s = xj/r; } else { c = 1; s = 0; } // in the next iteration xj is r xj = r; // compute U^T = U^T_(x+1) * U^T_x for( int col = j; col < m; col++ ) { double q1 = U_tran.data[j*m+col]; double q2 = U_tran.data[(j+1)*m+col]; U_tran.data[j*m+col] = c*q1 + s*q2; U_tran.data[(j+1)*m+col] = c*q2 - s*q1; } } } public DenseMatrix64F getU_tran() { return U_tran; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/svd/000077500000000000000000000000001256171534400244145ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/svd/SafeSvd.java000066400000000000000000000047641256171534400266250ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.SingularValueDecomposition; /** * Wraps around a {@link SingularValueDecomposition} and ensures that the input is not modified. * * @author Peter Abeles */ public class SafeSvd implements SingularValueDecomposition { // the decomposition algorithm SingularValueDecomposition alg; // storage for the input if it would be modified DenseMatrix64F work = new DenseMatrix64F(1,1); public SafeSvd(SingularValueDecomposition alg) { this.alg = alg; } @Override public double[] getSingularValues() { return alg.getSingularValues(); } @Override public int numberOfSingularValues() { return alg.numberOfSingularValues(); } @Override public boolean isCompact() { return alg.isCompact(); } @Override public DenseMatrix64F getU(DenseMatrix64F U, boolean transposed) { return alg.getU(U,transposed); } @Override public DenseMatrix64F getV(DenseMatrix64F V, boolean transposed) { return alg.getV(V,transposed); } @Override public DenseMatrix64F getW(DenseMatrix64F W) { return alg.getW(W); } @Override public int numRows() { return alg.numRows(); } @Override public int numCols() { return alg.numCols(); } @Override public boolean decompose(DenseMatrix64F orig) { if( alg.inputModified() ) { work.reshape(orig.numRows,orig.numCols); work.set(orig); return alg.decompose(work); } else { return alg.decompose(orig); } } @Override public boolean inputModified() { return false; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/svd/SvdImplicitQrDecompose_D64.java000066400000000000000000000247421256171534400322760ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.alg.dense.decomposition.bidiagonal.BidiagonalDecompositionRow_D64; import org.ejml.alg.dense.decomposition.bidiagonal.BidiagonalDecompositionTall_D64; import org.ejml.alg.dense.decomposition.svd.implicitqr.SvdImplicitQrAlgorithm; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.BidiagonalDecomposition; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.CommonOps; /** *

* Computes the Singular value decomposition of a matrix using the implicit QR algorithm * for singular value decomposition. It works by first by transforming the matrix * to a bidiagonal A=U*B*VT form, then it implicitly computing the eigenvalues of the BTB matrix, * which are the same as the singular values in the original A matrix. *

* *

* Based off of the description provided in:
*
* David S. Watkins, "Fundamentals of Matrix Computations," Second Edition. Page 404-411 *

* * @author Peter Abeles */ public class SvdImplicitQrDecompose_D64 implements SingularValueDecomposition { private int numRows; private int numCols; // dimensions of transposed matrix private int numRowsT; private int numColsT; // if true then it can use the special Bidiagonal decomposition private boolean canUseTallBidiagonal; // If U is not being computed and the input matrix is 'tall' then a special bidiagonal decomposition // can be used which is faster. private BidiagonalDecomposition bidiag; private SvdImplicitQrAlgorithm qralg = new SvdImplicitQrAlgorithm(); double diag[]; double off[]; private DenseMatrix64F Ut; private DenseMatrix64F Vt; private double singularValues[]; private int numSingular; // compute a compact SVD private boolean compact; // What is actually computed private boolean computeU; private boolean computeV; // What the user requested to be computed // If the transpose is computed instead then what is actually computed is swapped private boolean prefComputeU; private boolean prefComputeV; // Should it compute the transpose instead private boolean transposed; // Either a copy of the input matrix or a copy of it transposed private DenseMatrix64F A_mod = new DenseMatrix64F(1,1); /** * Configures the class * * @param compact Compute a compact SVD * @param computeU If true it will compute the U matrix * @param computeV If true it will compute the V matrix * @param canUseTallBidiagonal If true then it can choose to use a tall Bidiagonal decomposition to improve runtime performance. */ public SvdImplicitQrDecompose_D64(boolean compact, boolean computeU, boolean computeV, boolean canUseTallBidiagonal) { this.compact = compact; this.prefComputeU = computeU; this.prefComputeV = computeV; this.canUseTallBidiagonal = canUseTallBidiagonal; } @Override public double[] getSingularValues() { return singularValues; } @Override public int numberOfSingularValues() { return numSingular; } @Override public boolean isCompact() { return compact; } @Override public DenseMatrix64F getU( DenseMatrix64F U , boolean transpose) { if( !prefComputeU ) throw new IllegalArgumentException("As requested U was not computed."); if( transpose ) { if( U == null ) return Ut; else if( U.numRows != Ut.numRows || U.numCols != Ut.numCols ) throw new IllegalArgumentException("Unexpected shape of U"); U.set(Ut); } else { if( U == null ) U = new DenseMatrix64F(Ut.numCols,Ut.numRows); else if( U.numRows != Ut.numCols || U.numCols != Ut.numRows ) throw new IllegalArgumentException("Unexpected shape of U"); CommonOps.transpose(Ut,U); } return U; } @Override public DenseMatrix64F getV( DenseMatrix64F V , boolean transpose ) { if( !prefComputeV ) throw new IllegalArgumentException("As requested V was not computed."); if( transpose ) { if( V == null ) return Vt; else if( V.numRows != Vt.numRows || V.numCols != Vt.numCols ) throw new IllegalArgumentException("Unexpected shape of V"); V.set(Vt); } else { if( V == null ) V = new DenseMatrix64F(Vt.numCols,Vt.numRows); else if( V.numRows != Vt.numCols || V.numCols != Vt.numRows ) throw new IllegalArgumentException("Unexpected shape of V"); CommonOps.transpose(Vt,V); } return V; } @Override public DenseMatrix64F getW( DenseMatrix64F W ) { int m = compact ? numSingular : numRows; int n = compact ? numSingular : numCols; if( W == null ) W = new DenseMatrix64F(m,n); else { W.reshape(m,n, false); W.zero(); } for( int i = 0; i < numSingular; i++ ) { W.unsafe_set(i,i, singularValues[i]); } return W; } @Override public boolean decompose(DenseMatrix64F orig) { if( !setup(orig) ) return false; if (bidiagonalization(orig)) return false; if( computeUWV() ) return false; // make sure all the singular values or positive makeSingularPositive(); // if transposed undo the transposition undoTranspose(); return true; } @Override public boolean inputModified() { return false; } private boolean bidiagonalization(DenseMatrix64F orig) { // change the matrix to bidiagonal form if( transposed ) { A_mod.reshape(orig.numCols,orig.numRows,false); CommonOps.transpose(orig,A_mod); } else { A_mod.reshape(orig.numRows,orig.numCols,false); A_mod.set(orig); } return !bidiag.decompose(A_mod); } /** * If the transpose was computed instead do some additional computations */ private void undoTranspose() { if( transposed ) { DenseMatrix64F temp = Vt; Vt = Ut; Ut = temp; } } /** * Compute singular values and U and V at the same time */ private boolean computeUWV() { bidiag.getDiagonal(diag,off); qralg.setMatrix(numRowsT,numColsT,diag,off); // long pointA = System.currentTimeMillis(); // compute U and V matrices if( computeU ) Ut = bidiag.getU(Ut,true,compact); if( computeV ) Vt = bidiag.getV(Vt,true,compact); qralg.setFastValues(false); if( computeU ) qralg.setUt(Ut); else qralg.setUt(null); if( computeV ) qralg.setVt(Vt); else qralg.setVt(null); // long pointB = System.currentTimeMillis(); boolean ret = !qralg.process(); // long pointC = System.currentTimeMillis(); // System.out.println(" compute UV "+(pointB-pointA)+" QR = "+(pointC-pointB)); return ret; } private boolean setup(DenseMatrix64F orig) { transposed = orig.numCols > orig.numRows; // flag what should be computed and what should not be computed if( transposed ) { computeU = prefComputeV; computeV = prefComputeU; numRowsT = orig.numCols; numColsT = orig.numRows; } else { computeU = prefComputeU; computeV = prefComputeV; numRowsT = orig.numRows; numColsT = orig.numCols; } numRows = orig.numRows; numCols = orig.numCols; if( numRows == 0 || numCols == 0 ) return false; if( diag == null || diag.length < numColsT ) { diag = new double[ numColsT ]; off = new double[ numColsT-1 ]; } // if it is a tall matrix and U is not needed then there is faster decomposition algorithm if( canUseTallBidiagonal && numRows > numCols * 2 && !computeU ) { if( bidiag == null || !(bidiag instanceof BidiagonalDecompositionTall_D64) ) { bidiag = new BidiagonalDecompositionTall_D64(); } } else if( bidiag == null || !(bidiag instanceof BidiagonalDecompositionRow_D64) ) { bidiag = new BidiagonalDecompositionRow_D64(); } return true; } /** * With the QR algorithm it is possible for the found singular values to be negative. This * makes them all positive by multiplying it by a diagonal matrix that has */ private void makeSingularPositive() { numSingular = qralg.getNumberOfSingularValues(); singularValues = qralg.getSingularValues(); for( int i = 0; i < numSingular; i++ ) { double val = qralg.getSingularValue(i); if( val < 0 ) { singularValues[i] = 0.0d - val; if( computeU ) { // compute the results of multiplying it by an element of -1 at this location in // a diagonal matrix. int start = i* Ut.numCols; int stop = start+ Ut.numCols; for( int j = start; j < stop; j++ ) { Ut.set(j, 0.0d - Ut.get(j)); } } } else { singularValues[i] = val; } } } @Override public int numRows() { return numRows; } @Override public int numCols() { return numCols; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/svd/implicitqr/000077500000000000000000000000001256171534400265715ustar00rootroot00000000000000SvdImplicitQrAlgorithm.java000066400000000000000000000551571256171534400337730ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/decomposition/svd/implicitqr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd.implicitqr; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.eig.EigenvalueSmall; import org.ejml.data.DenseMatrix64F; import java.util.Random; /** *

* Computes the QR decomposition of a bidiagonal matrix. Internally this matrix is stored as * two arrays. Shifts can either be provided to it or it can generate the shifts on its own. * It optionally computes the U and V matrices. This comparability allows it to be used to * compute singular values and associated matrices efficiently.
*
* A = U*S*VT
* where A is the original m by n matrix. *

* *

* Based off of the outline provided in:
*
* David S. Watkins, "Fundamentals of Matrix Computations," Second Edition. Page 404-411 *

* *

* Note: To watch it process the matrix step by step uncomment commented out code. *

* * @author Peter Abeles */ public class SvdImplicitQrAlgorithm { // used in exceptional shifts protected Random rand = new Random(0x34671e); // U and V matrices in singular value decomposition. Stored in the transpose // to reduce cache jumps protected DenseMatrix64F Ut; protected DenseMatrix64F Vt; // number of times it has performed an implicit step, the most costly part of the // algorithm protected int totalSteps; // max value in original matrix. used to test for zeros protected double maxValue; // matrix's size protected int N; // used to compute eigenvalues directly protected EigenvalueSmall eigenSmall = new EigenvalueSmall(); // how many exception shifts has it performed protected int numExceptional; // the step number of the last exception shift protected int nextExceptional; // diagonal elements in the matrix protected double diag[]; // the off diagonal elements protected double off[]; // value of the bulge double bulge; // the submatrix its working on protected int x1; protected int x2; // how many cycles has it run through looking for the current singular value int steps; // where splits are performed protected int splits[]; protected int numSplits; // After this many iterations it will perform an exceptional private int exceptionalThresh = 15; private int maxIterations = exceptionalThresh*100; // should the steps use a sequence of predefined lambdas? boolean followScript; // --------- variables for scripted step // if following a sequence of steps, this is the point at which it decides its // going no where and needs to use a different step private static final int giveUpOnKnown = 10; private double values[]; //can it compute singularvalues directly private boolean fastValues = false; // if not in scripted mode is it looking for new zeros first? private boolean findingZeros; double c,s; // for debugging // SimpleMatrix B; public SvdImplicitQrAlgorithm( boolean fastValues ) { this.fastValues = fastValues; } public SvdImplicitQrAlgorithm() { } public DenseMatrix64F getUt() { return Ut; } public void setUt(DenseMatrix64F ut) { Ut = ut; } public DenseMatrix64F getVt() { return Vt; } public void setVt(DenseMatrix64F vt) { Vt = vt; } /** * */ public void setMatrix( int numRows , int numCols, double diag[], double off[] ) { initParam(numRows,numCols); this.diag = diag; this.off = off; maxValue = Math.abs(diag[0]); for( int i = 1; i < N; i++ ) { double a = Math.abs(diag[i]); double b = Math.abs(off[i-1]); if( a > maxValue ) { maxValue = Math.abs(a); } if( b > maxValue ) { maxValue = Math.abs(b); } } } public double[] swapDiag( double diag[] ) { double[] ret = this.diag; this.diag = diag; return ret; } public double[] swapOff( double off[] ) { double[] ret = this.off; this.off = off; return ret; } public void setMaxValue(double maxValue) { this.maxValue = maxValue; } public void initParam( int M , int N ) { if( N > M ) throw new RuntimeException("Must be a square or tall matrix"); this.N = N; if( splits == null || splits.length < N ) { splits = new int[N]; } x1 = 0; x2 = this.N-1; steps = 0; totalSteps = 0; numSplits = 0; numExceptional = 0; nextExceptional = exceptionalThresh; } public boolean process() { this.followScript = false; findingZeros = true; return _process(); } /** * Perform a sequence of steps based off of the singular values provided. * * @param values * @return */ public boolean process(double values[] ) { this.followScript = true; this.values = values; this.findingZeros = false; return _process(); } public boolean _process() { // it is a zero matrix if( maxValue == 0 ) return true; while( x2 >= 0 ) { // if it has cycled too many times give up if( steps > maxIterations ) { return false; } if( x1 == x2 ) { // System.out.println("steps = "+steps+" script = "+followScript+" at "+x1); // System.out.println("Split"); // see if it is done processing this submatrix resetSteps(); if( !nextSplit() ) break; } else if( fastValues && x2-x1 == 1 ) { // There are analytical solutions to this case. Just compute them directly. resetSteps(); eigenBB_2x2(x1); setSubmatrix(x2,x2); } else if( steps >= nextExceptional ){ exceptionShift(); } else { // perform a step if (!checkForAndHandleZeros()) { if( followScript ) { performScriptedStep(); } else { performDynamicStep(); } } } // printMatrix(); } return true; } /** * Here the lambda in the implicit step is determined dynamically. At first * it selects zeros to quickly reveal singular values that are zero or close to zero. * Then it computes it using a Wilkinson shift. */ private void performDynamicStep() { // initially look for singular values of zero if( findingZeros ) { if( steps > 6 ) { findingZeros = false; } else { double scale = computeBulgeScale(); performImplicitSingleStep(scale,0,false); } } else { // For very large and very small numbers the only way to prevent overflow/underflow // is to have a common scale between the wilkinson shift and the implicit single step // What happens if you don't is that when the wilkinson shift returns the value it // computed it multiplies it by the scale twice, which will cause an overflow double scale = computeBulgeScale(); // use the wilkinson shift to perform a step double lambda = selectWilkinsonShift(scale); performImplicitSingleStep(scale,lambda,false); } } /** * Shifts are performed based upon singular values computed previously. If it does not converge * using one of those singular values it uses a Wilkinson shift instead. */ private void performScriptedStep() { double scale = computeBulgeScale(); if( steps > giveUpOnKnown ) { // give up on the script followScript = false; } else { // use previous singular value to step double s = values[x2]/scale; performImplicitSingleStep(scale,s*s,false); } } public void incrementSteps() { steps++; totalSteps++; } public boolean isOffZero(int i) { double bottom = Math.abs(diag[i])+Math.abs(diag[i+1]); return Math.abs(off[i]) <= bottom* UtilEjml.EPS; } public boolean isDiagonalZero(int i) { // return Math.abs(diag[i]) <= maxValue* UtilEjml.EPS; double bottom = Math.abs(diag[i+1])+Math.abs(off[i]); return Math.abs(diag[i]) <= bottom* UtilEjml.EPS; } public void resetSteps() { steps = 0; nextExceptional = exceptionalThresh; numExceptional = 0; } /** * Tells it to process the submatrix at the next split. Should be called after the * current submatrix has been processed. */ public boolean nextSplit() { if( numSplits == 0 ) return false; x2 = splits[--numSplits]; if( numSplits > 0 ) x1 = splits[numSplits-1]+1; else x1 = 0; return true; } /** * Given the lambda value perform an implicit QR step on the matrix. * * B^T*B-lambda*I * * @param lambda Stepping factor. */ public void performImplicitSingleStep(double scale , double lambda , boolean byAngle) { createBulge(x1,lambda,scale,byAngle); for( int i = x1; i < x2-1 && bulge != 0.0; i++ ) { removeBulgeLeft(i,true); if( bulge == 0 ) break; removeBulgeRight(i); } if( bulge != 0 ) removeBulgeLeft(x2-1,false); incrementSteps(); } /** * Multiplied a transpose orthogonal matrix Q by the specified rotator. This is used * to update the U and V matrices. Updating the transpose of the matrix is faster * since it only modifies the rows. * * * @param Q Orthogonal matrix * @param m Coordinate of rotator. * @param n Coordinate of rotator. * @param c cosine of rotator. * @param s sine of rotator. */ protected void updateRotator( DenseMatrix64F Q , int m, int n, double c, double s) { int rowA = m*Q.numCols; int rowB = n*Q.numCols; // for( int i = 0; i < Q.numCols; i++ ) { // double a = Q.get(rowA+i); // double b = Q.get(rowB+i); // Q.set( rowA+i, c*a + s*b); // Q.set( rowB+i, -s*a + c*b); // } // System.out.println("------ AFter Update Rotator "+m+" "+n); // Q.print(); // System.out.println(); int endA = rowA + Q.numCols; for( ; rowA != endA; rowA++ , rowB++ ) { double a = Q.get(rowA); double b = Q.get(rowB); Q.set(rowA, c*a + s*b); Q.set(rowB, -s*a + c*b); } } private double computeBulgeScale() { double b11 = diag[x1]; double b12 = off[x1]; return Math.max( Math.abs(b11) , Math.abs(b12)); // // double b22 = diag[x1+1]; // // double scale = Math.max( Math.abs(b11) , Math.abs(b12)); // // return Math.max(scale,Math.abs(b22)); } /** * Performs a similar transform on BTB-pI */ protected void createBulge( int x1 , double p , double scale , boolean byAngle ) { double b11 = diag[x1]; double b12 = off[x1]; double b22 = diag[x1+1]; if( byAngle ) { c = Math.cos(p); s = Math.sin(p); } else { // normalize to improve resistance to overflow/underflow double u1 = (b11/scale)*(b11/scale)-p; double u2 = (b12/scale)*(b11/scale); double gamma = Math.sqrt(u1*u1 + u2*u2); c = u1/gamma; s = u2/gamma; } // multiply the rotator on the top left. diag[x1] = b11*c + b12*s; off[x1] = b12*c - b11*s; diag[x1+1] = b22*c; bulge = b22*s; // SimpleMatrix Q = createQ(x1, c, s, false); // B=B.mult(Q); // // B.print(); // printMatrix(); // System.out.println(" bulge = "+bulge); if( Vt != null ) { updateRotator(Vt,x1,x1+1,c,s); // SimpleMatrix.wrap(Ut).mult(B).mult(SimpleMatrix.wrap(Vt).transpose()).print(); // printMatrix(); // System.out.println("bulge = "+bulge); // System.out.println(); } } /** * Computes a rotator that will set run to zero (?) */ protected void computeRotator( double rise , double run ) { // double gamma = Math.sqrt(rise*rise + run*run); // // c = rise/gamma; // s = run/gamma; // See page 384 of Fundamentals of Matrix Computations 2nd if( Math.abs(rise) < Math.abs(run)) { double k = rise/run; double bottom = Math.sqrt(1.0d+k*k); s = 1.0/bottom; c = k/bottom; } else { double t = run/rise; double bottom = Math.sqrt(1.0d + t*t); c = 1.0/bottom; s = t/bottom; } } protected void removeBulgeLeft( int x1 , boolean notLast ) { double b11 = diag[x1]; double b12 = off[x1]; double b22 = diag[x1+1]; computeRotator(b11,bulge); // apply rotator on the left diag[x1] = c*b11 + s*bulge; off[x1] = c*b12 + s*b22; diag[x1+1] = c*b22-s*b12; if( notLast ) { double b23 = off[x1+1]; bulge = s*b23; off[x1+1] = c*b23; } // SimpleMatrix Q = createQ(x1, c, s, true); // B=Q.mult(B); // // B.print(); // printMatrix(); // System.out.println(" bulge = "+bulge); if( Ut != null ) { updateRotator(Ut,x1,x1+1,c,s); // SimpleMatrix.wrap(Ut).mult(B).mult(SimpleMatrix.wrap(Vt).transpose()).print(); // printMatrix(); // System.out.println("bulge = "+bulge); // System.out.println(); } } protected void removeBulgeRight( int x1 ) { double b12 = off[x1]; double b22 = diag[x1+1]; double b23 = off[x1+1]; computeRotator(b12,bulge); // apply rotator on the right off[x1] = b12*c + bulge*s; diag[x1+1] = b22*c + b23*s; off[x1+1] = -b22*s + b23*c; double b33 = diag[x1+2]; diag[x1+2] = b33*c; bulge = b33*s; // SimpleMatrix Q = createQ(x1+1, c, s, false); // B=B.mult(Q); // // B.print(); // printMatrix(); // System.out.println(" bulge = "+bulge); if( Vt != null ) { updateRotator(Vt,x1+1,x1+2,c,s); // SimpleMatrix.wrap(Ut).mult(B).mult(SimpleMatrix.wrap(Vt).transpose()).print(); // printMatrix(); // System.out.println("bulge = "+bulge); // System.out.println(); } } public void setSubmatrix(int x1, int x2) { this.x1 = x1; this.x2 = x2; } /** * Selects the Wilkinson's shift for BTB. See page 410. It is guaranteed to converge * and converges fast in practice. * * @param scale Scale factor used to help prevent overflow/underflow * @return Shifting factor lambda/(scale*scale) */ public double selectWilkinsonShift( double scale ) { double a11,a22; if( x2-x1 > 1 ) { double d1 = diag[x2-1] / scale; double o1 = off[x2-2] / scale; double d2 = diag[x2] / scale; double o2 = off[x2-1] / scale; a11 = o1*o1 + d1*d1; a22 = o2*o2 + d2*d2; eigenSmall.symm2x2_fast(a11 , o2*d1 , a22); } else { double a = diag[x2-1]/scale; double b = off[x2-1]/scale; double c = diag[x2]/scale; a11 = a*a; a22 = b*b + c*c; eigenSmall.symm2x2_fast(a11, a*b , a22); } // return the eigenvalue closest to a22 double diff0 = Math.abs(eigenSmall.value0.real-a22); double diff1 = Math.abs(eigenSmall.value1.real-a22); return diff0 < diff1 ? eigenSmall.value0.real : eigenSmall.value1.real; } /** * Computes the eigenvalue of the 2 by 2 matrix BTB */ protected void eigenBB_2x2( int x1 ) { double b11 = diag[x1]; double b12 = off[x1]; double b22 = diag[x1+1]; // normalize to reduce overflow double absA = Math.abs(b11); double absB = Math.abs(b12); double absC = Math.abs(b22); double scale = absA > absB ? absA : absB; if( absC > scale ) scale = absC; // see if it is a pathological case. the diagonal must already be zero // and the eigenvalues are all zero. so just return if( scale == 0 ) return; b11 /= scale; b12 /= scale; b22 /= scale; eigenSmall.symm2x2_fast(b11*b11, b11*b12 , b12*b12+b22*b22); off[x1] = 0; diag[x1] = scale*Math.sqrt(eigenSmall.value0.real); double sgn = Math.signum(eigenSmall.value1.real); diag[x1+1] = sgn*scale*Math.sqrt(Math.abs(eigenSmall.value1.real)); } /** * Checks to see if either the diagonal element or off diagonal element is zero. If one is * then it performs a split or pushes it off the matrix. * * @return True if there was a zero. */ protected boolean checkForAndHandleZeros() { // check for zeros along off diagonal for( int i = x2-1; i >= x1; i-- ) { if( isOffZero(i) ) { // System.out.println("steps at split = "+steps); resetSteps(); splits[numSplits++] = i; x1 = i+1; return true; } } // check for zeros along diagonal for( int i = x2-1; i >= x1; i-- ) { if( isDiagonalZero(i)) { // System.out.println("steps at split = "+steps); pushRight(i); resetSteps(); splits[numSplits++] = i; x1 = i+1; return true; } } return false; } /** * If there is a zero on the diagonal element, the off diagonal element needs pushed * off so that all the algorithms assumptions are two and so that it can split the matrix. */ private void pushRight( int row ) { if( isOffZero(row)) return; // B = createB(); // B.print(); rotatorPushRight(row); int end = N-2-row; for( int i = 0; i < end && bulge != 0; i++ ) { rotatorPushRight2(row,i+2); } // } } /** * Start pushing the element off to the right. */ private void rotatorPushRight( int m ) { double b11 = off[m]; double b21 = diag[m+1]; computeRotator(b21,-b11); // apply rotator on the right off[m] = 0; diag[m+1] = b21*c-b11*s; if( m+2 < N) { double b22 = off[m+1]; off[m+1] = b22*c; bulge = b22*s; } else { bulge = 0; } // SimpleMatrix Q = createQ(m,m+1, c, s, true); // B=Q.mult(B); // // B.print(); // printMatrix(); // System.out.println(" bulge = "+bulge); // System.out.println(); if( Ut != null ) { updateRotator(Ut,m,m+1,c,s); // SimpleMatrix.wrap(Ut).mult(B).mult(SimpleMatrix.wrap(Vt).transpose()).print(); // printMatrix(); // System.out.println("bulge = "+bulge); // System.out.println(); } } /** * Used to finish up pushing the bulge off the matrix. */ private void rotatorPushRight2( int m , int offset) { double b11 = bulge; double b12 = diag[m+offset]; computeRotator(b12,-b11); diag[m+offset] = b12*c-b11*s; if( m+offset { /** * Adds a row to A. This has the same effect as creating a new A and calling {@link #setA}. * * @param A_row The row in A. * @param rowIndex Where the row appears in A. * @return if it succeeded or not. */ public boolean addRowToA( double []A_row , int rowIndex ); /** * Removes a row from A. This has the same effect as creating a new A and calling {@link #setA}. * * @param index which row is removed from A. * @return If it succeeded or not. */ public boolean removeRowFromA( int index ); } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/InvertUsingSolve.java000066400000000000000000000036111256171534400263760ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; /** * A matrix can be easily inverted by solving a system with an identify matrix. The only * disadvantage of this approach is that additional computations are required compared to * a specialized solution. * * @author Peter Abeles */ public class InvertUsingSolve { public static void invert( LinearSolver solver , RowD1Matrix64F A , DenseMatrix64F A_inv , DenseMatrix64F storage) { if( A.numRows != A_inv.numRows || A.numCols != A_inv.numCols) { throw new IllegalArgumentException("A and A_inv must have the same dimensions"); } CommonOps.setIdentity(storage); solver.solve(storage,A_inv); } public static void invert( LinearSolver solver , RowD1Matrix64F A , DenseMatrix64F A_inv ) { if( A.numRows != A_inv.numRows || A.numCols != A_inv.numCols) { throw new IllegalArgumentException("A and A_inv must have the same dimensions"); } CommonOps.setIdentity(A_inv); solver.solve(A_inv,A_inv); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/LinearSolverAbstract_D64.java000066400000000000000000000031721256171534400276200ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** *

* An abstract class that provides some common functionality and a default implementation * of invert that uses the solve function of the child class. *

* *

* The extending class must explicity call {@link #_setA(org.ejml.data.DenseMatrix64F)} * inside of its {@link #setA} function. *

* * @author Peter Abeles */ public abstract class LinearSolverAbstract_D64 implements LinearSolver { protected DenseMatrix64F A; protected int numRows; protected int numCols; public DenseMatrix64F getA() { return A; } protected void _setA(DenseMatrix64F A) { this.A = A; this.numRows = A.numRows; this.numCols = A.numCols; } @Override public void invert(DenseMatrix64F A_inv) { InvertUsingSolve.invert(this,A,A_inv); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/LinearSolverUnrolled.java000066400000000000000000000041701256171534400272230ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.misc.UnrolledInverseFromMinor; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.ejml.interfaces.linsol.LinearSolver; /** * Solver which uses an unrolled inverse to compute the inverse. This can only invert matrices and not solve. * This is faster than LU inverse but only supports small matrices.. * * @author Peter Abeles */ public class LinearSolverUnrolled implements LinearSolver { DenseMatrix64F A; @Override public boolean setA(DenseMatrix64F A) { if( A.numRows != A.numCols) return false; this.A = A; return A.numRows <= UnrolledInverseFromMinor.MAX; } @Override public double quality() { throw new IllegalArgumentException("Not supported by this solver."); } @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { throw new RuntimeException("Not supported"); } @Override public void invert(DenseMatrix64F A_inv) { if( A.numRows == 1 ) A_inv.set(0, 1.0/A.get(0)); UnrolledInverseFromMinor.inv(A,A_inv); } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public D getDecomposition() { return null; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/LinearSolver_B64_to_D64.java000066400000000000000000000073231256171534400272530ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.linsol.chol.BlockCholeskyOuterSolver; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.ejml.interfaces.linsol.LinearSolver; /** * Wrapper that allows {@link org.ejml.interfaces.linsol.LinearSolver } to implements {@link org.ejml.interfaces.linsol.LinearSolver}. It works * by converting {@link DenseMatrix64F} into {@link BlockMatrix64F} and calling the equivalent * functions. Since a local copy is made all input matrices are never modified. * * @author Peter Abeles */ public class LinearSolver_B64_to_D64 implements LinearSolver { protected LinearSolver alg = new BlockCholeskyOuterSolver(); // block matrix copy of the system A matrix. protected BlockMatrix64F blockA = new BlockMatrix64F(1,1); // block matrix copy of B matrix passed into solve protected BlockMatrix64F blockB = new BlockMatrix64F(1,1); // block matrix copy of X matrix passed into solve protected BlockMatrix64F blockX = new BlockMatrix64F(1,1); public LinearSolver_B64_to_D64(LinearSolver alg) { this.alg = alg; } /** * Converts 'A' into a block matrix and call setA() on the block matrix solver. * * @param A The A matrix in the linear equation. Not modified. Reference saved. * @return true if it can solve the system. */ @Override public boolean setA(DenseMatrix64F A) { blockA.reshape(A.numRows,A.numCols,false); BlockMatrixOps.convert(A,blockA); return alg.setA(blockA); } @Override public double quality() { return alg.quality(); } /** * Converts B and X into block matrices and calls the block matrix solve routine. * * @param B A matrix ℜ m × p. Not modified. * @param X A matrix ℜ n × p, where the solution is written to. Modified. */ @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { blockB.reshape(B.numRows,B.numCols,false); blockX.reshape(X.numRows,X.numCols,false); BlockMatrixOps.convert(B,blockB); alg.solve(blockB,blockX); BlockMatrixOps.convert(blockX,X); } /** * Creates a block matrix the same size as A_inv, inverts the matrix and copies the results back * onto A_inv. * * @param A_inv Where the inverted matrix saved. Modified. */ @Override public void invert(DenseMatrix64F A_inv) { blockB.reshape(A_inv.numRows,A_inv.numCols,false); alg.invert(blockB); BlockMatrixOps.convert(blockB,A_inv); } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public D getDecomposition() { return alg.getDecomposition(); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/chol/000077500000000000000000000000001256171534400231715ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/chol/LinearSolverCholLDL_D64.java000066400000000000000000000116061256171534400302240ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionLDL_D64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyLDLDecomposition; import org.ejml.ops.SpecializedOps; /** * @author Peter Abeles */ public class LinearSolverCholLDL_D64 extends LinearSolverAbstract_D64 { private CholeskyDecompositionLDL_D64 decomposer; private int n; private double vv[]; private double el[]; private double d[]; public LinearSolverCholLDL_D64(CholeskyDecompositionLDL_D64 decomposer) { this.decomposer = decomposer; } public LinearSolverCholLDL_D64() { this.decomposer = new CholeskyDecompositionLDL_D64(); } @Override public boolean setA(DenseMatrix64F A) { _setA(A); if( decomposer.decompose(A) ){ n = A.numCols; vv = decomposer._getVV(); el = decomposer.getL().data; d = decomposer.getDiagonal(); return true; } else { return false; } } @Override public double quality() { return Math.abs(SpecializedOps.diagProd(decomposer.getL())); } /** *

* Using the decomposition, finds the value of 'X' in the linear equation below:
* * A*x = b
* * where A has dimension of n by n, x and b are n by m dimension. *

*

* *Note* that 'b' and 'x' can be the same matrix instance. *

* * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is writen to. Modified. */ @Override public void solve( DenseMatrix64F B , DenseMatrix64F X ) { if( B.numCols != X.numCols && B.numRows != n && X.numRows != n) { throw new IllegalArgumentException("Unexpected matrix size"); } int numCols = B.numCols; double dataB[] = B.data; double dataX[] = X.data; for( int j = 0; j < numCols; j++ ) { for( int i = 0; i < n; i++ ) vv[i] = dataB[i*numCols+j]; solveInternal(); for( int i = 0; i < n; i++ ) dataX[i*numCols+j] = vv[i]; } } /** * Used internally to find the solution to a single column vector. */ private void solveInternal() { // solve L*s=b storing y in x TriangularSolver.solveL(el,vv,n); // solve D*y=s for( int i = 0; i < n; i++ ) { vv[i] /= d[i]; } // solve L^T*x=y TriangularSolver.solveTranL(el,vv,n); } /** * Sets the matrix 'inv' equal to the inverse of the matrix that was decomposed. * * @param inv Where the value of the inverse will be stored. Modified. */ @Override public void invert( DenseMatrix64F inv ) { if( inv.numRows != n || inv.numCols != n ) { throw new RuntimeException("Unexpected matrix dimension"); } double a[] = inv.data; // solve L*z = b for( int i =0; i < n; i++ ) { for( int j = 0; j <= i; j++ ) { double sum = (i==j) ? 1.0 : 0.0; for( int k=i-1; k >=j; k-- ) { sum -= el[i*n+k]*a[j*n+k]; } a[j*n+i] = sum; } } // solve D*y=z for( int i =0; i < n; i++ ) { double inv_d = 1.0/d[i]; for( int j = 0; j <= i; j++ ) { a[j*n+i] *= inv_d; } } // solve L^T*x = y for( int i=n-1; i>=0; i-- ) { for( int j = 0; j <= i; j++ ) { double sum = (i getDecomposition() { return decomposer; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/chol/LinearSolverChol_B64.java000066400000000000000000000036341256171534400276700ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.linsol.chol.BlockCholeskyOuterSolver; import org.ejml.alg.dense.linsol.LinearSolver_B64_to_D64; import org.ejml.data.DenseMatrix64F; /** * A wrapper around {@link org.ejml.interfaces.decomposition.CholeskyDecomposition}(BlockMatrix64F) that allows * it to be easily used with {@link org.ejml.data.DenseMatrix64F}. * * @author Peter Abeles */ public class LinearSolverChol_B64 extends LinearSolver_B64_to_D64 { public LinearSolverChol_B64() { super(new BlockCholeskyOuterSolver()); } /** * Only converts the B matrix and passes that onto solve. Te result is then copied into * the input 'X' matrix. * * @param B A matrix ℜ m × p. Not modified. * @param X A matrix ℜ n × p, where the solution is written to. Modified. */ @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { blockB.reshape(B.numRows,B.numCols,false); BlockMatrixOps.convert(B,blockB); // since overwrite B is true X does not need to be passed in alg.solve(blockB,null); BlockMatrixOps.convert(blockB,X); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/chol/LinearSolverChol_D64.java000066400000000000000000000126131256171534400276670ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionCommon_D64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.ops.SpecializedOps; /** * @author Peter Abeles */ public class LinearSolverChol_D64 extends LinearSolverAbstract_D64 { CholeskyDecompositionCommon_D64 decomposer; int n; double vv[]; double t[]; public LinearSolverChol_D64(CholeskyDecompositionCommon_D64 decomposer) { this.decomposer = decomposer; } @Override public boolean setA(DenseMatrix64F A) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("Matrix must be square"); _setA(A); if( decomposer.decompose(A) ){ n = A.numCols; vv = decomposer._getVV(); t = decomposer.getT().data; return true; } else { return false; } } @Override public double quality() { return SpecializedOps.qualityTriangular(decomposer.getT()); } /** *

* Using the decomposition, finds the value of 'X' in the linear equation below:
* * A*x = b
* * where A has dimension of n by n, x and b are n by m dimension. *

*

* *Note* that 'b' and 'x' can be the same matrix instance. *

* * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is writen to. Modified. */ @Override public void solve( DenseMatrix64F B , DenseMatrix64F X ) { if( B.numCols != X.numCols || B.numRows != n || X.numRows != n) { throw new IllegalArgumentException("Unexpected matrix size"); } int numCols = B.numCols; double dataB[] = B.data; double dataX[] = X.data; if(decomposer.isLower()) { for( int j = 0; j < numCols; j++ ) { for( int i = 0; i < n; i++ ) vv[i] = dataB[i*numCols+j]; solveInternalL(); for( int i = 0; i < n; i++ ) dataX[i*numCols+j] = vv[i]; } } else { throw new RuntimeException("Implement"); } } /** * Used internally to find the solution to a single column vector. */ private void solveInternalL() { // solve L*y=b storing y in x TriangularSolver.solveL(t,vv,n); // solve L^T*x=y TriangularSolver.solveTranL(t,vv,n); } /** * Sets the matrix 'inv' equal to the inverse of the matrix that was decomposed. * * @param inv Where the value of the inverse will be stored. Modified. */ @Override public void invert( DenseMatrix64F inv ) { if( inv.numRows != n || inv.numCols != n ) { throw new RuntimeException("Unexpected matrix dimension"); } if( inv.data == t ) { throw new IllegalArgumentException("Passing in the same matrix that was decomposed."); } double a[] = inv.data; if(decomposer.isLower()) { setToInverseL(a); } else { throw new RuntimeException("Implement"); } } /** * Sets the matrix to the inverse using a lower triangular matrix. */ public void setToInverseL( double a[] ) { // TODO reorder these operations to avoid cache misses // inverts the lower triangular system and saves the result // in the upper triangle to minimize cache misses for( int i =0; i < n; i++ ) { double el_ii = t[i*n+i]; for( int j = 0; j <= i; j++ ) { double sum = (i==j) ? 1.0 : 0; for( int k=i-1; k >=j; k-- ) { sum -= t[i*n+k]*a[j*n+k]; } a[j*n+i] = sum / el_ii; } } // solve the system and handle the previous solution being in the upper triangle // takes advantage of symmetry for( int i=n-1; i>=0; i-- ) { double el_ii = t[i*n+i]; for( int j = 0; j <= i; j++ ) { double sum = (i getDecomposition() { return decomposer; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/lu/000077500000000000000000000000001256171534400226645ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/lu/LinearSolverLuBase_D64.java000066400000000000000000000075541256171534400276600ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decomposition.lu.LUDecompositionBase_D64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.data.DenseMatrix64F; /** * @author Peter Abeles */ public abstract class LinearSolverLuBase_D64 extends LinearSolverAbstract_D64 { protected LUDecompositionBase_D64 decomp; public LinearSolverLuBase_D64(LUDecompositionBase_D64 decomp) { this.decomp = decomp; } @Override public boolean setA(DenseMatrix64F A) { _setA(A); return decomp.decompose(A); } @Override public double quality() { return decomp.quality(); } @Override public void invert(DenseMatrix64F A_inv) { double []vv = decomp._getVV(); DenseMatrix64F LU = decomp.getLU(); if( A_inv.numCols != LU.numCols || A_inv.numRows != LU.numRows ) throw new IllegalArgumentException("Unexpected matrix dimension"); int n = A.numCols; double dataInv[] = A_inv.data; for( int j = 0; j < n; j++ ) { // don't need to change inv into an identity matrix before hand for( int i = 0; i < n; i++ ) vv[i] = i == j ? 1 : 0; decomp._solveVectorInternal(vv); // for( int i = 0; i < n; i++ ) dataInv[i* n +j] = vv[i]; int index = j; for( int i = 0; i < n; i++ , index += n) dataInv[ index ] = vv[i]; } } /** * This attempts to improve upon the solution generated by account * for numerical imprecisions. See numerical recipes for more information. It * is assumed that solve has already been run on 'b' and 'x' at least once. * * @param b A matrix. Not modified. * @param x A matrix. Modified. */ public void improveSol( DenseMatrix64F b , DenseMatrix64F x ) { if( b.numCols != x.numCols ) { throw new IllegalArgumentException("bad shapes"); } double dataA[] = A.data; double dataB[] = b.data; double dataX[] = x.data; final int nc = b.numCols; final int n = b.numCols; double []vv = decomp._getVV(); // BigDecimal sdp = new BigDecimal(0); for( int k = 0; k < nc; k++ ) { for( int i = 0; i < n; i++ ) { // *NOTE* in the book this is a long double. extra precision might be required double sdp = -dataB[ i * nc + k]; // BigDecimal sdp = new BigDecimal(-dataB[ i * nc + k]); for( int j = 0; j < n; j++ ) { sdp += dataA[i* n +j] * dataX[ j * nc + k]; // sdp = sdp.add( BigDecimal.valueOf(dataA[i* n +j] * dataX[ j * nc + k])); } vv[i] = sdp; // vv[i] = sdp.doubleValue(); } decomp._solveVectorInternal(vv); for( int i = 0; i < n; i++ ) { dataX[i*nc + k] -= vv[i]; } } } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public LUDecompositionBase_D64 getDecomposition() { return decomp; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/lu/LinearSolverLuKJI_D64.java000066400000000000000000000063101256171534400274100ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decomposition.lu.LUDecompositionBase_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.SpecializedOps; /** * To avoid cpu cache issues the order in which the arrays are traversed have been changed. * There seems to be no performance benit relative to {@link LinearSolverLu_D64} in this approach * and b and x can't be the same instance, which means it has slightly less functionality. * * @author Peter Abeles */ public class LinearSolverLuKJI_D64 extends LinearSolverLuBase_D64 { private double []dataLU; private int[] pivot; public LinearSolverLuKJI_D64(LUDecompositionBase_D64 decomp) { super(decomp); } @Override public boolean setA(DenseMatrix64F A) { boolean ret = super.setA(A); pivot = decomp.getPivot(); dataLU = decomp.getLU().data; return ret; } /** * An other implementation of solve() that processes the matrices in a different order. * It seems to have the same runtime performance as {@link #solve} and is more complicated. * It is being kept around to avoid future replication of work. * * @param b A matrix that is n by m. Not modified. * @param x An n by m matrix where the solution is writen to. Modified. */ @Override public void solve(DenseMatrix64F b, DenseMatrix64F x) { if( b.numCols != x.numCols || b.numRows != numRows || x.numRows != numCols) { throw new IllegalArgumentException("Unexpected matrix size"); } if( b != x ) { SpecializedOps.copyChangeRow(pivot,b,x); } else { throw new IllegalArgumentException("Current doesn't support using the same matrix instance"); } // Copy right hand side with pivoting int nx = b.numCols; double[] dataX = x.data; // Solve L*Y = B(piv,:) for (int k = 0; k < numCols; k++) { for (int i = k+1; i < numCols; i++) { for (int j = 0; j < nx; j++) { dataX[i*nx+j] -= dataX[k*nx+j]*dataLU[i* numCols +k]; } } } // Solve U*X = Y; for (int k = numCols -1; k >= 0; k--) { for (int j = 0; j < nx; j++) { dataX[k*nx+j] /= dataLU[k* numCols +k]; } for (int i = 0; i < k; i++) { for (int j = 0; j < nx; j++) { dataX[i*nx+j] -= dataX[k*nx+j]*dataLU[i* numCols +k]; } } } } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/lu/LinearSolverLu_D64.java000066400000000000000000000046121256171534400270550ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decomposition.lu.LUDecompositionBase_D64; import org.ejml.data.DenseMatrix64F; /** * For each column in the B matrix it makes a copy, which is then solved for and * writen into X. By making a copy of the column cpu cache issues are reduced. * * @author Peter Abeles */ public class LinearSolverLu_D64 extends LinearSolverLuBase_D64 { boolean doImprove = false; public LinearSolverLu_D64(LUDecompositionBase_D64 decomp) { super(decomp); } public LinearSolverLu_D64(LUDecompositionBase_D64 decomp, boolean doImprove) { super(decomp); this.doImprove = doImprove; } @Override public void solve(DenseMatrix64F b, DenseMatrix64F x) { if( b.numCols != x.numCols || b.numRows != numRows || x.numRows != numCols) { throw new IllegalArgumentException("Unexpected matrix size"); } int numCols = b.numCols; double dataB[] = b.data; double dataX[] = x.data; double []vv = decomp._getVV(); // for( int j = 0; j < numCols; j++ ) { // for( int i = 0; i < this.numCols; i++ ) vv[i] = dataB[i*numCols+j]; // decomp._solveVectorInternal(vv); // for( int i = 0; i < this.numCols; i++ ) dataX[i*numCols+j] = vv[i]; // } for( int j = 0; j < numCols; j++ ) { int index = j; for( int i = 0; i < this.numCols; i++ , index += numCols ) vv[i] = dataB[index]; decomp._solveVectorInternal(vv); index = j; for( int i = 0; i < this.numCols; i++ , index += numCols ) dataX[index] = vv[i]; } if( doImprove ) { improveSol(b,x); } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/000077500000000000000000000000001256171534400226665ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/AdjLinearSolverQr_D64.java000066400000000000000000000052441256171534400275020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.decomposition.qr.QrUpdate; import org.ejml.alg.dense.linsol.AdjustableLinearSolver; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; /** * A solver for QR decomposition that can efficiently modify the previous decomposition when * data is added or removed. * * @author Peter Abeles */ public class AdjLinearSolverQr_D64 extends LinearSolverQr_D64 implements AdjustableLinearSolver { private QrUpdate update; private DenseMatrix64F A; public AdjLinearSolverQr_D64() { super( new QRDecompositionHouseholderColumn_D64() ); } @Override public void setMaxSize( int maxRows , int maxCols ) { // allow it some room to grow maxRows += 5; super.setMaxSize(maxRows,maxCols); update = new QrUpdate(maxRows,maxCols,true); A = new DenseMatrix64F(maxRows,maxCols); } /** * Compute the A matrix from the Q and R matrices. * * @return The A matrix. */ @Override public DenseMatrix64F getA() { if( A.data.length < numRows*numCols ) { A = new DenseMatrix64F(numRows,numCols); } A.reshape(numRows,numCols, false); CommonOps.mult(Q,R,A); return A; } @Override public boolean addRowToA(double[] A_row , int rowIndex ) { // see if it needs to grow the data structures if( numRows + 1 > maxRows) { // grow by 10% int grow = maxRows / 10; if( grow < 1 ) grow = 1; maxRows = numRows + grow; Q.reshape(maxRows,maxRows,true); R.reshape(maxRows,maxCols,true); } update.addRow(Q,R,A_row,rowIndex,true); numRows++; return true; } @Override public boolean removeRowFromA(int index) { update.deleteRow(Q,R,index,true); numRows--; return true; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/BaseLinearSolverQrp_D64.java000066400000000000000000000142131256171534400300320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.decomposition.QRPDecomposition; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.SpecializedOps; /** *

* Base class for QR pivot based pseudo inverse classes. It will return either the * basic of minimal 2-norm solution. See [1] for details. The minimal 2-norm solution refers to the solution * 'x' whose 2-norm is the smallest making it unique, not some other error function. *

* *

*

 * R = [ R12  R12 ] r      P^T*x = [ y ] r       Q^T*b = [ c ] r
 *     [  0    0  ] m-r            [ z ] n -r            [ d ] m-r
 *        r   n-r
 *
 * where r is the rank of the matrix and (m,n) is the dimension of the linear system.
 * 
*

* *

*

 * The solution 'x' is found by solving the system below.  The basic solution is found by setting z=0
 *
 *     [ R_11^-1*(c - R12*z) ]
 * x = [          z          ]
 * 
*

* *

* NOTE: The matrix rank is determined using the provided QR decomposition. [1] mentions that this will not always * work and could cause some problems. *

* *

* [1] See page 258-259 in Gene H. Golub and Charles F. Van Loan "Matrix Computations" 3rd Ed, 1996 *

* * @author Peter Abeles */ public abstract class BaseLinearSolverQrp_D64 extends LinearSolverAbstract_D64 { QRPDecomposition decomposition; // if true then only the basic solution will be found protected boolean norm2Solution; protected DenseMatrix64F Y = new DenseMatrix64F(1,1); protected DenseMatrix64F R = new DenseMatrix64F(1,1); // stores sub-matrices inside the R matrix protected DenseMatrix64F R11 = new DenseMatrix64F(1,1); // store an identity matrix for computing the inverse protected DenseMatrix64F I = new DenseMatrix64F(1,1); // rank of the system matrix protected int rank; protected LinearSolver internalSolver = LinearSolverFactory.leastSquares(1, 1); // used to compute optimal 2-norm solution private DenseMatrix64F W = new DenseMatrix64F(1,1); /** * Configures internal parameters. * * @param decomposition Used to solve the linear system. * @param norm2Solution If true then the optimal 2-norm solution will be computed for degenerate systems. */ protected BaseLinearSolverQrp_D64(QRPDecomposition decomposition, boolean norm2Solution) { this.decomposition = decomposition; this.norm2Solution = norm2Solution; if( internalSolver.modifiesA() ) internalSolver = new LinearSolverSafe(internalSolver); } @Override public boolean setA(DenseMatrix64F A) { _setA(A); if( !decomposition.decompose(A) ) return false; rank = decomposition.getRank(); R.reshape(numRows,numCols); decomposition.getR(R,false); // extract the r11 triangle sub matrix R11.reshape(rank, rank); CommonOps.extract(R, 0, rank, 0, rank, R11, 0, 0); if( norm2Solution && rank < numCols ) { // extract the R12 sub-matrix W.reshape(rank,numCols - rank); CommonOps.extract(R,0,rank,rank,numCols,W,0,0); // W=inv(R11)*R12 TriangularSolver.solveU(R11.data, 0, R11.numCols, R11.numCols, W.data, 0, W.numCols, W.numCols); // set the identity matrix in the upper portion W.reshape(numCols, W.numCols,true); for( int i = 0; i < numCols-rank; i++ ) { for( int j = 0; j < numCols-rank; j++ ) { if( i == j ) W.set(i+rank,j,-1); else W.set(i+rank,j,0); } } } return true; } @Override public double quality() { return SpecializedOps.qualityTriangular(R); } /** *

* Upgrades the basic solution to the optimal 2-norm solution. *

* *
     * First solves for 'z'
     *
     *       || x_b - P*[ R_11^-1 * R_12 ] * z ||2
     * min z ||         [ - I_{n-r}      ]     ||
     *
     * 
* * @param X basic solution, also output solution */ protected void upgradeSolution( DenseMatrix64F X ) { DenseMatrix64F z = Y; // recycle Y // compute the z which will minimize the 2-norm of X // because of the identity matrix tacked onto the end 'A' should never be singular if( !internalSolver.setA(W) ) throw new RuntimeException("This should never happen. Is input NaN?"); z.reshape(numCols-rank,1); internalSolver.solve(X, z); // compute X by tweaking the original CommonOps.multAdd(-1, W, z, X); } @Override public void invert(DenseMatrix64F A_inv) { if( A_inv.numCols != numRows || A_inv.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for A_inv"); I.reshape(numRows, numRows); CommonOps.setIdentity(I); solve(I, A_inv); } public QRPDecomposition getDecomposition() { return decomposition; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrBlock64_D64.java000066400000000000000000000022301256171534400302000ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.block.linsol.qr.BlockQrHouseHolderSolver; import org.ejml.alg.dense.linsol.LinearSolver_B64_to_D64; /** * Wrapper around {@link BlockQrHouseHolderSolver} that allows it to process * {@link org.ejml.data.DenseMatrix64F}. * * @author Peter Abeles */ public class LinearSolverQrBlock64_D64 extends LinearSolver_B64_to_D64 { public LinearSolverQrBlock64_D64() { super(new BlockQrHouseHolderSolver()); } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrHouseCol_D64.java000066400000000000000000000117321256171534400305240ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.decomposition.qr.QrHelperFunctions_D64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.SpecializedOps; /** *

* QR decomposition can be used to solve for systems. However, this is not as computationally efficient * as LU decomposition and costs about 3n2 flops. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^T b
*

* *

* A column major decomposition is used in this solver. *

* * @author Peter Abeles */ public class LinearSolverQrHouseCol_D64 extends LinearSolverAbstract_D64 { private QRDecompositionHouseholderColumn_D64 decomposer; private DenseMatrix64F a = new DenseMatrix64F(1,1); private DenseMatrix64F temp = new DenseMatrix64F(1,1); protected int maxRows = -1; protected int maxCols = -1; private double[][] QR; // a column major QR matrix private DenseMatrix64F R = new DenseMatrix64F(1,1); private double gammas[]; /** * Creates a linear solver that uses QR decomposition. */ public LinearSolverQrHouseCol_D64() { decomposer = new QRDecompositionHouseholderColumn_D64(); } public void setMaxSize( int maxRows , int maxCols ) { this.maxRows = maxRows; this.maxCols = maxCols; } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(DenseMatrix64F A) { if( A.numRows < A.numCols ) throw new IllegalArgumentException("Can't solve for wide systems. More variables than equations."); if( A.numRows > maxRows || A.numCols > maxCols ) setMaxSize(A.numRows,A.numCols); R.reshape(A.numCols,A.numCols); a.reshape(A.numRows,1); temp.reshape(A.numRows,1); _setA(A); if( !decomposer.decompose(A) ) return false; gammas = decomposer.getGammas(); QR = decomposer.getQR(); decomposer.getR(R,true); return true; } @Override public double quality() { return SpecializedOps.qualityTriangular(R); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is written to. Modified. */ @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X: X rows = "+X.numRows+" expected = "+numCols); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { a.data[i] = B.data[i*BnumCols + colB]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for( int n = 0; n < numCols; n++ ) { double []u = QR[n]; double vv = u[n]; u[n] = 1; QrHelperFunctions_D64.rank1UpdateMultR(a, u, gammas[n], 0, n, numRows, temp.data); u[n] = vv; } // solve for Rx = b using the standard upper triangular solver TriangularSolver.solveU(R.data,a.data,numCols); // save the results for( int i = 0; i < numCols; i++ ) { X.data[i*X.numCols+colB] = a.data[i]; } } } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public QRDecomposition getDecomposition() { return decomposer; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrHouseTran_D64.java000066400000000000000000000117501256171534400307130ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderTran_D64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.SpecializedOps; /** *

* QR decomposition can be used to solve for systems. However, this is not as computationally efficient * as LU decomposition and costs about 3n2 flops. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^T b
*

* *

* A column major decomposition is used in this solver. *

* * @author Peter Abeles */ public class LinearSolverQrHouseTran_D64 extends LinearSolverAbstract_D64 { private QRDecompositionHouseholderTran_D64 decomposer; private double []a; protected int maxRows = -1; protected int maxCols = -1; private DenseMatrix64F QR; // a column major QR matrix private DenseMatrix64F U; /** * Creates a linear solver that uses QR decomposition. */ public LinearSolverQrHouseTran_D64() { decomposer = new QRDecompositionHouseholderTran_D64(); } public void setMaxSize( int maxRows , int maxCols ) { this.maxRows = maxRows; this.maxCols = maxCols; a = new double[ maxRows ]; } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(DenseMatrix64F A) { if( A.numRows > maxRows || A.numCols > maxCols ) setMaxSize(A.numRows,A.numCols); _setA(A); if( !decomposer.decompose(A) ) return false; QR = decomposer.getQR(); return true; } @Override public double quality() { // even those it is transposed the diagonal elements are at the same // elements return SpecializedOps.qualityTriangular(QR); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is written to. Modified. */ @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X: X rows = "+X.numRows+" expected = "+numCols); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); U = decomposer.getR(U,true); final double gammas[] = decomposer.getGammas(); final double dataQR[] = QR.data; final int BnumCols = B.numCols; // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { a[i] = B.data[i*BnumCols + colB]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for( int n = 0; n < numCols; n++ ) { int indexU = n*numRows + n + 1; double ub = a[n]; // U^T*b for( int i = n+1; i < numRows; i++ , indexU++ ) { ub += dataQR[indexU]*a[i]; } // gamma*U^T*b ub *= gammas[n]; a[n] -= ub; indexU = n*numRows + n + 1; for( int i = n+1; i < numRows; i++ , indexU++) { a[i] -= dataQR[indexU]*ub; } } // solve for Rx = b using the standard upper triangular solver TriangularSolver.solveU(U.data,a,numCols); // save the results for( int i = 0; i < numCols; i++ ) { X.data[i*X.numCols+colB] = a[i]; } } } @Override public boolean modifiesA() { return decomposer.inputModified(); } @Override public boolean modifiesB() { return false; } @Override public QRDecomposition getDecomposition() { return decomposer; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrHouse_D64.java000066400000000000000000000107061256171534400300660ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholder_D64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.SpecializedOps; /** *

* QR decomposition can be used to solve for systems. However, this is not as computationally efficient * as LU decomposition and costs about 3n2 flops. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^T b
*

* * @author Peter Abeles */ public class LinearSolverQrHouse_D64 extends LinearSolverAbstract_D64 { private QRDecompositionHouseholder_D64 decomposer; private double []a,u; private int maxRows = -1; private DenseMatrix64F QR; private double gammas[]; /** * Creates a linear solver that uses QR decomposition. */ public LinearSolverQrHouse_D64() { decomposer = new QRDecompositionHouseholder_D64(); } public void setMaxSize( int maxRows ) { this.maxRows = maxRows; a = new double[ maxRows ]; u = new double[ maxRows ]; } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(DenseMatrix64F A) { if( A.numRows > maxRows ) { setMaxSize(A.numRows); } _setA(A); if( !decomposer.decompose(A) ) return false; gammas = decomposer.getGammas(); QR = decomposer.getQR(); return true; } @Override public double quality() { return SpecializedOps.qualityTriangular(QR); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is writen to. Modified. */ @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X"); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { a[i] = B.data[i*BnumCols + colB]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for( int n = 0; n < numCols; n++ ) { u[n] = 1; double ub = a[n]; // U^T*b for( int i = n+1; i < numRows; i++ ) { ub += (u[i] = QR.unsafe_get(i,n))*a[i]; } // gamma*U^T*b ub *= gammas[n]; for( int i = n; i < numRows; i++ ) { a[i] -= u[i]*ub; } } // solve for Rx = b using the standard upper triangular solver TriangularSolver.solveU(QR.data,a,numCols); // save the results for( int i = 0; i < numCols; i++ ) { X.data[i*X.numCols+colB] = a[i]; } } } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public QRDecomposition getDecomposition() { return decomposer; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQr_D64.java000066400000000000000000000113521256171534400270600ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.linsol.LinearSolverAbstract_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.SpecializedOps; /** *

* A solver for a generic QR decomposition algorithm. This will in general be a bit slower than the * specialized once since the full Q and R matrices need to be extracted. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^T b
*

* * @author Peter Abeles */ public class LinearSolverQr_D64 extends LinearSolverAbstract_D64 { private QRDecomposition decomposer; protected int maxRows = -1; protected int maxCols = -1; protected DenseMatrix64F Q; protected DenseMatrix64F R; private DenseMatrix64F Y,Z; /** * Creates a linear solver that uses QR decomposition. * */ public LinearSolverQr_D64(QRDecomposition decomposer) { this.decomposer = decomposer; } /** * Changes the size of the matrix it can solve for * * @param maxRows Maximum number of rows in the matrix it will decompose. * @param maxCols Maximum number of columns in the matrix it will decompose. */ public void setMaxSize( int maxRows , int maxCols ) { this.maxRows = maxRows; this.maxCols = maxCols; Q = new DenseMatrix64F(maxRows,maxRows); R = new DenseMatrix64F(maxRows,maxCols); Y = new DenseMatrix64F(maxRows,1); Z = new DenseMatrix64F(maxRows,1); } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(DenseMatrix64F A) { if( A.numRows > maxRows || A.numCols > maxCols ) { setMaxSize(A.numRows,A.numCols); } _setA(A); if( !decomposer.decompose(A) ) return false; Q.reshape(numRows,numRows, false); R.reshape(numRows,numCols, false); decomposer.getQ(Q,false); decomposer.getR(R,false); return true; } @Override public double quality() { return SpecializedOps.qualityTriangular(R); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is written to. Modified. */ @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X"); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; Y.reshape(numRows,1, false); Z.reshape(numRows,1, false); // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { Y.data[i] = B.get(i,colB); } // Solve Qa=b // a = Q'b CommonOps.multTransA(Q,Y,Z); // solve for Rx = b using the standard upper triangular solver TriangularSolver.solveU(R.data,Z.data,numCols); // save the results for( int i = 0; i < numCols; i++ ) { X.set(i,colB,Z.data[i]); } } } @Override public boolean modifiesA() { return decomposer.inputModified(); } @Override public boolean modifiesB() { return false; } @Override public QRDecomposition getDecomposition() { return decomposer; } public QRDecomposition getDecomposer() { return decomposer; } public DenseMatrix64F getQ() { return Q; } public DenseMatrix64F getR() { return R; } }ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrpHouseCol_D64.java000066400000000000000000000074721256171534400307120ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.alg.dense.decomposition.qr.QRColPivDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.decomposition.qr.QrHelperFunctions_D64; import org.ejml.data.DenseMatrix64F; /** *

* Performs a pseudo inverse solver using the {@link org.ejml.alg.dense.decomposition.qr.QRColPivDecompositionHouseholderColumn_D64} decomposition * directly. For details on how the pseudo inverse is computed see {@link BaseLinearSolverQrp_D64}. *

* * @author Peter Abeles */ public class LinearSolverQrpHouseCol_D64 extends BaseLinearSolverQrp_D64 { // Computes the QR decomposition private QRColPivDecompositionHouseholderColumn_D64 decomposition; // storage for basic solution private DenseMatrix64F x_basic = new DenseMatrix64F(1,1); public LinearSolverQrpHouseCol_D64(QRColPivDecompositionHouseholderColumn_D64 decomposition, boolean norm2Solution) { super(decomposition,norm2Solution); this.decomposition = decomposition; } @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X"); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; // get the pivots and transpose them int pivots[] = decomposition.getPivots(); double qr[][] = decomposition.getQR(); double gammas[] = decomposition.getGammas(); // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { x_basic.reshape(numRows, 1); Y.reshape(numRows,1); // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { x_basic.data[i] = B.get(i,colB); } // Solve Q*x=b => x = Q'*b // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for( int i = 0; i < rank; i++ ) { double u[] = qr[i]; double vv = u[i]; u[i] = 1; QrHelperFunctions_D64.rank1UpdateMultR(x_basic, u, gammas[i], 0, i, numRows, Y.data); u[i] = vv; } // solve for Rx = b using the standard upper triangular solver TriangularSolver.solveU(R11.data, x_basic.data, rank); // finish the basic solution by filling in zeros x_basic.reshape(numCols, 1, true); for( int i = rank; i < numCols; i++) x_basic.data[i] = 0; if( norm2Solution && rank < numCols ) upgradeSolution(x_basic); // save the results for( int i = 0; i < numCols; i++ ) { X.set(pivots[i],colB,x_basic.data[i]); } } } @Override public boolean modifiesA() { return decomposition.inputModified(); } @Override public boolean modifiesB() { return false; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/qr/SolvePseudoInverseQrp_D64.java000066400000000000000000000072471256171534400304470ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.TriangularSolver; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRPDecomposition; import org.ejml.ops.CommonOps; /** *

* A pseudo inverse solver for a generic QR column pivot decomposition algorithm. See * {@link BaseLinearSolverQrp_D64} for technical details on the algorithm. *

* * @author Peter Abeles */ public class SolvePseudoInverseQrp_D64 extends BaseLinearSolverQrp_D64 { // stores the orthogonal Q matrix from QR decomposition private DenseMatrix64F Q=new DenseMatrix64F(1,1); // storage for basic solution private DenseMatrix64F x_basic =new DenseMatrix64F(1,1); /** * Configure and provide decomposition * * @param decomposition Decomposition used. * @param norm2Solution If true the basic solution will be returned, false the minimal 2-norm solution. */ public SolvePseudoInverseQrp_D64(QRPDecomposition decomposition, boolean norm2Solution) { super(decomposition,norm2Solution); } @Override public boolean setA(DenseMatrix64F A) { if( !super.setA(A)) return false; Q.reshape(A.numRows, A.numRows); decomposition.getQ(Q, false); return true; } @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X"); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; // get the pivots and transpose them int pivots[] = decomposition.getPivots(); // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { x_basic.reshape(numRows, 1); Y.reshape(numRows,1); // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { Y.data[i] = B.get(i,colB); } // Solve Q*a=b => a = Q'*b CommonOps.multTransA(Q, Y, x_basic); // solve for Rx = b using the standard upper triangular solver TriangularSolver.solveU(R11.data, x_basic.data, rank); // finish the basic solution by filling in zeros x_basic.reshape(numCols, 1, true); for( int i = rank; i < numCols; i++) x_basic.data[i] = 0; if( norm2Solution && rank < numCols ) upgradeSolution(x_basic); // save the results for( int i = 0; i < numCols; i++ ) { X.set(pivots[i],colB,x_basic.data[i]); } } } @Override public boolean modifiesA() { return decomposition.inputModified(); } @Override public boolean modifiesB() { return false; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/svd/000077500000000000000000000000001256171534400230405ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/linsol/svd/SolvePseudoInverseSvd.java000066400000000000000000000112001256171534400301560ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.svd; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; /** *

* The pseudo-inverse is typically used to solve over determined system for which there is no unique solution.
* x=inv(ATA)ATb
* where A ∈ ℜ m × n and m ≥ n. *

* *

* This class implements the Moore-Penrose pseudo-inverse using SVD and should never fail. Alternative implementations * can use Cholesky decomposition, but those will fail if the ATA matrix is singular. * However the Cholesky implementation is much faster. *

* * @author Peter Abeles */ public class SolvePseudoInverseSvd implements LinearSolver { // Used to compute pseudo inverse private SingularValueDecomposition svd; // the results of the pseudo-inverse private DenseMatrix64F pinv = new DenseMatrix64F(1,1); // relative threshold used to select singular values private double threshold = UtilEjml.EPS; /** * Creates a new solver targeted at the specified matrix size. * * @param maxRows The expected largest matrix it might have to process. Can be larger. * @param maxCols The expected largest matrix it might have to process. Can be larger. */ public SolvePseudoInverseSvd(int maxRows, int maxCols) { svd = DecompositionFactory.svd(maxRows,maxCols,true,true,true); } /** * Creates a solver targeted at matrices around 100x100 */ public SolvePseudoInverseSvd() { this(100,100); } @Override public boolean setA(DenseMatrix64F A) { pinv.reshape(A.numCols,A.numRows,false); if( !svd.decompose(A) ) return false; DenseMatrix64F U_t = svd.getU(null,true); DenseMatrix64F V = svd.getV(null,false); double []S = svd.getSingularValues(); int N = Math.min(A.numRows,A.numCols); // compute the threshold for singular values which are to be zeroed double maxSingular = 0; for( int i = 0; i < N; i++ ) { if( S[i] > maxSingular ) maxSingular = S[i]; } double tau = threshold*Math.max(A.numCols,A.numRows)*maxSingular; // computer the pseudo inverse of A if( maxSingular != 0.0 ) { for (int i = 0; i < N; i++) { double s = S[i]; if (s < tau) S[i] = 0; else S[i] = 1.0 / S[i]; } } // V*W for( int i = 0; i < V.numRows; i++ ) { int index = i*V.numCols; for( int j = 0; j < V.numCols; j++ ) { V.data[index++] *= S[j]; } } // V*W*U^T CommonOps.mult(V,U_t, pinv); return true; } @Override public double quality() { throw new IllegalArgumentException("Not supported by this solver."); } @Override public void solve( DenseMatrix64F b, DenseMatrix64F x) { CommonOps.mult(pinv,b,x); } @Override public void invert(DenseMatrix64F A_inv) { A_inv.set(pinv); } @Override public boolean modifiesA() { return svd.inputModified(); } @Override public boolean modifiesB() { return false; } @Override public SingularValueDecomposition getDecomposition() { return svd; } /** * Specify the relative threshold used to select singular values. By default it's UtilEjml.EPS. * @param threshold The singular value threshold */ public void setThreshold(double threshold) { this.threshold = threshold; } public SingularValueDecomposition getDecomposer() { return svd; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400216775ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/DeterminantFromMinor.java000066400000000000000000000160161256171534400266510ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; /** *

* Computes the determinant of a matrix using Laplace expansion. This is done * using minor matrices as is shown below:
*
* |A| = Sum{ i=1:k ; aij Cij }
*
* Cij = (-1)i+j Mij
*
* Where M_ij is the minor of matrix A formed by eliminating row i and column j from A. *

* *

* This is significantly more computationally expensive than using LU decomposition, but * its computation has the advantage being independent of the matrices value. *

* * @see org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64 * * @author Peter Abeles */ public class DeterminantFromMinor { // how wide the square matrix is private int width; // used to decide at which point it uses a direct algorithm to compute the determinant private int minWidth; // used to keep track of which submatrix it is computing the results for private int []levelIndexes; // the results at different levels of minor matrices private double []levelResults; // which columns where removed at what level private int []levelRemoved; // columns that are currently open private int open[]; private int numOpen; // a minor matrix which is created at the lowest level private DenseMatrix64F tempMat; private boolean dirty = false; /** * * @param width The width of the matrices that it will be computing the determinant for */ public DeterminantFromMinor( int width ) { this(width,5); } /** * * @param width The width of the matrices that it will be computing the determinant for * @param minWidth At which point should it use a predefined function to compute the determinant. */ public DeterminantFromMinor( int width , int minWidth ) { if( minWidth > 5 || minWidth < 2 ) { throw new IllegalArgumentException("No direct function for that width"); } if( width < minWidth ) minWidth = width; this.minWidth = minWidth; this.width = width; int numLevels = width-(minWidth-2); levelResults = new double[numLevels]; levelRemoved = new int[numLevels]; levelIndexes = new int[numLevels]; open = new int[ width ]; tempMat = new DenseMatrix64F(minWidth-1,minWidth-1); } /** * Computes the determinant for the specified matrix. It must be square and have * the same width and height as what was specified in the constructor. * * @param mat The matrix whose determinant is to be computed. * @return The determinant. */ public double compute( RowD1Matrix64F mat ) { if( width != mat.numCols || width != mat.numRows ) { throw new RuntimeException("Unexpected matrix dimension"); } // make sure everything is in the proper state before it starts initStructures(); // System.arraycopy(mat.data,0,minorMatrix[0],0,mat.data.length); int level = 0; while( true ) { int levelWidth = width-level; int levelIndex = levelIndexes[level]; if( levelIndex == levelWidth ) { if( level == 0 ) { return levelResults[0]; } int prevLevelIndex = levelIndexes[level-1]++; double val = mat.get((level-1)*width+levelRemoved[level-1]); if( prevLevelIndex % 2 == 0 ) { levelResults[level-1] += val * levelResults[level]; } else { levelResults[level-1] -= val * levelResults[level]; } putIntoOpen(level-1); levelResults[level] = 0; levelIndexes[level] = 0; level--; } else { int excluded = openRemove( levelIndex ); levelRemoved[level] = excluded; if( levelWidth == minWidth ) { createMinor(mat); double subresult = mat.get(level*width+levelRemoved[level]); subresult *= UnrolledDeterminantFromMinor.det(tempMat); if( levelIndex % 2 == 0 ) { levelResults[level] += subresult; } else { levelResults[level] -= subresult; } // put it back into the list putIntoOpen(level); levelIndexes[level]++; } else { level++; } } } } private void initStructures() { for( int i = 0; i < width; i++ ) { open[i] = i; } numOpen = width; if( dirty ) { for( int i = 0; i < levelIndexes.length; i++ ) { levelIndexes[i] = 0; levelResults[i] = 0; levelRemoved[i] = 0; } } dirty = true; } private int openRemove( int where ) { int val = open[where]; System.arraycopy(open,where+1,open,where,(numOpen-where-1)); numOpen--; return val; } private void openAdd( int where, int val ) { for( int i = numOpen; i > where; i-- ) { open[i] = open[i-1]; } numOpen++; open[where] = val; } private void openAdd( int val ) { open[numOpen++] = val; } private void putIntoOpen(int level) { boolean added = false; for( int i = 0; i < numOpen; i++ ) { if( open[i] > levelRemoved[level]) { added = true; openAdd(i,levelRemoved[level]); break; } } if( !added ) { openAdd(levelRemoved[level]); } } private void createMinor( RowD1Matrix64F mat ) { int w = minWidth-1; int firstRow = (width-w)*width; for( int i = 0; i < numOpen; i++ ) { int col = open[i]; int srcIndex = firstRow + col; int dstIndex = i; for( int j = 0; j < w; j++ ) { tempMat.set( dstIndex , mat.get( srcIndex ) ); dstIndex += w; srcIndex += width; } } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/ImplCommonOps_DenseMatrix64F.java000066400000000000000000000027621256171534400300700ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; /** * Implementations of common ops routines for {@link org.ejml.data.DenseMatrix64F}. In general * there is no need to directly invoke these functions. * * @author Peter Abeles */ public class ImplCommonOps_DenseMatrix64F { public static void extract(DenseMatrix64F src, int srcY0, int srcX0, DenseMatrix64F dst, int dstY0, int dstX0, int numRows, int numCols) { for( int y = 0; y < numRows; y++ ) { int indexSrc = src.getIndex(y+srcY0,srcX0); int indexDst = dst.getIndex(y+dstY0,dstX0); System.arraycopy(src.data,indexSrc,dst.data,indexDst, numCols); } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/ImplCommonOps_Matrix64F.java000066400000000000000000000027161256171534400271100ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.RealMatrix64F; /** * Implementations of common ops routines for {@link org.ejml.data.DenseMatrix64F}. In general * there is no need to directly invoke these functions. * * @author Peter Abeles */ public class ImplCommonOps_Matrix64F { public static void extract(RealMatrix64F src, int srcY0, int srcX0, RealMatrix64F dst, int dstY0, int dstX0, int numRows, int numCols ) { for( int y = 0; y < numRows; y++ ) { for( int x = 0; x < numCols; x++ ) { double v = src.get(y+srcY0,x+srcX0); dst.set(dstY0+y , dstX0 +x, v); } } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/RrefGaussJordanRowPivot.java000066400000000000000000000070361256171534400273210ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.ReducedRowEchelonForm; /** * Reduction to RREF using Gauss-Jordan elimination with row (partial) pivots. * * @author Peter Abeles */ public class RrefGaussJordanRowPivot implements ReducedRowEchelonForm { // tolerance for singular matrix double tol; @Override public void setTolerance(double tol) { this.tol = tol; } @Override public void reduce( DenseMatrix64F A , int coefficientColumns) { if( A.numCols < coefficientColumns) throw new IllegalArgumentException("The system must be at least as wide as A"); // number of leading ones which have been found int leadIndex = 0; // compute the decomposition for( int i = 0; i < coefficientColumns; i++ ) { // select the row to pivot by finding the row with the largest column in 'i' int pivotRow = -1; double maxValue = tol; for( int row = leadIndex; row < A.numRows; row++ ) { double v = Math.abs(A.data[row*A.numCols + i]); if( v > maxValue ) { maxValue = v; pivotRow = row; } } if( pivotRow == -1 ) continue; // perform the row pivot // NOTE: performance could be improved by delaying the physical swap of rows until the end // and using a technique which does the minimal number of swaps if( leadIndex != pivotRow) swapRows(A,leadIndex,pivotRow); // zero column 'i' in all but the pivot row for( int row = 0; row < A.numRows; row++ ) { if( row == leadIndex ) continue; int indexPivot = leadIndex*A.numCols+i; int indexTarget = row*A.numCols+i; double alpha = A.data[indexTarget]/A.data[indexPivot++]; A.data[indexTarget++] = 0; for( int col = i+1; col < A.numCols; col++ ) { A.data[indexTarget++] -= A.data[indexPivot++]*alpha; } } // update the pivot row int indexPivot = leadIndex*A.numCols+i; double alpha = 1.0/A.data[indexPivot]; A.data[indexPivot++] = 1; for( int col = i+1; col < A.numCols; col++ ) { A.data[indexPivot++] *= alpha; } leadIndex++; } } protected static void swapRows( DenseMatrix64F A , int rowA , int rowB ) { int indexA = rowA*A.numCols; int indexB = rowB*A.numCols; for( int i = 0; i < A.numCols; i++ , indexA++,indexB++) { double temp = A.data[indexA]; A.data[indexA] = A.data[indexB]; A.data[indexB] = temp; } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/TransposeAlgs.java000066400000000000000000000101671256171534400253340ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.RowD1Matrix64F; /** * Low level transpose algorithms. No sanity checks are performed. Take a look at BenchmarkTranspose to * see which one is faster on your computer. * * @author Peter Abeles */ public class TransposeAlgs { /** * In-place transpose for a square matrix. On most architectures it is faster than the standard transpose * algorithm, but on most modern computers it's slower than block transpose. * * @param mat The matrix that is transposed in-place. Modified. */ public static void square( RowD1Matrix64F mat ) { int index = 1; int indexEnd = mat.numCols; for( int i = 0; i < mat.numRows; i++ , index += i+1 , indexEnd += mat.numCols ) { int indexOther = (i+1)*mat.numCols + i; for( ; index < indexEnd; index++, indexOther += mat.numCols) { double val = mat.data[ index ]; mat.data[ index ] = mat.data[ indexOther ]; mat.data[indexOther] = val; } } } /** * Performs a transpose across block sub-matrices. Reduces * the number of cache misses on larger matrices. * * *NOTE* If this is beneficial is highly dependent on the computer it is run on. e.g: * - Q6600 Almost twice as fast as standard. * - Pentium-M Same speed and some times a bit slower than standard. * * @param A Original matrix. Not modified. * @param A_tran Transposed matrix. Modified. * @param blockLength Length of a block. */ public static void block( RowD1Matrix64F A , RowD1Matrix64F A_tran , final int blockLength ) { for( int i = 0; i < A.numRows; i += blockLength ) { int blockHeight = Math.min( blockLength , A.numRows - i); int indexSrc = i*A.numCols; int indexDst = i; for( int j = 0; j < A.numCols; j += blockLength ) { int blockWidth = Math.min( blockLength , A.numCols - j); // int indexSrc = i*A.numCols + j; // int indexDst = j*A_tran.numCols + i; int indexSrcEnd = indexSrc + blockWidth; // for( int l = 0; l < blockWidth; l++ , indexSrc++ ) { for( ; indexSrc < indexSrcEnd; indexSrc++ ) { int rowSrc = indexSrc; int rowDst = indexDst; int end = rowDst + blockHeight; // for( int k = 0; k < blockHeight; k++ , rowSrc += A.numCols ) { for( ; rowDst < end; rowSrc += A.numCols ) { // faster to write in sequence than to read in sequence A_tran.data[ rowDst++ ] = A.data[ rowSrc ]; } indexDst += A_tran.numCols; } } } } /** * A straight forward transpose. Good for small non-square matrices. * * @param A Original matrix. Not modified. * @param A_tran Transposed matrix. Modified. */ public static void standard( RowD1Matrix64F A, RowD1Matrix64F A_tran) { int index = 0; for( int i = 0; i < A_tran.numRows; i++ ) { int index2 = i; int end = index + A_tran.numCols; while( index < end ) { A_tran.data[index++ ] = A.data[ index2 ]; index2 += A.numCols; } } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/UnrolledDeterminantFromMinor.java000066400000000000000000000442411256171534400303570ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.RowD1Matrix64F; /** * This code was auto generated by {@link GenerateDeterminantFromMinor} and should not be modified * directly. * * @author Peter Abeles */ public class UnrolledDeterminantFromMinor { public static final int MAX = 6; public static double det( RowD1Matrix64F mat ) { switch( mat.numRows ) { case 2: return det2(mat); case 3: return det3(mat); case 4: return det4(mat); case 5: return det5(mat); case 6: return det6(mat); default: throw new IllegalArgumentException("Not supported"); } } public static double det2( RowD1Matrix64F mat ) { double m[] = mat.data; return m[0]*m[3] - m[1]*m[2]; } public static double det3( RowD1Matrix64F mat ) { double m[] = mat.data; double a11 = m[0]; double a12 = m[1]; double a13 = m[2]; double a21 = m[3]; double a22 = m[4]; double a23 = m[5]; double a31 = m[6]; double a32 = m[7]; double a33 = m[8]; double a = a11*(a22*a33 - a23*a32); double b = a12*(a21*a33 - a23*a31); double c = a13*(a21*a32 - a31*a22); return a-b+c; } public static double det4( RowD1Matrix64F mat ) { double []data = mat.data; double a11 = data[ 5 ]; double a12 = data[ 6 ]; double a13 = data[ 7 ]; double a21 = data[ 9 ]; double a22 = data[ 10 ];double a23 = data[ 11 ]; double a31 = data[ 13 ];double a32 = data[ 14 ];double a33 = data[ 15 ]; double ret = 0; ret += data[ 0 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); a11 = data[ 4 ]; a21 = data[ 8 ]; a31 = data[ 12 ]; ret -= data[ 1 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); a12 = data[ 5 ]; a22 = data[ 9 ]; a32 = data[ 13 ]; ret += data[ 2 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); a13 = data[ 6 ]; a23 = data[ 10 ]; a33 = data[ 14 ]; ret -= data[ 3 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); return ret; } public static double det5( RowD1Matrix64F mat ) { double []data = mat.data; double a11 = data[ 6 ]; double a12 = data[ 7 ]; double a13 = data[ 8 ]; double a14 = data[ 9 ]; double a21 = data[ 11 ]; double a22 = data[ 12 ]; double a23 = data[ 13 ]; double a24 = data[ 14 ]; double a31 = data[ 16 ]; double a32 = data[ 17 ]; double a33 = data[ 18 ]; double a34 = data[ 19 ]; double a41 = data[ 21 ]; double a42 = data[ 22 ]; double a43 = data[ 23 ]; double a44 = data[ 24 ]; double ret = 0; ret += data[ 0 ] * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a11 = data[ 5 ]; a21 = data[ 10 ]; a31 = data[ 15 ]; a41 = data[ 20 ]; ret -= data[ 1 ] * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a12 = data[ 6 ]; a22 = data[ 11 ]; a32 = data[ 16 ]; a42 = data[ 21 ]; ret += data[ 2 ] * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a13 = data[ 7 ]; a23 = data[ 12 ]; a33 = data[ 17 ]; a43 = data[ 22 ]; ret -= data[ 3 ] * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a14 = data[ 8 ]; a24 = data[ 13 ]; a34 = data[ 18 ]; a44 = data[ 23 ]; ret += data[ 4 ] * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); return ret; } public static double det6( RowD1Matrix64F mat ) { double []data = mat.data; double a11 = data[ 7 ]; double a12 = data[ 8 ]; double a13 = data[ 9 ]; double a14 = data[ 10 ]; double a15 = data[ 11 ]; double a21 = data[ 13 ]; double a22 = data[ 14 ]; double a23 = data[ 15 ]; double a24 = data[ 16 ]; double a25 = data[ 17 ]; double a31 = data[ 19 ]; double a32 = data[ 20 ]; double a33 = data[ 21 ]; double a34 = data[ 22 ]; double a35 = data[ 23 ]; double a41 = data[ 25 ]; double a42 = data[ 26 ]; double a43 = data[ 27 ]; double a44 = data[ 28 ]; double a45 = data[ 29 ]; double a51 = data[ 31 ]; double a52 = data[ 32 ]; double a53 = data[ 33 ]; double a54 = data[ 34 ]; double a55 = data[ 35 ]; double ret = 0; ret += data[ 0 ] * ( + a11*( + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))) - a12*( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))) + a13*( + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))) - a14*( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))) + a15*( + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)))); a11 = data[ 6 ]; a21 = data[ 12 ]; a31 = data[ 18 ]; a41 = data[ 24 ]; a51 = data[ 30 ]; ret -= data[ 1 ] * ( + a11*( + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))) - a12*( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))) + a13*( + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))) - a14*( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))) + a15*( + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)))); a12 = data[ 7 ]; a22 = data[ 13 ]; a32 = data[ 19 ]; a42 = data[ 25 ]; a52 = data[ 31 ]; ret += data[ 2 ] * ( + a11*( + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))) - a12*( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))) + a13*( + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))) - a14*( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))) + a15*( + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)))); a13 = data[ 8 ]; a23 = data[ 14 ]; a33 = data[ 20 ]; a43 = data[ 26 ]; a53 = data[ 32 ]; ret -= data[ 3 ] * ( + a11*( + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))) - a12*( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))) + a13*( + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))) - a14*( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))) + a15*( + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)))); a14 = data[ 9 ]; a24 = data[ 15 ]; a34 = data[ 21 ]; a44 = data[ 27 ]; a54 = data[ 33 ]; ret += data[ 4 ] * ( + a11*( + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))) - a12*( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))) + a13*( + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))) - a14*( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))) + a15*( + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)))); a15 = data[ 10 ]; a25 = data[ 16 ]; a35 = data[ 22 ]; a45 = data[ 28 ]; a55 = data[ 34 ]; ret -= data[ 5 ] * ( + a11*( + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))) - a12*( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))) + a13*( + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))) - a14*( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))) + a15*( + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)))); return ret; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/misc/UnrolledInverseFromMinor.java000066400000000000000000000424751256171534400275270ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; /** * This code was auto generated by {@link GenerateInverseFromMinor} and should not be modified * directly. The input matrix is scaled make it much less prone to overflow and underflow issues. * * @author Peter Abeles */ public class UnrolledInverseFromMinor { public static final int MAX = 5; public static void inv( DenseMatrix64F mat , DenseMatrix64F inv ) { double max = Math.abs(mat.data[0]); int N = mat.getNumElements(); for( int i = 1; i < N; i++ ) { double a = Math.abs(mat.data[i]); if( a > max ) max = a; } switch( mat.numRows ) { case 2: inv2(mat,inv,1.0/max); break; case 3: inv3(mat,inv,1.0/max); break; case 4: inv4(mat,inv,1.0/max); break; case 5: inv5(mat,inv,1.0/max); break; default: throw new IllegalArgumentException("Not supported"); } } public static void inv2( DenseMatrix64F mat , DenseMatrix64F inv , double scale ) { double []data = mat.data; double a11 = data[ 0 ]*scale; double a12 = data[ 1 ]*scale; double a21 = data[ 2 ]*scale; double a22 = data[ 3 ]*scale; double m11 = a22; double m12 = -( a21); double m21 = -( a12); double m22 = a11; double det = (a11*m11 + a12*m12)/scale; data = inv.data; data[0] = m11 / det; data[1] = m21 / det; data[2] = m12 / det; data[3] = m22 / det; } public static void inv3( DenseMatrix64F mat , DenseMatrix64F inv , double scale ) { double []data = mat.data; double a11 = data[ 0 ]*scale; double a12 = data[ 1 ]*scale; double a13 = data[ 2 ]*scale; double a21 = data[ 3 ]*scale; double a22 = data[ 4 ]*scale; double a23 = data[ 5 ]*scale; double a31 = data[ 6 ]*scale; double a32 = data[ 7 ]*scale; double a33 = data[ 8 ]*scale; double m11 = a22*a33 - a23*a32; double m12 = -( a21*a33 - a23*a31); double m13 = a21*a32 - a22*a31; double m21 = -( a12*a33 - a13*a32); double m22 = a11*a33 - a13*a31; double m23 = -( a11*a32 - a12*a31); double m31 = a12*a23 - a13*a22; double m32 = -( a11*a23 - a13*a21); double m33 = a11*a22 - a12*a21; double det = (a11*m11 + a12*m12 + a13*m13)/scale; data = inv.data; data[0] = m11 / det; data[1] = m21 / det; data[2] = m31 / det; data[3] = m12 / det; data[4] = m22 / det; data[5] = m32 / det; data[6] = m13 / det; data[7] = m23 / det; data[8] = m33 / det; } public static void inv4( DenseMatrix64F mat , DenseMatrix64F inv , double scale ) { double []data = mat.data; double a11 = data[ 0 ]*scale; double a12 = data[ 1 ]*scale; double a13 = data[ 2 ]*scale; double a14 = data[ 3 ]*scale; double a21 = data[ 4 ]*scale; double a22 = data[ 5 ]*scale; double a23 = data[ 6 ]*scale; double a24 = data[ 7 ]*scale; double a31 = data[ 8 ]*scale; double a32 = data[ 9 ]*scale; double a33 = data[ 10 ]*scale; double a34 = data[ 11 ]*scale; double a41 = data[ 12 ]*scale; double a42 = data[ 13 ]*scale; double a43 = data[ 14 ]*scale; double a44 = data[ 15 ]*scale; double m11 = + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42); double m12 = -( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)); double m13 = + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41); double m14 = -( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41)); double m21 = -( + a12*(a33*a44 - a34*a43) - a13*(a32*a44 - a34*a42) + a14*(a32*a43 - a33*a42)); double m22 = + a11*(a33*a44 - a34*a43) - a13*(a31*a44 - a34*a41) + a14*(a31*a43 - a33*a41); double m23 = -( + a11*(a32*a44 - a34*a42) - a12*(a31*a44 - a34*a41) + a14*(a31*a42 - a32*a41)); double m24 = + a11*(a32*a43 - a33*a42) - a12*(a31*a43 - a33*a41) + a13*(a31*a42 - a32*a41); double m31 = + a12*(a23*a44 - a24*a43) - a13*(a22*a44 - a24*a42) + a14*(a22*a43 - a23*a42); double m32 = -( + a11*(a23*a44 - a24*a43) - a13*(a21*a44 - a24*a41) + a14*(a21*a43 - a23*a41)); double m33 = + a11*(a22*a44 - a24*a42) - a12*(a21*a44 - a24*a41) + a14*(a21*a42 - a22*a41); double m34 = -( + a11*(a22*a43 - a23*a42) - a12*(a21*a43 - a23*a41) + a13*(a21*a42 - a22*a41)); double m41 = -( + a12*(a23*a34 - a24*a33) - a13*(a22*a34 - a24*a32) + a14*(a22*a33 - a23*a32)); double m42 = + a11*(a23*a34 - a24*a33) - a13*(a21*a34 - a24*a31) + a14*(a21*a33 - a23*a31); double m43 = -( + a11*(a22*a34 - a24*a32) - a12*(a21*a34 - a24*a31) + a14*(a21*a32 - a22*a31)); double m44 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); double det = (a11*m11 + a12*m12 + a13*m13 + a14*m14)/scale; data = inv.data; data[0] = m11 / det; data[1] = m21 / det; data[2] = m31 / det; data[3] = m41 / det; data[4] = m12 / det; data[5] = m22 / det; data[6] = m32 / det; data[7] = m42 / det; data[8] = m13 / det; data[9] = m23 / det; data[10] = m33 / det; data[11] = m43 / det; data[12] = m14 / det; data[13] = m24 / det; data[14] = m34 / det; data[15] = m44 / det; } public static void inv5( DenseMatrix64F mat , DenseMatrix64F inv , double scale ) { double []data = mat.data; double a11 = data[ 0 ]*scale; double a12 = data[ 1 ]*scale; double a13 = data[ 2 ]*scale; double a14 = data[ 3 ]*scale; double a15 = data[ 4 ]*scale; double a21 = data[ 5 ]*scale; double a22 = data[ 6 ]*scale; double a23 = data[ 7 ]*scale; double a24 = data[ 8 ]*scale; double a25 = data[ 9 ]*scale; double a31 = data[ 10 ]*scale; double a32 = data[ 11 ]*scale; double a33 = data[ 12 ]*scale; double a34 = data[ 13 ]*scale; double a35 = data[ 14 ]*scale; double a41 = data[ 15 ]*scale; double a42 = data[ 16 ]*scale; double a43 = data[ 17 ]*scale; double a44 = data[ 18 ]*scale; double a45 = data[ 19 ]*scale; double a51 = data[ 20 ]*scale; double a52 = data[ 21 ]*scale; double a53 = data[ 22 ]*scale; double a54 = data[ 23 ]*scale; double a55 = data[ 24 ]*scale; double m11 = + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)); double m12 = -( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))); double m13 = + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)); double m14 = -( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))); double m15 = + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)); double m21 = -( + a12*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a13*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a14*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a15*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))); double m22 = + a11*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a13*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a14*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a15*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)); double m23 = -( + a11*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a12*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a14*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a15*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))); double m24 = + a11*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a12*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a13*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a15*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)); double m25 = -( + a11*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a12*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a13*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a14*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))); double m31 = + a12*( + a23*(a44*a55 - a45*a54) - a24*(a43*a55 - a45*a53) + a25*(a43*a54 - a44*a53)) - a13*( + a22*(a44*a55 - a45*a54) - a24*(a42*a55 - a45*a52) + a25*(a42*a54 - a44*a52)) + a14*( + a22*(a43*a55 - a45*a53) - a23*(a42*a55 - a45*a52) + a25*(a42*a53 - a43*a52)) - a15*( + a22*(a43*a54 - a44*a53) - a23*(a42*a54 - a44*a52) + a24*(a42*a53 - a43*a52)); double m32 = -( + a11*( + a23*(a44*a55 - a45*a54) - a24*(a43*a55 - a45*a53) + a25*(a43*a54 - a44*a53)) - a13*( + a21*(a44*a55 - a45*a54) - a24*(a41*a55 - a45*a51) + a25*(a41*a54 - a44*a51)) + a14*( + a21*(a43*a55 - a45*a53) - a23*(a41*a55 - a45*a51) + a25*(a41*a53 - a43*a51)) - a15*( + a21*(a43*a54 - a44*a53) - a23*(a41*a54 - a44*a51) + a24*(a41*a53 - a43*a51))); double m33 = + a11*( + a22*(a44*a55 - a45*a54) - a24*(a42*a55 - a45*a52) + a25*(a42*a54 - a44*a52)) - a12*( + a21*(a44*a55 - a45*a54) - a24*(a41*a55 - a45*a51) + a25*(a41*a54 - a44*a51)) + a14*( + a21*(a42*a55 - a45*a52) - a22*(a41*a55 - a45*a51) + a25*(a41*a52 - a42*a51)) - a15*( + a21*(a42*a54 - a44*a52) - a22*(a41*a54 - a44*a51) + a24*(a41*a52 - a42*a51)); double m34 = -( + a11*( + a22*(a43*a55 - a45*a53) - a23*(a42*a55 - a45*a52) + a25*(a42*a53 - a43*a52)) - a12*( + a21*(a43*a55 - a45*a53) - a23*(a41*a55 - a45*a51) + a25*(a41*a53 - a43*a51)) + a13*( + a21*(a42*a55 - a45*a52) - a22*(a41*a55 - a45*a51) + a25*(a41*a52 - a42*a51)) - a15*( + a21*(a42*a53 - a43*a52) - a22*(a41*a53 - a43*a51) + a23*(a41*a52 - a42*a51))); double m35 = + a11*( + a22*(a43*a54 - a44*a53) - a23*(a42*a54 - a44*a52) + a24*(a42*a53 - a43*a52)) - a12*( + a21*(a43*a54 - a44*a53) - a23*(a41*a54 - a44*a51) + a24*(a41*a53 - a43*a51)) + a13*( + a21*(a42*a54 - a44*a52) - a22*(a41*a54 - a44*a51) + a24*(a41*a52 - a42*a51)) - a14*( + a21*(a42*a53 - a43*a52) - a22*(a41*a53 - a43*a51) + a23*(a41*a52 - a42*a51)); double m41 = -( + a12*( + a23*(a34*a55 - a35*a54) - a24*(a33*a55 - a35*a53) + a25*(a33*a54 - a34*a53)) - a13*( + a22*(a34*a55 - a35*a54) - a24*(a32*a55 - a35*a52) + a25*(a32*a54 - a34*a52)) + a14*( + a22*(a33*a55 - a35*a53) - a23*(a32*a55 - a35*a52) + a25*(a32*a53 - a33*a52)) - a15*( + a22*(a33*a54 - a34*a53) - a23*(a32*a54 - a34*a52) + a24*(a32*a53 - a33*a52))); double m42 = + a11*( + a23*(a34*a55 - a35*a54) - a24*(a33*a55 - a35*a53) + a25*(a33*a54 - a34*a53)) - a13*( + a21*(a34*a55 - a35*a54) - a24*(a31*a55 - a35*a51) + a25*(a31*a54 - a34*a51)) + a14*( + a21*(a33*a55 - a35*a53) - a23*(a31*a55 - a35*a51) + a25*(a31*a53 - a33*a51)) - a15*( + a21*(a33*a54 - a34*a53) - a23*(a31*a54 - a34*a51) + a24*(a31*a53 - a33*a51)); double m43 = -( + a11*( + a22*(a34*a55 - a35*a54) - a24*(a32*a55 - a35*a52) + a25*(a32*a54 - a34*a52)) - a12*( + a21*(a34*a55 - a35*a54) - a24*(a31*a55 - a35*a51) + a25*(a31*a54 - a34*a51)) + a14*( + a21*(a32*a55 - a35*a52) - a22*(a31*a55 - a35*a51) + a25*(a31*a52 - a32*a51)) - a15*( + a21*(a32*a54 - a34*a52) - a22*(a31*a54 - a34*a51) + a24*(a31*a52 - a32*a51))); double m44 = + a11*( + a22*(a33*a55 - a35*a53) - a23*(a32*a55 - a35*a52) + a25*(a32*a53 - a33*a52)) - a12*( + a21*(a33*a55 - a35*a53) - a23*(a31*a55 - a35*a51) + a25*(a31*a53 - a33*a51)) + a13*( + a21*(a32*a55 - a35*a52) - a22*(a31*a55 - a35*a51) + a25*(a31*a52 - a32*a51)) - a15*( + a21*(a32*a53 - a33*a52) - a22*(a31*a53 - a33*a51) + a23*(a31*a52 - a32*a51)); double m45 = -( + a11*( + a22*(a33*a54 - a34*a53) - a23*(a32*a54 - a34*a52) + a24*(a32*a53 - a33*a52)) - a12*( + a21*(a33*a54 - a34*a53) - a23*(a31*a54 - a34*a51) + a24*(a31*a53 - a33*a51)) + a13*( + a21*(a32*a54 - a34*a52) - a22*(a31*a54 - a34*a51) + a24*(a31*a52 - a32*a51)) - a14*( + a21*(a32*a53 - a33*a52) - a22*(a31*a53 - a33*a51) + a23*(a31*a52 - a32*a51))); double m51 = + a12*( + a23*(a34*a45 - a35*a44) - a24*(a33*a45 - a35*a43) + a25*(a33*a44 - a34*a43)) - a13*( + a22*(a34*a45 - a35*a44) - a24*(a32*a45 - a35*a42) + a25*(a32*a44 - a34*a42)) + a14*( + a22*(a33*a45 - a35*a43) - a23*(a32*a45 - a35*a42) + a25*(a32*a43 - a33*a42)) - a15*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)); double m52 = -( + a11*( + a23*(a34*a45 - a35*a44) - a24*(a33*a45 - a35*a43) + a25*(a33*a44 - a34*a43)) - a13*( + a21*(a34*a45 - a35*a44) - a24*(a31*a45 - a35*a41) + a25*(a31*a44 - a34*a41)) + a14*( + a21*(a33*a45 - a35*a43) - a23*(a31*a45 - a35*a41) + a25*(a31*a43 - a33*a41)) - a15*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41))); double m53 = + a11*( + a22*(a34*a45 - a35*a44) - a24*(a32*a45 - a35*a42) + a25*(a32*a44 - a34*a42)) - a12*( + a21*(a34*a45 - a35*a44) - a24*(a31*a45 - a35*a41) + a25*(a31*a44 - a34*a41)) + a14*( + a21*(a32*a45 - a35*a42) - a22*(a31*a45 - a35*a41) + a25*(a31*a42 - a32*a41)) - a15*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)); double m54 = -( + a11*( + a22*(a33*a45 - a35*a43) - a23*(a32*a45 - a35*a42) + a25*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a45 - a35*a43) - a23*(a31*a45 - a35*a41) + a25*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a45 - a35*a42) - a22*(a31*a45 - a35*a41) + a25*(a31*a42 - a32*a41)) - a15*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); double m55 = + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41)); double det = (a11*m11 + a12*m12 + a13*m13 + a14*m14 + a15*m15)/scale; data = inv.data; data[0] = m11 / det; data[1] = m21 / det; data[2] = m31 / det; data[3] = m41 / det; data[4] = m51 / det; data[5] = m12 / det; data[6] = m22 / det; data[7] = m32 / det; data[8] = m42 / det; data[9] = m52 / det; data[10] = m13 / det; data[11] = m23 / det; data[12] = m33 / det; data[13] = m43 / det; data[14] = m53 / det; data[15] = m14 / det; data[16] = m24 / det; data[17] = m34 / det; data[18] = m44 / det; data[19] = m54 / det; data[20] = m15 / det; data[21] = m25 / det; data[22] = m35 / det; data[23] = m45 / det; data[24] = m55 / det; } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400217255ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/dense/mult/MatrixMatrixMult.java000066400000000000000000001346001256171534400260670ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.RowD1Matrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixDimensionException; /** *

* This class contains various types of matrix matrix multiplication operations for {@link RowD1Matrix64F}. *

*

* Two algorithms that are equivalent can often have very different runtime performance. * This is because of how modern computers uses fast memory caches to speed up reading/writing to data. * Depending on the order in which variables are processed different algorithms can run much faster than others, * even if the number of operations is the same. *

* *

* Algorithms that are labeled as 'reorder' are designed to avoid caching jumping issues, some times at the cost * of increasing the number of operations. This is important for large matrices. The straight forward * implementation seems to be faster for small matrices. *

* *

* Algorithms that are labeled as 'aux' use an auxiliary array of length n. This array is used to create * a copy of an out of sequence column vector that is referenced several times. This reduces the number * of cache misses. If the 'aux' parameter passed in is null then the array is declared internally. *

* *

* Typically the straight forward implementation runs about 30% faster on smaller matrices and * about 5 times slower on larger matrices. This is all computer architecture and matrix shape/size specific. *

* *

*

******** IMPORTANT **********
* This class was auto generated using {@link org.ejml.alg.dense.mult.GeneratorMatrixMatrixMult} *

* * @author Peter Abeles */ public class MatrixMatrixMult { /** * @see org.ejml.ops.CommonOps#mult( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F) */ public static void mult_reorder( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( a.numCols == 0 || a.numRows == 0 ) { CommonOps.fill(c,0); return; } double valA; int indexCbase= 0; int endOfKLoop = b.numRows*b.numCols; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*a.numCols; // need to assign c.data to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + b.numCols; valA = a.get(indexA++); while( indexB < end ) { c.set(indexC++ , valA*b.get(indexB++)); } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + b.numCols; valA = a.get(indexA++); while( indexB < end ) { // j loop c.plus(indexC++ , valA*b.get(indexB++)); } } indexCbase += c.numCols; } } /** * @see org.ejml.ops.CommonOps#mult( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F) */ public static void mult_small( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } int aIndexStart = 0; int cIndex = 0; for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < b.numCols; j++ ) { double total = 0; int indexA = aIndexStart; int indexB = j; int end = indexA + b.numRows; while( indexA < end ) { total += a.get(indexA++) * b.get(indexB); indexB += b.numCols; } c.set( cIndex++ , total ); } aIndexStart += a.numCols; } } /** * @see org.ejml.ops.CommonOps#mult( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F) */ public static void mult_aux( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c , double []aux ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( aux == null ) aux = new double[ b.numRows ]; for( int j = 0; j < b.numCols; j++ ) { // create a copy of the column in B to avoid cache issues for( int k = 0; k < b.numRows; k++ ) { aux[k] = b.unsafe_get(k,j); } int indexA = 0; for( int i = 0; i < a.numRows; i++ ) { double total = 0; for( int k = 0; k < b.numRows; ) { total += a.get(indexA++)*aux[k++]; } c.set( i*c.numCols+j , total ); } } } /** * @see org.ejml.ops.CommonOps#multTransA( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F) */ public static void multTransA_reorder( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numRows != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numCols != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( a.numCols == 0 || a.numRows == 0 ) { CommonOps.fill(c,0); return; } double valA; for( int i = 0; i < a.numCols; i++ ) { int indexC_start = i*c.numCols; // first assign R valA = a.get(i); int indexB = 0; int end = indexB+b.numCols; int indexC = indexC_start; while( indexB * Specialized operations for performing inner and outer products for matrices. *

* *

* inner product: B=AT*A
* outer product: B=A*AT *

* * @author Peter Abeles */ public class MatrixMultProduct { public static void outer(RowD1Matrix64F a, RowD1Matrix64F c) { for( int i = 0; i < a.numRows; i++ ) { int indexC1 = i*c.numCols+i; int indexC2 = indexC1; for( int j = i; j < a.numRows; j++ , indexC2 += c.numCols) { int indexA = i*a.numCols; int indexB = j*a.numCols; double sum = 0; int end = indexA + a.numCols; for( ; indexA < end; indexA++,indexB++ ) { sum += a.data[indexA]*a.data[indexB]; } c.data[indexC2] = c.data[indexC1++] = sum; } } // for( int i = 0; i < a.numRows; i++ ) { // for( int j = 0; j < a.numRows; j++ ) { // double sum = 0; // for( int k = 0; k < a.numCols; k++ ) { // sum += a.get(i,k)*a.get(j,k); // } // c.set(i,j,sum); // } // } } public static void inner_small(RowD1Matrix64F a, RowD1Matrix64F c) { for( int i = 0; i < a.numCols; i++ ) { for( int j = i; j < a.numCols; j++ ) { int indexC1 = i*c.numCols+j; int indexC2 = j*c.numCols+i; int indexA = i; int indexB = j; double sum = 0; int end = indexA + a.numRows*a.numCols; for( ; indexA < end; indexA += a.numCols, indexB += a.numCols ) { sum += a.data[indexA]*a.data[indexB]; } c.data[indexC1] = c.data[indexC2] = sum; } } // for( int i = 0; i < a.numCols; i++ ) { // for( int j = i; j < a.numCols; j++ ) { // double sum = 0; // for( int k = 0; k < a.numRows; k++ ) { // sum += a.get(k,i)*a.get(k,j); // } // c.set(i,j,sum); // c.set(j,i,sum); // } // } } public static void inner_reorder(RowD1Matrix64F a, RowD1Matrix64F c) { for( int i = 0; i < a.numCols; i++ ) { int indexC = i*c.numCols+i; double valAi = a.data[i]; for( int j = i; j < a.numCols; j++ ) { c.data[indexC++] = valAi*a.data[j]; } for( int k = 1; k < a.numRows; k++ ) { indexC = i*c.numCols+i; int indexB = k*a.numCols+i; valAi = a.data[indexB]; for( int j = i; j < a.numCols; j++ ) { c.data[indexC++] += valAi*a.data[indexB++]; } } indexC = i*c.numCols+i; int indexC2 = indexC; for( int j = i; j < a.numCols; j++ , indexC2 += c.numCols) { c.data[indexC2] = c.data[indexC++]; } } // for( int i = 0; i < a.numCols; i++ ) { // for( int j = i; j < a.numCols; j++ ) { // c.set(i,j,a.get(0,i)*a.get(0,j)); // } // // for( int k = 1; k < a.numRows; k++ ) { // for( int j = i; j < a.numCols; j++ ) { // c.set(i,j, c.get(i,j)+ a.get(k,i)*a.get(k,j)); // } // } // for( int j = i; j < a.numCols; j++ ) { // c.set(j,i,c.get(i,j)); // } // } } public static void inner_reorder_upper(RowD1Matrix64F a, RowD1Matrix64F c) { for( int i = 0; i < a.numCols; i++ ) { int indexC = i*c.numCols+i; double valAi = a.data[i]; for( int j = i; j < a.numCols; j++ ) { c.data[indexC++] = valAi*a.data[j]; } for( int k = 1; k < a.numRows; k++ ) { indexC = i*c.numCols+i; int indexB = k*a.numCols+i; valAi = a.data[indexB]; for( int j = i; j < a.numCols; j++ ) { c.data[indexC++] += valAi*a.data[indexB++]; } } } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/mult/MatrixVectorMult.java000066400000000000000000000275351256171534400260750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixDimensionException; /** *

* This class contains various types of matrix vector multiplcation operations for {@link DenseMatrix64F}. *

*

* If a matrix has only one column or row then it is a vector. There are faster algorithms * that can be used to multiply matrices by vectors. Strangely, even though the operations * count smaller, the difference between this and a regular matrix multiply is insignificant * for large matrices. The smaller matrices there is about a 40% speed improvement. In * practice the speed improvement for smaller matrices is not noticeable unless 10s of millions * of matrix multiplications are being performed. *

* * @author Peter Abeles */ @SuppressWarnings({"ForLoopReplaceableByForEach"}) public class MatrixVectorMult { /** *

* Performs a matrix vector multiply.
*
* c = A * b
* and
* c = A * bT
*
* ci = Sum{ j=1:n, aij * bj}
*
* where A is a matrix, b is a column or transposed row vector, and c is a column vector. *

* * @param A A matrix that is m by n. Not modified. * @param B A vector that has length n. Not modified. * @param C A column vector that has length m. Modified. */ public static void mult( RowD1Matrix64F A, D1Matrix64F B, D1Matrix64F C) { if( C.numCols != 1 ) { throw new MatrixDimensionException("C is not a column vector"); } else if( C.numRows != A.numRows ) { throw new MatrixDimensionException("C is not the expected length"); } if( B.numRows == 1 ) { if( A.numCols != B.numCols ) { throw new MatrixDimensionException("A and B are not compatible"); } } else if( B.numCols == 1 ) { if( A.numCols != B.numRows ) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if( A.numCols == 0 ) { CommonOps.fill(C,0); return; } int indexA = 0; int cIndex = 0; double b0 = B.get(0); for( int i = 0; i < A.numRows; i++ ) { double total = A.get(indexA++) * b0; for( int j = 1; j < A.numCols; j++ ) { total += A.get(indexA++) * B.get(j); } C.set(cIndex++, total); } } /** *

* Performs a matrix vector multiply.
*
* C = C + A * B
* or
* C = C + A * BT
*
* ci = Sum{ j=1:n, ci + aij * bj}
*
* where A is a matrix, B is a column or transposed row vector, and C is a column vector. *

* * @param A A matrix that is m by n. Not modified. * @param B A vector that has length n. Not modified. * @param C A column vector that has length m. Modified. */ public static void multAdd( RowD1Matrix64F A , D1Matrix64F B , D1Matrix64F C ) { if( C.numCols != 1 ) { throw new MatrixDimensionException("C is not a column vector"); } else if( C.numRows != A.numRows ) { throw new MatrixDimensionException("C is not the expected length"); } if( B.numRows == 1 ) { if( A.numCols != B.numCols ) { throw new MatrixDimensionException("A and B are not compatible"); } } else if( B.numCols == 1 ) { if( A.numCols != B.numRows ) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if( A.numCols == 0 ) { return; } int indexA = 0; int cIndex = 0; for( int i = 0; i < A.numRows; i++ ) { double total = A.get(indexA++) * B.get(0); for( int j = 1; j < A.numCols; j++ ) { total += A.get(indexA++) * B.get(j); } C.plus(cIndex++ , total ); } } /** *

* Performs a matrix vector multiply.
*
* C = AT * B
* where B is a column vector.
* or
* C = AT * BT
* where B is a row vector.
*
* ci = Sum{ j=1:n, aji * bj}
*
* where A is a matrix, B is a column or transposed row vector, and C is a column vector. *

*

* This implementation is optimal for small matrices. There is a huge performance hit when * used on large matrices due to CPU cache issues. *

* * @param A A matrix that is m by n. Not modified. * @param B A that has length m and is a column. Not modified. * @param C A column vector that has length n. Modified. */ public static void multTransA_small( RowD1Matrix64F A , D1Matrix64F B , D1Matrix64F C ) { if( C.numCols != 1 ) { throw new MatrixDimensionException("C is not a column vector"); } else if( C.numRows != A.numCols ) { throw new MatrixDimensionException("C is not the expected length"); } if( B.numRows == 1 ) { if( A.numRows != B.numCols ) { throw new MatrixDimensionException("A and B are not compatible"); } } else if( B.numCols == 1 ) { if( A.numRows != B.numRows ) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } int cIndex = 0; for( int i = 0; i < A.numCols; i++ ) { double total = 0.0; int indexA = i; for( int j = 0; j < A.numRows; j++ ) { total += A.get(indexA) * B.get(j); indexA += A.numCols; } C.set(cIndex++ , total); } } /** * An alternative implementation of {@link #multTransA_small} that performs well on large * matrices. There is a relative performance hit when used on small matrices. * * @param A A matrix that is m by n. Not modified. * @param B A Vector that has length m. Not modified. * @param C A column vector that has length n. Modified. */ public static void multTransA_reorder( RowD1Matrix64F A , D1Matrix64F B , D1Matrix64F C ) { if( C.numCols != 1 ) { throw new MatrixDimensionException("C is not a column vector"); } else if( C.numRows != A.numCols ) { throw new MatrixDimensionException("C is not the expected length"); } if( B.numRows == 1 ) { if( A.numRows != B.numCols ) { throw new MatrixDimensionException("A and B are not compatible"); } } else if( B.numCols == 1 ) { if( A.numRows != B.numRows ) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if( A.numRows == 0 ) { CommonOps.fill(C,0); return; } double B_val = B.get(0); for( int i = 0; i < A.numCols; i++ ) { C.set( i , A.get(i) * B_val ); } int indexA = A.numCols; for( int i = 1; i < A.numRows; i++ ) { B_val = B.get(i); for( int j = 0; j < A.numCols; j++ ) { C.plus( j , A.get(indexA++) * B_val ); } } } /** *

* Performs a matrix vector multiply.
*
* C = C + AT * B
* or
* C = CT + AT * BT
*
* ci = Sum{ j=1:n, ci + aji * bj}
*
* where A is a matrix, B is a column or transposed row vector, and C is a column vector. *

*

* This implementation is optimal for small matrices. There is a huge performance hit when * used on large matrices due to CPU cache issues. *

* * @param A A matrix that is m by n. Not modified. * @param B A vector that has length m. Not modified. * @param C A column vector that has length n. Modified. */ public static void multAddTransA_small( RowD1Matrix64F A , D1Matrix64F B , D1Matrix64F C ) { if( C.numCols != 1 ) { throw new MatrixDimensionException("C is not a column vector"); } else if( C.numRows != A.numCols ) { throw new MatrixDimensionException("C is not the expected length"); } if( B.numRows == 1 ) { if( A.numRows != B.numCols ) { throw new MatrixDimensionException("A and B are not compatible"); } } else if( B.numCols == 1 ) { if( A.numRows != B.numRows ) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } int cIndex = 0; for( int i = 0; i < A.numCols; i++ ) { double total = 0.0; int indexA = i; for( int j = 0; j < A.numRows; j++ ) { total += A.get(indexA) * B.get(j); indexA += A.numCols; } C.plus( cIndex++ , total ); } } /** * An alternative implementation of {@link #multAddTransA_small} that performs well on large * matrices. There is a relative performance hit when used on small matrices. * * @param A A matrix that is m by n. Not modified. * @param B A vector that has length m. Not modified. * @param C A column vector that has length n. Modified. */ public static void multAddTransA_reorder( RowD1Matrix64F A , D1Matrix64F B , D1Matrix64F C ) { if( C.numCols != 1 ) { throw new MatrixDimensionException("C is not a column vector"); } else if( C.numRows != A.numCols ) { throw new MatrixDimensionException("C is not the expected length"); } if( B.numRows == 1 ) { if( A.numRows != B.numCols ) { throw new MatrixDimensionException("A and B are not compatible"); } } else if( B.numCols == 1 ) { if( A.numRows != B.numRows ) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if( A.numRows == 0 ) { return; } int indexA = 0; for( int j = 0; j < A.numRows; j++ ) { double B_val = B.get(j); for( int i = 0; i < A.numCols; i++ ) { C.plus( i , A.get(indexA++) * B_val ); } } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/mult/SubmatrixOps.java000066400000000000000000000025461256171534400252370ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.RowD1Matrix64F; /** * Operations that are performed on a submatrix inside a larger matrix. * * @author Peter Abeles */ public class SubmatrixOps { public static void setSubMatrix( RowD1Matrix64F src , RowD1Matrix64F dst , int srcRow , int srcCol , int dstRow , int dstCol , int numSubRows, int numSubCols ) { for( int i = 0; i < numSubRows; i++ ) { for( int j = 0; j < numSubCols; j++ ) { double val = src.get(i+srcRow,j+srcCol); dst.set(i+dstRow,j+dstCol,val); } } } } ejml-0.28/main/dense64/src/org/ejml/alg/dense/mult/VectorVectorMult.java000066400000000000000000000230711256171534400260620ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; /** * Operations that involve multiplication of two vectors. * * @author Peter Abeles */ public class VectorVectorMult { /** *

* Computes the inner product of the two vectors. In geometry this is known as the dot product.
*
* ∑k=1:n xk * yk
* where x and y are vectors with n elements. *

* *

* These functions are often used inside of highly optimized code and therefor sanity checks are * kept to a minimum. It is not recommended that any of these functions be used directly. *

* * @param x A vector with n elements. Not modified. * @param y A vector with n elements. Not modified. * @return The inner product of the two vectors. */ public static double innerProd( D1Matrix64F x, D1Matrix64F y ) { int m = x.getNumElements(); double total = 0; for( int i = 0; i < m; i++ ) { total += x.get(i) * y.get(i); } return total; } /** *

* return = xT*A*y *

* * @param x A vector with n elements. Not modified. * @param A A matrix with n by m elements. Not modified. * @param y A vector with m elements. Not modified. * @return The results. */ public static double innerProdA( D1Matrix64F x, D1Matrix64F A , D1Matrix64F y ) { int n = A.numRows; int m = A.numCols; if( x.getNumElements() != n ) throw new IllegalArgumentException("Unexpected number of elements in x"); if( y.getNumElements() != m ) throw new IllegalArgumentException("Unexpected number of elements in y"); double result = 0; for( int i = 0; i < m; i++ ) { double total = 0; for( int j = 0; j < n; j++ ) { total += x.get(j)*A.unsafe_get(j,i); } result += total*y.get(i); } return result; } /** *

* xTATy *

* * @param x A vector with n elements. Not modified. * @param A A matrix with n by n elements. Not modified. * @param y A vector with n elements. Not modified. * @return The results. */ // TODO better name for this public static double innerProdTranA( D1Matrix64F x, D1Matrix64F A , D1Matrix64F y ) { int n = A.numRows; if( n != A.numCols) throw new IllegalArgumentException("A must be square"); if( x.getNumElements() != n ) throw new IllegalArgumentException("Unexpected number of elements in x"); if( y.getNumElements() != n ) throw new IllegalArgumentException("Unexpected number of elements in y"); double result = 0; for( int i = 0; i < n; i++ ) { double total = 0; for( int j = 0; j < n; j++ ) { total += x.get(j)*A.unsafe_get(i,j); } result += total*y.get(i); } return result; } /** *

* Sets A ∈ ℜ m × n equal to an outer product multiplication of the two * vectors. This is also known as a rank-1 operation.
*
* A = x * y' * where x ∈ ℜ m and y ∈ ℜ n are vectors. *

*

* Which is equivalent to: Aij = xi*yj *

* *

* These functions are often used inside of highly optimized code and therefor sanity checks are * kept to a minimum. It is not recommended that any of these functions be used directly. *

* * @param x A vector with m elements. Not modified. * @param y A vector with n elements. Not modified. * @param A A Matrix with m by n elements. Modified. */ public static void outerProd( D1Matrix64F x, D1Matrix64F y, RowD1Matrix64F A ) { int m = A.numRows; int n = A.numCols; int index = 0; for( int i = 0; i < m; i++ ) { double xdat = x.get(i); for( int j = 0; j < n; j++ ) { A.set(index++ , xdat*y.get(j) ); } } } /** *

* Adds to A ∈ ℜ m × n the results of an outer product multiplication * of the two vectors. This is also known as a rank 1 update.
*
* A = A + γ x * yT * where x ∈ ℜ m and y ∈ ℜ n are vectors. *

*

* Which is equivalent to: Aij = Aij + γ xi*yj *

* *

* These functions are often used inside of highly optimized code and therefor sanity checks are * kept to a minimum. It is not recommended that any of these functions be used directly. *

* * @param gamma A multiplication factor for the outer product. * @param x A vector with m elements. Not modified. * @param y A vector with n elements. Not modified. * @param A A Matrix with m by n elements. Modified. */ public static void addOuterProd( double gamma , D1Matrix64F x, D1Matrix64F y, RowD1Matrix64F A ) { int m = A.numRows; int n = A.numCols; int index = 0; if( gamma == 1.0 ) { for( int i = 0; i < m; i++ ) { double xdat = x.get(i); for( int j = 0; j < n; j++ ) { A.plus( index++ , xdat*y.get(j) ); } } } else { for( int i = 0; i < m; i++ ) { double xdat = x.get(i); for( int j = 0; j < n; j++ ) { A.plus( index++ , gamma*xdat*y.get(j)); } } } } /** *

* Multiplies a householder reflection against a vector:
*
* y = (I + γ u uT)x
*

*

* The Householder reflection is used in some implementations of QR decomposition. *

* @param u A vector. Not modified. * @param x a vector. Not modified. * @param y Vector where the result are written to. */ public static void householder( double gamma, D1Matrix64F u , D1Matrix64F x , D1Matrix64F y ) { int n = u.getNumElements(); double sum = 0; for( int i = 0; i < n; i++ ) { sum += u.get(i)*x.get(i); } for( int i = 0; i < n; i++ ) { y.set( i , x.get(i) + gamma*u.get(i)*sum); } } /** *

* Performs a rank one update on matrix A using vectors u and w. The results are stored in B.
*
* B = A + γ u wT
*

*

* This is called a rank1 update because the matrix u wT has a rank of 1. Both A and B * can be the same matrix instance, but there is a special rank1Update for that. *

* * @param gamma A scalar. * @param A A m by m matrix. Not modified. * @param u A vector with m elements. Not modified. * @param w A vector with m elements. Not modified. * @param B A m by m matrix where the results are stored. Modified. */ public static void rank1Update( double gamma, DenseMatrix64F A , DenseMatrix64F u , DenseMatrix64F w , DenseMatrix64F B ) { int n = u.getNumElements(); int matrixIndex = 0; for( int i = 0; i < n; i++ ) { double elementU = u.data[i]; for( int j = 0; j < n; j++ , matrixIndex++) { B.data[matrixIndex] = A.data[matrixIndex] + gamma*elementU*w.data[j]; } } } /** *

* Performs a rank one update on matrix A using vectors u and w. The results are stored in A.
*
* A = A + γ u wT
*

*

* This is called a rank1 update because the matrix u wT has a rank of 1. *

* * @param gamma A scalar. * @param A A m by m matrix. Modified. * @param u A vector with m elements. Not modified. */ public static void rank1Update( double gamma, DenseMatrix64F A , DenseMatrix64F u , DenseMatrix64F w ) { int n = u.getNumElements(); int matrixIndex = 0; for( int i = 0; i < n; i++ ) { double elementU = u.data[i]; for( int j = 0; j < n; j++ ) { A.data[matrixIndex++] += gamma*elementU*w.data[j]; } } } } ejml-0.28/main/dense64/src/org/ejml/alg/fixed/000077500000000000000000000000001256171534400207455ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/fixed/FixedOps2.java000066400000000000000000000756221256171534400234270ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix2_64F; import org.ejml.data.FixedMatrix2x2_64F; /** *

Common matrix operations for fixed sized matrices which are 2 x 2 or 2 element vectors.

*

DO NOT MODIFY. Automatically generated code created by GenerateFixedOps

* * @author Peter Abeles */ public class FixedOps2 { /** *

Performs the following operation:
*
* c = a + b
* cij = aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c ) { c.a11 = a.a11 + b.a11; c.a12 = a.a12 + b.a12; c.a21 = a.a21 + b.a21; c.a22 = a.a22 + b.a22; } /** *

Performs the following operation:
*
* c = a + b
* ci = ai + bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void add( FixedMatrix2_64F a , FixedMatrix2_64F b , FixedMatrix2_64F c ) { c.a1 = a.a1 + b.a1; c.a2 = a.a2 + b.a2; } /** *

Performs the following operation:
*
* a = a + b
* aij = aij + bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b ) { a.a11 += b.a11; a.a12 += b.a12; a.a21 += b.a21; a.a22 += b.a22; } /** *

Performs the following operation:
*
* a = a + b
* ai = ai + bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void addEquals( FixedMatrix2_64F a , FixedMatrix2_64F b ) { a.a1 += b.a1; a.a2 += b.a2; } /** *

Performs the following operation:
*
* c = a - b
* cij = aij - bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void subtract( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c ) { c.a11 = a.a11 - b.a11; c.a12 = a.a12 - b.a12; c.a21 = a.a21 - b.a21; c.a22 = a.a22 - b.a22; } /** *

Performs the following operation:
*
* c = a - b
* ci = ai - bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void subtract( FixedMatrix2_64F a , FixedMatrix2_64F b , FixedMatrix2_64F c ) { c.a1 = a.a1 - b.a1; c.a2 = a.a2 - b.a2; } /** *

Performs the following operation:
*
* a = a - b
* aij = aij - bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void subtractEquals( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b ) { a.a11 -= b.a11; a.a12 -= b.a12; a.a21 -= b.a21; a.a22 -= b.a22; } /** *

Performs the following operation:
*
* a = a - b
* ai = ai - bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void subtractEquals( FixedMatrix2_64F a , FixedMatrix2_64F b ) { a.a1 -= b.a1; a.a2 -= b.a2; } /** * Performs an in-place transpose. This algorithm is only efficient for square * matrices. * * @param m The matrix that is to be transposed. Modified. */ public static void transpose( FixedMatrix2x2_64F m ) { double tmp; tmp = m.a12; m.a12 = m.a21; m.a21 = tmp; } /** *

* Transposes matrix 'a' and stores the results in 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'. *

* * @param input The original matrix. Not modified. * @param output Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static FixedMatrix2x2_64F transpose( FixedMatrix2x2_64F input , FixedMatrix2x2_64F output ) { if( input == null ) input = new FixedMatrix2x2_64F(); output.a11 = input.a11; output.a12 = input.a21; output.a21 = input.a12; output.a22 = input.a22; return output; } /** *

Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a21; c.a12 = a.a11*b.a12 + a.a12*b.a22; c.a21 = a.a21*b.a11 + a.a22*b.a21; c.a22 = a.a21*b.a12 + a.a22*b.a22; } /** *

Performs the following operation:
*
* c = aT * b
*
* cij = ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a21; c.a12 = a.a11*b.a12 + a.a21*b.a22; c.a21 = a.a12*b.a11 + a.a22*b.a21; c.a22 = a.a12*b.a12 + a.a22*b.a22; } /** *

* Performs the following operation:
*
* c = aT * bT
* cij = ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransAB( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a12; c.a12 = a.a11*b.a21 + a.a21*b.a22; c.a21 = a.a12*b.a11 + a.a22*b.a12; c.a22 = a.a12*b.a21 + a.a22*b.a22; } /** *

* Performs the following operation:
*
* c = a * bT
* cij = ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransB( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a12; c.a12 = a.a11*b.a21 + a.a12*b.a22; c.a21 = a.a21*b.a11 + a.a22*b.a12; c.a22 = a.a21*b.a21 + a.a22*b.a22; } /** *

Performs the following operation:
*
* c += a * b
*
* cij += ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a21; c.a12 += a.a11*b.a12 + a.a12*b.a22; c.a21 += a.a21*b.a11 + a.a22*b.a21; c.a22 += a.a21*b.a12 + a.a22*b.a22; } /** *

Performs the following operation:
*
* c += aT * b
*
* cij += ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a21; c.a12 += a.a11*b.a12 + a.a21*b.a22; c.a21 += a.a12*b.a11 + a.a22*b.a21; c.a22 += a.a12*b.a12 + a.a22*b.a22; } /** *

* Performs the following operation:
*
* c += aT * bT
* cij += ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a12; c.a12 += a.a11*b.a21 + a.a21*b.a22; c.a21 += a.a12*b.a11 + a.a22*b.a12; c.a22 += a.a12*b.a21 + a.a22*b.a22; } /** *

* Performs the following operation:
*
* c += a * bT
* cij += ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransB( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a12; c.a12 += a.a11*b.a21 + a.a12*b.a22; c.a21 += a.a21*b.a11 + a.a22*b.a12; c.a22 += a.a21*b.a21 + a.a22*b.a22; } /** *

Performs matrix to vector multiplication:
*
* c = a * b
*
* ci = ∑k=1:n { aik * bk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix2x2_64F a , FixedMatrix2_64F b , FixedMatrix2_64F c) { c.a1 = a.a11*b.a1 + a.a12*b.a2; c.a2 = a.a21*b.a1 + a.a22*b.a2; } /** *

Performs vector to matrix multiplication:
*
* c = a * b
*
* cj = ∑k=1:n { bk * akj } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix2_64F a , FixedMatrix2x2_64F b , FixedMatrix2_64F c) { c.a1 = a.a1*b.a11 + a.a2*b.a21; c.a2 = a.a1*b.a12 + a.a2*b.a22; } /** *

Performs the vector dot product:
*
* c = a * b
*
* c> = ∑k=1:n { bk * ak } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @return The dot product */ public static double dot( FixedMatrix2_64F a , FixedMatrix2_64F b ) { return a.a1*b.a1 + a.a2*b.a2; } /** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @param a A matrix. */ public static void setIdentity( FixedMatrix2x2_64F a ) { a.a11 = 1; a.a21 = 0; a.a12 = 0; a.a22 = 1; } /** * Inverts matrix 'a' using minor matrices and stores the results in 'inv'. Scaling is applied to improve * stability against overflow and underflow. * * WARNING: Potentially less stable than using LU decomposition. * * @param a Input matrix. Not modified. * @param inv Inverted output matrix. Modified. * @return true if it was successful or false if it failed. Not always reliable. */ public static boolean invert( FixedMatrix2x2_64F a , FixedMatrix2x2_64F inv ) { double scale = 1.0/elementMaxAbs(a); double a11 = a.a11*scale; double a12 = a.a12*scale; double a21 = a.a21*scale; double a22 = a.a22*scale; double m11 = a22; double m12 = -( a21); double m21 = -( a12); double m22 = a11; double det = (a11*m11 + a12*m12)/scale; inv.a11 = m11/det; inv.a12 = m21/det; inv.a21 = m12/det; inv.a22 = m22/det; return !Double.isNaN(det) && !Double.isInfinite(det); } /** * Computes the determinant using minor matrices. *

* WARNING: Potentially less stable than using LU decomposition. * * @param mat Input matrix. Not modified. * @return The determinant. */ public static double det( FixedMatrix2x2_64F mat ) { return mat.a11*mat.a22 - mat.a12*mat.a21; } /** *

* This computes the trace of the matrix:
*
* trace = ∑i=1:n { aii } *

*

* The trace is only defined for square matrices. *

* * @param a A square matrix. Not modified. */ public static double trace( FixedMatrix2x2_64F a ) { return a.a11 + a.a21; } /** *

* Extracts all diagonal elements from 'input' and places them inside the 'out' vector. Elements * are in sequential order. *

* * * @param input Matrix. Not modified. * @param out Vector containing diagonal elements. Modified. */ public static void diag( FixedMatrix2x2_64F input , FixedMatrix2_64F out ) { out.a1 = input.a11; out.a2 = input.a22; } /** *

* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix2x2_64F a ) { double max = a.a11; max = Math.max(max,a.a12); max = Math.max(max,a.a21); max = Math.max(max,a.a22); return max; } /** *

* Returns the value of the element in the vector that has the largest value.
*
* Max{ ai } for all i
*

* * @param a A vector. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix2_64F a ) { double max = a.a1; max = Math.max(max,a.a2); return max; } /** *

* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementMaxAbs( FixedMatrix2x2_64F a ) { double max = a.a11; max = Math.max(max,Math.abs(a.a12)); max = Math.max(max,Math.abs(a.a21)); max = Math.max(max,Math.abs(a.a22)); return max; } /** *

* Returns the absolute value of the element in the vector that has the largest absolute value.
*
* Max{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max abs element value of the vector. */ public static double elementMaxAbs( FixedMatrix2_64F a ) { double max = a.a1; max = Math.max(max,Math.abs(a.a2)); return max; } /** *

* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The value of element in the matrix with the minimum value. */ public static double elementMin( FixedMatrix2x2_64F a ) { double min = a.a11; min = Math.min(min, a.a12); min = Math.min(min, a.a21); min = Math.min(min, a.a22); return min; } /** *

* Returns the value of the element in the vector that has the minimum value.
*
* Min{ ai } for all
*

* * @param a A matrix. Not modified. * @return The value of element in the vector with the minimum value. */ public static double elementMin( FixedMatrix2_64F a ) { double min = a.a1; min = Math.min(min, a.a2); return min; } /** *

* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMinAbs( FixedMatrix2x2_64F a ) { double min = a.a11; min = Math.min(min,Math.abs(a.a12)); min = Math.min(min,Math.abs(a.a21)); min = Math.min(min,Math.abs(a.a22)); return min; } /** *

* Returns the absolute value of the element in the vector that has the smallest absolute value.
*
* Min{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max element value of the vector. */ public static double elementMinAbs( FixedMatrix2_64F a ) { double min = a.a1; min = Math.min(min,Math.abs(a.a2)); return min; } /** *

Performs an element by element multiplication operation:
*
* aij = aij * bij
*

* @param a The left matrix in the multiplication operation. Modified. * @param b The right matrix in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b) { a.a11 *= b.a11; a.a12 *= b.a12; a.a21 *= b.a21; a.a22 *= b.a22; } /** *

Performs an element by element multiplication operation:
*
* ai = ai * bi
*

* @param a The left vector in the multiplication operation. Modified. * @param b The right vector in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix2_64F a , FixedMatrix2_64F b) { a.a1 *= b.a1; a.a2 *= b.a2; } /** *

Performs an element by element multiplication operation:
*
* cij = aij * bij
*

* @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c ) { c.a11 = a.a11*b.a11; c.a12 = a.a12*b.a12; c.a21 = a.a21*b.a21; c.a22 = a.a22*b.a22; } /** *

Performs an element by element multiplication operation:
*
* ci = ai * bj
*

* @param a The left vector in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix2_64F a , FixedMatrix2_64F b , FixedMatrix2_64F c ) { c.a1 = a.a1*b.a1; c.a2 = a.a2*b.a2; } /** *

Performs an element by element division operation:
*
* aij = aij / bij
*

* @param a The left matrix in the division operation. Modified. * @param b The right matrix in the division operation. Not modified. */ public static void elementDiv( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b) { a.a11 /= b.a11; a.a12 /= b.a12; a.a21 /= b.a21; a.a22 /= b.a22; } /** *

Performs an element by element division operation:
*
* ai = ai / bi
*

* @param a The left vector in the division operation. Modified. * @param b The right vector in the division operation. Not modified. */ public static void elementDiv( FixedMatrix2_64F a , FixedMatrix2_64F b) { a.a1 /= b.a1; a.a2 /= b.a2; } /** *

Performs an element by element division operation:
*
* cij = aij / bij
*

* @param a The left matrix in the division operation. Not modified. * @param b The right matrix in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix2x2_64F a , FixedMatrix2x2_64F b , FixedMatrix2x2_64F c ) { c.a11 = a.a11/b.a11; c.a12 = a.a12/b.a12; c.a21 = a.a21/b.a21; c.a22 = a.a22/b.a22; } /** *

Performs an element by element division operation:
*
* ci = ai / bi
*

* @param a The left vector in the division operation. Not modified. * @param b The right vector in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix2_64F a , FixedMatrix2_64F b , FixedMatrix2_64F c ) { c.a1 = a.a1/b.a1; c.a2 = a.a2/b.a2; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The matrix that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix2x2_64F a ) { a.a11 *= alpha; a.a12 *= alpha; a.a21 *= alpha; a.a22 *= alpha; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The vector that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix2_64F a ) { a.a1 *= alpha; a.a2 *= alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bij = α*aij *

* * @param alpha the amount each element is multiplied by. * @param a The matrix that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix2x2_64F a , FixedMatrix2x2_64F b ) { b.a11 = a.a11*alpha; b.a12 = a.a12*alpha; b.a21 = a.a21*alpha; b.a22 = a.a22*alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bi = α*ai *

* * @param alpha the amount each element is multiplied by. * @param a The vector that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix2_64F a , FixedMatrix2_64F b ) { b.a1 = a.a1*alpha; b.a2 = a.a2*alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* aij = aij/α *

* * @param a The matrix whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix2x2_64F a , double alpha ) { a.a11 /= alpha; a.a12 /= alpha; a.a21 /= alpha; a.a22 /= alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* ai = ai/α *

* * @param a The vector whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix2_64F a , double alpha ) { a.a1 /= alpha; a.a2 /= alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bij = aij /α *

* * @param alpha the amount each element is divided by. * @param a The matrix whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix2x2_64F a , double alpha , FixedMatrix2x2_64F b ) { b.a11 = a.a11/alpha; b.a12 = a.a12/alpha; b.a21 = a.a21/alpha; b.a22 = a.a22/alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bi = ai /α *

* * @param alpha the amount each element is divided by. * @param a The vector whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix2_64F a , double alpha , FixedMatrix2_64F b ) { b.a1 = a.a1/alpha; b.a2 = a.a2/alpha; } /** *

* Changes the sign of every element in the matrix.
*
* aij = -aij *

* * @param a A matrix. Modified. */ public static void changeSign( FixedMatrix2x2_64F a ) { a.a11 = -a.a11; a.a12 = -a.a12; a.a21 = -a.a21; a.a22 = -a.a22; } /** *

* Changes the sign of every element in the vector.
*
* ai = -ai *

* * @param a A vector. Modified. */ public static void changeSign( FixedMatrix2_64F a ) { a.a1 = -a.a1; a.a2 = -a.a2; } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param a A matrix whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix2x2_64F a , double v ) { a.a11 = v; a.a12 = v; a.a21 = v; a.a22 = v; } /** *

* Sets every element in the vector to the specified value.
*
* ai = value *

* * @param a A vector whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix2_64F a , double v ) { a.a1 = v; a.a2 = v; } /** * Extracts the row from the matrix a. * @param a Input matrix * @param row Which row is to be extracted * @param out output. Storage for the extracted row. If null then a new vector will be returned. * @return The extracted row. */ public static FixedMatrix2_64F extractRow( FixedMatrix2x2_64F a , int row , FixedMatrix2_64F out ) { if( out == null) out = new FixedMatrix2_64F(); switch( row ) { case 0: out.a1 = a.a11; out.a2 = a.a12; break; case 1: out.a1 = a.a21; out.a2 = a.a22; break; default: throw new IllegalArgumentException("Out of bounds row. row = "+row); } return out; } /** * Extracts the column from the matrix a. * @param a Input matrix * @param column Which column is to be extracted * @param out output. Storage for the extracted column. If null then a new vector will be returned. * @return The extracted column. */ public static FixedMatrix2_64F extractColumn( FixedMatrix2x2_64F a , int column , FixedMatrix2_64F out ) { if( out == null) out = new FixedMatrix2_64F(); switch( column ) { case 0: out.a1 = a.a11; out.a2 = a.a21; break; case 1: out.a1 = a.a12; out.a2 = a.a22; break; default: throw new IllegalArgumentException("Out of bounds column. column = "+column); } return out; } } ejml-0.28/main/dense64/src/org/ejml/alg/fixed/FixedOps3.java000066400000000000000000001137061256171534400234240ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix3_64F; import org.ejml.data.FixedMatrix3x3_64F; /** *

Common matrix operations for fixed sized matrices which are 3 x 3 or 3 element vectors.

*

DO NOT MODIFY. Automatically generated code created by GenerateFixedOps

* * @author Peter Abeles */ public class FixedOps3 { /** *

Performs the following operation:
*
* c = a + b
* cij = aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c ) { c.a11 = a.a11 + b.a11; c.a12 = a.a12 + b.a12; c.a13 = a.a13 + b.a13; c.a21 = a.a21 + b.a21; c.a22 = a.a22 + b.a22; c.a23 = a.a23 + b.a23; c.a31 = a.a31 + b.a31; c.a32 = a.a32 + b.a32; c.a33 = a.a33 + b.a33; } /** *

Performs the following operation:
*
* c = a + b
* ci = ai + bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void add( FixedMatrix3_64F a , FixedMatrix3_64F b , FixedMatrix3_64F c ) { c.a1 = a.a1 + b.a1; c.a2 = a.a2 + b.a2; c.a3 = a.a3 + b.a3; } /** *

Performs the following operation:
*
* a = a + b
* aij = aij + bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b ) { a.a11 += b.a11; a.a12 += b.a12; a.a13 += b.a13; a.a21 += b.a21; a.a22 += b.a22; a.a23 += b.a23; a.a31 += b.a31; a.a32 += b.a32; a.a33 += b.a33; } /** *

Performs the following operation:
*
* a = a + b
* ai = ai + bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void addEquals( FixedMatrix3_64F a , FixedMatrix3_64F b ) { a.a1 += b.a1; a.a2 += b.a2; a.a3 += b.a3; } /** *

Performs the following operation:
*
* c = a - b
* cij = aij - bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void subtract( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c ) { c.a11 = a.a11 - b.a11; c.a12 = a.a12 - b.a12; c.a13 = a.a13 - b.a13; c.a21 = a.a21 - b.a21; c.a22 = a.a22 - b.a22; c.a23 = a.a23 - b.a23; c.a31 = a.a31 - b.a31; c.a32 = a.a32 - b.a32; c.a33 = a.a33 - b.a33; } /** *

Performs the following operation:
*
* c = a - b
* ci = ai - bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void subtract( FixedMatrix3_64F a , FixedMatrix3_64F b , FixedMatrix3_64F c ) { c.a1 = a.a1 - b.a1; c.a2 = a.a2 - b.a2; c.a3 = a.a3 - b.a3; } /** *

Performs the following operation:
*
* a = a - b
* aij = aij - bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void subtractEquals( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b ) { a.a11 -= b.a11; a.a12 -= b.a12; a.a13 -= b.a13; a.a21 -= b.a21; a.a22 -= b.a22; a.a23 -= b.a23; a.a31 -= b.a31; a.a32 -= b.a32; a.a33 -= b.a33; } /** *

Performs the following operation:
*
* a = a - b
* ai = ai - bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void subtractEquals( FixedMatrix3_64F a , FixedMatrix3_64F b ) { a.a1 -= b.a1; a.a2 -= b.a2; a.a3 -= b.a3; } /** * Performs an in-place transpose. This algorithm is only efficient for square * matrices. * * @param m The matrix that is to be transposed. Modified. */ public static void transpose( FixedMatrix3x3_64F m ) { double tmp; tmp = m.a12; m.a12 = m.a21; m.a21 = tmp; tmp = m.a13; m.a13 = m.a31; m.a31 = tmp; tmp = m.a23; m.a23 = m.a32; m.a32 = tmp; } /** *

* Transposes matrix 'a' and stores the results in 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'. *

* * @param input The original matrix. Not modified. * @param output Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static FixedMatrix3x3_64F transpose( FixedMatrix3x3_64F input , FixedMatrix3x3_64F output ) { if( input == null ) input = new FixedMatrix3x3_64F(); output.a11 = input.a11; output.a12 = input.a21; output.a13 = input.a31; output.a21 = input.a12; output.a22 = input.a22; output.a23 = input.a32; output.a31 = input.a13; output.a32 = input.a23; output.a33 = input.a33; return output; } /** *

Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31; c.a12 = a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32; c.a13 = a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33; c.a21 = a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31; c.a22 = a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32; c.a23 = a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33; c.a31 = a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31; c.a32 = a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32; c.a33 = a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33; } /** *

Performs the following operation:
*
* c = aT * b
*
* cij = ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31; c.a12 = a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32; c.a13 = a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33; c.a21 = a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31; c.a22 = a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32; c.a23 = a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33; c.a31 = a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31; c.a32 = a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32; c.a33 = a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33; } /** *

* Performs the following operation:
*
* c = aT * bT
* cij = ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransAB( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13; c.a12 = a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23; c.a13 = a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33; c.a21 = a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13; c.a22 = a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23; c.a23 = a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33; c.a31 = a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13; c.a32 = a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23; c.a33 = a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33; } /** *

* Performs the following operation:
*
* c = a * bT
* cij = ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransB( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13; c.a12 = a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23; c.a13 = a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33; c.a21 = a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13; c.a22 = a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23; c.a23 = a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33; c.a31 = a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13; c.a32 = a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23; c.a33 = a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33; } /** *

Performs the following operation:
*
* c += a * b
*
* cij += ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31; c.a12 += a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32; c.a13 += a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33; c.a21 += a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31; c.a22 += a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32; c.a23 += a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33; c.a31 += a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31; c.a32 += a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32; c.a33 += a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33; } /** *

Performs the following operation:
*
* c += aT * b
*
* cij += ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31; c.a12 += a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32; c.a13 += a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33; c.a21 += a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31; c.a22 += a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32; c.a23 += a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33; c.a31 += a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31; c.a32 += a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32; c.a33 += a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33; } /** *

* Performs the following operation:
*
* c += aT * bT
* cij += ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13; c.a12 += a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23; c.a13 += a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33; c.a21 += a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13; c.a22 += a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23; c.a23 += a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33; c.a31 += a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13; c.a32 += a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23; c.a33 += a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33; } /** *

* Performs the following operation:
*
* c += a * bT
* cij += ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransB( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13; c.a12 += a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23; c.a13 += a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33; c.a21 += a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13; c.a22 += a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23; c.a23 += a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33; c.a31 += a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13; c.a32 += a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23; c.a33 += a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33; } /** *

Performs matrix to vector multiplication:
*
* c = a * b
*
* ci = ∑k=1:n { aik * bk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix3x3_64F a , FixedMatrix3_64F b , FixedMatrix3_64F c) { c.a1 = a.a11*b.a1 + a.a12*b.a2 + a.a13*b.a3; c.a2 = a.a21*b.a1 + a.a22*b.a2 + a.a23*b.a3; c.a3 = a.a31*b.a1 + a.a32*b.a2 + a.a33*b.a3; } /** *

Performs vector to matrix multiplication:
*
* c = a * b
*
* cj = ∑k=1:n { bk * akj } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix3_64F a , FixedMatrix3x3_64F b , FixedMatrix3_64F c) { c.a1 = a.a1*b.a11 + a.a2*b.a21 + a.a3*b.a31; c.a2 = a.a1*b.a12 + a.a2*b.a22 + a.a3*b.a32; c.a3 = a.a1*b.a13 + a.a2*b.a23 + a.a3*b.a33; } /** *

Performs the vector dot product:
*
* c = a * b
*
* c> = ∑k=1:n { bk * ak } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @return The dot product */ public static double dot( FixedMatrix3_64F a , FixedMatrix3_64F b ) { return a.a1*b.a1 + a.a2*b.a2 + a.a3*b.a3; } /** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @param a A matrix. */ public static void setIdentity( FixedMatrix3x3_64F a ) { a.a11 = 1; a.a21 = 0; a.a31 = 0; a.a12 = 0; a.a22 = 1; a.a32 = 0; a.a13 = 0; a.a23 = 0; a.a33 = 1; } /** * Inverts matrix 'a' using minor matrices and stores the results in 'inv'. Scaling is applied to improve * stability against overflow and underflow. * * WARNING: Potentially less stable than using LU decomposition. * * @param a Input matrix. Not modified. * @param inv Inverted output matrix. Modified. * @return true if it was successful or false if it failed. Not always reliable. */ public static boolean invert( FixedMatrix3x3_64F a , FixedMatrix3x3_64F inv ) { double scale = 1.0/elementMaxAbs(a); double a11 = a.a11*scale; double a12 = a.a12*scale; double a13 = a.a13*scale; double a21 = a.a21*scale; double a22 = a.a22*scale; double a23 = a.a23*scale; double a31 = a.a31*scale; double a32 = a.a32*scale; double a33 = a.a33*scale; double m11 = a22*a33 - a23*a32; double m12 = -( a21*a33 - a23*a31); double m13 = a21*a32 - a22*a31; double m21 = -( a12*a33 - a13*a32); double m22 = a11*a33 - a13*a31; double m23 = -( a11*a32 - a12*a31); double m31 = a12*a23 - a13*a22; double m32 = -( a11*a23 - a13*a21); double m33 = a11*a22 - a12*a21; double det = (a11*m11 + a12*m12 + a13*m13)/scale; inv.a11 = m11/det; inv.a12 = m21/det; inv.a13 = m31/det; inv.a21 = m12/det; inv.a22 = m22/det; inv.a23 = m32/det; inv.a31 = m13/det; inv.a32 = m23/det; inv.a33 = m33/det; return !Double.isNaN(det) && !Double.isInfinite(det); } /** * Computes the determinant using minor matrices. *

* WARNING: Potentially less stable than using LU decomposition. * * @param mat Input matrix. Not modified. * @return The determinant. */ public static double det( FixedMatrix3x3_64F mat ) { double a = mat.a11*(mat.a22*mat.a33 - mat.a23*mat.a32); double b = mat.a12*(mat.a21*mat.a33 - mat.a23*mat.a31); double c = mat.a13*(mat.a21*mat.a32 - mat.a31*mat.a22); return a-b+c; } /** *

* This computes the trace of the matrix:
*
* trace = ∑i=1:n { aii } *

*

* The trace is only defined for square matrices. *

* * @param a A square matrix. Not modified. */ public static double trace( FixedMatrix3x3_64F a ) { return a.a11 + a.a21 + a.a31; } /** *

* Extracts all diagonal elements from 'input' and places them inside the 'out' vector. Elements * are in sequential order. *

* * * @param input Matrix. Not modified. * @param out Vector containing diagonal elements. Modified. */ public static void diag( FixedMatrix3x3_64F input , FixedMatrix3_64F out ) { out.a1 = input.a11; out.a2 = input.a22; out.a3 = input.a33; } /** *

* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix3x3_64F a ) { double max = a.a11; max = Math.max(max,a.a12); max = Math.max(max,a.a13); max = Math.max(max,a.a21); max = Math.max(max,a.a22); max = Math.max(max,a.a23); max = Math.max(max,a.a31); max = Math.max(max,a.a32); max = Math.max(max,a.a33); return max; } /** *

* Returns the value of the element in the vector that has the largest value.
*
* Max{ ai } for all i
*

* * @param a A vector. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix3_64F a ) { double max = a.a1; max = Math.max(max,a.a2); max = Math.max(max,a.a3); return max; } /** *

* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementMaxAbs( FixedMatrix3x3_64F a ) { double max = a.a11; max = Math.max(max,Math.abs(a.a12)); max = Math.max(max,Math.abs(a.a13)); max = Math.max(max,Math.abs(a.a21)); max = Math.max(max,Math.abs(a.a22)); max = Math.max(max,Math.abs(a.a23)); max = Math.max(max,Math.abs(a.a31)); max = Math.max(max,Math.abs(a.a32)); max = Math.max(max,Math.abs(a.a33)); return max; } /** *

* Returns the absolute value of the element in the vector that has the largest absolute value.
*
* Max{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max abs element value of the vector. */ public static double elementMaxAbs( FixedMatrix3_64F a ) { double max = a.a1; max = Math.max(max,Math.abs(a.a2)); max = Math.max(max,Math.abs(a.a3)); return max; } /** *

* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The value of element in the matrix with the minimum value. */ public static double elementMin( FixedMatrix3x3_64F a ) { double min = a.a11; min = Math.min(min, a.a12); min = Math.min(min, a.a13); min = Math.min(min, a.a21); min = Math.min(min, a.a22); min = Math.min(min, a.a23); min = Math.min(min, a.a31); min = Math.min(min, a.a32); min = Math.min(min, a.a33); return min; } /** *

* Returns the value of the element in the vector that has the minimum value.
*
* Min{ ai } for all
*

* * @param a A matrix. Not modified. * @return The value of element in the vector with the minimum value. */ public static double elementMin( FixedMatrix3_64F a ) { double min = a.a1; min = Math.min(min, a.a2); min = Math.min(min, a.a3); return min; } /** *

* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMinAbs( FixedMatrix3x3_64F a ) { double min = a.a11; min = Math.min(min,Math.abs(a.a12)); min = Math.min(min,Math.abs(a.a13)); min = Math.min(min,Math.abs(a.a21)); min = Math.min(min,Math.abs(a.a22)); min = Math.min(min,Math.abs(a.a23)); min = Math.min(min,Math.abs(a.a31)); min = Math.min(min,Math.abs(a.a32)); min = Math.min(min,Math.abs(a.a33)); return min; } /** *

* Returns the absolute value of the element in the vector that has the smallest absolute value.
*
* Min{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max element value of the vector. */ public static double elementMinAbs( FixedMatrix3_64F a ) { double min = a.a1; min = Math.min(min,Math.abs(a.a2)); min = Math.min(min,Math.abs(a.a3)); return min; } /** *

Performs an element by element multiplication operation:
*
* aij = aij * bij
*

* @param a The left matrix in the multiplication operation. Modified. * @param b The right matrix in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b) { a.a11 *= b.a11; a.a12 *= b.a12; a.a13 *= b.a13; a.a21 *= b.a21; a.a22 *= b.a22; a.a23 *= b.a23; a.a31 *= b.a31; a.a32 *= b.a32; a.a33 *= b.a33; } /** *

Performs an element by element multiplication operation:
*
* ai = ai * bi
*

* @param a The left vector in the multiplication operation. Modified. * @param b The right vector in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix3_64F a , FixedMatrix3_64F b) { a.a1 *= b.a1; a.a2 *= b.a2; a.a3 *= b.a3; } /** *

Performs an element by element multiplication operation:
*
* cij = aij * bij
*

* @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c ) { c.a11 = a.a11*b.a11; c.a12 = a.a12*b.a12; c.a13 = a.a13*b.a13; c.a21 = a.a21*b.a21; c.a22 = a.a22*b.a22; c.a23 = a.a23*b.a23; c.a31 = a.a31*b.a31; c.a32 = a.a32*b.a32; c.a33 = a.a33*b.a33; } /** *

Performs an element by element multiplication operation:
*
* ci = ai * bj
*

* @param a The left vector in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix3_64F a , FixedMatrix3_64F b , FixedMatrix3_64F c ) { c.a1 = a.a1*b.a1; c.a2 = a.a2*b.a2; c.a3 = a.a3*b.a3; } /** *

Performs an element by element division operation:
*
* aij = aij / bij
*

* @param a The left matrix in the division operation. Modified. * @param b The right matrix in the division operation. Not modified. */ public static void elementDiv( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b) { a.a11 /= b.a11; a.a12 /= b.a12; a.a13 /= b.a13; a.a21 /= b.a21; a.a22 /= b.a22; a.a23 /= b.a23; a.a31 /= b.a31; a.a32 /= b.a32; a.a33 /= b.a33; } /** *

Performs an element by element division operation:
*
* ai = ai / bi
*

* @param a The left vector in the division operation. Modified. * @param b The right vector in the division operation. Not modified. */ public static void elementDiv( FixedMatrix3_64F a , FixedMatrix3_64F b) { a.a1 /= b.a1; a.a2 /= b.a2; a.a3 /= b.a3; } /** *

Performs an element by element division operation:
*
* cij = aij / bij
*

* @param a The left matrix in the division operation. Not modified. * @param b The right matrix in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix3x3_64F a , FixedMatrix3x3_64F b , FixedMatrix3x3_64F c ) { c.a11 = a.a11/b.a11; c.a12 = a.a12/b.a12; c.a13 = a.a13/b.a13; c.a21 = a.a21/b.a21; c.a22 = a.a22/b.a22; c.a23 = a.a23/b.a23; c.a31 = a.a31/b.a31; c.a32 = a.a32/b.a32; c.a33 = a.a33/b.a33; } /** *

Performs an element by element division operation:
*
* ci = ai / bi
*

* @param a The left vector in the division operation. Not modified. * @param b The right vector in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix3_64F a , FixedMatrix3_64F b , FixedMatrix3_64F c ) { c.a1 = a.a1/b.a1; c.a2 = a.a2/b.a2; c.a3 = a.a3/b.a3; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The matrix that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix3x3_64F a ) { a.a11 *= alpha; a.a12 *= alpha; a.a13 *= alpha; a.a21 *= alpha; a.a22 *= alpha; a.a23 *= alpha; a.a31 *= alpha; a.a32 *= alpha; a.a33 *= alpha; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The vector that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix3_64F a ) { a.a1 *= alpha; a.a2 *= alpha; a.a3 *= alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bij = α*aij *

* * @param alpha the amount each element is multiplied by. * @param a The matrix that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix3x3_64F a , FixedMatrix3x3_64F b ) { b.a11 = a.a11*alpha; b.a12 = a.a12*alpha; b.a13 = a.a13*alpha; b.a21 = a.a21*alpha; b.a22 = a.a22*alpha; b.a23 = a.a23*alpha; b.a31 = a.a31*alpha; b.a32 = a.a32*alpha; b.a33 = a.a33*alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bi = α*ai *

* * @param alpha the amount each element is multiplied by. * @param a The vector that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix3_64F a , FixedMatrix3_64F b ) { b.a1 = a.a1*alpha; b.a2 = a.a2*alpha; b.a3 = a.a3*alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* aij = aij/α *

* * @param a The matrix whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix3x3_64F a , double alpha ) { a.a11 /= alpha; a.a12 /= alpha; a.a13 /= alpha; a.a21 /= alpha; a.a22 /= alpha; a.a23 /= alpha; a.a31 /= alpha; a.a32 /= alpha; a.a33 /= alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* ai = ai/α *

* * @param a The vector whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix3_64F a , double alpha ) { a.a1 /= alpha; a.a2 /= alpha; a.a3 /= alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bij = aij /α *

* * @param alpha the amount each element is divided by. * @param a The matrix whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix3x3_64F a , double alpha , FixedMatrix3x3_64F b ) { b.a11 = a.a11/alpha; b.a12 = a.a12/alpha; b.a13 = a.a13/alpha; b.a21 = a.a21/alpha; b.a22 = a.a22/alpha; b.a23 = a.a23/alpha; b.a31 = a.a31/alpha; b.a32 = a.a32/alpha; b.a33 = a.a33/alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bi = ai /α *

* * @param alpha the amount each element is divided by. * @param a The vector whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix3_64F a , double alpha , FixedMatrix3_64F b ) { b.a1 = a.a1/alpha; b.a2 = a.a2/alpha; b.a3 = a.a3/alpha; } /** *

* Changes the sign of every element in the matrix.
*
* aij = -aij *

* * @param a A matrix. Modified. */ public static void changeSign( FixedMatrix3x3_64F a ) { a.a11 = -a.a11; a.a12 = -a.a12; a.a13 = -a.a13; a.a21 = -a.a21; a.a22 = -a.a22; a.a23 = -a.a23; a.a31 = -a.a31; a.a32 = -a.a32; a.a33 = -a.a33; } /** *

* Changes the sign of every element in the vector.
*
* ai = -ai *

* * @param a A vector. Modified. */ public static void changeSign( FixedMatrix3_64F a ) { a.a1 = -a.a1; a.a2 = -a.a2; a.a3 = -a.a3; } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param a A matrix whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix3x3_64F a , double v ) { a.a11 = v; a.a12 = v; a.a13 = v; a.a21 = v; a.a22 = v; a.a23 = v; a.a31 = v; a.a32 = v; a.a33 = v; } /** *

* Sets every element in the vector to the specified value.
*
* ai = value *

* * @param a A vector whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix3_64F a , double v ) { a.a1 = v; a.a2 = v; a.a3 = v; } /** * Extracts the row from the matrix a. * @param a Input matrix * @param row Which row is to be extracted * @param out output. Storage for the extracted row. If null then a new vector will be returned. * @return The extracted row. */ public static FixedMatrix3_64F extractRow( FixedMatrix3x3_64F a , int row , FixedMatrix3_64F out ) { if( out == null) out = new FixedMatrix3_64F(); switch( row ) { case 0: out.a1 = a.a11; out.a2 = a.a12; out.a3 = a.a13; break; case 1: out.a1 = a.a21; out.a2 = a.a22; out.a3 = a.a23; break; case 2: out.a1 = a.a31; out.a2 = a.a32; out.a3 = a.a33; break; default: throw new IllegalArgumentException("Out of bounds row. row = "+row); } return out; } /** * Extracts the column from the matrix a. * @param a Input matrix * @param column Which column is to be extracted * @param out output. Storage for the extracted column. If null then a new vector will be returned. * @return The extracted column. */ public static FixedMatrix3_64F extractColumn( FixedMatrix3x3_64F a , int column , FixedMatrix3_64F out ) { if( out == null) out = new FixedMatrix3_64F(); switch( column ) { case 0: out.a1 = a.a11; out.a2 = a.a21; out.a3 = a.a31; break; case 1: out.a1 = a.a12; out.a2 = a.a22; out.a3 = a.a32; break; case 2: out.a1 = a.a13; out.a2 = a.a23; out.a3 = a.a33; break; default: throw new IllegalArgumentException("Out of bounds column. column = "+column); } return out; } } ejml-0.28/main/dense64/src/org/ejml/alg/fixed/FixedOps4.java000066400000000000000000001440671256171534400234310ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix4_64F; import org.ejml.data.FixedMatrix4x4_64F; /** *

Common matrix operations for fixed sized matrices which are 4 x 4 or 4 element vectors.

*

DO NOT MODIFY. Automatically generated code created by GenerateFixedOps

* * @author Peter Abeles */ public class FixedOps4 { /** *

Performs the following operation:
*
* c = a + b
* cij = aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c ) { c.a11 = a.a11 + b.a11; c.a12 = a.a12 + b.a12; c.a13 = a.a13 + b.a13; c.a14 = a.a14 + b.a14; c.a21 = a.a21 + b.a21; c.a22 = a.a22 + b.a22; c.a23 = a.a23 + b.a23; c.a24 = a.a24 + b.a24; c.a31 = a.a31 + b.a31; c.a32 = a.a32 + b.a32; c.a33 = a.a33 + b.a33; c.a34 = a.a34 + b.a34; c.a41 = a.a41 + b.a41; c.a42 = a.a42 + b.a42; c.a43 = a.a43 + b.a43; c.a44 = a.a44 + b.a44; } /** *

Performs the following operation:
*
* c = a + b
* ci = ai + bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void add( FixedMatrix4_64F a , FixedMatrix4_64F b , FixedMatrix4_64F c ) { c.a1 = a.a1 + b.a1; c.a2 = a.a2 + b.a2; c.a3 = a.a3 + b.a3; c.a4 = a.a4 + b.a4; } /** *

Performs the following operation:
*
* a = a + b
* aij = aij + bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b ) { a.a11 += b.a11; a.a12 += b.a12; a.a13 += b.a13; a.a14 += b.a14; a.a21 += b.a21; a.a22 += b.a22; a.a23 += b.a23; a.a24 += b.a24; a.a31 += b.a31; a.a32 += b.a32; a.a33 += b.a33; a.a34 += b.a34; a.a41 += b.a41; a.a42 += b.a42; a.a43 += b.a43; a.a44 += b.a44; } /** *

Performs the following operation:
*
* a = a + b
* ai = ai + bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void addEquals( FixedMatrix4_64F a , FixedMatrix4_64F b ) { a.a1 += b.a1; a.a2 += b.a2; a.a3 += b.a3; a.a4 += b.a4; } /** *

Performs the following operation:
*
* c = a - b
* cij = aij - bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void subtract( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c ) { c.a11 = a.a11 - b.a11; c.a12 = a.a12 - b.a12; c.a13 = a.a13 - b.a13; c.a14 = a.a14 - b.a14; c.a21 = a.a21 - b.a21; c.a22 = a.a22 - b.a22; c.a23 = a.a23 - b.a23; c.a24 = a.a24 - b.a24; c.a31 = a.a31 - b.a31; c.a32 = a.a32 - b.a32; c.a33 = a.a33 - b.a33; c.a34 = a.a34 - b.a34; c.a41 = a.a41 - b.a41; c.a42 = a.a42 - b.a42; c.a43 = a.a43 - b.a43; c.a44 = a.a44 - b.a44; } /** *

Performs the following operation:
*
* c = a - b
* ci = ai - bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void subtract( FixedMatrix4_64F a , FixedMatrix4_64F b , FixedMatrix4_64F c ) { c.a1 = a.a1 - b.a1; c.a2 = a.a2 - b.a2; c.a3 = a.a3 - b.a3; c.a4 = a.a4 - b.a4; } /** *

Performs the following operation:
*
* a = a - b
* aij = aij - bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void subtractEquals( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b ) { a.a11 -= b.a11; a.a12 -= b.a12; a.a13 -= b.a13; a.a14 -= b.a14; a.a21 -= b.a21; a.a22 -= b.a22; a.a23 -= b.a23; a.a24 -= b.a24; a.a31 -= b.a31; a.a32 -= b.a32; a.a33 -= b.a33; a.a34 -= b.a34; a.a41 -= b.a41; a.a42 -= b.a42; a.a43 -= b.a43; a.a44 -= b.a44; } /** *

Performs the following operation:
*
* a = a - b
* ai = ai - bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void subtractEquals( FixedMatrix4_64F a , FixedMatrix4_64F b ) { a.a1 -= b.a1; a.a2 -= b.a2; a.a3 -= b.a3; a.a4 -= b.a4; } /** * Performs an in-place transpose. This algorithm is only efficient for square * matrices. * * @param m The matrix that is to be transposed. Modified. */ public static void transpose( FixedMatrix4x4_64F m ) { double tmp; tmp = m.a12; m.a12 = m.a21; m.a21 = tmp; tmp = m.a13; m.a13 = m.a31; m.a31 = tmp; tmp = m.a14; m.a14 = m.a41; m.a41 = tmp; tmp = m.a23; m.a23 = m.a32; m.a32 = tmp; tmp = m.a24; m.a24 = m.a42; m.a42 = tmp; tmp = m.a34; m.a34 = m.a43; m.a43 = tmp; } /** *

* Transposes matrix 'a' and stores the results in 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'. *

* * @param input The original matrix. Not modified. * @param output Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static FixedMatrix4x4_64F transpose( FixedMatrix4x4_64F input , FixedMatrix4x4_64F output ) { if( input == null ) input = new FixedMatrix4x4_64F(); output.a11 = input.a11; output.a12 = input.a21; output.a13 = input.a31; output.a14 = input.a41; output.a21 = input.a12; output.a22 = input.a22; output.a23 = input.a32; output.a24 = input.a42; output.a31 = input.a13; output.a32 = input.a23; output.a33 = input.a33; output.a34 = input.a43; output.a41 = input.a14; output.a42 = input.a24; output.a43 = input.a34; output.a44 = input.a44; return output; } /** *

Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41; c.a12 = a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42; c.a13 = a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43; c.a14 = a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44; c.a21 = a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41; c.a22 = a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42; c.a23 = a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43; c.a24 = a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44; c.a31 = a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41; c.a32 = a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42; c.a33 = a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43; c.a34 = a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44; c.a41 = a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41; c.a42 = a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42; c.a43 = a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43; c.a44 = a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44; } /** *

Performs the following operation:
*
* c = aT * b
*
* cij = ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31 + a.a41*b.a41; c.a12 = a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32 + a.a41*b.a42; c.a13 = a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33 + a.a41*b.a43; c.a14 = a.a11*b.a14 + a.a21*b.a24 + a.a31*b.a34 + a.a41*b.a44; c.a21 = a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31 + a.a42*b.a41; c.a22 = a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32 + a.a42*b.a42; c.a23 = a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33 + a.a42*b.a43; c.a24 = a.a12*b.a14 + a.a22*b.a24 + a.a32*b.a34 + a.a42*b.a44; c.a31 = a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31 + a.a43*b.a41; c.a32 = a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32 + a.a43*b.a42; c.a33 = a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33 + a.a43*b.a43; c.a34 = a.a13*b.a14 + a.a23*b.a24 + a.a33*b.a34 + a.a43*b.a44; c.a41 = a.a14*b.a11 + a.a24*b.a21 + a.a34*b.a31 + a.a44*b.a41; c.a42 = a.a14*b.a12 + a.a24*b.a22 + a.a34*b.a32 + a.a44*b.a42; c.a43 = a.a14*b.a13 + a.a24*b.a23 + a.a34*b.a33 + a.a44*b.a43; c.a44 = a.a14*b.a14 + a.a24*b.a24 + a.a34*b.a34 + a.a44*b.a44; } /** *

* Performs the following operation:
*
* c = aT * bT
* cij = ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransAB( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13 + a.a41*b.a14; c.a12 = a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23 + a.a41*b.a24; c.a13 = a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33 + a.a41*b.a34; c.a14 = a.a11*b.a41 + a.a21*b.a42 + a.a31*b.a43 + a.a41*b.a44; c.a21 = a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13 + a.a42*b.a14; c.a22 = a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23 + a.a42*b.a24; c.a23 = a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33 + a.a42*b.a34; c.a24 = a.a12*b.a41 + a.a22*b.a42 + a.a32*b.a43 + a.a42*b.a44; c.a31 = a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13 + a.a43*b.a14; c.a32 = a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23 + a.a43*b.a24; c.a33 = a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33 + a.a43*b.a34; c.a34 = a.a13*b.a41 + a.a23*b.a42 + a.a33*b.a43 + a.a43*b.a44; c.a41 = a.a14*b.a11 + a.a24*b.a12 + a.a34*b.a13 + a.a44*b.a14; c.a42 = a.a14*b.a21 + a.a24*b.a22 + a.a34*b.a23 + a.a44*b.a24; c.a43 = a.a14*b.a31 + a.a24*b.a32 + a.a34*b.a33 + a.a44*b.a34; c.a44 = a.a14*b.a41 + a.a24*b.a42 + a.a34*b.a43 + a.a44*b.a44; } /** *

* Performs the following operation:
*
* c = a * bT
* cij = ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransB( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13 + a.a14*b.a14; c.a12 = a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23 + a.a14*b.a24; c.a13 = a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33 + a.a14*b.a34; c.a14 = a.a11*b.a41 + a.a12*b.a42 + a.a13*b.a43 + a.a14*b.a44; c.a21 = a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13 + a.a24*b.a14; c.a22 = a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23 + a.a24*b.a24; c.a23 = a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33 + a.a24*b.a34; c.a24 = a.a21*b.a41 + a.a22*b.a42 + a.a23*b.a43 + a.a24*b.a44; c.a31 = a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13 + a.a34*b.a14; c.a32 = a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23 + a.a34*b.a24; c.a33 = a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33 + a.a34*b.a34; c.a34 = a.a31*b.a41 + a.a32*b.a42 + a.a33*b.a43 + a.a34*b.a44; c.a41 = a.a41*b.a11 + a.a42*b.a12 + a.a43*b.a13 + a.a44*b.a14; c.a42 = a.a41*b.a21 + a.a42*b.a22 + a.a43*b.a23 + a.a44*b.a24; c.a43 = a.a41*b.a31 + a.a42*b.a32 + a.a43*b.a33 + a.a44*b.a34; c.a44 = a.a41*b.a41 + a.a42*b.a42 + a.a43*b.a43 + a.a44*b.a44; } /** *

Performs the following operation:
*
* c += a * b
*
* cij += ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41; c.a12 += a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42; c.a13 += a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43; c.a14 += a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44; c.a21 += a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41; c.a22 += a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42; c.a23 += a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43; c.a24 += a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44; c.a31 += a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41; c.a32 += a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42; c.a33 += a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43; c.a34 += a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44; c.a41 += a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41; c.a42 += a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42; c.a43 += a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43; c.a44 += a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44; } /** *

Performs the following operation:
*
* c += aT * b
*
* cij += ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31 + a.a41*b.a41; c.a12 += a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32 + a.a41*b.a42; c.a13 += a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33 + a.a41*b.a43; c.a14 += a.a11*b.a14 + a.a21*b.a24 + a.a31*b.a34 + a.a41*b.a44; c.a21 += a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31 + a.a42*b.a41; c.a22 += a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32 + a.a42*b.a42; c.a23 += a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33 + a.a42*b.a43; c.a24 += a.a12*b.a14 + a.a22*b.a24 + a.a32*b.a34 + a.a42*b.a44; c.a31 += a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31 + a.a43*b.a41; c.a32 += a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32 + a.a43*b.a42; c.a33 += a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33 + a.a43*b.a43; c.a34 += a.a13*b.a14 + a.a23*b.a24 + a.a33*b.a34 + a.a43*b.a44; c.a41 += a.a14*b.a11 + a.a24*b.a21 + a.a34*b.a31 + a.a44*b.a41; c.a42 += a.a14*b.a12 + a.a24*b.a22 + a.a34*b.a32 + a.a44*b.a42; c.a43 += a.a14*b.a13 + a.a24*b.a23 + a.a34*b.a33 + a.a44*b.a43; c.a44 += a.a14*b.a14 + a.a24*b.a24 + a.a34*b.a34 + a.a44*b.a44; } /** *

* Performs the following operation:
*
* c += aT * bT
* cij += ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13 + a.a41*b.a14; c.a12 += a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23 + a.a41*b.a24; c.a13 += a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33 + a.a41*b.a34; c.a14 += a.a11*b.a41 + a.a21*b.a42 + a.a31*b.a43 + a.a41*b.a44; c.a21 += a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13 + a.a42*b.a14; c.a22 += a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23 + a.a42*b.a24; c.a23 += a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33 + a.a42*b.a34; c.a24 += a.a12*b.a41 + a.a22*b.a42 + a.a32*b.a43 + a.a42*b.a44; c.a31 += a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13 + a.a43*b.a14; c.a32 += a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23 + a.a43*b.a24; c.a33 += a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33 + a.a43*b.a34; c.a34 += a.a13*b.a41 + a.a23*b.a42 + a.a33*b.a43 + a.a43*b.a44; c.a41 += a.a14*b.a11 + a.a24*b.a12 + a.a34*b.a13 + a.a44*b.a14; c.a42 += a.a14*b.a21 + a.a24*b.a22 + a.a34*b.a23 + a.a44*b.a24; c.a43 += a.a14*b.a31 + a.a24*b.a32 + a.a34*b.a33 + a.a44*b.a34; c.a44 += a.a14*b.a41 + a.a24*b.a42 + a.a34*b.a43 + a.a44*b.a44; } /** *

* Performs the following operation:
*
* c += a * bT
* cij += ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransB( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13 + a.a14*b.a14; c.a12 += a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23 + a.a14*b.a24; c.a13 += a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33 + a.a14*b.a34; c.a14 += a.a11*b.a41 + a.a12*b.a42 + a.a13*b.a43 + a.a14*b.a44; c.a21 += a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13 + a.a24*b.a14; c.a22 += a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23 + a.a24*b.a24; c.a23 += a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33 + a.a24*b.a34; c.a24 += a.a21*b.a41 + a.a22*b.a42 + a.a23*b.a43 + a.a24*b.a44; c.a31 += a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13 + a.a34*b.a14; c.a32 += a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23 + a.a34*b.a24; c.a33 += a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33 + a.a34*b.a34; c.a34 += a.a31*b.a41 + a.a32*b.a42 + a.a33*b.a43 + a.a34*b.a44; c.a41 += a.a41*b.a11 + a.a42*b.a12 + a.a43*b.a13 + a.a44*b.a14; c.a42 += a.a41*b.a21 + a.a42*b.a22 + a.a43*b.a23 + a.a44*b.a24; c.a43 += a.a41*b.a31 + a.a42*b.a32 + a.a43*b.a33 + a.a44*b.a34; c.a44 += a.a41*b.a41 + a.a42*b.a42 + a.a43*b.a43 + a.a44*b.a44; } /** *

Performs matrix to vector multiplication:
*
* c = a * b
*
* ci = ∑k=1:n { aik * bk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix4x4_64F a , FixedMatrix4_64F b , FixedMatrix4_64F c) { c.a1 = a.a11*b.a1 + a.a12*b.a2 + a.a13*b.a3 + a.a14*b.a4; c.a2 = a.a21*b.a1 + a.a22*b.a2 + a.a23*b.a3 + a.a24*b.a4; c.a3 = a.a31*b.a1 + a.a32*b.a2 + a.a33*b.a3 + a.a34*b.a4; c.a4 = a.a41*b.a1 + a.a42*b.a2 + a.a43*b.a3 + a.a44*b.a4; } /** *

Performs vector to matrix multiplication:
*
* c = a * b
*
* cj = ∑k=1:n { bk * akj } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix4_64F a , FixedMatrix4x4_64F b , FixedMatrix4_64F c) { c.a1 = a.a1*b.a11 + a.a2*b.a21 + a.a3*b.a31 + a.a4*b.a41; c.a2 = a.a1*b.a12 + a.a2*b.a22 + a.a3*b.a32 + a.a4*b.a42; c.a3 = a.a1*b.a13 + a.a2*b.a23 + a.a3*b.a33 + a.a4*b.a43; c.a4 = a.a1*b.a14 + a.a2*b.a24 + a.a3*b.a34 + a.a4*b.a44; } /** *

Performs the vector dot product:
*
* c = a * b
*
* c> = ∑k=1:n { bk * ak } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @return The dot product */ public static double dot( FixedMatrix4_64F a , FixedMatrix4_64F b ) { return a.a1*b.a1 + a.a2*b.a2 + a.a3*b.a3 + a.a4*b.a4; } /** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @param a A matrix. */ public static void setIdentity( FixedMatrix4x4_64F a ) { a.a11 = 1; a.a21 = 0; a.a31 = 0; a.a41 = 0; a.a12 = 0; a.a22 = 1; a.a32 = 0; a.a42 = 0; a.a13 = 0; a.a23 = 0; a.a33 = 1; a.a43 = 0; a.a14 = 0; a.a24 = 0; a.a34 = 0; a.a44 = 1; } /** * Inverts matrix 'a' using minor matrices and stores the results in 'inv'. Scaling is applied to improve * stability against overflow and underflow. * * WARNING: Potentially less stable than using LU decomposition. * * @param a Input matrix. Not modified. * @param inv Inverted output matrix. Modified. * @return true if it was successful or false if it failed. Not always reliable. */ public static boolean invert( FixedMatrix4x4_64F a , FixedMatrix4x4_64F inv ) { double scale = 1.0/elementMaxAbs(a); double a11 = a.a11*scale; double a12 = a.a12*scale; double a13 = a.a13*scale; double a14 = a.a14*scale; double a21 = a.a21*scale; double a22 = a.a22*scale; double a23 = a.a23*scale; double a24 = a.a24*scale; double a31 = a.a31*scale; double a32 = a.a32*scale; double a33 = a.a33*scale; double a34 = a.a34*scale; double a41 = a.a41*scale; double a42 = a.a42*scale; double a43 = a.a43*scale; double a44 = a.a44*scale; double m11 = + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42); double m12 = -( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)); double m13 = + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41); double m14 = -( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41)); double m21 = -( + a12*(a33*a44 - a34*a43) - a13*(a32*a44 - a34*a42) + a14*(a32*a43 - a33*a42)); double m22 = + a11*(a33*a44 - a34*a43) - a13*(a31*a44 - a34*a41) + a14*(a31*a43 - a33*a41); double m23 = -( + a11*(a32*a44 - a34*a42) - a12*(a31*a44 - a34*a41) + a14*(a31*a42 - a32*a41)); double m24 = + a11*(a32*a43 - a33*a42) - a12*(a31*a43 - a33*a41) + a13*(a31*a42 - a32*a41); double m31 = + a12*(a23*a44 - a24*a43) - a13*(a22*a44 - a24*a42) + a14*(a22*a43 - a23*a42); double m32 = -( + a11*(a23*a44 - a24*a43) - a13*(a21*a44 - a24*a41) + a14*(a21*a43 - a23*a41)); double m33 = + a11*(a22*a44 - a24*a42) - a12*(a21*a44 - a24*a41) + a14*(a21*a42 - a22*a41); double m34 = -( + a11*(a22*a43 - a23*a42) - a12*(a21*a43 - a23*a41) + a13*(a21*a42 - a22*a41)); double m41 = -( + a12*(a23*a34 - a24*a33) - a13*(a22*a34 - a24*a32) + a14*(a22*a33 - a23*a32)); double m42 = + a11*(a23*a34 - a24*a33) - a13*(a21*a34 - a24*a31) + a14*(a21*a33 - a23*a31); double m43 = -( + a11*(a22*a34 - a24*a32) - a12*(a21*a34 - a24*a31) + a14*(a21*a32 - a22*a31)); double m44 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); double det = (a11*m11 + a12*m12 + a13*m13 + a14*m14)/scale; inv.a11 = m11/det; inv.a12 = m21/det; inv.a13 = m31/det; inv.a14 = m41/det; inv.a21 = m12/det; inv.a22 = m22/det; inv.a23 = m32/det; inv.a24 = m42/det; inv.a31 = m13/det; inv.a32 = m23/det; inv.a33 = m33/det; inv.a34 = m43/det; inv.a41 = m14/det; inv.a42 = m24/det; inv.a43 = m34/det; inv.a44 = m44/det; return !Double.isNaN(det) && !Double.isInfinite(det); } /** * Computes the determinant using minor matrices. *

* WARNING: Potentially less stable than using LU decomposition. * * @param mat Input matrix. Not modified. * @return The determinant. */ public static double det( FixedMatrix4x4_64F mat ) { double a11 = mat.a22; double a12 = mat.a23; double a13 = mat.a24; double a21 = mat.a32; double a22 = mat.a33; double a23 = mat.a34; double a31 = mat.a42; double a32 = mat.a43; double a33 = mat.a44; double ret = 0; ret += mat.a11 * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); a11 = mat.a21; a21 = mat.a31; a31 = mat.a41; ret -= mat.a12 * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); a12 = mat.a22; a22 = mat.a32; a32 = mat.a42; ret += mat.a13 * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); a13 = mat.a23; a23 = mat.a33; a33 = mat.a43; ret -= mat.a14 * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); return ret; } /** *

* This computes the trace of the matrix:
*
* trace = ∑i=1:n { aii } *

*

* The trace is only defined for square matrices. *

* * @param a A square matrix. Not modified. */ public static double trace( FixedMatrix4x4_64F a ) { return a.a11 + a.a21 + a.a31 + a.a41; } /** *

* Extracts all diagonal elements from 'input' and places them inside the 'out' vector. Elements * are in sequential order. *

* * * @param input Matrix. Not modified. * @param out Vector containing diagonal elements. Modified. */ public static void diag( FixedMatrix4x4_64F input , FixedMatrix4_64F out ) { out.a1 = input.a11; out.a2 = input.a22; out.a3 = input.a33; out.a4 = input.a44; } /** *

* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix4x4_64F a ) { double max = a.a11; max = Math.max(max,a.a12); max = Math.max(max,a.a13); max = Math.max(max,a.a14); max = Math.max(max,a.a21); max = Math.max(max,a.a22); max = Math.max(max,a.a23); max = Math.max(max,a.a24); max = Math.max(max,a.a31); max = Math.max(max,a.a32); max = Math.max(max,a.a33); max = Math.max(max,a.a34); max = Math.max(max,a.a41); max = Math.max(max,a.a42); max = Math.max(max,a.a43); max = Math.max(max,a.a44); return max; } /** *

* Returns the value of the element in the vector that has the largest value.
*
* Max{ ai } for all i
*

* * @param a A vector. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix4_64F a ) { double max = a.a1; max = Math.max(max,a.a2); max = Math.max(max,a.a3); max = Math.max(max,a.a4); return max; } /** *

* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementMaxAbs( FixedMatrix4x4_64F a ) { double max = a.a11; max = Math.max(max,Math.abs(a.a12)); max = Math.max(max,Math.abs(a.a13)); max = Math.max(max,Math.abs(a.a14)); max = Math.max(max,Math.abs(a.a21)); max = Math.max(max,Math.abs(a.a22)); max = Math.max(max,Math.abs(a.a23)); max = Math.max(max,Math.abs(a.a24)); max = Math.max(max,Math.abs(a.a31)); max = Math.max(max,Math.abs(a.a32)); max = Math.max(max,Math.abs(a.a33)); max = Math.max(max,Math.abs(a.a34)); max = Math.max(max,Math.abs(a.a41)); max = Math.max(max,Math.abs(a.a42)); max = Math.max(max,Math.abs(a.a43)); max = Math.max(max,Math.abs(a.a44)); return max; } /** *

* Returns the absolute value of the element in the vector that has the largest absolute value.
*
* Max{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max abs element value of the vector. */ public static double elementMaxAbs( FixedMatrix4_64F a ) { double max = a.a1; max = Math.max(max,Math.abs(a.a2)); max = Math.max(max,Math.abs(a.a3)); max = Math.max(max,Math.abs(a.a4)); return max; } /** *

* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The value of element in the matrix with the minimum value. */ public static double elementMin( FixedMatrix4x4_64F a ) { double min = a.a11; min = Math.min(min, a.a12); min = Math.min(min, a.a13); min = Math.min(min, a.a14); min = Math.min(min, a.a21); min = Math.min(min, a.a22); min = Math.min(min, a.a23); min = Math.min(min, a.a24); min = Math.min(min, a.a31); min = Math.min(min, a.a32); min = Math.min(min, a.a33); min = Math.min(min, a.a34); min = Math.min(min, a.a41); min = Math.min(min, a.a42); min = Math.min(min, a.a43); min = Math.min(min, a.a44); return min; } /** *

* Returns the value of the element in the vector that has the minimum value.
*
* Min{ ai } for all
*

* * @param a A matrix. Not modified. * @return The value of element in the vector with the minimum value. */ public static double elementMin( FixedMatrix4_64F a ) { double min = a.a1; min = Math.min(min, a.a2); min = Math.min(min, a.a3); min = Math.min(min, a.a4); return min; } /** *

* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMinAbs( FixedMatrix4x4_64F a ) { double min = a.a11; min = Math.min(min,Math.abs(a.a12)); min = Math.min(min,Math.abs(a.a13)); min = Math.min(min,Math.abs(a.a14)); min = Math.min(min,Math.abs(a.a21)); min = Math.min(min,Math.abs(a.a22)); min = Math.min(min,Math.abs(a.a23)); min = Math.min(min,Math.abs(a.a24)); min = Math.min(min,Math.abs(a.a31)); min = Math.min(min,Math.abs(a.a32)); min = Math.min(min,Math.abs(a.a33)); min = Math.min(min,Math.abs(a.a34)); min = Math.min(min,Math.abs(a.a41)); min = Math.min(min,Math.abs(a.a42)); min = Math.min(min,Math.abs(a.a43)); min = Math.min(min,Math.abs(a.a44)); return min; } /** *

* Returns the absolute value of the element in the vector that has the smallest absolute value.
*
* Min{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max element value of the vector. */ public static double elementMinAbs( FixedMatrix4_64F a ) { double min = a.a1; min = Math.min(min,Math.abs(a.a2)); min = Math.min(min,Math.abs(a.a3)); min = Math.min(min,Math.abs(a.a4)); return min; } /** *

Performs an element by element multiplication operation:
*
* aij = aij * bij
*

* @param a The left matrix in the multiplication operation. Modified. * @param b The right matrix in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b) { a.a11 *= b.a11; a.a12 *= b.a12; a.a13 *= b.a13; a.a14 *= b.a14; a.a21 *= b.a21; a.a22 *= b.a22; a.a23 *= b.a23; a.a24 *= b.a24; a.a31 *= b.a31; a.a32 *= b.a32; a.a33 *= b.a33; a.a34 *= b.a34; a.a41 *= b.a41; a.a42 *= b.a42; a.a43 *= b.a43; a.a44 *= b.a44; } /** *

Performs an element by element multiplication operation:
*
* ai = ai * bi
*

* @param a The left vector in the multiplication operation. Modified. * @param b The right vector in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix4_64F a , FixedMatrix4_64F b) { a.a1 *= b.a1; a.a2 *= b.a2; a.a3 *= b.a3; a.a4 *= b.a4; } /** *

Performs an element by element multiplication operation:
*
* cij = aij * bij
*

* @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c ) { c.a11 = a.a11*b.a11; c.a12 = a.a12*b.a12; c.a13 = a.a13*b.a13; c.a14 = a.a14*b.a14; c.a21 = a.a21*b.a21; c.a22 = a.a22*b.a22; c.a23 = a.a23*b.a23; c.a24 = a.a24*b.a24; c.a31 = a.a31*b.a31; c.a32 = a.a32*b.a32; c.a33 = a.a33*b.a33; c.a34 = a.a34*b.a34; c.a41 = a.a41*b.a41; c.a42 = a.a42*b.a42; c.a43 = a.a43*b.a43; c.a44 = a.a44*b.a44; } /** *

Performs an element by element multiplication operation:
*
* ci = ai * bj
*

* @param a The left vector in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix4_64F a , FixedMatrix4_64F b , FixedMatrix4_64F c ) { c.a1 = a.a1*b.a1; c.a2 = a.a2*b.a2; c.a3 = a.a3*b.a3; c.a4 = a.a4*b.a4; } /** *

Performs an element by element division operation:
*
* aij = aij / bij
*

* @param a The left matrix in the division operation. Modified. * @param b The right matrix in the division operation. Not modified. */ public static void elementDiv( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b) { a.a11 /= b.a11; a.a12 /= b.a12; a.a13 /= b.a13; a.a14 /= b.a14; a.a21 /= b.a21; a.a22 /= b.a22; a.a23 /= b.a23; a.a24 /= b.a24; a.a31 /= b.a31; a.a32 /= b.a32; a.a33 /= b.a33; a.a34 /= b.a34; a.a41 /= b.a41; a.a42 /= b.a42; a.a43 /= b.a43; a.a44 /= b.a44; } /** *

Performs an element by element division operation:
*
* ai = ai / bi
*

* @param a The left vector in the division operation. Modified. * @param b The right vector in the division operation. Not modified. */ public static void elementDiv( FixedMatrix4_64F a , FixedMatrix4_64F b) { a.a1 /= b.a1; a.a2 /= b.a2; a.a3 /= b.a3; a.a4 /= b.a4; } /** *

Performs an element by element division operation:
*
* cij = aij / bij
*

* @param a The left matrix in the division operation. Not modified. * @param b The right matrix in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix4x4_64F a , FixedMatrix4x4_64F b , FixedMatrix4x4_64F c ) { c.a11 = a.a11/b.a11; c.a12 = a.a12/b.a12; c.a13 = a.a13/b.a13; c.a14 = a.a14/b.a14; c.a21 = a.a21/b.a21; c.a22 = a.a22/b.a22; c.a23 = a.a23/b.a23; c.a24 = a.a24/b.a24; c.a31 = a.a31/b.a31; c.a32 = a.a32/b.a32; c.a33 = a.a33/b.a33; c.a34 = a.a34/b.a34; c.a41 = a.a41/b.a41; c.a42 = a.a42/b.a42; c.a43 = a.a43/b.a43; c.a44 = a.a44/b.a44; } /** *

Performs an element by element division operation:
*
* ci = ai / bi
*

* @param a The left vector in the division operation. Not modified. * @param b The right vector in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix4_64F a , FixedMatrix4_64F b , FixedMatrix4_64F c ) { c.a1 = a.a1/b.a1; c.a2 = a.a2/b.a2; c.a3 = a.a3/b.a3; c.a4 = a.a4/b.a4; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The matrix that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix4x4_64F a ) { a.a11 *= alpha; a.a12 *= alpha; a.a13 *= alpha; a.a14 *= alpha; a.a21 *= alpha; a.a22 *= alpha; a.a23 *= alpha; a.a24 *= alpha; a.a31 *= alpha; a.a32 *= alpha; a.a33 *= alpha; a.a34 *= alpha; a.a41 *= alpha; a.a42 *= alpha; a.a43 *= alpha; a.a44 *= alpha; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The vector that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix4_64F a ) { a.a1 *= alpha; a.a2 *= alpha; a.a3 *= alpha; a.a4 *= alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bij = α*aij *

* * @param alpha the amount each element is multiplied by. * @param a The matrix that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix4x4_64F a , FixedMatrix4x4_64F b ) { b.a11 = a.a11*alpha; b.a12 = a.a12*alpha; b.a13 = a.a13*alpha; b.a14 = a.a14*alpha; b.a21 = a.a21*alpha; b.a22 = a.a22*alpha; b.a23 = a.a23*alpha; b.a24 = a.a24*alpha; b.a31 = a.a31*alpha; b.a32 = a.a32*alpha; b.a33 = a.a33*alpha; b.a34 = a.a34*alpha; b.a41 = a.a41*alpha; b.a42 = a.a42*alpha; b.a43 = a.a43*alpha; b.a44 = a.a44*alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bi = α*ai *

* * @param alpha the amount each element is multiplied by. * @param a The vector that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix4_64F a , FixedMatrix4_64F b ) { b.a1 = a.a1*alpha; b.a2 = a.a2*alpha; b.a3 = a.a3*alpha; b.a4 = a.a4*alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* aij = aij/α *

* * @param a The matrix whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix4x4_64F a , double alpha ) { a.a11 /= alpha; a.a12 /= alpha; a.a13 /= alpha; a.a14 /= alpha; a.a21 /= alpha; a.a22 /= alpha; a.a23 /= alpha; a.a24 /= alpha; a.a31 /= alpha; a.a32 /= alpha; a.a33 /= alpha; a.a34 /= alpha; a.a41 /= alpha; a.a42 /= alpha; a.a43 /= alpha; a.a44 /= alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* ai = ai/α *

* * @param a The vector whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix4_64F a , double alpha ) { a.a1 /= alpha; a.a2 /= alpha; a.a3 /= alpha; a.a4 /= alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bij = aij /α *

* * @param alpha the amount each element is divided by. * @param a The matrix whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix4x4_64F a , double alpha , FixedMatrix4x4_64F b ) { b.a11 = a.a11/alpha; b.a12 = a.a12/alpha; b.a13 = a.a13/alpha; b.a14 = a.a14/alpha; b.a21 = a.a21/alpha; b.a22 = a.a22/alpha; b.a23 = a.a23/alpha; b.a24 = a.a24/alpha; b.a31 = a.a31/alpha; b.a32 = a.a32/alpha; b.a33 = a.a33/alpha; b.a34 = a.a34/alpha; b.a41 = a.a41/alpha; b.a42 = a.a42/alpha; b.a43 = a.a43/alpha; b.a44 = a.a44/alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bi = ai /α *

* * @param alpha the amount each element is divided by. * @param a The vector whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix4_64F a , double alpha , FixedMatrix4_64F b ) { b.a1 = a.a1/alpha; b.a2 = a.a2/alpha; b.a3 = a.a3/alpha; b.a4 = a.a4/alpha; } /** *

* Changes the sign of every element in the matrix.
*
* aij = -aij *

* * @param a A matrix. Modified. */ public static void changeSign( FixedMatrix4x4_64F a ) { a.a11 = -a.a11; a.a12 = -a.a12; a.a13 = -a.a13; a.a14 = -a.a14; a.a21 = -a.a21; a.a22 = -a.a22; a.a23 = -a.a23; a.a24 = -a.a24; a.a31 = -a.a31; a.a32 = -a.a32; a.a33 = -a.a33; a.a34 = -a.a34; a.a41 = -a.a41; a.a42 = -a.a42; a.a43 = -a.a43; a.a44 = -a.a44; } /** *

* Changes the sign of every element in the vector.
*
* ai = -ai *

* * @param a A vector. Modified. */ public static void changeSign( FixedMatrix4_64F a ) { a.a1 = -a.a1; a.a2 = -a.a2; a.a3 = -a.a3; a.a4 = -a.a4; } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param a A matrix whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix4x4_64F a , double v ) { a.a11 = v; a.a12 = v; a.a13 = v; a.a14 = v; a.a21 = v; a.a22 = v; a.a23 = v; a.a24 = v; a.a31 = v; a.a32 = v; a.a33 = v; a.a34 = v; a.a41 = v; a.a42 = v; a.a43 = v; a.a44 = v; } /** *

* Sets every element in the vector to the specified value.
*
* ai = value *

* * @param a A vector whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix4_64F a , double v ) { a.a1 = v; a.a2 = v; a.a3 = v; a.a4 = v; } /** * Extracts the row from the matrix a. * @param a Input matrix * @param row Which row is to be extracted * @param out output. Storage for the extracted row. If null then a new vector will be returned. * @return The extracted row. */ public static FixedMatrix4_64F extractRow( FixedMatrix4x4_64F a , int row , FixedMatrix4_64F out ) { if( out == null) out = new FixedMatrix4_64F(); switch( row ) { case 0: out.a1 = a.a11; out.a2 = a.a12; out.a3 = a.a13; out.a4 = a.a14; break; case 1: out.a1 = a.a21; out.a2 = a.a22; out.a3 = a.a23; out.a4 = a.a24; break; case 2: out.a1 = a.a31; out.a2 = a.a32; out.a3 = a.a33; out.a4 = a.a34; break; case 3: out.a1 = a.a41; out.a2 = a.a42; out.a3 = a.a43; out.a4 = a.a44; break; default: throw new IllegalArgumentException("Out of bounds row. row = "+row); } return out; } /** * Extracts the column from the matrix a. * @param a Input matrix * @param column Which column is to be extracted * @param out output. Storage for the extracted column. If null then a new vector will be returned. * @return The extracted column. */ public static FixedMatrix4_64F extractColumn( FixedMatrix4x4_64F a , int column , FixedMatrix4_64F out ) { if( out == null) out = new FixedMatrix4_64F(); switch( column ) { case 0: out.a1 = a.a11; out.a2 = a.a21; out.a3 = a.a31; out.a4 = a.a41; break; case 1: out.a1 = a.a12; out.a2 = a.a22; out.a3 = a.a32; out.a4 = a.a42; break; case 2: out.a1 = a.a13; out.a2 = a.a23; out.a3 = a.a33; out.a4 = a.a43; break; case 3: out.a1 = a.a14; out.a2 = a.a24; out.a3 = a.a34; out.a4 = a.a44; break; default: throw new IllegalArgumentException("Out of bounds column. column = "+column); } return out; } } ejml-0.28/main/dense64/src/org/ejml/alg/fixed/FixedOps5.java000066400000000000000000002232261256171534400234250ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix5_64F; import org.ejml.data.FixedMatrix5x5_64F; /** *

Common matrix operations for fixed sized matrices which are 5 x 5 or 5 element vectors.

*

DO NOT MODIFY. Automatically generated code created by GenerateFixedOps

* * @author Peter Abeles */ public class FixedOps5 { /** *

Performs the following operation:
*
* c = a + b
* cij = aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c ) { c.a11 = a.a11 + b.a11; c.a12 = a.a12 + b.a12; c.a13 = a.a13 + b.a13; c.a14 = a.a14 + b.a14; c.a15 = a.a15 + b.a15; c.a21 = a.a21 + b.a21; c.a22 = a.a22 + b.a22; c.a23 = a.a23 + b.a23; c.a24 = a.a24 + b.a24; c.a25 = a.a25 + b.a25; c.a31 = a.a31 + b.a31; c.a32 = a.a32 + b.a32; c.a33 = a.a33 + b.a33; c.a34 = a.a34 + b.a34; c.a35 = a.a35 + b.a35; c.a41 = a.a41 + b.a41; c.a42 = a.a42 + b.a42; c.a43 = a.a43 + b.a43; c.a44 = a.a44 + b.a44; c.a45 = a.a45 + b.a45; c.a51 = a.a51 + b.a51; c.a52 = a.a52 + b.a52; c.a53 = a.a53 + b.a53; c.a54 = a.a54 + b.a54; c.a55 = a.a55 + b.a55; } /** *

Performs the following operation:
*
* c = a + b
* ci = ai + bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void add( FixedMatrix5_64F a , FixedMatrix5_64F b , FixedMatrix5_64F c ) { c.a1 = a.a1 + b.a1; c.a2 = a.a2 + b.a2; c.a3 = a.a3 + b.a3; c.a4 = a.a4 + b.a4; c.a5 = a.a5 + b.a5; } /** *

Performs the following operation:
*
* a = a + b
* aij = aij + bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b ) { a.a11 += b.a11; a.a12 += b.a12; a.a13 += b.a13; a.a14 += b.a14; a.a15 += b.a15; a.a21 += b.a21; a.a22 += b.a22; a.a23 += b.a23; a.a24 += b.a24; a.a25 += b.a25; a.a31 += b.a31; a.a32 += b.a32; a.a33 += b.a33; a.a34 += b.a34; a.a35 += b.a35; a.a41 += b.a41; a.a42 += b.a42; a.a43 += b.a43; a.a44 += b.a44; a.a45 += b.a45; a.a51 += b.a51; a.a52 += b.a52; a.a53 += b.a53; a.a54 += b.a54; a.a55 += b.a55; } /** *

Performs the following operation:
*
* a = a + b
* ai = ai + bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void addEquals( FixedMatrix5_64F a , FixedMatrix5_64F b ) { a.a1 += b.a1; a.a2 += b.a2; a.a3 += b.a3; a.a4 += b.a4; a.a5 += b.a5; } /** *

Performs the following operation:
*
* c = a - b
* cij = aij - bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void subtract( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c ) { c.a11 = a.a11 - b.a11; c.a12 = a.a12 - b.a12; c.a13 = a.a13 - b.a13; c.a14 = a.a14 - b.a14; c.a15 = a.a15 - b.a15; c.a21 = a.a21 - b.a21; c.a22 = a.a22 - b.a22; c.a23 = a.a23 - b.a23; c.a24 = a.a24 - b.a24; c.a25 = a.a25 - b.a25; c.a31 = a.a31 - b.a31; c.a32 = a.a32 - b.a32; c.a33 = a.a33 - b.a33; c.a34 = a.a34 - b.a34; c.a35 = a.a35 - b.a35; c.a41 = a.a41 - b.a41; c.a42 = a.a42 - b.a42; c.a43 = a.a43 - b.a43; c.a44 = a.a44 - b.a44; c.a45 = a.a45 - b.a45; c.a51 = a.a51 - b.a51; c.a52 = a.a52 - b.a52; c.a53 = a.a53 - b.a53; c.a54 = a.a54 - b.a54; c.a55 = a.a55 - b.a55; } /** *

Performs the following operation:
*
* c = a - b
* ci = ai - bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void subtract( FixedMatrix5_64F a , FixedMatrix5_64F b , FixedMatrix5_64F c ) { c.a1 = a.a1 - b.a1; c.a2 = a.a2 - b.a2; c.a3 = a.a3 - b.a3; c.a4 = a.a4 - b.a4; c.a5 = a.a5 - b.a5; } /** *

Performs the following operation:
*
* a = a - b
* aij = aij - bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void subtractEquals( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b ) { a.a11 -= b.a11; a.a12 -= b.a12; a.a13 -= b.a13; a.a14 -= b.a14; a.a15 -= b.a15; a.a21 -= b.a21; a.a22 -= b.a22; a.a23 -= b.a23; a.a24 -= b.a24; a.a25 -= b.a25; a.a31 -= b.a31; a.a32 -= b.a32; a.a33 -= b.a33; a.a34 -= b.a34; a.a35 -= b.a35; a.a41 -= b.a41; a.a42 -= b.a42; a.a43 -= b.a43; a.a44 -= b.a44; a.a45 -= b.a45; a.a51 -= b.a51; a.a52 -= b.a52; a.a53 -= b.a53; a.a54 -= b.a54; a.a55 -= b.a55; } /** *

Performs the following operation:
*
* a = a - b
* ai = ai - bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void subtractEquals( FixedMatrix5_64F a , FixedMatrix5_64F b ) { a.a1 -= b.a1; a.a2 -= b.a2; a.a3 -= b.a3; a.a4 -= b.a4; a.a5 -= b.a5; } /** * Performs an in-place transpose. This algorithm is only efficient for square * matrices. * * @param m The matrix that is to be transposed. Modified. */ public static void transpose( FixedMatrix5x5_64F m ) { double tmp; tmp = m.a12; m.a12 = m.a21; m.a21 = tmp; tmp = m.a13; m.a13 = m.a31; m.a31 = tmp; tmp = m.a14; m.a14 = m.a41; m.a41 = tmp; tmp = m.a15; m.a15 = m.a51; m.a51 = tmp; tmp = m.a23; m.a23 = m.a32; m.a32 = tmp; tmp = m.a24; m.a24 = m.a42; m.a42 = tmp; tmp = m.a25; m.a25 = m.a52; m.a52 = tmp; tmp = m.a34; m.a34 = m.a43; m.a43 = tmp; tmp = m.a35; m.a35 = m.a53; m.a53 = tmp; tmp = m.a45; m.a45 = m.a54; m.a54 = tmp; } /** *

* Transposes matrix 'a' and stores the results in 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'. *

* * @param input The original matrix. Not modified. * @param output Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static FixedMatrix5x5_64F transpose( FixedMatrix5x5_64F input , FixedMatrix5x5_64F output ) { if( input == null ) input = new FixedMatrix5x5_64F(); output.a11 = input.a11; output.a12 = input.a21; output.a13 = input.a31; output.a14 = input.a41; output.a15 = input.a51; output.a21 = input.a12; output.a22 = input.a22; output.a23 = input.a32; output.a24 = input.a42; output.a25 = input.a52; output.a31 = input.a13; output.a32 = input.a23; output.a33 = input.a33; output.a34 = input.a43; output.a35 = input.a53; output.a41 = input.a14; output.a42 = input.a24; output.a43 = input.a34; output.a44 = input.a44; output.a45 = input.a54; output.a51 = input.a15; output.a52 = input.a25; output.a53 = input.a35; output.a54 = input.a45; output.a55 = input.a55; return output; } /** *

Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41 + a.a15*b.a51; c.a12 = a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42 + a.a15*b.a52; c.a13 = a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43 + a.a15*b.a53; c.a14 = a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44 + a.a15*b.a54; c.a15 = a.a11*b.a15 + a.a12*b.a25 + a.a13*b.a35 + a.a14*b.a45 + a.a15*b.a55; c.a21 = a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41 + a.a25*b.a51; c.a22 = a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42 + a.a25*b.a52; c.a23 = a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43 + a.a25*b.a53; c.a24 = a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44 + a.a25*b.a54; c.a25 = a.a21*b.a15 + a.a22*b.a25 + a.a23*b.a35 + a.a24*b.a45 + a.a25*b.a55; c.a31 = a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41 + a.a35*b.a51; c.a32 = a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42 + a.a35*b.a52; c.a33 = a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43 + a.a35*b.a53; c.a34 = a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44 + a.a35*b.a54; c.a35 = a.a31*b.a15 + a.a32*b.a25 + a.a33*b.a35 + a.a34*b.a45 + a.a35*b.a55; c.a41 = a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41 + a.a45*b.a51; c.a42 = a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42 + a.a45*b.a52; c.a43 = a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43 + a.a45*b.a53; c.a44 = a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44 + a.a45*b.a54; c.a45 = a.a41*b.a15 + a.a42*b.a25 + a.a43*b.a35 + a.a44*b.a45 + a.a45*b.a55; c.a51 = a.a51*b.a11 + a.a52*b.a21 + a.a53*b.a31 + a.a54*b.a41 + a.a55*b.a51; c.a52 = a.a51*b.a12 + a.a52*b.a22 + a.a53*b.a32 + a.a54*b.a42 + a.a55*b.a52; c.a53 = a.a51*b.a13 + a.a52*b.a23 + a.a53*b.a33 + a.a54*b.a43 + a.a55*b.a53; c.a54 = a.a51*b.a14 + a.a52*b.a24 + a.a53*b.a34 + a.a54*b.a44 + a.a55*b.a54; c.a55 = a.a51*b.a15 + a.a52*b.a25 + a.a53*b.a35 + a.a54*b.a45 + a.a55*b.a55; } /** *

Performs the following operation:
*
* c = aT * b
*
* cij = ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31 + a.a41*b.a41 + a.a51*b.a51; c.a12 = a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32 + a.a41*b.a42 + a.a51*b.a52; c.a13 = a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33 + a.a41*b.a43 + a.a51*b.a53; c.a14 = a.a11*b.a14 + a.a21*b.a24 + a.a31*b.a34 + a.a41*b.a44 + a.a51*b.a54; c.a15 = a.a11*b.a15 + a.a21*b.a25 + a.a31*b.a35 + a.a41*b.a45 + a.a51*b.a55; c.a21 = a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31 + a.a42*b.a41 + a.a52*b.a51; c.a22 = a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32 + a.a42*b.a42 + a.a52*b.a52; c.a23 = a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33 + a.a42*b.a43 + a.a52*b.a53; c.a24 = a.a12*b.a14 + a.a22*b.a24 + a.a32*b.a34 + a.a42*b.a44 + a.a52*b.a54; c.a25 = a.a12*b.a15 + a.a22*b.a25 + a.a32*b.a35 + a.a42*b.a45 + a.a52*b.a55; c.a31 = a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31 + a.a43*b.a41 + a.a53*b.a51; c.a32 = a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32 + a.a43*b.a42 + a.a53*b.a52; c.a33 = a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33 + a.a43*b.a43 + a.a53*b.a53; c.a34 = a.a13*b.a14 + a.a23*b.a24 + a.a33*b.a34 + a.a43*b.a44 + a.a53*b.a54; c.a35 = a.a13*b.a15 + a.a23*b.a25 + a.a33*b.a35 + a.a43*b.a45 + a.a53*b.a55; c.a41 = a.a14*b.a11 + a.a24*b.a21 + a.a34*b.a31 + a.a44*b.a41 + a.a54*b.a51; c.a42 = a.a14*b.a12 + a.a24*b.a22 + a.a34*b.a32 + a.a44*b.a42 + a.a54*b.a52; c.a43 = a.a14*b.a13 + a.a24*b.a23 + a.a34*b.a33 + a.a44*b.a43 + a.a54*b.a53; c.a44 = a.a14*b.a14 + a.a24*b.a24 + a.a34*b.a34 + a.a44*b.a44 + a.a54*b.a54; c.a45 = a.a14*b.a15 + a.a24*b.a25 + a.a34*b.a35 + a.a44*b.a45 + a.a54*b.a55; c.a51 = a.a15*b.a11 + a.a25*b.a21 + a.a35*b.a31 + a.a45*b.a41 + a.a55*b.a51; c.a52 = a.a15*b.a12 + a.a25*b.a22 + a.a35*b.a32 + a.a45*b.a42 + a.a55*b.a52; c.a53 = a.a15*b.a13 + a.a25*b.a23 + a.a35*b.a33 + a.a45*b.a43 + a.a55*b.a53; c.a54 = a.a15*b.a14 + a.a25*b.a24 + a.a35*b.a34 + a.a45*b.a44 + a.a55*b.a54; c.a55 = a.a15*b.a15 + a.a25*b.a25 + a.a35*b.a35 + a.a45*b.a45 + a.a55*b.a55; } /** *

* Performs the following operation:
*
* c = aT * bT
* cij = ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransAB( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13 + a.a41*b.a14 + a.a51*b.a15; c.a12 = a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23 + a.a41*b.a24 + a.a51*b.a25; c.a13 = a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33 + a.a41*b.a34 + a.a51*b.a35; c.a14 = a.a11*b.a41 + a.a21*b.a42 + a.a31*b.a43 + a.a41*b.a44 + a.a51*b.a45; c.a15 = a.a11*b.a51 + a.a21*b.a52 + a.a31*b.a53 + a.a41*b.a54 + a.a51*b.a55; c.a21 = a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13 + a.a42*b.a14 + a.a52*b.a15; c.a22 = a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23 + a.a42*b.a24 + a.a52*b.a25; c.a23 = a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33 + a.a42*b.a34 + a.a52*b.a35; c.a24 = a.a12*b.a41 + a.a22*b.a42 + a.a32*b.a43 + a.a42*b.a44 + a.a52*b.a45; c.a25 = a.a12*b.a51 + a.a22*b.a52 + a.a32*b.a53 + a.a42*b.a54 + a.a52*b.a55; c.a31 = a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13 + a.a43*b.a14 + a.a53*b.a15; c.a32 = a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23 + a.a43*b.a24 + a.a53*b.a25; c.a33 = a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33 + a.a43*b.a34 + a.a53*b.a35; c.a34 = a.a13*b.a41 + a.a23*b.a42 + a.a33*b.a43 + a.a43*b.a44 + a.a53*b.a45; c.a35 = a.a13*b.a51 + a.a23*b.a52 + a.a33*b.a53 + a.a43*b.a54 + a.a53*b.a55; c.a41 = a.a14*b.a11 + a.a24*b.a12 + a.a34*b.a13 + a.a44*b.a14 + a.a54*b.a15; c.a42 = a.a14*b.a21 + a.a24*b.a22 + a.a34*b.a23 + a.a44*b.a24 + a.a54*b.a25; c.a43 = a.a14*b.a31 + a.a24*b.a32 + a.a34*b.a33 + a.a44*b.a34 + a.a54*b.a35; c.a44 = a.a14*b.a41 + a.a24*b.a42 + a.a34*b.a43 + a.a44*b.a44 + a.a54*b.a45; c.a45 = a.a14*b.a51 + a.a24*b.a52 + a.a34*b.a53 + a.a44*b.a54 + a.a54*b.a55; c.a51 = a.a15*b.a11 + a.a25*b.a12 + a.a35*b.a13 + a.a45*b.a14 + a.a55*b.a15; c.a52 = a.a15*b.a21 + a.a25*b.a22 + a.a35*b.a23 + a.a45*b.a24 + a.a55*b.a25; c.a53 = a.a15*b.a31 + a.a25*b.a32 + a.a35*b.a33 + a.a45*b.a34 + a.a55*b.a35; c.a54 = a.a15*b.a41 + a.a25*b.a42 + a.a35*b.a43 + a.a45*b.a44 + a.a55*b.a45; c.a55 = a.a15*b.a51 + a.a25*b.a52 + a.a35*b.a53 + a.a45*b.a54 + a.a55*b.a55; } /** *

* Performs the following operation:
*
* c = a * bT
* cij = ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransB( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13 + a.a14*b.a14 + a.a15*b.a15; c.a12 = a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23 + a.a14*b.a24 + a.a15*b.a25; c.a13 = a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33 + a.a14*b.a34 + a.a15*b.a35; c.a14 = a.a11*b.a41 + a.a12*b.a42 + a.a13*b.a43 + a.a14*b.a44 + a.a15*b.a45; c.a15 = a.a11*b.a51 + a.a12*b.a52 + a.a13*b.a53 + a.a14*b.a54 + a.a15*b.a55; c.a21 = a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13 + a.a24*b.a14 + a.a25*b.a15; c.a22 = a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23 + a.a24*b.a24 + a.a25*b.a25; c.a23 = a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33 + a.a24*b.a34 + a.a25*b.a35; c.a24 = a.a21*b.a41 + a.a22*b.a42 + a.a23*b.a43 + a.a24*b.a44 + a.a25*b.a45; c.a25 = a.a21*b.a51 + a.a22*b.a52 + a.a23*b.a53 + a.a24*b.a54 + a.a25*b.a55; c.a31 = a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13 + a.a34*b.a14 + a.a35*b.a15; c.a32 = a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23 + a.a34*b.a24 + a.a35*b.a25; c.a33 = a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33 + a.a34*b.a34 + a.a35*b.a35; c.a34 = a.a31*b.a41 + a.a32*b.a42 + a.a33*b.a43 + a.a34*b.a44 + a.a35*b.a45; c.a35 = a.a31*b.a51 + a.a32*b.a52 + a.a33*b.a53 + a.a34*b.a54 + a.a35*b.a55; c.a41 = a.a41*b.a11 + a.a42*b.a12 + a.a43*b.a13 + a.a44*b.a14 + a.a45*b.a15; c.a42 = a.a41*b.a21 + a.a42*b.a22 + a.a43*b.a23 + a.a44*b.a24 + a.a45*b.a25; c.a43 = a.a41*b.a31 + a.a42*b.a32 + a.a43*b.a33 + a.a44*b.a34 + a.a45*b.a35; c.a44 = a.a41*b.a41 + a.a42*b.a42 + a.a43*b.a43 + a.a44*b.a44 + a.a45*b.a45; c.a45 = a.a41*b.a51 + a.a42*b.a52 + a.a43*b.a53 + a.a44*b.a54 + a.a45*b.a55; c.a51 = a.a51*b.a11 + a.a52*b.a12 + a.a53*b.a13 + a.a54*b.a14 + a.a55*b.a15; c.a52 = a.a51*b.a21 + a.a52*b.a22 + a.a53*b.a23 + a.a54*b.a24 + a.a55*b.a25; c.a53 = a.a51*b.a31 + a.a52*b.a32 + a.a53*b.a33 + a.a54*b.a34 + a.a55*b.a35; c.a54 = a.a51*b.a41 + a.a52*b.a42 + a.a53*b.a43 + a.a54*b.a44 + a.a55*b.a45; c.a55 = a.a51*b.a51 + a.a52*b.a52 + a.a53*b.a53 + a.a54*b.a54 + a.a55*b.a55; } /** *

Performs the following operation:
*
* c += a * b
*
* cij += ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41 + a.a15*b.a51; c.a12 += a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42 + a.a15*b.a52; c.a13 += a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43 + a.a15*b.a53; c.a14 += a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44 + a.a15*b.a54; c.a15 += a.a11*b.a15 + a.a12*b.a25 + a.a13*b.a35 + a.a14*b.a45 + a.a15*b.a55; c.a21 += a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41 + a.a25*b.a51; c.a22 += a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42 + a.a25*b.a52; c.a23 += a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43 + a.a25*b.a53; c.a24 += a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44 + a.a25*b.a54; c.a25 += a.a21*b.a15 + a.a22*b.a25 + a.a23*b.a35 + a.a24*b.a45 + a.a25*b.a55; c.a31 += a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41 + a.a35*b.a51; c.a32 += a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42 + a.a35*b.a52; c.a33 += a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43 + a.a35*b.a53; c.a34 += a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44 + a.a35*b.a54; c.a35 += a.a31*b.a15 + a.a32*b.a25 + a.a33*b.a35 + a.a34*b.a45 + a.a35*b.a55; c.a41 += a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41 + a.a45*b.a51; c.a42 += a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42 + a.a45*b.a52; c.a43 += a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43 + a.a45*b.a53; c.a44 += a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44 + a.a45*b.a54; c.a45 += a.a41*b.a15 + a.a42*b.a25 + a.a43*b.a35 + a.a44*b.a45 + a.a45*b.a55; c.a51 += a.a51*b.a11 + a.a52*b.a21 + a.a53*b.a31 + a.a54*b.a41 + a.a55*b.a51; c.a52 += a.a51*b.a12 + a.a52*b.a22 + a.a53*b.a32 + a.a54*b.a42 + a.a55*b.a52; c.a53 += a.a51*b.a13 + a.a52*b.a23 + a.a53*b.a33 + a.a54*b.a43 + a.a55*b.a53; c.a54 += a.a51*b.a14 + a.a52*b.a24 + a.a53*b.a34 + a.a54*b.a44 + a.a55*b.a54; c.a55 += a.a51*b.a15 + a.a52*b.a25 + a.a53*b.a35 + a.a54*b.a45 + a.a55*b.a55; } /** *

Performs the following operation:
*
* c += aT * b
*
* cij += ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31 + a.a41*b.a41 + a.a51*b.a51; c.a12 += a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32 + a.a41*b.a42 + a.a51*b.a52; c.a13 += a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33 + a.a41*b.a43 + a.a51*b.a53; c.a14 += a.a11*b.a14 + a.a21*b.a24 + a.a31*b.a34 + a.a41*b.a44 + a.a51*b.a54; c.a15 += a.a11*b.a15 + a.a21*b.a25 + a.a31*b.a35 + a.a41*b.a45 + a.a51*b.a55; c.a21 += a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31 + a.a42*b.a41 + a.a52*b.a51; c.a22 += a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32 + a.a42*b.a42 + a.a52*b.a52; c.a23 += a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33 + a.a42*b.a43 + a.a52*b.a53; c.a24 += a.a12*b.a14 + a.a22*b.a24 + a.a32*b.a34 + a.a42*b.a44 + a.a52*b.a54; c.a25 += a.a12*b.a15 + a.a22*b.a25 + a.a32*b.a35 + a.a42*b.a45 + a.a52*b.a55; c.a31 += a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31 + a.a43*b.a41 + a.a53*b.a51; c.a32 += a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32 + a.a43*b.a42 + a.a53*b.a52; c.a33 += a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33 + a.a43*b.a43 + a.a53*b.a53; c.a34 += a.a13*b.a14 + a.a23*b.a24 + a.a33*b.a34 + a.a43*b.a44 + a.a53*b.a54; c.a35 += a.a13*b.a15 + a.a23*b.a25 + a.a33*b.a35 + a.a43*b.a45 + a.a53*b.a55; c.a41 += a.a14*b.a11 + a.a24*b.a21 + a.a34*b.a31 + a.a44*b.a41 + a.a54*b.a51; c.a42 += a.a14*b.a12 + a.a24*b.a22 + a.a34*b.a32 + a.a44*b.a42 + a.a54*b.a52; c.a43 += a.a14*b.a13 + a.a24*b.a23 + a.a34*b.a33 + a.a44*b.a43 + a.a54*b.a53; c.a44 += a.a14*b.a14 + a.a24*b.a24 + a.a34*b.a34 + a.a44*b.a44 + a.a54*b.a54; c.a45 += a.a14*b.a15 + a.a24*b.a25 + a.a34*b.a35 + a.a44*b.a45 + a.a54*b.a55; c.a51 += a.a15*b.a11 + a.a25*b.a21 + a.a35*b.a31 + a.a45*b.a41 + a.a55*b.a51; c.a52 += a.a15*b.a12 + a.a25*b.a22 + a.a35*b.a32 + a.a45*b.a42 + a.a55*b.a52; c.a53 += a.a15*b.a13 + a.a25*b.a23 + a.a35*b.a33 + a.a45*b.a43 + a.a55*b.a53; c.a54 += a.a15*b.a14 + a.a25*b.a24 + a.a35*b.a34 + a.a45*b.a44 + a.a55*b.a54; c.a55 += a.a15*b.a15 + a.a25*b.a25 + a.a35*b.a35 + a.a45*b.a45 + a.a55*b.a55; } /** *

* Performs the following operation:
*
* c += aT * bT
* cij += ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13 + a.a41*b.a14 + a.a51*b.a15; c.a12 += a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23 + a.a41*b.a24 + a.a51*b.a25; c.a13 += a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33 + a.a41*b.a34 + a.a51*b.a35; c.a14 += a.a11*b.a41 + a.a21*b.a42 + a.a31*b.a43 + a.a41*b.a44 + a.a51*b.a45; c.a15 += a.a11*b.a51 + a.a21*b.a52 + a.a31*b.a53 + a.a41*b.a54 + a.a51*b.a55; c.a21 += a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13 + a.a42*b.a14 + a.a52*b.a15; c.a22 += a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23 + a.a42*b.a24 + a.a52*b.a25; c.a23 += a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33 + a.a42*b.a34 + a.a52*b.a35; c.a24 += a.a12*b.a41 + a.a22*b.a42 + a.a32*b.a43 + a.a42*b.a44 + a.a52*b.a45; c.a25 += a.a12*b.a51 + a.a22*b.a52 + a.a32*b.a53 + a.a42*b.a54 + a.a52*b.a55; c.a31 += a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13 + a.a43*b.a14 + a.a53*b.a15; c.a32 += a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23 + a.a43*b.a24 + a.a53*b.a25; c.a33 += a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33 + a.a43*b.a34 + a.a53*b.a35; c.a34 += a.a13*b.a41 + a.a23*b.a42 + a.a33*b.a43 + a.a43*b.a44 + a.a53*b.a45; c.a35 += a.a13*b.a51 + a.a23*b.a52 + a.a33*b.a53 + a.a43*b.a54 + a.a53*b.a55; c.a41 += a.a14*b.a11 + a.a24*b.a12 + a.a34*b.a13 + a.a44*b.a14 + a.a54*b.a15; c.a42 += a.a14*b.a21 + a.a24*b.a22 + a.a34*b.a23 + a.a44*b.a24 + a.a54*b.a25; c.a43 += a.a14*b.a31 + a.a24*b.a32 + a.a34*b.a33 + a.a44*b.a34 + a.a54*b.a35; c.a44 += a.a14*b.a41 + a.a24*b.a42 + a.a34*b.a43 + a.a44*b.a44 + a.a54*b.a45; c.a45 += a.a14*b.a51 + a.a24*b.a52 + a.a34*b.a53 + a.a44*b.a54 + a.a54*b.a55; c.a51 += a.a15*b.a11 + a.a25*b.a12 + a.a35*b.a13 + a.a45*b.a14 + a.a55*b.a15; c.a52 += a.a15*b.a21 + a.a25*b.a22 + a.a35*b.a23 + a.a45*b.a24 + a.a55*b.a25; c.a53 += a.a15*b.a31 + a.a25*b.a32 + a.a35*b.a33 + a.a45*b.a34 + a.a55*b.a35; c.a54 += a.a15*b.a41 + a.a25*b.a42 + a.a35*b.a43 + a.a45*b.a44 + a.a55*b.a45; c.a55 += a.a15*b.a51 + a.a25*b.a52 + a.a35*b.a53 + a.a45*b.a54 + a.a55*b.a55; } /** *

* Performs the following operation:
*
* c += a * bT
* cij += ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransB( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13 + a.a14*b.a14 + a.a15*b.a15; c.a12 += a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23 + a.a14*b.a24 + a.a15*b.a25; c.a13 += a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33 + a.a14*b.a34 + a.a15*b.a35; c.a14 += a.a11*b.a41 + a.a12*b.a42 + a.a13*b.a43 + a.a14*b.a44 + a.a15*b.a45; c.a15 += a.a11*b.a51 + a.a12*b.a52 + a.a13*b.a53 + a.a14*b.a54 + a.a15*b.a55; c.a21 += a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13 + a.a24*b.a14 + a.a25*b.a15; c.a22 += a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23 + a.a24*b.a24 + a.a25*b.a25; c.a23 += a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33 + a.a24*b.a34 + a.a25*b.a35; c.a24 += a.a21*b.a41 + a.a22*b.a42 + a.a23*b.a43 + a.a24*b.a44 + a.a25*b.a45; c.a25 += a.a21*b.a51 + a.a22*b.a52 + a.a23*b.a53 + a.a24*b.a54 + a.a25*b.a55; c.a31 += a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13 + a.a34*b.a14 + a.a35*b.a15; c.a32 += a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23 + a.a34*b.a24 + a.a35*b.a25; c.a33 += a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33 + a.a34*b.a34 + a.a35*b.a35; c.a34 += a.a31*b.a41 + a.a32*b.a42 + a.a33*b.a43 + a.a34*b.a44 + a.a35*b.a45; c.a35 += a.a31*b.a51 + a.a32*b.a52 + a.a33*b.a53 + a.a34*b.a54 + a.a35*b.a55; c.a41 += a.a41*b.a11 + a.a42*b.a12 + a.a43*b.a13 + a.a44*b.a14 + a.a45*b.a15; c.a42 += a.a41*b.a21 + a.a42*b.a22 + a.a43*b.a23 + a.a44*b.a24 + a.a45*b.a25; c.a43 += a.a41*b.a31 + a.a42*b.a32 + a.a43*b.a33 + a.a44*b.a34 + a.a45*b.a35; c.a44 += a.a41*b.a41 + a.a42*b.a42 + a.a43*b.a43 + a.a44*b.a44 + a.a45*b.a45; c.a45 += a.a41*b.a51 + a.a42*b.a52 + a.a43*b.a53 + a.a44*b.a54 + a.a45*b.a55; c.a51 += a.a51*b.a11 + a.a52*b.a12 + a.a53*b.a13 + a.a54*b.a14 + a.a55*b.a15; c.a52 += a.a51*b.a21 + a.a52*b.a22 + a.a53*b.a23 + a.a54*b.a24 + a.a55*b.a25; c.a53 += a.a51*b.a31 + a.a52*b.a32 + a.a53*b.a33 + a.a54*b.a34 + a.a55*b.a35; c.a54 += a.a51*b.a41 + a.a52*b.a42 + a.a53*b.a43 + a.a54*b.a44 + a.a55*b.a45; c.a55 += a.a51*b.a51 + a.a52*b.a52 + a.a53*b.a53 + a.a54*b.a54 + a.a55*b.a55; } /** *

Performs matrix to vector multiplication:
*
* c = a * b
*
* ci = ∑k=1:n { aik * bk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix5x5_64F a , FixedMatrix5_64F b , FixedMatrix5_64F c) { c.a1 = a.a11*b.a1 + a.a12*b.a2 + a.a13*b.a3 + a.a14*b.a4 + a.a15*b.a5; c.a2 = a.a21*b.a1 + a.a22*b.a2 + a.a23*b.a3 + a.a24*b.a4 + a.a25*b.a5; c.a3 = a.a31*b.a1 + a.a32*b.a2 + a.a33*b.a3 + a.a34*b.a4 + a.a35*b.a5; c.a4 = a.a41*b.a1 + a.a42*b.a2 + a.a43*b.a3 + a.a44*b.a4 + a.a45*b.a5; c.a5 = a.a51*b.a1 + a.a52*b.a2 + a.a53*b.a3 + a.a54*b.a4 + a.a55*b.a5; } /** *

Performs vector to matrix multiplication:
*
* c = a * b
*
* cj = ∑k=1:n { bk * akj } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix5_64F a , FixedMatrix5x5_64F b , FixedMatrix5_64F c) { c.a1 = a.a1*b.a11 + a.a2*b.a21 + a.a3*b.a31 + a.a4*b.a41 + a.a5*b.a51; c.a2 = a.a1*b.a12 + a.a2*b.a22 + a.a3*b.a32 + a.a4*b.a42 + a.a5*b.a52; c.a3 = a.a1*b.a13 + a.a2*b.a23 + a.a3*b.a33 + a.a4*b.a43 + a.a5*b.a53; c.a4 = a.a1*b.a14 + a.a2*b.a24 + a.a3*b.a34 + a.a4*b.a44 + a.a5*b.a54; c.a5 = a.a1*b.a15 + a.a2*b.a25 + a.a3*b.a35 + a.a4*b.a45 + a.a5*b.a55; } /** *

Performs the vector dot product:
*
* c = a * b
*
* c> = ∑k=1:n { bk * ak } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @return The dot product */ public static double dot( FixedMatrix5_64F a , FixedMatrix5_64F b ) { return a.a1*b.a1 + a.a2*b.a2 + a.a3*b.a3 + a.a4*b.a4 + a.a5*b.a5; } /** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @param a A matrix. */ public static void setIdentity( FixedMatrix5x5_64F a ) { a.a11 = 1; a.a21 = 0; a.a31 = 0; a.a41 = 0; a.a51 = 0; a.a12 = 0; a.a22 = 1; a.a32 = 0; a.a42 = 0; a.a52 = 0; a.a13 = 0; a.a23 = 0; a.a33 = 1; a.a43 = 0; a.a53 = 0; a.a14 = 0; a.a24 = 0; a.a34 = 0; a.a44 = 1; a.a54 = 0; a.a15 = 0; a.a25 = 0; a.a35 = 0; a.a45 = 0; a.a55 = 1; } /** * Inverts matrix 'a' using minor matrices and stores the results in 'inv'. Scaling is applied to improve * stability against overflow and underflow. * * WARNING: Potentially less stable than using LU decomposition. * * @param a Input matrix. Not modified. * @param inv Inverted output matrix. Modified. * @return true if it was successful or false if it failed. Not always reliable. */ public static boolean invert( FixedMatrix5x5_64F a , FixedMatrix5x5_64F inv ) { double scale = 1.0/elementMaxAbs(a); double a11 = a.a11*scale; double a12 = a.a12*scale; double a13 = a.a13*scale; double a14 = a.a14*scale; double a15 = a.a15*scale; double a21 = a.a21*scale; double a22 = a.a22*scale; double a23 = a.a23*scale; double a24 = a.a24*scale; double a25 = a.a25*scale; double a31 = a.a31*scale; double a32 = a.a32*scale; double a33 = a.a33*scale; double a34 = a.a34*scale; double a35 = a.a35*scale; double a41 = a.a41*scale; double a42 = a.a42*scale; double a43 = a.a43*scale; double a44 = a.a44*scale; double a45 = a.a45*scale; double a51 = a.a51*scale; double a52 = a.a52*scale; double a53 = a.a53*scale; double a54 = a.a54*scale; double a55 = a.a55*scale; double m11 = + a22*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a24*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a25*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)); double m12 = -( + a21*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a23*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a25*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51))); double m13 = + a21*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a22*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a24*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)); double m14 = -( + a21*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a25*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))); double m15 = + a21*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a22*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a23*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a24*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)); double m21 = -( + a12*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a13*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) + a14*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a15*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52))); double m22 = + a11*( + a33*(a44*a55 - a45*a54) - a34*(a43*a55 - a45*a53) + a35*(a43*a54 - a44*a53)) - a13*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a14*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) - a15*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)); double m23 = -( + a11*( + a32*(a44*a55 - a45*a54) - a34*(a42*a55 - a45*a52) + a35*(a42*a54 - a44*a52)) - a12*( + a31*(a44*a55 - a45*a54) - a34*(a41*a55 - a45*a51) + a35*(a41*a54 - a44*a51)) + a14*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a15*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51))); double m24 = + a11*( + a32*(a43*a55 - a45*a53) - a33*(a42*a55 - a45*a52) + a35*(a42*a53 - a43*a52)) - a12*( + a31*(a43*a55 - a45*a53) - a33*(a41*a55 - a45*a51) + a35*(a41*a53 - a43*a51)) + a13*( + a31*(a42*a55 - a45*a52) - a32*(a41*a55 - a45*a51) + a35*(a41*a52 - a42*a51)) - a15*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51)); double m25 = -( + a11*( + a32*(a43*a54 - a44*a53) - a33*(a42*a54 - a44*a52) + a34*(a42*a53 - a43*a52)) - a12*( + a31*(a43*a54 - a44*a53) - a33*(a41*a54 - a44*a51) + a34*(a41*a53 - a43*a51)) + a13*( + a31*(a42*a54 - a44*a52) - a32*(a41*a54 - a44*a51) + a34*(a41*a52 - a42*a51)) - a14*( + a31*(a42*a53 - a43*a52) - a32*(a41*a53 - a43*a51) + a33*(a41*a52 - a42*a51))); double m31 = + a12*( + a23*(a44*a55 - a45*a54) - a24*(a43*a55 - a45*a53) + a25*(a43*a54 - a44*a53)) - a13*( + a22*(a44*a55 - a45*a54) - a24*(a42*a55 - a45*a52) + a25*(a42*a54 - a44*a52)) + a14*( + a22*(a43*a55 - a45*a53) - a23*(a42*a55 - a45*a52) + a25*(a42*a53 - a43*a52)) - a15*( + a22*(a43*a54 - a44*a53) - a23*(a42*a54 - a44*a52) + a24*(a42*a53 - a43*a52)); double m32 = -( + a11*( + a23*(a44*a55 - a45*a54) - a24*(a43*a55 - a45*a53) + a25*(a43*a54 - a44*a53)) - a13*( + a21*(a44*a55 - a45*a54) - a24*(a41*a55 - a45*a51) + a25*(a41*a54 - a44*a51)) + a14*( + a21*(a43*a55 - a45*a53) - a23*(a41*a55 - a45*a51) + a25*(a41*a53 - a43*a51)) - a15*( + a21*(a43*a54 - a44*a53) - a23*(a41*a54 - a44*a51) + a24*(a41*a53 - a43*a51))); double m33 = + a11*( + a22*(a44*a55 - a45*a54) - a24*(a42*a55 - a45*a52) + a25*(a42*a54 - a44*a52)) - a12*( + a21*(a44*a55 - a45*a54) - a24*(a41*a55 - a45*a51) + a25*(a41*a54 - a44*a51)) + a14*( + a21*(a42*a55 - a45*a52) - a22*(a41*a55 - a45*a51) + a25*(a41*a52 - a42*a51)) - a15*( + a21*(a42*a54 - a44*a52) - a22*(a41*a54 - a44*a51) + a24*(a41*a52 - a42*a51)); double m34 = -( + a11*( + a22*(a43*a55 - a45*a53) - a23*(a42*a55 - a45*a52) + a25*(a42*a53 - a43*a52)) - a12*( + a21*(a43*a55 - a45*a53) - a23*(a41*a55 - a45*a51) + a25*(a41*a53 - a43*a51)) + a13*( + a21*(a42*a55 - a45*a52) - a22*(a41*a55 - a45*a51) + a25*(a41*a52 - a42*a51)) - a15*( + a21*(a42*a53 - a43*a52) - a22*(a41*a53 - a43*a51) + a23*(a41*a52 - a42*a51))); double m35 = + a11*( + a22*(a43*a54 - a44*a53) - a23*(a42*a54 - a44*a52) + a24*(a42*a53 - a43*a52)) - a12*( + a21*(a43*a54 - a44*a53) - a23*(a41*a54 - a44*a51) + a24*(a41*a53 - a43*a51)) + a13*( + a21*(a42*a54 - a44*a52) - a22*(a41*a54 - a44*a51) + a24*(a41*a52 - a42*a51)) - a14*( + a21*(a42*a53 - a43*a52) - a22*(a41*a53 - a43*a51) + a23*(a41*a52 - a42*a51)); double m41 = -( + a12*( + a23*(a34*a55 - a35*a54) - a24*(a33*a55 - a35*a53) + a25*(a33*a54 - a34*a53)) - a13*( + a22*(a34*a55 - a35*a54) - a24*(a32*a55 - a35*a52) + a25*(a32*a54 - a34*a52)) + a14*( + a22*(a33*a55 - a35*a53) - a23*(a32*a55 - a35*a52) + a25*(a32*a53 - a33*a52)) - a15*( + a22*(a33*a54 - a34*a53) - a23*(a32*a54 - a34*a52) + a24*(a32*a53 - a33*a52))); double m42 = + a11*( + a23*(a34*a55 - a35*a54) - a24*(a33*a55 - a35*a53) + a25*(a33*a54 - a34*a53)) - a13*( + a21*(a34*a55 - a35*a54) - a24*(a31*a55 - a35*a51) + a25*(a31*a54 - a34*a51)) + a14*( + a21*(a33*a55 - a35*a53) - a23*(a31*a55 - a35*a51) + a25*(a31*a53 - a33*a51)) - a15*( + a21*(a33*a54 - a34*a53) - a23*(a31*a54 - a34*a51) + a24*(a31*a53 - a33*a51)); double m43 = -( + a11*( + a22*(a34*a55 - a35*a54) - a24*(a32*a55 - a35*a52) + a25*(a32*a54 - a34*a52)) - a12*( + a21*(a34*a55 - a35*a54) - a24*(a31*a55 - a35*a51) + a25*(a31*a54 - a34*a51)) + a14*( + a21*(a32*a55 - a35*a52) - a22*(a31*a55 - a35*a51) + a25*(a31*a52 - a32*a51)) - a15*( + a21*(a32*a54 - a34*a52) - a22*(a31*a54 - a34*a51) + a24*(a31*a52 - a32*a51))); double m44 = + a11*( + a22*(a33*a55 - a35*a53) - a23*(a32*a55 - a35*a52) + a25*(a32*a53 - a33*a52)) - a12*( + a21*(a33*a55 - a35*a53) - a23*(a31*a55 - a35*a51) + a25*(a31*a53 - a33*a51)) + a13*( + a21*(a32*a55 - a35*a52) - a22*(a31*a55 - a35*a51) + a25*(a31*a52 - a32*a51)) - a15*( + a21*(a32*a53 - a33*a52) - a22*(a31*a53 - a33*a51) + a23*(a31*a52 - a32*a51)); double m45 = -( + a11*( + a22*(a33*a54 - a34*a53) - a23*(a32*a54 - a34*a52) + a24*(a32*a53 - a33*a52)) - a12*( + a21*(a33*a54 - a34*a53) - a23*(a31*a54 - a34*a51) + a24*(a31*a53 - a33*a51)) + a13*( + a21*(a32*a54 - a34*a52) - a22*(a31*a54 - a34*a51) + a24*(a31*a52 - a32*a51)) - a14*( + a21*(a32*a53 - a33*a52) - a22*(a31*a53 - a33*a51) + a23*(a31*a52 - a32*a51))); double m51 = + a12*( + a23*(a34*a45 - a35*a44) - a24*(a33*a45 - a35*a43) + a25*(a33*a44 - a34*a43)) - a13*( + a22*(a34*a45 - a35*a44) - a24*(a32*a45 - a35*a42) + a25*(a32*a44 - a34*a42)) + a14*( + a22*(a33*a45 - a35*a43) - a23*(a32*a45 - a35*a42) + a25*(a32*a43 - a33*a42)) - a15*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)); double m52 = -( + a11*( + a23*(a34*a45 - a35*a44) - a24*(a33*a45 - a35*a43) + a25*(a33*a44 - a34*a43)) - a13*( + a21*(a34*a45 - a35*a44) - a24*(a31*a45 - a35*a41) + a25*(a31*a44 - a34*a41)) + a14*( + a21*(a33*a45 - a35*a43) - a23*(a31*a45 - a35*a41) + a25*(a31*a43 - a33*a41)) - a15*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41))); double m53 = + a11*( + a22*(a34*a45 - a35*a44) - a24*(a32*a45 - a35*a42) + a25*(a32*a44 - a34*a42)) - a12*( + a21*(a34*a45 - a35*a44) - a24*(a31*a45 - a35*a41) + a25*(a31*a44 - a34*a41)) + a14*( + a21*(a32*a45 - a35*a42) - a22*(a31*a45 - a35*a41) + a25*(a31*a42 - a32*a41)) - a15*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)); double m54 = -( + a11*( + a22*(a33*a45 - a35*a43) - a23*(a32*a45 - a35*a42) + a25*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a45 - a35*a43) - a23*(a31*a45 - a35*a41) + a25*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a45 - a35*a42) - a22*(a31*a45 - a35*a41) + a25*(a31*a42 - a32*a41)) - a15*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); double m55 = + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41)); double det = (a11*m11 + a12*m12 + a13*m13 + a14*m14 + a15*m15)/scale; inv.a11 = m11/det; inv.a12 = m21/det; inv.a13 = m31/det; inv.a14 = m41/det; inv.a15 = m51/det; inv.a21 = m12/det; inv.a22 = m22/det; inv.a23 = m32/det; inv.a24 = m42/det; inv.a25 = m52/det; inv.a31 = m13/det; inv.a32 = m23/det; inv.a33 = m33/det; inv.a34 = m43/det; inv.a35 = m53/det; inv.a41 = m14/det; inv.a42 = m24/det; inv.a43 = m34/det; inv.a44 = m44/det; inv.a45 = m54/det; inv.a51 = m15/det; inv.a52 = m25/det; inv.a53 = m35/det; inv.a54 = m45/det; inv.a55 = m55/det; return !Double.isNaN(det) && !Double.isInfinite(det); } /** * Computes the determinant using minor matrices. *

* WARNING: Potentially less stable than using LU decomposition. * * @param mat Input matrix. Not modified. * @return The determinant. */ public static double det( FixedMatrix5x5_64F mat ) { double a11 = mat.a22; double a12 = mat.a23; double a13 = mat.a24; double a14 = mat.a25; double a21 = mat.a32; double a22 = mat.a33; double a23 = mat.a34; double a24 = mat.a35; double a31 = mat.a42; double a32 = mat.a43; double a33 = mat.a44; double a34 = mat.a45; double a41 = mat.a52; double a42 = mat.a53; double a43 = mat.a54; double a44 = mat.a55; double ret = 0; ret += mat.a11 * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a11 = mat.a21; a21 = mat.a31; a31 = mat.a41; a41 = mat.a51; ret -= mat.a12 * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a12 = mat.a22; a22 = mat.a32; a32 = mat.a42; a42 = mat.a52; ret += mat.a13 * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a13 = mat.a23; a23 = mat.a33; a33 = mat.a43; a43 = mat.a53; ret -= mat.a14 * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); a14 = mat.a24; a24 = mat.a34; a34 = mat.a44; a44 = mat.a54; ret += mat.a15 * ( + a11*( + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42)) - a12*( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)) + a13*( + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41)) - a14*( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41))); return ret; } /** *

* This computes the trace of the matrix:
*
* trace = ∑i=1:n { aii } *

*

* The trace is only defined for square matrices. *

* * @param a A square matrix. Not modified. */ public static double trace( FixedMatrix5x5_64F a ) { return a.a11 + a.a21 + a.a31 + a.a41 + a.a51; } /** *

* Extracts all diagonal elements from 'input' and places them inside the 'out' vector. Elements * are in sequential order. *

* * * @param input Matrix. Not modified. * @param out Vector containing diagonal elements. Modified. */ public static void diag( FixedMatrix5x5_64F input , FixedMatrix5_64F out ) { out.a1 = input.a11; out.a2 = input.a22; out.a3 = input.a33; out.a4 = input.a44; out.a5 = input.a55; } /** *

* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix5x5_64F a ) { double max = a.a11; max = Math.max(max,a.a12); max = Math.max(max,a.a13); max = Math.max(max,a.a14); max = Math.max(max,a.a15); max = Math.max(max,a.a21); max = Math.max(max,a.a22); max = Math.max(max,a.a23); max = Math.max(max,a.a24); max = Math.max(max,a.a25); max = Math.max(max,a.a31); max = Math.max(max,a.a32); max = Math.max(max,a.a33); max = Math.max(max,a.a34); max = Math.max(max,a.a35); max = Math.max(max,a.a41); max = Math.max(max,a.a42); max = Math.max(max,a.a43); max = Math.max(max,a.a44); max = Math.max(max,a.a45); max = Math.max(max,a.a51); max = Math.max(max,a.a52); max = Math.max(max,a.a53); max = Math.max(max,a.a54); max = Math.max(max,a.a55); return max; } /** *

* Returns the value of the element in the vector that has the largest value.
*
* Max{ ai } for all i
*

* * @param a A vector. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix5_64F a ) { double max = a.a1; max = Math.max(max,a.a2); max = Math.max(max,a.a3); max = Math.max(max,a.a4); max = Math.max(max,a.a5); return max; } /** *

* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementMaxAbs( FixedMatrix5x5_64F a ) { double max = a.a11; max = Math.max(max,Math.abs(a.a12)); max = Math.max(max,Math.abs(a.a13)); max = Math.max(max,Math.abs(a.a14)); max = Math.max(max,Math.abs(a.a15)); max = Math.max(max,Math.abs(a.a21)); max = Math.max(max,Math.abs(a.a22)); max = Math.max(max,Math.abs(a.a23)); max = Math.max(max,Math.abs(a.a24)); max = Math.max(max,Math.abs(a.a25)); max = Math.max(max,Math.abs(a.a31)); max = Math.max(max,Math.abs(a.a32)); max = Math.max(max,Math.abs(a.a33)); max = Math.max(max,Math.abs(a.a34)); max = Math.max(max,Math.abs(a.a35)); max = Math.max(max,Math.abs(a.a41)); max = Math.max(max,Math.abs(a.a42)); max = Math.max(max,Math.abs(a.a43)); max = Math.max(max,Math.abs(a.a44)); max = Math.max(max,Math.abs(a.a45)); max = Math.max(max,Math.abs(a.a51)); max = Math.max(max,Math.abs(a.a52)); max = Math.max(max,Math.abs(a.a53)); max = Math.max(max,Math.abs(a.a54)); max = Math.max(max,Math.abs(a.a55)); return max; } /** *

* Returns the absolute value of the element in the vector that has the largest absolute value.
*
* Max{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max abs element value of the vector. */ public static double elementMaxAbs( FixedMatrix5_64F a ) { double max = a.a1; max = Math.max(max,Math.abs(a.a2)); max = Math.max(max,Math.abs(a.a3)); max = Math.max(max,Math.abs(a.a4)); max = Math.max(max,Math.abs(a.a5)); return max; } /** *

* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The value of element in the matrix with the minimum value. */ public static double elementMin( FixedMatrix5x5_64F a ) { double min = a.a11; min = Math.min(min, a.a12); min = Math.min(min, a.a13); min = Math.min(min, a.a14); min = Math.min(min, a.a15); min = Math.min(min, a.a21); min = Math.min(min, a.a22); min = Math.min(min, a.a23); min = Math.min(min, a.a24); min = Math.min(min, a.a25); min = Math.min(min, a.a31); min = Math.min(min, a.a32); min = Math.min(min, a.a33); min = Math.min(min, a.a34); min = Math.min(min, a.a35); min = Math.min(min, a.a41); min = Math.min(min, a.a42); min = Math.min(min, a.a43); min = Math.min(min, a.a44); min = Math.min(min, a.a45); min = Math.min(min, a.a51); min = Math.min(min, a.a52); min = Math.min(min, a.a53); min = Math.min(min, a.a54); min = Math.min(min, a.a55); return min; } /** *

* Returns the value of the element in the vector that has the minimum value.
*
* Min{ ai } for all
*

* * @param a A matrix. Not modified. * @return The value of element in the vector with the minimum value. */ public static double elementMin( FixedMatrix5_64F a ) { double min = a.a1; min = Math.min(min, a.a2); min = Math.min(min, a.a3); min = Math.min(min, a.a4); min = Math.min(min, a.a5); return min; } /** *

* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMinAbs( FixedMatrix5x5_64F a ) { double min = a.a11; min = Math.min(min,Math.abs(a.a12)); min = Math.min(min,Math.abs(a.a13)); min = Math.min(min,Math.abs(a.a14)); min = Math.min(min,Math.abs(a.a15)); min = Math.min(min,Math.abs(a.a21)); min = Math.min(min,Math.abs(a.a22)); min = Math.min(min,Math.abs(a.a23)); min = Math.min(min,Math.abs(a.a24)); min = Math.min(min,Math.abs(a.a25)); min = Math.min(min,Math.abs(a.a31)); min = Math.min(min,Math.abs(a.a32)); min = Math.min(min,Math.abs(a.a33)); min = Math.min(min,Math.abs(a.a34)); min = Math.min(min,Math.abs(a.a35)); min = Math.min(min,Math.abs(a.a41)); min = Math.min(min,Math.abs(a.a42)); min = Math.min(min,Math.abs(a.a43)); min = Math.min(min,Math.abs(a.a44)); min = Math.min(min,Math.abs(a.a45)); min = Math.min(min,Math.abs(a.a51)); min = Math.min(min,Math.abs(a.a52)); min = Math.min(min,Math.abs(a.a53)); min = Math.min(min,Math.abs(a.a54)); min = Math.min(min,Math.abs(a.a55)); return min; } /** *

* Returns the absolute value of the element in the vector that has the smallest absolute value.
*
* Min{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max element value of the vector. */ public static double elementMinAbs( FixedMatrix5_64F a ) { double min = a.a1; min = Math.min(min,Math.abs(a.a2)); min = Math.min(min,Math.abs(a.a3)); min = Math.min(min,Math.abs(a.a4)); min = Math.min(min,Math.abs(a.a5)); return min; } /** *

Performs an element by element multiplication operation:
*
* aij = aij * bij
*

* @param a The left matrix in the multiplication operation. Modified. * @param b The right matrix in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b) { a.a11 *= b.a11; a.a12 *= b.a12; a.a13 *= b.a13; a.a14 *= b.a14; a.a15 *= b.a15; a.a21 *= b.a21; a.a22 *= b.a22; a.a23 *= b.a23; a.a24 *= b.a24; a.a25 *= b.a25; a.a31 *= b.a31; a.a32 *= b.a32; a.a33 *= b.a33; a.a34 *= b.a34; a.a35 *= b.a35; a.a41 *= b.a41; a.a42 *= b.a42; a.a43 *= b.a43; a.a44 *= b.a44; a.a45 *= b.a45; a.a51 *= b.a51; a.a52 *= b.a52; a.a53 *= b.a53; a.a54 *= b.a54; a.a55 *= b.a55; } /** *

Performs an element by element multiplication operation:
*
* ai = ai * bi
*

* @param a The left vector in the multiplication operation. Modified. * @param b The right vector in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix5_64F a , FixedMatrix5_64F b) { a.a1 *= b.a1; a.a2 *= b.a2; a.a3 *= b.a3; a.a4 *= b.a4; a.a5 *= b.a5; } /** *

Performs an element by element multiplication operation:
*
* cij = aij * bij
*

* @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c ) { c.a11 = a.a11*b.a11; c.a12 = a.a12*b.a12; c.a13 = a.a13*b.a13; c.a14 = a.a14*b.a14; c.a15 = a.a15*b.a15; c.a21 = a.a21*b.a21; c.a22 = a.a22*b.a22; c.a23 = a.a23*b.a23; c.a24 = a.a24*b.a24; c.a25 = a.a25*b.a25; c.a31 = a.a31*b.a31; c.a32 = a.a32*b.a32; c.a33 = a.a33*b.a33; c.a34 = a.a34*b.a34; c.a35 = a.a35*b.a35; c.a41 = a.a41*b.a41; c.a42 = a.a42*b.a42; c.a43 = a.a43*b.a43; c.a44 = a.a44*b.a44; c.a45 = a.a45*b.a45; c.a51 = a.a51*b.a51; c.a52 = a.a52*b.a52; c.a53 = a.a53*b.a53; c.a54 = a.a54*b.a54; c.a55 = a.a55*b.a55; } /** *

Performs an element by element multiplication operation:
*
* ci = ai * bj
*

* @param a The left vector in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix5_64F a , FixedMatrix5_64F b , FixedMatrix5_64F c ) { c.a1 = a.a1*b.a1; c.a2 = a.a2*b.a2; c.a3 = a.a3*b.a3; c.a4 = a.a4*b.a4; c.a5 = a.a5*b.a5; } /** *

Performs an element by element division operation:
*
* aij = aij / bij
*

* @param a The left matrix in the division operation. Modified. * @param b The right matrix in the division operation. Not modified. */ public static void elementDiv( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b) { a.a11 /= b.a11; a.a12 /= b.a12; a.a13 /= b.a13; a.a14 /= b.a14; a.a15 /= b.a15; a.a21 /= b.a21; a.a22 /= b.a22; a.a23 /= b.a23; a.a24 /= b.a24; a.a25 /= b.a25; a.a31 /= b.a31; a.a32 /= b.a32; a.a33 /= b.a33; a.a34 /= b.a34; a.a35 /= b.a35; a.a41 /= b.a41; a.a42 /= b.a42; a.a43 /= b.a43; a.a44 /= b.a44; a.a45 /= b.a45; a.a51 /= b.a51; a.a52 /= b.a52; a.a53 /= b.a53; a.a54 /= b.a54; a.a55 /= b.a55; } /** *

Performs an element by element division operation:
*
* ai = ai / bi
*

* @param a The left vector in the division operation. Modified. * @param b The right vector in the division operation. Not modified. */ public static void elementDiv( FixedMatrix5_64F a , FixedMatrix5_64F b) { a.a1 /= b.a1; a.a2 /= b.a2; a.a3 /= b.a3; a.a4 /= b.a4; a.a5 /= b.a5; } /** *

Performs an element by element division operation:
*
* cij = aij / bij
*

* @param a The left matrix in the division operation. Not modified. * @param b The right matrix in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix5x5_64F a , FixedMatrix5x5_64F b , FixedMatrix5x5_64F c ) { c.a11 = a.a11/b.a11; c.a12 = a.a12/b.a12; c.a13 = a.a13/b.a13; c.a14 = a.a14/b.a14; c.a15 = a.a15/b.a15; c.a21 = a.a21/b.a21; c.a22 = a.a22/b.a22; c.a23 = a.a23/b.a23; c.a24 = a.a24/b.a24; c.a25 = a.a25/b.a25; c.a31 = a.a31/b.a31; c.a32 = a.a32/b.a32; c.a33 = a.a33/b.a33; c.a34 = a.a34/b.a34; c.a35 = a.a35/b.a35; c.a41 = a.a41/b.a41; c.a42 = a.a42/b.a42; c.a43 = a.a43/b.a43; c.a44 = a.a44/b.a44; c.a45 = a.a45/b.a45; c.a51 = a.a51/b.a51; c.a52 = a.a52/b.a52; c.a53 = a.a53/b.a53; c.a54 = a.a54/b.a54; c.a55 = a.a55/b.a55; } /** *

Performs an element by element division operation:
*
* ci = ai / bi
*

* @param a The left vector in the division operation. Not modified. * @param b The right vector in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix5_64F a , FixedMatrix5_64F b , FixedMatrix5_64F c ) { c.a1 = a.a1/b.a1; c.a2 = a.a2/b.a2; c.a3 = a.a3/b.a3; c.a4 = a.a4/b.a4; c.a5 = a.a5/b.a5; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The matrix that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix5x5_64F a ) { a.a11 *= alpha; a.a12 *= alpha; a.a13 *= alpha; a.a14 *= alpha; a.a15 *= alpha; a.a21 *= alpha; a.a22 *= alpha; a.a23 *= alpha; a.a24 *= alpha; a.a25 *= alpha; a.a31 *= alpha; a.a32 *= alpha; a.a33 *= alpha; a.a34 *= alpha; a.a35 *= alpha; a.a41 *= alpha; a.a42 *= alpha; a.a43 *= alpha; a.a44 *= alpha; a.a45 *= alpha; a.a51 *= alpha; a.a52 *= alpha; a.a53 *= alpha; a.a54 *= alpha; a.a55 *= alpha; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The vector that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix5_64F a ) { a.a1 *= alpha; a.a2 *= alpha; a.a3 *= alpha; a.a4 *= alpha; a.a5 *= alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bij = α*aij *

* * @param alpha the amount each element is multiplied by. * @param a The matrix that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix5x5_64F a , FixedMatrix5x5_64F b ) { b.a11 = a.a11*alpha; b.a12 = a.a12*alpha; b.a13 = a.a13*alpha; b.a14 = a.a14*alpha; b.a15 = a.a15*alpha; b.a21 = a.a21*alpha; b.a22 = a.a22*alpha; b.a23 = a.a23*alpha; b.a24 = a.a24*alpha; b.a25 = a.a25*alpha; b.a31 = a.a31*alpha; b.a32 = a.a32*alpha; b.a33 = a.a33*alpha; b.a34 = a.a34*alpha; b.a35 = a.a35*alpha; b.a41 = a.a41*alpha; b.a42 = a.a42*alpha; b.a43 = a.a43*alpha; b.a44 = a.a44*alpha; b.a45 = a.a45*alpha; b.a51 = a.a51*alpha; b.a52 = a.a52*alpha; b.a53 = a.a53*alpha; b.a54 = a.a54*alpha; b.a55 = a.a55*alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bi = α*ai *

* * @param alpha the amount each element is multiplied by. * @param a The vector that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix5_64F a , FixedMatrix5_64F b ) { b.a1 = a.a1*alpha; b.a2 = a.a2*alpha; b.a3 = a.a3*alpha; b.a4 = a.a4*alpha; b.a5 = a.a5*alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* aij = aij/α *

* * @param a The matrix whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix5x5_64F a , double alpha ) { a.a11 /= alpha; a.a12 /= alpha; a.a13 /= alpha; a.a14 /= alpha; a.a15 /= alpha; a.a21 /= alpha; a.a22 /= alpha; a.a23 /= alpha; a.a24 /= alpha; a.a25 /= alpha; a.a31 /= alpha; a.a32 /= alpha; a.a33 /= alpha; a.a34 /= alpha; a.a35 /= alpha; a.a41 /= alpha; a.a42 /= alpha; a.a43 /= alpha; a.a44 /= alpha; a.a45 /= alpha; a.a51 /= alpha; a.a52 /= alpha; a.a53 /= alpha; a.a54 /= alpha; a.a55 /= alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* ai = ai/α *

* * @param a The vector whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix5_64F a , double alpha ) { a.a1 /= alpha; a.a2 /= alpha; a.a3 /= alpha; a.a4 /= alpha; a.a5 /= alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bij = aij /α *

* * @param alpha the amount each element is divided by. * @param a The matrix whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix5x5_64F a , double alpha , FixedMatrix5x5_64F b ) { b.a11 = a.a11/alpha; b.a12 = a.a12/alpha; b.a13 = a.a13/alpha; b.a14 = a.a14/alpha; b.a15 = a.a15/alpha; b.a21 = a.a21/alpha; b.a22 = a.a22/alpha; b.a23 = a.a23/alpha; b.a24 = a.a24/alpha; b.a25 = a.a25/alpha; b.a31 = a.a31/alpha; b.a32 = a.a32/alpha; b.a33 = a.a33/alpha; b.a34 = a.a34/alpha; b.a35 = a.a35/alpha; b.a41 = a.a41/alpha; b.a42 = a.a42/alpha; b.a43 = a.a43/alpha; b.a44 = a.a44/alpha; b.a45 = a.a45/alpha; b.a51 = a.a51/alpha; b.a52 = a.a52/alpha; b.a53 = a.a53/alpha; b.a54 = a.a54/alpha; b.a55 = a.a55/alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bi = ai /α *

* * @param alpha the amount each element is divided by. * @param a The vector whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix5_64F a , double alpha , FixedMatrix5_64F b ) { b.a1 = a.a1/alpha; b.a2 = a.a2/alpha; b.a3 = a.a3/alpha; b.a4 = a.a4/alpha; b.a5 = a.a5/alpha; } /** *

* Changes the sign of every element in the matrix.
*
* aij = -aij *

* * @param a A matrix. Modified. */ public static void changeSign( FixedMatrix5x5_64F a ) { a.a11 = -a.a11; a.a12 = -a.a12; a.a13 = -a.a13; a.a14 = -a.a14; a.a15 = -a.a15; a.a21 = -a.a21; a.a22 = -a.a22; a.a23 = -a.a23; a.a24 = -a.a24; a.a25 = -a.a25; a.a31 = -a.a31; a.a32 = -a.a32; a.a33 = -a.a33; a.a34 = -a.a34; a.a35 = -a.a35; a.a41 = -a.a41; a.a42 = -a.a42; a.a43 = -a.a43; a.a44 = -a.a44; a.a45 = -a.a45; a.a51 = -a.a51; a.a52 = -a.a52; a.a53 = -a.a53; a.a54 = -a.a54; a.a55 = -a.a55; } /** *

* Changes the sign of every element in the vector.
*
* ai = -ai *

* * @param a A vector. Modified. */ public static void changeSign( FixedMatrix5_64F a ) { a.a1 = -a.a1; a.a2 = -a.a2; a.a3 = -a.a3; a.a4 = -a.a4; a.a5 = -a.a5; } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param a A matrix whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix5x5_64F a , double v ) { a.a11 = v; a.a12 = v; a.a13 = v; a.a14 = v; a.a15 = v; a.a21 = v; a.a22 = v; a.a23 = v; a.a24 = v; a.a25 = v; a.a31 = v; a.a32 = v; a.a33 = v; a.a34 = v; a.a35 = v; a.a41 = v; a.a42 = v; a.a43 = v; a.a44 = v; a.a45 = v; a.a51 = v; a.a52 = v; a.a53 = v; a.a54 = v; a.a55 = v; } /** *

* Sets every element in the vector to the specified value.
*
* ai = value *

* * @param a A vector whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix5_64F a , double v ) { a.a1 = v; a.a2 = v; a.a3 = v; a.a4 = v; a.a5 = v; } /** * Extracts the row from the matrix a. * @param a Input matrix * @param row Which row is to be extracted * @param out output. Storage for the extracted row. If null then a new vector will be returned. * @return The extracted row. */ public static FixedMatrix5_64F extractRow( FixedMatrix5x5_64F a , int row , FixedMatrix5_64F out ) { if( out == null) out = new FixedMatrix5_64F(); switch( row ) { case 0: out.a1 = a.a11; out.a2 = a.a12; out.a3 = a.a13; out.a4 = a.a14; out.a5 = a.a15; break; case 1: out.a1 = a.a21; out.a2 = a.a22; out.a3 = a.a23; out.a4 = a.a24; out.a5 = a.a25; break; case 2: out.a1 = a.a31; out.a2 = a.a32; out.a3 = a.a33; out.a4 = a.a34; out.a5 = a.a35; break; case 3: out.a1 = a.a41; out.a2 = a.a42; out.a3 = a.a43; out.a4 = a.a44; out.a5 = a.a45; break; case 4: out.a1 = a.a51; out.a2 = a.a52; out.a3 = a.a53; out.a4 = a.a54; out.a5 = a.a55; break; default: throw new IllegalArgumentException("Out of bounds row. row = "+row); } return out; } /** * Extracts the column from the matrix a. * @param a Input matrix * @param column Which column is to be extracted * @param out output. Storage for the extracted column. If null then a new vector will be returned. * @return The extracted column. */ public static FixedMatrix5_64F extractColumn( FixedMatrix5x5_64F a , int column , FixedMatrix5_64F out ) { if( out == null) out = new FixedMatrix5_64F(); switch( column ) { case 0: out.a1 = a.a11; out.a2 = a.a21; out.a3 = a.a31; out.a4 = a.a41; out.a5 = a.a51; break; case 1: out.a1 = a.a12; out.a2 = a.a22; out.a3 = a.a32; out.a4 = a.a42; out.a5 = a.a52; break; case 2: out.a1 = a.a13; out.a2 = a.a23; out.a3 = a.a33; out.a4 = a.a43; out.a5 = a.a53; break; case 3: out.a1 = a.a14; out.a2 = a.a24; out.a3 = a.a34; out.a4 = a.a44; out.a5 = a.a54; break; case 4: out.a1 = a.a15; out.a2 = a.a25; out.a3 = a.a35; out.a4 = a.a45; out.a5 = a.a55; break; default: throw new IllegalArgumentException("Out of bounds column. column = "+column); } return out; } } ejml-0.28/main/dense64/src/org/ejml/alg/fixed/FixedOps6.java000066400000000000000000002334371256171534400234330ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix6_64F; import org.ejml.data.FixedMatrix6x6_64F; /** *

Common matrix operations for fixed sized matrices which are 6 x 6 or 6 element vectors.

*

DO NOT MODIFY. Automatically generated code created by GenerateFixedOps

* * @author Peter Abeles */ public class FixedOps6 { /** *

Performs the following operation:
*
* c = a + b
* cij = aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c ) { c.a11 = a.a11 + b.a11; c.a12 = a.a12 + b.a12; c.a13 = a.a13 + b.a13; c.a14 = a.a14 + b.a14; c.a15 = a.a15 + b.a15; c.a16 = a.a16 + b.a16; c.a21 = a.a21 + b.a21; c.a22 = a.a22 + b.a22; c.a23 = a.a23 + b.a23; c.a24 = a.a24 + b.a24; c.a25 = a.a25 + b.a25; c.a26 = a.a26 + b.a26; c.a31 = a.a31 + b.a31; c.a32 = a.a32 + b.a32; c.a33 = a.a33 + b.a33; c.a34 = a.a34 + b.a34; c.a35 = a.a35 + b.a35; c.a36 = a.a36 + b.a36; c.a41 = a.a41 + b.a41; c.a42 = a.a42 + b.a42; c.a43 = a.a43 + b.a43; c.a44 = a.a44 + b.a44; c.a45 = a.a45 + b.a45; c.a46 = a.a46 + b.a46; c.a51 = a.a51 + b.a51; c.a52 = a.a52 + b.a52; c.a53 = a.a53 + b.a53; c.a54 = a.a54 + b.a54; c.a55 = a.a55 + b.a55; c.a56 = a.a56 + b.a56; c.a61 = a.a61 + b.a61; c.a62 = a.a62 + b.a62; c.a63 = a.a63 + b.a63; c.a64 = a.a64 + b.a64; c.a65 = a.a65 + b.a65; c.a66 = a.a66 + b.a66; } /** *

Performs the following operation:
*
* c = a + b
* ci = ai + bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void add( FixedMatrix6_64F a , FixedMatrix6_64F b , FixedMatrix6_64F c ) { c.a1 = a.a1 + b.a1; c.a2 = a.a2 + b.a2; c.a3 = a.a3 + b.a3; c.a4 = a.a4 + b.a4; c.a5 = a.a5 + b.a5; c.a6 = a.a6 + b.a6; } /** *

Performs the following operation:
*
* a = a + b
* aij = aij + bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b ) { a.a11 += b.a11; a.a12 += b.a12; a.a13 += b.a13; a.a14 += b.a14; a.a15 += b.a15; a.a16 += b.a16; a.a21 += b.a21; a.a22 += b.a22; a.a23 += b.a23; a.a24 += b.a24; a.a25 += b.a25; a.a26 += b.a26; a.a31 += b.a31; a.a32 += b.a32; a.a33 += b.a33; a.a34 += b.a34; a.a35 += b.a35; a.a36 += b.a36; a.a41 += b.a41; a.a42 += b.a42; a.a43 += b.a43; a.a44 += b.a44; a.a45 += b.a45; a.a46 += b.a46; a.a51 += b.a51; a.a52 += b.a52; a.a53 += b.a53; a.a54 += b.a54; a.a55 += b.a55; a.a56 += b.a56; a.a61 += b.a61; a.a62 += b.a62; a.a63 += b.a63; a.a64 += b.a64; a.a65 += b.a65; a.a66 += b.a66; } /** *

Performs the following operation:
*
* a = a + b
* ai = ai + bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void addEquals( FixedMatrix6_64F a , FixedMatrix6_64F b ) { a.a1 += b.a1; a.a2 += b.a2; a.a3 += b.a3; a.a4 += b.a4; a.a5 += b.a5; a.a6 += b.a6; } /** *

Performs the following operation:
*
* c = a - b
* cij = aij - bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void subtract( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c ) { c.a11 = a.a11 - b.a11; c.a12 = a.a12 - b.a12; c.a13 = a.a13 - b.a13; c.a14 = a.a14 - b.a14; c.a15 = a.a15 - b.a15; c.a16 = a.a16 - b.a16; c.a21 = a.a21 - b.a21; c.a22 = a.a22 - b.a22; c.a23 = a.a23 - b.a23; c.a24 = a.a24 - b.a24; c.a25 = a.a25 - b.a25; c.a26 = a.a26 - b.a26; c.a31 = a.a31 - b.a31; c.a32 = a.a32 - b.a32; c.a33 = a.a33 - b.a33; c.a34 = a.a34 - b.a34; c.a35 = a.a35 - b.a35; c.a36 = a.a36 - b.a36; c.a41 = a.a41 - b.a41; c.a42 = a.a42 - b.a42; c.a43 = a.a43 - b.a43; c.a44 = a.a44 - b.a44; c.a45 = a.a45 - b.a45; c.a46 = a.a46 - b.a46; c.a51 = a.a51 - b.a51; c.a52 = a.a52 - b.a52; c.a53 = a.a53 - b.a53; c.a54 = a.a54 - b.a54; c.a55 = a.a55 - b.a55; c.a56 = a.a56 - b.a56; c.a61 = a.a61 - b.a61; c.a62 = a.a62 - b.a62; c.a63 = a.a63 - b.a63; c.a64 = a.a64 - b.a64; c.a65 = a.a65 - b.a65; c.a66 = a.a66 - b.a66; } /** *

Performs the following operation:
*
* c = a - b
* ci = ai - bi
*

* *

* Vector C can be the same instance as Vector A and/or B. *

* * @param a A Vector. Not modified. * @param b A Vector. Not modified. * @param c A Vector where the results are stored. Modified. */ public static void subtract( FixedMatrix6_64F a , FixedMatrix6_64F b , FixedMatrix6_64F c ) { c.a1 = a.a1 - b.a1; c.a2 = a.a2 - b.a2; c.a3 = a.a3 - b.a3; c.a4 = a.a4 - b.a4; c.a5 = a.a5 - b.a5; c.a6 = a.a6 - b.a6; } /** *

Performs the following operation:
*
* a = a - b
* aij = aij - bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void subtractEquals( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b ) { a.a11 -= b.a11; a.a12 -= b.a12; a.a13 -= b.a13; a.a14 -= b.a14; a.a15 -= b.a15; a.a16 -= b.a16; a.a21 -= b.a21; a.a22 -= b.a22; a.a23 -= b.a23; a.a24 -= b.a24; a.a25 -= b.a25; a.a26 -= b.a26; a.a31 -= b.a31; a.a32 -= b.a32; a.a33 -= b.a33; a.a34 -= b.a34; a.a35 -= b.a35; a.a36 -= b.a36; a.a41 -= b.a41; a.a42 -= b.a42; a.a43 -= b.a43; a.a44 -= b.a44; a.a45 -= b.a45; a.a46 -= b.a46; a.a51 -= b.a51; a.a52 -= b.a52; a.a53 -= b.a53; a.a54 -= b.a54; a.a55 -= b.a55; a.a56 -= b.a56; a.a61 -= b.a61; a.a62 -= b.a62; a.a63 -= b.a63; a.a64 -= b.a64; a.a65 -= b.a65; a.a66 -= b.a66; } /** *

Performs the following operation:
*
* a = a - b
* ai = ai - bi
*

* * @param a A Vector. Modified. * @param b A Vector. Not modified. */ public static void subtractEquals( FixedMatrix6_64F a , FixedMatrix6_64F b ) { a.a1 -= b.a1; a.a2 -= b.a2; a.a3 -= b.a3; a.a4 -= b.a4; a.a5 -= b.a5; a.a6 -= b.a6; } /** * Performs an in-place transpose. This algorithm is only efficient for square * matrices. * * @param m The matrix that is to be transposed. Modified. */ public static void transpose( FixedMatrix6x6_64F m ) { double tmp; tmp = m.a12; m.a12 = m.a21; m.a21 = tmp; tmp = m.a13; m.a13 = m.a31; m.a31 = tmp; tmp = m.a14; m.a14 = m.a41; m.a41 = tmp; tmp = m.a15; m.a15 = m.a51; m.a51 = tmp; tmp = m.a16; m.a16 = m.a61; m.a61 = tmp; tmp = m.a23; m.a23 = m.a32; m.a32 = tmp; tmp = m.a24; m.a24 = m.a42; m.a42 = tmp; tmp = m.a25; m.a25 = m.a52; m.a52 = tmp; tmp = m.a26; m.a26 = m.a62; m.a62 = tmp; tmp = m.a34; m.a34 = m.a43; m.a43 = tmp; tmp = m.a35; m.a35 = m.a53; m.a53 = tmp; tmp = m.a36; m.a36 = m.a63; m.a63 = tmp; tmp = m.a45; m.a45 = m.a54; m.a54 = tmp; tmp = m.a46; m.a46 = m.a64; m.a64 = tmp; tmp = m.a56; m.a56 = m.a65; m.a65 = tmp; } /** *

* Transposes matrix 'a' and stores the results in 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'. *

* * @param input The original matrix. Not modified. * @param output Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static FixedMatrix6x6_64F transpose( FixedMatrix6x6_64F input , FixedMatrix6x6_64F output ) { if( input == null ) input = new FixedMatrix6x6_64F(); output.a11 = input.a11; output.a12 = input.a21; output.a13 = input.a31; output.a14 = input.a41; output.a15 = input.a51; output.a16 = input.a61; output.a21 = input.a12; output.a22 = input.a22; output.a23 = input.a32; output.a24 = input.a42; output.a25 = input.a52; output.a26 = input.a62; output.a31 = input.a13; output.a32 = input.a23; output.a33 = input.a33; output.a34 = input.a43; output.a35 = input.a53; output.a36 = input.a63; output.a41 = input.a14; output.a42 = input.a24; output.a43 = input.a34; output.a44 = input.a44; output.a45 = input.a54; output.a46 = input.a64; output.a51 = input.a15; output.a52 = input.a25; output.a53 = input.a35; output.a54 = input.a45; output.a55 = input.a55; output.a56 = input.a65; output.a61 = input.a16; output.a62 = input.a26; output.a63 = input.a36; output.a64 = input.a46; output.a65 = input.a56; output.a66 = input.a66; return output; } /** *

Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41 + a.a15*b.a51 + a.a16*b.a61; c.a12 = a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42 + a.a15*b.a52 + a.a16*b.a62; c.a13 = a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43 + a.a15*b.a53 + a.a16*b.a63; c.a14 = a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44 + a.a15*b.a54 + a.a16*b.a64; c.a15 = a.a11*b.a15 + a.a12*b.a25 + a.a13*b.a35 + a.a14*b.a45 + a.a15*b.a55 + a.a16*b.a65; c.a16 = a.a11*b.a16 + a.a12*b.a26 + a.a13*b.a36 + a.a14*b.a46 + a.a15*b.a56 + a.a16*b.a66; c.a21 = a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41 + a.a25*b.a51 + a.a26*b.a61; c.a22 = a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42 + a.a25*b.a52 + a.a26*b.a62; c.a23 = a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43 + a.a25*b.a53 + a.a26*b.a63; c.a24 = a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44 + a.a25*b.a54 + a.a26*b.a64; c.a25 = a.a21*b.a15 + a.a22*b.a25 + a.a23*b.a35 + a.a24*b.a45 + a.a25*b.a55 + a.a26*b.a65; c.a26 = a.a21*b.a16 + a.a22*b.a26 + a.a23*b.a36 + a.a24*b.a46 + a.a25*b.a56 + a.a26*b.a66; c.a31 = a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41 + a.a35*b.a51 + a.a36*b.a61; c.a32 = a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42 + a.a35*b.a52 + a.a36*b.a62; c.a33 = a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43 + a.a35*b.a53 + a.a36*b.a63; c.a34 = a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44 + a.a35*b.a54 + a.a36*b.a64; c.a35 = a.a31*b.a15 + a.a32*b.a25 + a.a33*b.a35 + a.a34*b.a45 + a.a35*b.a55 + a.a36*b.a65; c.a36 = a.a31*b.a16 + a.a32*b.a26 + a.a33*b.a36 + a.a34*b.a46 + a.a35*b.a56 + a.a36*b.a66; c.a41 = a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41 + a.a45*b.a51 + a.a46*b.a61; c.a42 = a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42 + a.a45*b.a52 + a.a46*b.a62; c.a43 = a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43 + a.a45*b.a53 + a.a46*b.a63; c.a44 = a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44 + a.a45*b.a54 + a.a46*b.a64; c.a45 = a.a41*b.a15 + a.a42*b.a25 + a.a43*b.a35 + a.a44*b.a45 + a.a45*b.a55 + a.a46*b.a65; c.a46 = a.a41*b.a16 + a.a42*b.a26 + a.a43*b.a36 + a.a44*b.a46 + a.a45*b.a56 + a.a46*b.a66; c.a51 = a.a51*b.a11 + a.a52*b.a21 + a.a53*b.a31 + a.a54*b.a41 + a.a55*b.a51 + a.a56*b.a61; c.a52 = a.a51*b.a12 + a.a52*b.a22 + a.a53*b.a32 + a.a54*b.a42 + a.a55*b.a52 + a.a56*b.a62; c.a53 = a.a51*b.a13 + a.a52*b.a23 + a.a53*b.a33 + a.a54*b.a43 + a.a55*b.a53 + a.a56*b.a63; c.a54 = a.a51*b.a14 + a.a52*b.a24 + a.a53*b.a34 + a.a54*b.a44 + a.a55*b.a54 + a.a56*b.a64; c.a55 = a.a51*b.a15 + a.a52*b.a25 + a.a53*b.a35 + a.a54*b.a45 + a.a55*b.a55 + a.a56*b.a65; c.a56 = a.a51*b.a16 + a.a52*b.a26 + a.a53*b.a36 + a.a54*b.a46 + a.a55*b.a56 + a.a56*b.a66; c.a61 = a.a61*b.a11 + a.a62*b.a21 + a.a63*b.a31 + a.a64*b.a41 + a.a65*b.a51 + a.a66*b.a61; c.a62 = a.a61*b.a12 + a.a62*b.a22 + a.a63*b.a32 + a.a64*b.a42 + a.a65*b.a52 + a.a66*b.a62; c.a63 = a.a61*b.a13 + a.a62*b.a23 + a.a63*b.a33 + a.a64*b.a43 + a.a65*b.a53 + a.a66*b.a63; c.a64 = a.a61*b.a14 + a.a62*b.a24 + a.a63*b.a34 + a.a64*b.a44 + a.a65*b.a54 + a.a66*b.a64; c.a65 = a.a61*b.a15 + a.a62*b.a25 + a.a63*b.a35 + a.a64*b.a45 + a.a65*b.a55 + a.a66*b.a65; c.a66 = a.a61*b.a16 + a.a62*b.a26 + a.a63*b.a36 + a.a64*b.a46 + a.a65*b.a56 + a.a66*b.a66; } /** *

Performs the following operation:
*
* c = aT * b
*
* cij = ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31 + a.a41*b.a41 + a.a51*b.a51 + a.a61*b.a61; c.a12 = a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32 + a.a41*b.a42 + a.a51*b.a52 + a.a61*b.a62; c.a13 = a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33 + a.a41*b.a43 + a.a51*b.a53 + a.a61*b.a63; c.a14 = a.a11*b.a14 + a.a21*b.a24 + a.a31*b.a34 + a.a41*b.a44 + a.a51*b.a54 + a.a61*b.a64; c.a15 = a.a11*b.a15 + a.a21*b.a25 + a.a31*b.a35 + a.a41*b.a45 + a.a51*b.a55 + a.a61*b.a65; c.a16 = a.a11*b.a16 + a.a21*b.a26 + a.a31*b.a36 + a.a41*b.a46 + a.a51*b.a56 + a.a61*b.a66; c.a21 = a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31 + a.a42*b.a41 + a.a52*b.a51 + a.a62*b.a61; c.a22 = a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32 + a.a42*b.a42 + a.a52*b.a52 + a.a62*b.a62; c.a23 = a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33 + a.a42*b.a43 + a.a52*b.a53 + a.a62*b.a63; c.a24 = a.a12*b.a14 + a.a22*b.a24 + a.a32*b.a34 + a.a42*b.a44 + a.a52*b.a54 + a.a62*b.a64; c.a25 = a.a12*b.a15 + a.a22*b.a25 + a.a32*b.a35 + a.a42*b.a45 + a.a52*b.a55 + a.a62*b.a65; c.a26 = a.a12*b.a16 + a.a22*b.a26 + a.a32*b.a36 + a.a42*b.a46 + a.a52*b.a56 + a.a62*b.a66; c.a31 = a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31 + a.a43*b.a41 + a.a53*b.a51 + a.a63*b.a61; c.a32 = a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32 + a.a43*b.a42 + a.a53*b.a52 + a.a63*b.a62; c.a33 = a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33 + a.a43*b.a43 + a.a53*b.a53 + a.a63*b.a63; c.a34 = a.a13*b.a14 + a.a23*b.a24 + a.a33*b.a34 + a.a43*b.a44 + a.a53*b.a54 + a.a63*b.a64; c.a35 = a.a13*b.a15 + a.a23*b.a25 + a.a33*b.a35 + a.a43*b.a45 + a.a53*b.a55 + a.a63*b.a65; c.a36 = a.a13*b.a16 + a.a23*b.a26 + a.a33*b.a36 + a.a43*b.a46 + a.a53*b.a56 + a.a63*b.a66; c.a41 = a.a14*b.a11 + a.a24*b.a21 + a.a34*b.a31 + a.a44*b.a41 + a.a54*b.a51 + a.a64*b.a61; c.a42 = a.a14*b.a12 + a.a24*b.a22 + a.a34*b.a32 + a.a44*b.a42 + a.a54*b.a52 + a.a64*b.a62; c.a43 = a.a14*b.a13 + a.a24*b.a23 + a.a34*b.a33 + a.a44*b.a43 + a.a54*b.a53 + a.a64*b.a63; c.a44 = a.a14*b.a14 + a.a24*b.a24 + a.a34*b.a34 + a.a44*b.a44 + a.a54*b.a54 + a.a64*b.a64; c.a45 = a.a14*b.a15 + a.a24*b.a25 + a.a34*b.a35 + a.a44*b.a45 + a.a54*b.a55 + a.a64*b.a65; c.a46 = a.a14*b.a16 + a.a24*b.a26 + a.a34*b.a36 + a.a44*b.a46 + a.a54*b.a56 + a.a64*b.a66; c.a51 = a.a15*b.a11 + a.a25*b.a21 + a.a35*b.a31 + a.a45*b.a41 + a.a55*b.a51 + a.a65*b.a61; c.a52 = a.a15*b.a12 + a.a25*b.a22 + a.a35*b.a32 + a.a45*b.a42 + a.a55*b.a52 + a.a65*b.a62; c.a53 = a.a15*b.a13 + a.a25*b.a23 + a.a35*b.a33 + a.a45*b.a43 + a.a55*b.a53 + a.a65*b.a63; c.a54 = a.a15*b.a14 + a.a25*b.a24 + a.a35*b.a34 + a.a45*b.a44 + a.a55*b.a54 + a.a65*b.a64; c.a55 = a.a15*b.a15 + a.a25*b.a25 + a.a35*b.a35 + a.a45*b.a45 + a.a55*b.a55 + a.a65*b.a65; c.a56 = a.a15*b.a16 + a.a25*b.a26 + a.a35*b.a36 + a.a45*b.a46 + a.a55*b.a56 + a.a65*b.a66; c.a61 = a.a16*b.a11 + a.a26*b.a21 + a.a36*b.a31 + a.a46*b.a41 + a.a56*b.a51 + a.a66*b.a61; c.a62 = a.a16*b.a12 + a.a26*b.a22 + a.a36*b.a32 + a.a46*b.a42 + a.a56*b.a52 + a.a66*b.a62; c.a63 = a.a16*b.a13 + a.a26*b.a23 + a.a36*b.a33 + a.a46*b.a43 + a.a56*b.a53 + a.a66*b.a63; c.a64 = a.a16*b.a14 + a.a26*b.a24 + a.a36*b.a34 + a.a46*b.a44 + a.a56*b.a54 + a.a66*b.a64; c.a65 = a.a16*b.a15 + a.a26*b.a25 + a.a36*b.a35 + a.a46*b.a45 + a.a56*b.a55 + a.a66*b.a65; c.a66 = a.a16*b.a16 + a.a26*b.a26 + a.a36*b.a36 + a.a46*b.a46 + a.a56*b.a56 + a.a66*b.a66; } /** *

* Performs the following operation:
*
* c = aT * bT
* cij = ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransAB( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 = a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13 + a.a41*b.a14 + a.a51*b.a15 + a.a61*b.a16; c.a12 = a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23 + a.a41*b.a24 + a.a51*b.a25 + a.a61*b.a26; c.a13 = a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33 + a.a41*b.a34 + a.a51*b.a35 + a.a61*b.a36; c.a14 = a.a11*b.a41 + a.a21*b.a42 + a.a31*b.a43 + a.a41*b.a44 + a.a51*b.a45 + a.a61*b.a46; c.a15 = a.a11*b.a51 + a.a21*b.a52 + a.a31*b.a53 + a.a41*b.a54 + a.a51*b.a55 + a.a61*b.a56; c.a16 = a.a11*b.a61 + a.a21*b.a62 + a.a31*b.a63 + a.a41*b.a64 + a.a51*b.a65 + a.a61*b.a66; c.a21 = a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13 + a.a42*b.a14 + a.a52*b.a15 + a.a62*b.a16; c.a22 = a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23 + a.a42*b.a24 + a.a52*b.a25 + a.a62*b.a26; c.a23 = a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33 + a.a42*b.a34 + a.a52*b.a35 + a.a62*b.a36; c.a24 = a.a12*b.a41 + a.a22*b.a42 + a.a32*b.a43 + a.a42*b.a44 + a.a52*b.a45 + a.a62*b.a46; c.a25 = a.a12*b.a51 + a.a22*b.a52 + a.a32*b.a53 + a.a42*b.a54 + a.a52*b.a55 + a.a62*b.a56; c.a26 = a.a12*b.a61 + a.a22*b.a62 + a.a32*b.a63 + a.a42*b.a64 + a.a52*b.a65 + a.a62*b.a66; c.a31 = a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13 + a.a43*b.a14 + a.a53*b.a15 + a.a63*b.a16; c.a32 = a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23 + a.a43*b.a24 + a.a53*b.a25 + a.a63*b.a26; c.a33 = a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33 + a.a43*b.a34 + a.a53*b.a35 + a.a63*b.a36; c.a34 = a.a13*b.a41 + a.a23*b.a42 + a.a33*b.a43 + a.a43*b.a44 + a.a53*b.a45 + a.a63*b.a46; c.a35 = a.a13*b.a51 + a.a23*b.a52 + a.a33*b.a53 + a.a43*b.a54 + a.a53*b.a55 + a.a63*b.a56; c.a36 = a.a13*b.a61 + a.a23*b.a62 + a.a33*b.a63 + a.a43*b.a64 + a.a53*b.a65 + a.a63*b.a66; c.a41 = a.a14*b.a11 + a.a24*b.a12 + a.a34*b.a13 + a.a44*b.a14 + a.a54*b.a15 + a.a64*b.a16; c.a42 = a.a14*b.a21 + a.a24*b.a22 + a.a34*b.a23 + a.a44*b.a24 + a.a54*b.a25 + a.a64*b.a26; c.a43 = a.a14*b.a31 + a.a24*b.a32 + a.a34*b.a33 + a.a44*b.a34 + a.a54*b.a35 + a.a64*b.a36; c.a44 = a.a14*b.a41 + a.a24*b.a42 + a.a34*b.a43 + a.a44*b.a44 + a.a54*b.a45 + a.a64*b.a46; c.a45 = a.a14*b.a51 + a.a24*b.a52 + a.a34*b.a53 + a.a44*b.a54 + a.a54*b.a55 + a.a64*b.a56; c.a46 = a.a14*b.a61 + a.a24*b.a62 + a.a34*b.a63 + a.a44*b.a64 + a.a54*b.a65 + a.a64*b.a66; c.a51 = a.a15*b.a11 + a.a25*b.a12 + a.a35*b.a13 + a.a45*b.a14 + a.a55*b.a15 + a.a65*b.a16; c.a52 = a.a15*b.a21 + a.a25*b.a22 + a.a35*b.a23 + a.a45*b.a24 + a.a55*b.a25 + a.a65*b.a26; c.a53 = a.a15*b.a31 + a.a25*b.a32 + a.a35*b.a33 + a.a45*b.a34 + a.a55*b.a35 + a.a65*b.a36; c.a54 = a.a15*b.a41 + a.a25*b.a42 + a.a35*b.a43 + a.a45*b.a44 + a.a55*b.a45 + a.a65*b.a46; c.a55 = a.a15*b.a51 + a.a25*b.a52 + a.a35*b.a53 + a.a45*b.a54 + a.a55*b.a55 + a.a65*b.a56; c.a56 = a.a15*b.a61 + a.a25*b.a62 + a.a35*b.a63 + a.a45*b.a64 + a.a55*b.a65 + a.a65*b.a66; c.a61 = a.a16*b.a11 + a.a26*b.a12 + a.a36*b.a13 + a.a46*b.a14 + a.a56*b.a15 + a.a66*b.a16; c.a62 = a.a16*b.a21 + a.a26*b.a22 + a.a36*b.a23 + a.a46*b.a24 + a.a56*b.a25 + a.a66*b.a26; c.a63 = a.a16*b.a31 + a.a26*b.a32 + a.a36*b.a33 + a.a46*b.a34 + a.a56*b.a35 + a.a66*b.a36; c.a64 = a.a16*b.a41 + a.a26*b.a42 + a.a36*b.a43 + a.a46*b.a44 + a.a56*b.a45 + a.a66*b.a46; c.a65 = a.a16*b.a51 + a.a26*b.a52 + a.a36*b.a53 + a.a46*b.a54 + a.a56*b.a55 + a.a66*b.a56; c.a66 = a.a16*b.a61 + a.a26*b.a62 + a.a36*b.a63 + a.a46*b.a64 + a.a56*b.a65 + a.a66*b.a66; } /** *

* Performs the following operation:
*
* c = a * bT
* cij = ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransB( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 = a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13 + a.a14*b.a14 + a.a15*b.a15 + a.a16*b.a16; c.a12 = a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23 + a.a14*b.a24 + a.a15*b.a25 + a.a16*b.a26; c.a13 = a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33 + a.a14*b.a34 + a.a15*b.a35 + a.a16*b.a36; c.a14 = a.a11*b.a41 + a.a12*b.a42 + a.a13*b.a43 + a.a14*b.a44 + a.a15*b.a45 + a.a16*b.a46; c.a15 = a.a11*b.a51 + a.a12*b.a52 + a.a13*b.a53 + a.a14*b.a54 + a.a15*b.a55 + a.a16*b.a56; c.a16 = a.a11*b.a61 + a.a12*b.a62 + a.a13*b.a63 + a.a14*b.a64 + a.a15*b.a65 + a.a16*b.a66; c.a21 = a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13 + a.a24*b.a14 + a.a25*b.a15 + a.a26*b.a16; c.a22 = a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23 + a.a24*b.a24 + a.a25*b.a25 + a.a26*b.a26; c.a23 = a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33 + a.a24*b.a34 + a.a25*b.a35 + a.a26*b.a36; c.a24 = a.a21*b.a41 + a.a22*b.a42 + a.a23*b.a43 + a.a24*b.a44 + a.a25*b.a45 + a.a26*b.a46; c.a25 = a.a21*b.a51 + a.a22*b.a52 + a.a23*b.a53 + a.a24*b.a54 + a.a25*b.a55 + a.a26*b.a56; c.a26 = a.a21*b.a61 + a.a22*b.a62 + a.a23*b.a63 + a.a24*b.a64 + a.a25*b.a65 + a.a26*b.a66; c.a31 = a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13 + a.a34*b.a14 + a.a35*b.a15 + a.a36*b.a16; c.a32 = a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23 + a.a34*b.a24 + a.a35*b.a25 + a.a36*b.a26; c.a33 = a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33 + a.a34*b.a34 + a.a35*b.a35 + a.a36*b.a36; c.a34 = a.a31*b.a41 + a.a32*b.a42 + a.a33*b.a43 + a.a34*b.a44 + a.a35*b.a45 + a.a36*b.a46; c.a35 = a.a31*b.a51 + a.a32*b.a52 + a.a33*b.a53 + a.a34*b.a54 + a.a35*b.a55 + a.a36*b.a56; c.a36 = a.a31*b.a61 + a.a32*b.a62 + a.a33*b.a63 + a.a34*b.a64 + a.a35*b.a65 + a.a36*b.a66; c.a41 = a.a41*b.a11 + a.a42*b.a12 + a.a43*b.a13 + a.a44*b.a14 + a.a45*b.a15 + a.a46*b.a16; c.a42 = a.a41*b.a21 + a.a42*b.a22 + a.a43*b.a23 + a.a44*b.a24 + a.a45*b.a25 + a.a46*b.a26; c.a43 = a.a41*b.a31 + a.a42*b.a32 + a.a43*b.a33 + a.a44*b.a34 + a.a45*b.a35 + a.a46*b.a36; c.a44 = a.a41*b.a41 + a.a42*b.a42 + a.a43*b.a43 + a.a44*b.a44 + a.a45*b.a45 + a.a46*b.a46; c.a45 = a.a41*b.a51 + a.a42*b.a52 + a.a43*b.a53 + a.a44*b.a54 + a.a45*b.a55 + a.a46*b.a56; c.a46 = a.a41*b.a61 + a.a42*b.a62 + a.a43*b.a63 + a.a44*b.a64 + a.a45*b.a65 + a.a46*b.a66; c.a51 = a.a51*b.a11 + a.a52*b.a12 + a.a53*b.a13 + a.a54*b.a14 + a.a55*b.a15 + a.a56*b.a16; c.a52 = a.a51*b.a21 + a.a52*b.a22 + a.a53*b.a23 + a.a54*b.a24 + a.a55*b.a25 + a.a56*b.a26; c.a53 = a.a51*b.a31 + a.a52*b.a32 + a.a53*b.a33 + a.a54*b.a34 + a.a55*b.a35 + a.a56*b.a36; c.a54 = a.a51*b.a41 + a.a52*b.a42 + a.a53*b.a43 + a.a54*b.a44 + a.a55*b.a45 + a.a56*b.a46; c.a55 = a.a51*b.a51 + a.a52*b.a52 + a.a53*b.a53 + a.a54*b.a54 + a.a55*b.a55 + a.a56*b.a56; c.a56 = a.a51*b.a61 + a.a52*b.a62 + a.a53*b.a63 + a.a54*b.a64 + a.a55*b.a65 + a.a56*b.a66; c.a61 = a.a61*b.a11 + a.a62*b.a12 + a.a63*b.a13 + a.a64*b.a14 + a.a65*b.a15 + a.a66*b.a16; c.a62 = a.a61*b.a21 + a.a62*b.a22 + a.a63*b.a23 + a.a64*b.a24 + a.a65*b.a25 + a.a66*b.a26; c.a63 = a.a61*b.a31 + a.a62*b.a32 + a.a63*b.a33 + a.a64*b.a34 + a.a65*b.a35 + a.a66*b.a36; c.a64 = a.a61*b.a41 + a.a62*b.a42 + a.a63*b.a43 + a.a64*b.a44 + a.a65*b.a45 + a.a66*b.a46; c.a65 = a.a61*b.a51 + a.a62*b.a52 + a.a63*b.a53 + a.a64*b.a54 + a.a65*b.a55 + a.a66*b.a56; c.a66 = a.a61*b.a61 + a.a62*b.a62 + a.a63*b.a63 + a.a64*b.a64 + a.a65*b.a65 + a.a66*b.a66; } /** *

Performs the following operation:
*
* c += a * b
*
* cij += ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41 + a.a15*b.a51 + a.a16*b.a61; c.a12 += a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42 + a.a15*b.a52 + a.a16*b.a62; c.a13 += a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43 + a.a15*b.a53 + a.a16*b.a63; c.a14 += a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44 + a.a15*b.a54 + a.a16*b.a64; c.a15 += a.a11*b.a15 + a.a12*b.a25 + a.a13*b.a35 + a.a14*b.a45 + a.a15*b.a55 + a.a16*b.a65; c.a16 += a.a11*b.a16 + a.a12*b.a26 + a.a13*b.a36 + a.a14*b.a46 + a.a15*b.a56 + a.a16*b.a66; c.a21 += a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41 + a.a25*b.a51 + a.a26*b.a61; c.a22 += a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42 + a.a25*b.a52 + a.a26*b.a62; c.a23 += a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43 + a.a25*b.a53 + a.a26*b.a63; c.a24 += a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44 + a.a25*b.a54 + a.a26*b.a64; c.a25 += a.a21*b.a15 + a.a22*b.a25 + a.a23*b.a35 + a.a24*b.a45 + a.a25*b.a55 + a.a26*b.a65; c.a26 += a.a21*b.a16 + a.a22*b.a26 + a.a23*b.a36 + a.a24*b.a46 + a.a25*b.a56 + a.a26*b.a66; c.a31 += a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41 + a.a35*b.a51 + a.a36*b.a61; c.a32 += a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42 + a.a35*b.a52 + a.a36*b.a62; c.a33 += a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43 + a.a35*b.a53 + a.a36*b.a63; c.a34 += a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44 + a.a35*b.a54 + a.a36*b.a64; c.a35 += a.a31*b.a15 + a.a32*b.a25 + a.a33*b.a35 + a.a34*b.a45 + a.a35*b.a55 + a.a36*b.a65; c.a36 += a.a31*b.a16 + a.a32*b.a26 + a.a33*b.a36 + a.a34*b.a46 + a.a35*b.a56 + a.a36*b.a66; c.a41 += a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41 + a.a45*b.a51 + a.a46*b.a61; c.a42 += a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42 + a.a45*b.a52 + a.a46*b.a62; c.a43 += a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43 + a.a45*b.a53 + a.a46*b.a63; c.a44 += a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44 + a.a45*b.a54 + a.a46*b.a64; c.a45 += a.a41*b.a15 + a.a42*b.a25 + a.a43*b.a35 + a.a44*b.a45 + a.a45*b.a55 + a.a46*b.a65; c.a46 += a.a41*b.a16 + a.a42*b.a26 + a.a43*b.a36 + a.a44*b.a46 + a.a45*b.a56 + a.a46*b.a66; c.a51 += a.a51*b.a11 + a.a52*b.a21 + a.a53*b.a31 + a.a54*b.a41 + a.a55*b.a51 + a.a56*b.a61; c.a52 += a.a51*b.a12 + a.a52*b.a22 + a.a53*b.a32 + a.a54*b.a42 + a.a55*b.a52 + a.a56*b.a62; c.a53 += a.a51*b.a13 + a.a52*b.a23 + a.a53*b.a33 + a.a54*b.a43 + a.a55*b.a53 + a.a56*b.a63; c.a54 += a.a51*b.a14 + a.a52*b.a24 + a.a53*b.a34 + a.a54*b.a44 + a.a55*b.a54 + a.a56*b.a64; c.a55 += a.a51*b.a15 + a.a52*b.a25 + a.a53*b.a35 + a.a54*b.a45 + a.a55*b.a55 + a.a56*b.a65; c.a56 += a.a51*b.a16 + a.a52*b.a26 + a.a53*b.a36 + a.a54*b.a46 + a.a55*b.a56 + a.a56*b.a66; c.a61 += a.a61*b.a11 + a.a62*b.a21 + a.a63*b.a31 + a.a64*b.a41 + a.a65*b.a51 + a.a66*b.a61; c.a62 += a.a61*b.a12 + a.a62*b.a22 + a.a63*b.a32 + a.a64*b.a42 + a.a65*b.a52 + a.a66*b.a62; c.a63 += a.a61*b.a13 + a.a62*b.a23 + a.a63*b.a33 + a.a64*b.a43 + a.a65*b.a53 + a.a66*b.a63; c.a64 += a.a61*b.a14 + a.a62*b.a24 + a.a63*b.a34 + a.a64*b.a44 + a.a65*b.a54 + a.a66*b.a64; c.a65 += a.a61*b.a15 + a.a62*b.a25 + a.a63*b.a35 + a.a64*b.a45 + a.a65*b.a55 + a.a66*b.a65; c.a66 += a.a61*b.a16 + a.a62*b.a26 + a.a63*b.a36 + a.a64*b.a46 + a.a65*b.a56 + a.a66*b.a66; } /** *

Performs the following operation:
*
* c += aT * b
*
* cij += ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a21 + a.a31*b.a31 + a.a41*b.a41 + a.a51*b.a51 + a.a61*b.a61; c.a12 += a.a11*b.a12 + a.a21*b.a22 + a.a31*b.a32 + a.a41*b.a42 + a.a51*b.a52 + a.a61*b.a62; c.a13 += a.a11*b.a13 + a.a21*b.a23 + a.a31*b.a33 + a.a41*b.a43 + a.a51*b.a53 + a.a61*b.a63; c.a14 += a.a11*b.a14 + a.a21*b.a24 + a.a31*b.a34 + a.a41*b.a44 + a.a51*b.a54 + a.a61*b.a64; c.a15 += a.a11*b.a15 + a.a21*b.a25 + a.a31*b.a35 + a.a41*b.a45 + a.a51*b.a55 + a.a61*b.a65; c.a16 += a.a11*b.a16 + a.a21*b.a26 + a.a31*b.a36 + a.a41*b.a46 + a.a51*b.a56 + a.a61*b.a66; c.a21 += a.a12*b.a11 + a.a22*b.a21 + a.a32*b.a31 + a.a42*b.a41 + a.a52*b.a51 + a.a62*b.a61; c.a22 += a.a12*b.a12 + a.a22*b.a22 + a.a32*b.a32 + a.a42*b.a42 + a.a52*b.a52 + a.a62*b.a62; c.a23 += a.a12*b.a13 + a.a22*b.a23 + a.a32*b.a33 + a.a42*b.a43 + a.a52*b.a53 + a.a62*b.a63; c.a24 += a.a12*b.a14 + a.a22*b.a24 + a.a32*b.a34 + a.a42*b.a44 + a.a52*b.a54 + a.a62*b.a64; c.a25 += a.a12*b.a15 + a.a22*b.a25 + a.a32*b.a35 + a.a42*b.a45 + a.a52*b.a55 + a.a62*b.a65; c.a26 += a.a12*b.a16 + a.a22*b.a26 + a.a32*b.a36 + a.a42*b.a46 + a.a52*b.a56 + a.a62*b.a66; c.a31 += a.a13*b.a11 + a.a23*b.a21 + a.a33*b.a31 + a.a43*b.a41 + a.a53*b.a51 + a.a63*b.a61; c.a32 += a.a13*b.a12 + a.a23*b.a22 + a.a33*b.a32 + a.a43*b.a42 + a.a53*b.a52 + a.a63*b.a62; c.a33 += a.a13*b.a13 + a.a23*b.a23 + a.a33*b.a33 + a.a43*b.a43 + a.a53*b.a53 + a.a63*b.a63; c.a34 += a.a13*b.a14 + a.a23*b.a24 + a.a33*b.a34 + a.a43*b.a44 + a.a53*b.a54 + a.a63*b.a64; c.a35 += a.a13*b.a15 + a.a23*b.a25 + a.a33*b.a35 + a.a43*b.a45 + a.a53*b.a55 + a.a63*b.a65; c.a36 += a.a13*b.a16 + a.a23*b.a26 + a.a33*b.a36 + a.a43*b.a46 + a.a53*b.a56 + a.a63*b.a66; c.a41 += a.a14*b.a11 + a.a24*b.a21 + a.a34*b.a31 + a.a44*b.a41 + a.a54*b.a51 + a.a64*b.a61; c.a42 += a.a14*b.a12 + a.a24*b.a22 + a.a34*b.a32 + a.a44*b.a42 + a.a54*b.a52 + a.a64*b.a62; c.a43 += a.a14*b.a13 + a.a24*b.a23 + a.a34*b.a33 + a.a44*b.a43 + a.a54*b.a53 + a.a64*b.a63; c.a44 += a.a14*b.a14 + a.a24*b.a24 + a.a34*b.a34 + a.a44*b.a44 + a.a54*b.a54 + a.a64*b.a64; c.a45 += a.a14*b.a15 + a.a24*b.a25 + a.a34*b.a35 + a.a44*b.a45 + a.a54*b.a55 + a.a64*b.a65; c.a46 += a.a14*b.a16 + a.a24*b.a26 + a.a34*b.a36 + a.a44*b.a46 + a.a54*b.a56 + a.a64*b.a66; c.a51 += a.a15*b.a11 + a.a25*b.a21 + a.a35*b.a31 + a.a45*b.a41 + a.a55*b.a51 + a.a65*b.a61; c.a52 += a.a15*b.a12 + a.a25*b.a22 + a.a35*b.a32 + a.a45*b.a42 + a.a55*b.a52 + a.a65*b.a62; c.a53 += a.a15*b.a13 + a.a25*b.a23 + a.a35*b.a33 + a.a45*b.a43 + a.a55*b.a53 + a.a65*b.a63; c.a54 += a.a15*b.a14 + a.a25*b.a24 + a.a35*b.a34 + a.a45*b.a44 + a.a55*b.a54 + a.a65*b.a64; c.a55 += a.a15*b.a15 + a.a25*b.a25 + a.a35*b.a35 + a.a45*b.a45 + a.a55*b.a55 + a.a65*b.a65; c.a56 += a.a15*b.a16 + a.a25*b.a26 + a.a35*b.a36 + a.a45*b.a46 + a.a55*b.a56 + a.a65*b.a66; c.a61 += a.a16*b.a11 + a.a26*b.a21 + a.a36*b.a31 + a.a46*b.a41 + a.a56*b.a51 + a.a66*b.a61; c.a62 += a.a16*b.a12 + a.a26*b.a22 + a.a36*b.a32 + a.a46*b.a42 + a.a56*b.a52 + a.a66*b.a62; c.a63 += a.a16*b.a13 + a.a26*b.a23 + a.a36*b.a33 + a.a46*b.a43 + a.a56*b.a53 + a.a66*b.a63; c.a64 += a.a16*b.a14 + a.a26*b.a24 + a.a36*b.a34 + a.a46*b.a44 + a.a56*b.a54 + a.a66*b.a64; c.a65 += a.a16*b.a15 + a.a26*b.a25 + a.a36*b.a35 + a.a46*b.a45 + a.a56*b.a55 + a.a66*b.a65; c.a66 += a.a16*b.a16 + a.a26*b.a26 + a.a36*b.a36 + a.a46*b.a46 + a.a56*b.a56 + a.a66*b.a66; } /** *

* Performs the following operation:
*
* c += aT * bT
* cij += ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 += a.a11*b.a11 + a.a21*b.a12 + a.a31*b.a13 + a.a41*b.a14 + a.a51*b.a15 + a.a61*b.a16; c.a12 += a.a11*b.a21 + a.a21*b.a22 + a.a31*b.a23 + a.a41*b.a24 + a.a51*b.a25 + a.a61*b.a26; c.a13 += a.a11*b.a31 + a.a21*b.a32 + a.a31*b.a33 + a.a41*b.a34 + a.a51*b.a35 + a.a61*b.a36; c.a14 += a.a11*b.a41 + a.a21*b.a42 + a.a31*b.a43 + a.a41*b.a44 + a.a51*b.a45 + a.a61*b.a46; c.a15 += a.a11*b.a51 + a.a21*b.a52 + a.a31*b.a53 + a.a41*b.a54 + a.a51*b.a55 + a.a61*b.a56; c.a16 += a.a11*b.a61 + a.a21*b.a62 + a.a31*b.a63 + a.a41*b.a64 + a.a51*b.a65 + a.a61*b.a66; c.a21 += a.a12*b.a11 + a.a22*b.a12 + a.a32*b.a13 + a.a42*b.a14 + a.a52*b.a15 + a.a62*b.a16; c.a22 += a.a12*b.a21 + a.a22*b.a22 + a.a32*b.a23 + a.a42*b.a24 + a.a52*b.a25 + a.a62*b.a26; c.a23 += a.a12*b.a31 + a.a22*b.a32 + a.a32*b.a33 + a.a42*b.a34 + a.a52*b.a35 + a.a62*b.a36; c.a24 += a.a12*b.a41 + a.a22*b.a42 + a.a32*b.a43 + a.a42*b.a44 + a.a52*b.a45 + a.a62*b.a46; c.a25 += a.a12*b.a51 + a.a22*b.a52 + a.a32*b.a53 + a.a42*b.a54 + a.a52*b.a55 + a.a62*b.a56; c.a26 += a.a12*b.a61 + a.a22*b.a62 + a.a32*b.a63 + a.a42*b.a64 + a.a52*b.a65 + a.a62*b.a66; c.a31 += a.a13*b.a11 + a.a23*b.a12 + a.a33*b.a13 + a.a43*b.a14 + a.a53*b.a15 + a.a63*b.a16; c.a32 += a.a13*b.a21 + a.a23*b.a22 + a.a33*b.a23 + a.a43*b.a24 + a.a53*b.a25 + a.a63*b.a26; c.a33 += a.a13*b.a31 + a.a23*b.a32 + a.a33*b.a33 + a.a43*b.a34 + a.a53*b.a35 + a.a63*b.a36; c.a34 += a.a13*b.a41 + a.a23*b.a42 + a.a33*b.a43 + a.a43*b.a44 + a.a53*b.a45 + a.a63*b.a46; c.a35 += a.a13*b.a51 + a.a23*b.a52 + a.a33*b.a53 + a.a43*b.a54 + a.a53*b.a55 + a.a63*b.a56; c.a36 += a.a13*b.a61 + a.a23*b.a62 + a.a33*b.a63 + a.a43*b.a64 + a.a53*b.a65 + a.a63*b.a66; c.a41 += a.a14*b.a11 + a.a24*b.a12 + a.a34*b.a13 + a.a44*b.a14 + a.a54*b.a15 + a.a64*b.a16; c.a42 += a.a14*b.a21 + a.a24*b.a22 + a.a34*b.a23 + a.a44*b.a24 + a.a54*b.a25 + a.a64*b.a26; c.a43 += a.a14*b.a31 + a.a24*b.a32 + a.a34*b.a33 + a.a44*b.a34 + a.a54*b.a35 + a.a64*b.a36; c.a44 += a.a14*b.a41 + a.a24*b.a42 + a.a34*b.a43 + a.a44*b.a44 + a.a54*b.a45 + a.a64*b.a46; c.a45 += a.a14*b.a51 + a.a24*b.a52 + a.a34*b.a53 + a.a44*b.a54 + a.a54*b.a55 + a.a64*b.a56; c.a46 += a.a14*b.a61 + a.a24*b.a62 + a.a34*b.a63 + a.a44*b.a64 + a.a54*b.a65 + a.a64*b.a66; c.a51 += a.a15*b.a11 + a.a25*b.a12 + a.a35*b.a13 + a.a45*b.a14 + a.a55*b.a15 + a.a65*b.a16; c.a52 += a.a15*b.a21 + a.a25*b.a22 + a.a35*b.a23 + a.a45*b.a24 + a.a55*b.a25 + a.a65*b.a26; c.a53 += a.a15*b.a31 + a.a25*b.a32 + a.a35*b.a33 + a.a45*b.a34 + a.a55*b.a35 + a.a65*b.a36; c.a54 += a.a15*b.a41 + a.a25*b.a42 + a.a35*b.a43 + a.a45*b.a44 + a.a55*b.a45 + a.a65*b.a46; c.a55 += a.a15*b.a51 + a.a25*b.a52 + a.a35*b.a53 + a.a45*b.a54 + a.a55*b.a55 + a.a65*b.a56; c.a56 += a.a15*b.a61 + a.a25*b.a62 + a.a35*b.a63 + a.a45*b.a64 + a.a55*b.a65 + a.a65*b.a66; c.a61 += a.a16*b.a11 + a.a26*b.a12 + a.a36*b.a13 + a.a46*b.a14 + a.a56*b.a15 + a.a66*b.a16; c.a62 += a.a16*b.a21 + a.a26*b.a22 + a.a36*b.a23 + a.a46*b.a24 + a.a56*b.a25 + a.a66*b.a26; c.a63 += a.a16*b.a31 + a.a26*b.a32 + a.a36*b.a33 + a.a46*b.a34 + a.a56*b.a35 + a.a66*b.a36; c.a64 += a.a16*b.a41 + a.a26*b.a42 + a.a36*b.a43 + a.a46*b.a44 + a.a56*b.a45 + a.a66*b.a46; c.a65 += a.a16*b.a51 + a.a26*b.a52 + a.a36*b.a53 + a.a46*b.a54 + a.a56*b.a55 + a.a66*b.a56; c.a66 += a.a16*b.a61 + a.a26*b.a62 + a.a36*b.a63 + a.a46*b.a64 + a.a56*b.a65 + a.a66*b.a66; } /** *

* Performs the following operation:
*
* c += a * bT
* cij += ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransB( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c) { c.a11 += a.a11*b.a11 + a.a12*b.a12 + a.a13*b.a13 + a.a14*b.a14 + a.a15*b.a15 + a.a16*b.a16; c.a12 += a.a11*b.a21 + a.a12*b.a22 + a.a13*b.a23 + a.a14*b.a24 + a.a15*b.a25 + a.a16*b.a26; c.a13 += a.a11*b.a31 + a.a12*b.a32 + a.a13*b.a33 + a.a14*b.a34 + a.a15*b.a35 + a.a16*b.a36; c.a14 += a.a11*b.a41 + a.a12*b.a42 + a.a13*b.a43 + a.a14*b.a44 + a.a15*b.a45 + a.a16*b.a46; c.a15 += a.a11*b.a51 + a.a12*b.a52 + a.a13*b.a53 + a.a14*b.a54 + a.a15*b.a55 + a.a16*b.a56; c.a16 += a.a11*b.a61 + a.a12*b.a62 + a.a13*b.a63 + a.a14*b.a64 + a.a15*b.a65 + a.a16*b.a66; c.a21 += a.a21*b.a11 + a.a22*b.a12 + a.a23*b.a13 + a.a24*b.a14 + a.a25*b.a15 + a.a26*b.a16; c.a22 += a.a21*b.a21 + a.a22*b.a22 + a.a23*b.a23 + a.a24*b.a24 + a.a25*b.a25 + a.a26*b.a26; c.a23 += a.a21*b.a31 + a.a22*b.a32 + a.a23*b.a33 + a.a24*b.a34 + a.a25*b.a35 + a.a26*b.a36; c.a24 += a.a21*b.a41 + a.a22*b.a42 + a.a23*b.a43 + a.a24*b.a44 + a.a25*b.a45 + a.a26*b.a46; c.a25 += a.a21*b.a51 + a.a22*b.a52 + a.a23*b.a53 + a.a24*b.a54 + a.a25*b.a55 + a.a26*b.a56; c.a26 += a.a21*b.a61 + a.a22*b.a62 + a.a23*b.a63 + a.a24*b.a64 + a.a25*b.a65 + a.a26*b.a66; c.a31 += a.a31*b.a11 + a.a32*b.a12 + a.a33*b.a13 + a.a34*b.a14 + a.a35*b.a15 + a.a36*b.a16; c.a32 += a.a31*b.a21 + a.a32*b.a22 + a.a33*b.a23 + a.a34*b.a24 + a.a35*b.a25 + a.a36*b.a26; c.a33 += a.a31*b.a31 + a.a32*b.a32 + a.a33*b.a33 + a.a34*b.a34 + a.a35*b.a35 + a.a36*b.a36; c.a34 += a.a31*b.a41 + a.a32*b.a42 + a.a33*b.a43 + a.a34*b.a44 + a.a35*b.a45 + a.a36*b.a46; c.a35 += a.a31*b.a51 + a.a32*b.a52 + a.a33*b.a53 + a.a34*b.a54 + a.a35*b.a55 + a.a36*b.a56; c.a36 += a.a31*b.a61 + a.a32*b.a62 + a.a33*b.a63 + a.a34*b.a64 + a.a35*b.a65 + a.a36*b.a66; c.a41 += a.a41*b.a11 + a.a42*b.a12 + a.a43*b.a13 + a.a44*b.a14 + a.a45*b.a15 + a.a46*b.a16; c.a42 += a.a41*b.a21 + a.a42*b.a22 + a.a43*b.a23 + a.a44*b.a24 + a.a45*b.a25 + a.a46*b.a26; c.a43 += a.a41*b.a31 + a.a42*b.a32 + a.a43*b.a33 + a.a44*b.a34 + a.a45*b.a35 + a.a46*b.a36; c.a44 += a.a41*b.a41 + a.a42*b.a42 + a.a43*b.a43 + a.a44*b.a44 + a.a45*b.a45 + a.a46*b.a46; c.a45 += a.a41*b.a51 + a.a42*b.a52 + a.a43*b.a53 + a.a44*b.a54 + a.a45*b.a55 + a.a46*b.a56; c.a46 += a.a41*b.a61 + a.a42*b.a62 + a.a43*b.a63 + a.a44*b.a64 + a.a45*b.a65 + a.a46*b.a66; c.a51 += a.a51*b.a11 + a.a52*b.a12 + a.a53*b.a13 + a.a54*b.a14 + a.a55*b.a15 + a.a56*b.a16; c.a52 += a.a51*b.a21 + a.a52*b.a22 + a.a53*b.a23 + a.a54*b.a24 + a.a55*b.a25 + a.a56*b.a26; c.a53 += a.a51*b.a31 + a.a52*b.a32 + a.a53*b.a33 + a.a54*b.a34 + a.a55*b.a35 + a.a56*b.a36; c.a54 += a.a51*b.a41 + a.a52*b.a42 + a.a53*b.a43 + a.a54*b.a44 + a.a55*b.a45 + a.a56*b.a46; c.a55 += a.a51*b.a51 + a.a52*b.a52 + a.a53*b.a53 + a.a54*b.a54 + a.a55*b.a55 + a.a56*b.a56; c.a56 += a.a51*b.a61 + a.a52*b.a62 + a.a53*b.a63 + a.a54*b.a64 + a.a55*b.a65 + a.a56*b.a66; c.a61 += a.a61*b.a11 + a.a62*b.a12 + a.a63*b.a13 + a.a64*b.a14 + a.a65*b.a15 + a.a66*b.a16; c.a62 += a.a61*b.a21 + a.a62*b.a22 + a.a63*b.a23 + a.a64*b.a24 + a.a65*b.a25 + a.a66*b.a26; c.a63 += a.a61*b.a31 + a.a62*b.a32 + a.a63*b.a33 + a.a64*b.a34 + a.a65*b.a35 + a.a66*b.a36; c.a64 += a.a61*b.a41 + a.a62*b.a42 + a.a63*b.a43 + a.a64*b.a44 + a.a65*b.a45 + a.a66*b.a46; c.a65 += a.a61*b.a51 + a.a62*b.a52 + a.a63*b.a53 + a.a64*b.a54 + a.a65*b.a55 + a.a66*b.a56; c.a66 += a.a61*b.a61 + a.a62*b.a62 + a.a63*b.a63 + a.a64*b.a64 + a.a65*b.a65 + a.a66*b.a66; } /** *

Performs matrix to vector multiplication:
*
* c = a * b
*
* ci = ∑k=1:n { aik * bk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix6x6_64F a , FixedMatrix6_64F b , FixedMatrix6_64F c) { c.a1 = a.a11*b.a1 + a.a12*b.a2 + a.a13*b.a3 + a.a14*b.a4 + a.a15*b.a5 + a.a16*b.a6; c.a2 = a.a21*b.a1 + a.a22*b.a2 + a.a23*b.a3 + a.a24*b.a4 + a.a25*b.a5 + a.a26*b.a6; c.a3 = a.a31*b.a1 + a.a32*b.a2 + a.a33*b.a3 + a.a34*b.a4 + a.a35*b.a5 + a.a36*b.a6; c.a4 = a.a41*b.a1 + a.a42*b.a2 + a.a43*b.a3 + a.a44*b.a4 + a.a45*b.a5 + a.a46*b.a6; c.a5 = a.a51*b.a1 + a.a52*b.a2 + a.a53*b.a3 + a.a54*b.a4 + a.a55*b.a5 + a.a56*b.a6; c.a6 = a.a61*b.a1 + a.a62*b.a2 + a.a63*b.a3 + a.a64*b.a4 + a.a65*b.a5 + a.a66*b.a6; } /** *

Performs vector to matrix multiplication:
*
* c = a * b
*
* cj = ∑k=1:n { bk * akj } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( FixedMatrix6_64F a , FixedMatrix6x6_64F b , FixedMatrix6_64F c) { c.a1 = a.a1*b.a11 + a.a2*b.a21 + a.a3*b.a31 + a.a4*b.a41 + a.a5*b.a51 + a.a6*b.a61; c.a2 = a.a1*b.a12 + a.a2*b.a22 + a.a3*b.a32 + a.a4*b.a42 + a.a5*b.a52 + a.a6*b.a62; c.a3 = a.a1*b.a13 + a.a2*b.a23 + a.a3*b.a33 + a.a4*b.a43 + a.a5*b.a53 + a.a6*b.a63; c.a4 = a.a1*b.a14 + a.a2*b.a24 + a.a3*b.a34 + a.a4*b.a44 + a.a5*b.a54 + a.a6*b.a64; c.a5 = a.a1*b.a15 + a.a2*b.a25 + a.a3*b.a35 + a.a4*b.a45 + a.a5*b.a55 + a.a6*b.a65; c.a6 = a.a1*b.a16 + a.a2*b.a26 + a.a3*b.a36 + a.a4*b.a46 + a.a5*b.a56 + a.a6*b.a66; } /** *

Performs the vector dot product:
*
* c = a * b
*
* c> = ∑k=1:n { bk * ak } *

* * @param a The left vector in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @return The dot product */ public static double dot( FixedMatrix6_64F a , FixedMatrix6_64F b ) { return a.a1*b.a1 + a.a2*b.a2 + a.a3*b.a3 + a.a4*b.a4 + a.a5*b.a5 + a.a6*b.a6; } /** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @param a A matrix. */ public static void setIdentity( FixedMatrix6x6_64F a ) { a.a11 = 1; a.a21 = 0; a.a31 = 0; a.a41 = 0; a.a51 = 0; a.a61 = 0; a.a12 = 0; a.a22 = 1; a.a32 = 0; a.a42 = 0; a.a52 = 0; a.a62 = 0; a.a13 = 0; a.a23 = 0; a.a33 = 1; a.a43 = 0; a.a53 = 0; a.a63 = 0; a.a14 = 0; a.a24 = 0; a.a34 = 0; a.a44 = 1; a.a54 = 0; a.a64 = 0; a.a15 = 0; a.a25 = 0; a.a35 = 0; a.a45 = 0; a.a55 = 1; a.a65 = 0; a.a16 = 0; a.a26 = 0; a.a36 = 0; a.a46 = 0; a.a56 = 0; a.a66 = 1; } /** *

* This computes the trace of the matrix:
*
* trace = ∑i=1:n { aii } *

*

* The trace is only defined for square matrices. *

* * @param a A square matrix. Not modified. */ public static double trace( FixedMatrix6x6_64F a ) { return a.a11 + a.a21 + a.a31 + a.a41 + a.a51 + a.a61; } /** *

* Extracts all diagonal elements from 'input' and places them inside the 'out' vector. Elements * are in sequential order. *

* * * @param input Matrix. Not modified. * @param out Vector containing diagonal elements. Modified. */ public static void diag( FixedMatrix6x6_64F input , FixedMatrix6_64F out ) { out.a1 = input.a11; out.a2 = input.a22; out.a3 = input.a33; out.a4 = input.a44; out.a5 = input.a55; out.a6 = input.a66; } /** *

* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix6x6_64F a ) { double max = a.a11; max = Math.max(max,a.a12); max = Math.max(max,a.a13); max = Math.max(max,a.a14); max = Math.max(max,a.a15); max = Math.max(max,a.a16); max = Math.max(max,a.a21); max = Math.max(max,a.a22); max = Math.max(max,a.a23); max = Math.max(max,a.a24); max = Math.max(max,a.a25); max = Math.max(max,a.a26); max = Math.max(max,a.a31); max = Math.max(max,a.a32); max = Math.max(max,a.a33); max = Math.max(max,a.a34); max = Math.max(max,a.a35); max = Math.max(max,a.a36); max = Math.max(max,a.a41); max = Math.max(max,a.a42); max = Math.max(max,a.a43); max = Math.max(max,a.a44); max = Math.max(max,a.a45); max = Math.max(max,a.a46); max = Math.max(max,a.a51); max = Math.max(max,a.a52); max = Math.max(max,a.a53); max = Math.max(max,a.a54); max = Math.max(max,a.a55); max = Math.max(max,a.a56); max = Math.max(max,a.a61); max = Math.max(max,a.a62); max = Math.max(max,a.a63); max = Math.max(max,a.a64); max = Math.max(max,a.a65); max = Math.max(max,a.a66); return max; } /** *

* Returns the value of the element in the vector that has the largest value.
*
* Max{ ai } for all i
*

* * @param a A vector. Not modified. * @return The max element value of the matrix. */ public static double elementMax( FixedMatrix6_64F a ) { double max = a.a1; max = Math.max(max,a.a2); max = Math.max(max,a.a3); max = Math.max(max,a.a4); max = Math.max(max,a.a5); max = Math.max(max,a.a6); return max; } /** *

* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementMaxAbs( FixedMatrix6x6_64F a ) { double max = a.a11; max = Math.max(max,Math.abs(a.a12)); max = Math.max(max,Math.abs(a.a13)); max = Math.max(max,Math.abs(a.a14)); max = Math.max(max,Math.abs(a.a15)); max = Math.max(max,Math.abs(a.a16)); max = Math.max(max,Math.abs(a.a21)); max = Math.max(max,Math.abs(a.a22)); max = Math.max(max,Math.abs(a.a23)); max = Math.max(max,Math.abs(a.a24)); max = Math.max(max,Math.abs(a.a25)); max = Math.max(max,Math.abs(a.a26)); max = Math.max(max,Math.abs(a.a31)); max = Math.max(max,Math.abs(a.a32)); max = Math.max(max,Math.abs(a.a33)); max = Math.max(max,Math.abs(a.a34)); max = Math.max(max,Math.abs(a.a35)); max = Math.max(max,Math.abs(a.a36)); max = Math.max(max,Math.abs(a.a41)); max = Math.max(max,Math.abs(a.a42)); max = Math.max(max,Math.abs(a.a43)); max = Math.max(max,Math.abs(a.a44)); max = Math.max(max,Math.abs(a.a45)); max = Math.max(max,Math.abs(a.a46)); max = Math.max(max,Math.abs(a.a51)); max = Math.max(max,Math.abs(a.a52)); max = Math.max(max,Math.abs(a.a53)); max = Math.max(max,Math.abs(a.a54)); max = Math.max(max,Math.abs(a.a55)); max = Math.max(max,Math.abs(a.a56)); max = Math.max(max,Math.abs(a.a61)); max = Math.max(max,Math.abs(a.a62)); max = Math.max(max,Math.abs(a.a63)); max = Math.max(max,Math.abs(a.a64)); max = Math.max(max,Math.abs(a.a65)); max = Math.max(max,Math.abs(a.a66)); return max; } /** *

* Returns the absolute value of the element in the vector that has the largest absolute value.
*
* Max{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max abs element value of the vector. */ public static double elementMaxAbs( FixedMatrix6_64F a ) { double max = a.a1; max = Math.max(max,Math.abs(a.a2)); max = Math.max(max,Math.abs(a.a3)); max = Math.max(max,Math.abs(a.a4)); max = Math.max(max,Math.abs(a.a5)); max = Math.max(max,Math.abs(a.a6)); return max; } /** *

* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The value of element in the matrix with the minimum value. */ public static double elementMin( FixedMatrix6x6_64F a ) { double min = a.a11; min = Math.min(min, a.a12); min = Math.min(min, a.a13); min = Math.min(min, a.a14); min = Math.min(min, a.a15); min = Math.min(min, a.a16); min = Math.min(min, a.a21); min = Math.min(min, a.a22); min = Math.min(min, a.a23); min = Math.min(min, a.a24); min = Math.min(min, a.a25); min = Math.min(min, a.a26); min = Math.min(min, a.a31); min = Math.min(min, a.a32); min = Math.min(min, a.a33); min = Math.min(min, a.a34); min = Math.min(min, a.a35); min = Math.min(min, a.a36); min = Math.min(min, a.a41); min = Math.min(min, a.a42); min = Math.min(min, a.a43); min = Math.min(min, a.a44); min = Math.min(min, a.a45); min = Math.min(min, a.a46); min = Math.min(min, a.a51); min = Math.min(min, a.a52); min = Math.min(min, a.a53); min = Math.min(min, a.a54); min = Math.min(min, a.a55); min = Math.min(min, a.a56); min = Math.min(min, a.a61); min = Math.min(min, a.a62); min = Math.min(min, a.a63); min = Math.min(min, a.a64); min = Math.min(min, a.a65); min = Math.min(min, a.a66); return min; } /** *

* Returns the value of the element in the vector that has the minimum value.
*
* Min{ ai } for all
*

* * @param a A matrix. Not modified. * @return The value of element in the vector with the minimum value. */ public static double elementMin( FixedMatrix6_64F a ) { double min = a.a1; min = Math.min(min, a.a2); min = Math.min(min, a.a3); min = Math.min(min, a.a4); min = Math.min(min, a.a5); min = Math.min(min, a.a6); return min; } /** *

* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMinAbs( FixedMatrix6x6_64F a ) { double min = a.a11; min = Math.min(min,Math.abs(a.a12)); min = Math.min(min,Math.abs(a.a13)); min = Math.min(min,Math.abs(a.a14)); min = Math.min(min,Math.abs(a.a15)); min = Math.min(min,Math.abs(a.a16)); min = Math.min(min,Math.abs(a.a21)); min = Math.min(min,Math.abs(a.a22)); min = Math.min(min,Math.abs(a.a23)); min = Math.min(min,Math.abs(a.a24)); min = Math.min(min,Math.abs(a.a25)); min = Math.min(min,Math.abs(a.a26)); min = Math.min(min,Math.abs(a.a31)); min = Math.min(min,Math.abs(a.a32)); min = Math.min(min,Math.abs(a.a33)); min = Math.min(min,Math.abs(a.a34)); min = Math.min(min,Math.abs(a.a35)); min = Math.min(min,Math.abs(a.a36)); min = Math.min(min,Math.abs(a.a41)); min = Math.min(min,Math.abs(a.a42)); min = Math.min(min,Math.abs(a.a43)); min = Math.min(min,Math.abs(a.a44)); min = Math.min(min,Math.abs(a.a45)); min = Math.min(min,Math.abs(a.a46)); min = Math.min(min,Math.abs(a.a51)); min = Math.min(min,Math.abs(a.a52)); min = Math.min(min,Math.abs(a.a53)); min = Math.min(min,Math.abs(a.a54)); min = Math.min(min,Math.abs(a.a55)); min = Math.min(min,Math.abs(a.a56)); min = Math.min(min,Math.abs(a.a61)); min = Math.min(min,Math.abs(a.a62)); min = Math.min(min,Math.abs(a.a63)); min = Math.min(min,Math.abs(a.a64)); min = Math.min(min,Math.abs(a.a65)); min = Math.min(min,Math.abs(a.a66)); return min; } /** *

* Returns the absolute value of the element in the vector that has the smallest absolute value.
*
* Min{ |ai| } for all i
*

* * @param a A matrix. Not modified. * @return The max element value of the vector. */ public static double elementMinAbs( FixedMatrix6_64F a ) { double min = a.a1; min = Math.min(min,Math.abs(a.a2)); min = Math.min(min,Math.abs(a.a3)); min = Math.min(min,Math.abs(a.a4)); min = Math.min(min,Math.abs(a.a5)); min = Math.min(min,Math.abs(a.a6)); return min; } /** *

Performs an element by element multiplication operation:
*
* aij = aij * bij
*

* @param a The left matrix in the multiplication operation. Modified. * @param b The right matrix in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b) { a.a11 *= b.a11; a.a12 *= b.a12; a.a13 *= b.a13; a.a14 *= b.a14; a.a15 *= b.a15; a.a16 *= b.a16; a.a21 *= b.a21; a.a22 *= b.a22; a.a23 *= b.a23; a.a24 *= b.a24; a.a25 *= b.a25; a.a26 *= b.a26; a.a31 *= b.a31; a.a32 *= b.a32; a.a33 *= b.a33; a.a34 *= b.a34; a.a35 *= b.a35; a.a36 *= b.a36; a.a41 *= b.a41; a.a42 *= b.a42; a.a43 *= b.a43; a.a44 *= b.a44; a.a45 *= b.a45; a.a46 *= b.a46; a.a51 *= b.a51; a.a52 *= b.a52; a.a53 *= b.a53; a.a54 *= b.a54; a.a55 *= b.a55; a.a56 *= b.a56; a.a61 *= b.a61; a.a62 *= b.a62; a.a63 *= b.a63; a.a64 *= b.a64; a.a65 *= b.a65; a.a66 *= b.a66; } /** *

Performs an element by element multiplication operation:
*
* ai = ai * bi
*

* @param a The left vector in the multiplication operation. Modified. * @param b The right vector in the multiplication operation. Not modified. */ public static void elementMult( FixedMatrix6_64F a , FixedMatrix6_64F b) { a.a1 *= b.a1; a.a2 *= b.a2; a.a3 *= b.a3; a.a4 *= b.a4; a.a5 *= b.a5; a.a6 *= b.a6; } /** *

Performs an element by element multiplication operation:
*
* cij = aij * bij
*

* @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c ) { c.a11 = a.a11*b.a11; c.a12 = a.a12*b.a12; c.a13 = a.a13*b.a13; c.a14 = a.a14*b.a14; c.a15 = a.a15*b.a15; c.a16 = a.a16*b.a16; c.a21 = a.a21*b.a21; c.a22 = a.a22*b.a22; c.a23 = a.a23*b.a23; c.a24 = a.a24*b.a24; c.a25 = a.a25*b.a25; c.a26 = a.a26*b.a26; c.a31 = a.a31*b.a31; c.a32 = a.a32*b.a32; c.a33 = a.a33*b.a33; c.a34 = a.a34*b.a34; c.a35 = a.a35*b.a35; c.a36 = a.a36*b.a36; c.a41 = a.a41*b.a41; c.a42 = a.a42*b.a42; c.a43 = a.a43*b.a43; c.a44 = a.a44*b.a44; c.a45 = a.a45*b.a45; c.a46 = a.a46*b.a46; c.a51 = a.a51*b.a51; c.a52 = a.a52*b.a52; c.a53 = a.a53*b.a53; c.a54 = a.a54*b.a54; c.a55 = a.a55*b.a55; c.a56 = a.a56*b.a56; c.a61 = a.a61*b.a61; c.a62 = a.a62*b.a62; c.a63 = a.a63*b.a63; c.a64 = a.a64*b.a64; c.a65 = a.a65*b.a65; c.a66 = a.a66*b.a66; } /** *

Performs an element by element multiplication operation:
*
* ci = ai * bj
*

* @param a The left vector in the multiplication operation. Not modified. * @param b The right vector in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( FixedMatrix6_64F a , FixedMatrix6_64F b , FixedMatrix6_64F c ) { c.a1 = a.a1*b.a1; c.a2 = a.a2*b.a2; c.a3 = a.a3*b.a3; c.a4 = a.a4*b.a4; c.a5 = a.a5*b.a5; c.a6 = a.a6*b.a6; } /** *

Performs an element by element division operation:
*
* aij = aij / bij
*

* @param a The left matrix in the division operation. Modified. * @param b The right matrix in the division operation. Not modified. */ public static void elementDiv( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b) { a.a11 /= b.a11; a.a12 /= b.a12; a.a13 /= b.a13; a.a14 /= b.a14; a.a15 /= b.a15; a.a16 /= b.a16; a.a21 /= b.a21; a.a22 /= b.a22; a.a23 /= b.a23; a.a24 /= b.a24; a.a25 /= b.a25; a.a26 /= b.a26; a.a31 /= b.a31; a.a32 /= b.a32; a.a33 /= b.a33; a.a34 /= b.a34; a.a35 /= b.a35; a.a36 /= b.a36; a.a41 /= b.a41; a.a42 /= b.a42; a.a43 /= b.a43; a.a44 /= b.a44; a.a45 /= b.a45; a.a46 /= b.a46; a.a51 /= b.a51; a.a52 /= b.a52; a.a53 /= b.a53; a.a54 /= b.a54; a.a55 /= b.a55; a.a56 /= b.a56; a.a61 /= b.a61; a.a62 /= b.a62; a.a63 /= b.a63; a.a64 /= b.a64; a.a65 /= b.a65; a.a66 /= b.a66; } /** *

Performs an element by element division operation:
*
* ai = ai / bi
*

* @param a The left vector in the division operation. Modified. * @param b The right vector in the division operation. Not modified. */ public static void elementDiv( FixedMatrix6_64F a , FixedMatrix6_64F b) { a.a1 /= b.a1; a.a2 /= b.a2; a.a3 /= b.a3; a.a4 /= b.a4; a.a5 /= b.a5; a.a6 /= b.a6; } /** *

Performs an element by element division operation:
*
* cij = aij / bij
*

* @param a The left matrix in the division operation. Not modified. * @param b The right matrix in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix6x6_64F a , FixedMatrix6x6_64F b , FixedMatrix6x6_64F c ) { c.a11 = a.a11/b.a11; c.a12 = a.a12/b.a12; c.a13 = a.a13/b.a13; c.a14 = a.a14/b.a14; c.a15 = a.a15/b.a15; c.a16 = a.a16/b.a16; c.a21 = a.a21/b.a21; c.a22 = a.a22/b.a22; c.a23 = a.a23/b.a23; c.a24 = a.a24/b.a24; c.a25 = a.a25/b.a25; c.a26 = a.a26/b.a26; c.a31 = a.a31/b.a31; c.a32 = a.a32/b.a32; c.a33 = a.a33/b.a33; c.a34 = a.a34/b.a34; c.a35 = a.a35/b.a35; c.a36 = a.a36/b.a36; c.a41 = a.a41/b.a41; c.a42 = a.a42/b.a42; c.a43 = a.a43/b.a43; c.a44 = a.a44/b.a44; c.a45 = a.a45/b.a45; c.a46 = a.a46/b.a46; c.a51 = a.a51/b.a51; c.a52 = a.a52/b.a52; c.a53 = a.a53/b.a53; c.a54 = a.a54/b.a54; c.a55 = a.a55/b.a55; c.a56 = a.a56/b.a56; c.a61 = a.a61/b.a61; c.a62 = a.a62/b.a62; c.a63 = a.a63/b.a63; c.a64 = a.a64/b.a64; c.a65 = a.a65/b.a65; c.a66 = a.a66/b.a66; } /** *

Performs an element by element division operation:
*
* ci = ai / bi
*

* @param a The left vector in the division operation. Not modified. * @param b The right vector in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( FixedMatrix6_64F a , FixedMatrix6_64F b , FixedMatrix6_64F c ) { c.a1 = a.a1/b.a1; c.a2 = a.a2/b.a2; c.a3 = a.a3/b.a3; c.a4 = a.a4/b.a4; c.a5 = a.a5/b.a5; c.a6 = a.a6/b.a6; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The matrix that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix6x6_64F a ) { a.a11 *= alpha; a.a12 *= alpha; a.a13 *= alpha; a.a14 *= alpha; a.a15 *= alpha; a.a16 *= alpha; a.a21 *= alpha; a.a22 *= alpha; a.a23 *= alpha; a.a24 *= alpha; a.a25 *= alpha; a.a26 *= alpha; a.a31 *= alpha; a.a32 *= alpha; a.a33 *= alpha; a.a34 *= alpha; a.a35 *= alpha; a.a36 *= alpha; a.a41 *= alpha; a.a42 *= alpha; a.a43 *= alpha; a.a44 *= alpha; a.a45 *= alpha; a.a46 *= alpha; a.a51 *= alpha; a.a52 *= alpha; a.a53 *= alpha; a.a54 *= alpha; a.a55 *= alpha; a.a56 *= alpha; a.a61 *= alpha; a.a62 *= alpha; a.a63 *= alpha; a.a64 *= alpha; a.a65 *= alpha; a.a66 *= alpha; } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The vector that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , FixedMatrix6_64F a ) { a.a1 *= alpha; a.a2 *= alpha; a.a3 *= alpha; a.a4 *= alpha; a.a5 *= alpha; a.a6 *= alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bij = α*aij *

* * @param alpha the amount each element is multiplied by. * @param a The matrix that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix6x6_64F a , FixedMatrix6x6_64F b ) { b.a11 = a.a11*alpha; b.a12 = a.a12*alpha; b.a13 = a.a13*alpha; b.a14 = a.a14*alpha; b.a15 = a.a15*alpha; b.a16 = a.a16*alpha; b.a21 = a.a21*alpha; b.a22 = a.a22*alpha; b.a23 = a.a23*alpha; b.a24 = a.a24*alpha; b.a25 = a.a25*alpha; b.a26 = a.a26*alpha; b.a31 = a.a31*alpha; b.a32 = a.a32*alpha; b.a33 = a.a33*alpha; b.a34 = a.a34*alpha; b.a35 = a.a35*alpha; b.a36 = a.a36*alpha; b.a41 = a.a41*alpha; b.a42 = a.a42*alpha; b.a43 = a.a43*alpha; b.a44 = a.a44*alpha; b.a45 = a.a45*alpha; b.a46 = a.a46*alpha; b.a51 = a.a51*alpha; b.a52 = a.a52*alpha; b.a53 = a.a53*alpha; b.a54 = a.a54*alpha; b.a55 = a.a55*alpha; b.a56 = a.a56*alpha; b.a61 = a.a61*alpha; b.a62 = a.a62*alpha; b.a63 = a.a63*alpha; b.a64 = a.a64*alpha; b.a65 = a.a65*alpha; b.a66 = a.a66*alpha; } /** *

* Performs an element by element scalar multiplication.
*
* bi = α*ai *

* * @param alpha the amount each element is multiplied by. * @param a The vector that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , FixedMatrix6_64F a , FixedMatrix6_64F b ) { b.a1 = a.a1*alpha; b.a2 = a.a2*alpha; b.a3 = a.a3*alpha; b.a4 = a.a4*alpha; b.a5 = a.a5*alpha; b.a6 = a.a6*alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* aij = aij/α *

* * @param a The matrix whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix6x6_64F a , double alpha ) { a.a11 /= alpha; a.a12 /= alpha; a.a13 /= alpha; a.a14 /= alpha; a.a15 /= alpha; a.a16 /= alpha; a.a21 /= alpha; a.a22 /= alpha; a.a23 /= alpha; a.a24 /= alpha; a.a25 /= alpha; a.a26 /= alpha; a.a31 /= alpha; a.a32 /= alpha; a.a33 /= alpha; a.a34 /= alpha; a.a35 /= alpha; a.a36 /= alpha; a.a41 /= alpha; a.a42 /= alpha; a.a43 /= alpha; a.a44 /= alpha; a.a45 /= alpha; a.a46 /= alpha; a.a51 /= alpha; a.a52 /= alpha; a.a53 /= alpha; a.a54 /= alpha; a.a55 /= alpha; a.a56 /= alpha; a.a61 /= alpha; a.a62 /= alpha; a.a63 /= alpha; a.a64 /= alpha; a.a65 /= alpha; a.a66 /= alpha; } /** *

* Performs an in-place element by element scalar division. Scalar denominator.
*
* ai = ai/α *

* * @param a The vector whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( FixedMatrix6_64F a , double alpha ) { a.a1 /= alpha; a.a2 /= alpha; a.a3 /= alpha; a.a4 /= alpha; a.a5 /= alpha; a.a6 /= alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bij = aij /α *

* * @param alpha the amount each element is divided by. * @param a The matrix whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix6x6_64F a , double alpha , FixedMatrix6x6_64F b ) { b.a11 = a.a11/alpha; b.a12 = a.a12/alpha; b.a13 = a.a13/alpha; b.a14 = a.a14/alpha; b.a15 = a.a15/alpha; b.a16 = a.a16/alpha; b.a21 = a.a21/alpha; b.a22 = a.a22/alpha; b.a23 = a.a23/alpha; b.a24 = a.a24/alpha; b.a25 = a.a25/alpha; b.a26 = a.a26/alpha; b.a31 = a.a31/alpha; b.a32 = a.a32/alpha; b.a33 = a.a33/alpha; b.a34 = a.a34/alpha; b.a35 = a.a35/alpha; b.a36 = a.a36/alpha; b.a41 = a.a41/alpha; b.a42 = a.a42/alpha; b.a43 = a.a43/alpha; b.a44 = a.a44/alpha; b.a45 = a.a45/alpha; b.a46 = a.a46/alpha; b.a51 = a.a51/alpha; b.a52 = a.a52/alpha; b.a53 = a.a53/alpha; b.a54 = a.a54/alpha; b.a55 = a.a55/alpha; b.a56 = a.a56/alpha; b.a61 = a.a61/alpha; b.a62 = a.a62/alpha; b.a63 = a.a63/alpha; b.a64 = a.a64/alpha; b.a65 = a.a65/alpha; b.a66 = a.a66/alpha; } /** *

* Performs an element by element scalar division. Scalar denominator.
*
* bi = ai /α *

* * @param alpha the amount each element is divided by. * @param a The vector whose elements are to be divided. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( FixedMatrix6_64F a , double alpha , FixedMatrix6_64F b ) { b.a1 = a.a1/alpha; b.a2 = a.a2/alpha; b.a3 = a.a3/alpha; b.a4 = a.a4/alpha; b.a5 = a.a5/alpha; b.a6 = a.a6/alpha; } /** *

* Changes the sign of every element in the matrix.
*
* aij = -aij *

* * @param a A matrix. Modified. */ public static void changeSign( FixedMatrix6x6_64F a ) { a.a11 = -a.a11; a.a12 = -a.a12; a.a13 = -a.a13; a.a14 = -a.a14; a.a15 = -a.a15; a.a16 = -a.a16; a.a21 = -a.a21; a.a22 = -a.a22; a.a23 = -a.a23; a.a24 = -a.a24; a.a25 = -a.a25; a.a26 = -a.a26; a.a31 = -a.a31; a.a32 = -a.a32; a.a33 = -a.a33; a.a34 = -a.a34; a.a35 = -a.a35; a.a36 = -a.a36; a.a41 = -a.a41; a.a42 = -a.a42; a.a43 = -a.a43; a.a44 = -a.a44; a.a45 = -a.a45; a.a46 = -a.a46; a.a51 = -a.a51; a.a52 = -a.a52; a.a53 = -a.a53; a.a54 = -a.a54; a.a55 = -a.a55; a.a56 = -a.a56; a.a61 = -a.a61; a.a62 = -a.a62; a.a63 = -a.a63; a.a64 = -a.a64; a.a65 = -a.a65; a.a66 = -a.a66; } /** *

* Changes the sign of every element in the vector.
*
* ai = -ai *

* * @param a A vector. Modified. */ public static void changeSign( FixedMatrix6_64F a ) { a.a1 = -a.a1; a.a2 = -a.a2; a.a3 = -a.a3; a.a4 = -a.a4; a.a5 = -a.a5; a.a6 = -a.a6; } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param a A matrix whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix6x6_64F a , double v ) { a.a11 = v; a.a12 = v; a.a13 = v; a.a14 = v; a.a15 = v; a.a16 = v; a.a21 = v; a.a22 = v; a.a23 = v; a.a24 = v; a.a25 = v; a.a26 = v; a.a31 = v; a.a32 = v; a.a33 = v; a.a34 = v; a.a35 = v; a.a36 = v; a.a41 = v; a.a42 = v; a.a43 = v; a.a44 = v; a.a45 = v; a.a46 = v; a.a51 = v; a.a52 = v; a.a53 = v; a.a54 = v; a.a55 = v; a.a56 = v; a.a61 = v; a.a62 = v; a.a63 = v; a.a64 = v; a.a65 = v; a.a66 = v; } /** *

* Sets every element in the vector to the specified value.
*
* ai = value *

* * @param a A vector whose elements are about to be set. Modified. * @param v The value each element will have. */ public static void fill( FixedMatrix6_64F a , double v ) { a.a1 = v; a.a2 = v; a.a3 = v; a.a4 = v; a.a5 = v; a.a6 = v; } /** * Extracts the row from the matrix a. * @param a Input matrix * @param row Which row is to be extracted * @param out output. Storage for the extracted row. If null then a new vector will be returned. * @return The extracted row. */ public static FixedMatrix6_64F extractRow( FixedMatrix6x6_64F a , int row , FixedMatrix6_64F out ) { if( out == null) out = new FixedMatrix6_64F(); switch( row ) { case 0: out.a1 = a.a11; out.a2 = a.a12; out.a3 = a.a13; out.a4 = a.a14; out.a5 = a.a15; out.a6 = a.a16; break; case 1: out.a1 = a.a21; out.a2 = a.a22; out.a3 = a.a23; out.a4 = a.a24; out.a5 = a.a25; out.a6 = a.a26; break; case 2: out.a1 = a.a31; out.a2 = a.a32; out.a3 = a.a33; out.a4 = a.a34; out.a5 = a.a35; out.a6 = a.a36; break; case 3: out.a1 = a.a41; out.a2 = a.a42; out.a3 = a.a43; out.a4 = a.a44; out.a5 = a.a45; out.a6 = a.a46; break; case 4: out.a1 = a.a51; out.a2 = a.a52; out.a3 = a.a53; out.a4 = a.a54; out.a5 = a.a55; out.a6 = a.a56; break; case 5: out.a1 = a.a61; out.a2 = a.a62; out.a3 = a.a63; out.a4 = a.a64; out.a5 = a.a65; out.a6 = a.a66; break; default: throw new IllegalArgumentException("Out of bounds row. row = "+row); } return out; } /** * Extracts the column from the matrix a. * @param a Input matrix * @param column Which column is to be extracted * @param out output. Storage for the extracted column. If null then a new vector will be returned. * @return The extracted column. */ public static FixedMatrix6_64F extractColumn( FixedMatrix6x6_64F a , int column , FixedMatrix6_64F out ) { if( out == null) out = new FixedMatrix6_64F(); switch( column ) { case 0: out.a1 = a.a11; out.a2 = a.a21; out.a3 = a.a31; out.a4 = a.a41; out.a5 = a.a51; out.a6 = a.a61; break; case 1: out.a1 = a.a12; out.a2 = a.a22; out.a3 = a.a32; out.a4 = a.a42; out.a5 = a.a52; out.a6 = a.a62; break; case 2: out.a1 = a.a13; out.a2 = a.a23; out.a3 = a.a33; out.a4 = a.a43; out.a5 = a.a53; out.a6 = a.a63; break; case 3: out.a1 = a.a14; out.a2 = a.a24; out.a3 = a.a34; out.a4 = a.a44; out.a5 = a.a54; out.a6 = a.a64; break; case 4: out.a1 = a.a15; out.a2 = a.a25; out.a3 = a.a35; out.a4 = a.a45; out.a5 = a.a55; out.a6 = a.a65; break; case 5: out.a1 = a.a16; out.a2 = a.a26; out.a3 = a.a36; out.a4 = a.a46; out.a5 = a.a56; out.a6 = a.a66; break; default: throw new IllegalArgumentException("Out of bounds column. column = "+column); } return out; } } ejml-0.28/main/dense64/src/org/ejml/alg/generic/000077500000000000000000000000001256171534400212625ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/alg/generic/CodeGeneratorMisc.java000066400000000000000000000035251256171534400254670ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.generic; /** * Various things related to auto generating code. * * @author Peter Abeles */ public class CodeGeneratorMisc { public final static String COPYRIGHT = "/*\n" + " * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved.\n" + " *\n" + " * This file is part of Efficient Java Matrix Library (EJML).\n" + " *\n" + " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" + " * you may not use this file except in compliance with the License.\n" + " * You may obtain a copy of the License at\n" + " *\n" + " * http://www.apache.org/licenses/LICENSE-2.0\n" + " *\n" + " * Unless required by applicable law or agreed to in writing, software\n" + " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" + " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + " * See the License for the specific language governing permissions and\n" + " * limitations under the License.\n" + " */\n"; } ejml-0.28/main/dense64/src/org/ejml/alg/generic/GenericMatrixOps.java000066400000000000000000000075661256171534400253660ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.generic; import org.ejml.data.RealMatrix64F; import java.util.Random; /** * @author Peter Abeles */ public class GenericMatrixOps { // public static DenseD2Matrix64F convertToD2( DenseMatrix64F orig ) { // DenseD2Matrix64F ret = new DenseD2Matrix64F(orig.getNumRows(),orig.getNumCols()); // // copy(orig,ret); // // return ret; // } public static boolean isEquivalent( RealMatrix64F a , RealMatrix64F b , double tol ) { if( a.getNumRows() != b.getNumRows() || a.getNumCols() != b.getNumCols() ) return false; for( int i = 0; i < a.getNumRows(); i++ ) { for( int j = 0; j < a.getNumCols(); j++ ) { double diff = Math.abs(a.get(i,j) - b.get(i,j)); if( diff > tol ) return false; } } return true; } /** * Returns true if the provided matrix is has a value of 1 along the diagonal * elements and zero along all the other elements. * * @param a Matrix being inspected. * @param tol How close to zero or one each element needs to be. * @return If it is within tolerance to an identity matrix. */ public static boolean isIdentity( RealMatrix64F a , double tol ) { for( int i = 0; i < a.getNumRows(); i++ ) { for( int j = 0; j < a.getNumCols(); j++ ) { if( i == j ) { if( Math.abs(a.get(i,j)-1.0) > tol ) return false; } else { if( Math.abs(a.get(i,j)) > tol ) return false; } } } return true; } public static boolean isEquivalentTriangle( boolean upper , RealMatrix64F a , RealMatrix64F b , double tol ) { if( a.getNumRows() != b.getNumRows() || a.getNumCols() != b.getNumCols() ) return false; if( upper ) { for( int i = 0; i < a.getNumRows(); i++ ) { for( int j = i; j < a.getNumCols(); j++ ) { double diff = Math.abs(a.get(i,j) - b.get(i,j)); if( diff > tol ) return false; } } } else { for( int j = 0; j < a.getNumCols(); j++ ) { for( int i = j; i < a.getNumRows(); i++ ) { double diff = Math.abs(a.get(i,j) - b.get(i,j)); if( diff > tol ) return false; } } } return true; } public static void copy( RealMatrix64F from , RealMatrix64F to ) { int numCols = from.getNumCols(); int numRows = from.getNumRows(); for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { to.set(i,j,from.get(i,j)); } } } public static void setRandom( RealMatrix64F a , double min , double max , Random rand ) { for( int i = 0; i < a.getNumRows(); i++ ) { for( int j = 0; j < a.getNumCols(); j++ ) { double val = rand.nextDouble()*(max-min)+min; a.set(i,j,val); } } } } ejml-0.28/main/dense64/src/org/ejml/factory/000077500000000000000000000000001256171534400205525ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/factory/DecompositionFactory.java000066400000000000000000000302241256171534400255620ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.factory; import org.ejml.EjmlParameters; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionBlock_D64; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionInner_D64; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionLDL_D64; import org.ejml.alg.dense.decomposition.chol.CholeskyDecomposition_B64_to_D64; import org.ejml.alg.dense.decomposition.eig.SwitchingEigenDecomposition; import org.ejml.alg.dense.decomposition.eig.SymmetricQRAlgorithmDecomposition_D64; import org.ejml.alg.dense.decomposition.eig.WatchedDoubleStepQRDecomposition_D64; import org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecompositionHouseholder_D64; import org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecomposition_B64_to_D64; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.decomposition.qr.QRColPivDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.decomposition.svd.SvdImplicitQrDecompose_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RealMatrix64F; import org.ejml.interfaces.decomposition.*; import org.ejml.ops.CommonOps; import org.ejml.ops.EigenOps; import org.ejml.ops.NormOps; import org.ejml.ops.SpecializedOps; /** *

* Contains operations related to creating and evaluating the quality of common matrix decompositions. Except * in specialized situations, matrix decompositions should be instantiated from this factory instead of being * directly constructed. Low level implementations are more prone to changes and new algorithms will be * automatically placed here. *

* *

* Several functions are also provided to evaluate the quality of a decomposition. This is provided * as a way to sanity check a decomposition. Often times a significant error in a decomposition will * result in a poor (larger) quality value. Typically a quality value of around 1e-15 means it is within * machine precision. *

* * @author Peter Abeles */ public class DecompositionFactory { /** *

* Returns a {@link CholeskyDecomposition} that has been optimized for the specified matrix size. *

* * @param matrixSize Number of rows and columns that the returned decomposition is optimized for. * @param lower should a lower or upper triangular matrix be used. If not sure set to true. * @return A new CholeskyDecomposition. */ public static CholeskyDecomposition chol( int matrixSize , boolean lower ) { if( matrixSize < EjmlParameters.SWITCH_BLOCK64_CHOLESKY ) { return new CholeskyDecompositionInner_D64(lower); } else if( EjmlParameters.MEMORY == EjmlParameters.MemoryUsage.FASTER ){ return new CholeskyDecomposition_B64_to_D64(lower); } else { return new CholeskyDecompositionBlock_D64(EjmlParameters.BLOCK_WIDTH_CHOL); } } /** *

* Returns a {@link org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionLDL_D64} that has been optimized for the specified matrix size. *

* * @param matrixSize Number of rows and columns that the returned decomposition is optimized for. * @return CholeskyLDLDecomposition */ public static CholeskyLDLDecomposition cholLDL( int matrixSize ) { return new CholeskyDecompositionLDL_D64(); } /** *

* Returns a {@link org.ejml.interfaces.decomposition.LUDecomposition} that has been optimized for the specified matrix size. *

* * @parm matrixWidth The matrix size that the decomposition should be optimized for. * @return LUDecomposition */ public static LUDecomposition lu( int numRows , int numCol ) { return new LUDecompositionAlt_D64(); } /** *

* Returns a {@link SingularValueDecomposition} that has been optimized for the specified matrix size. * For improved performance only the portion of the decomposition that the user requests will be computed. *

* * @param numRows Number of rows the returned decomposition is optimized for. * @param numCols Number of columns that the returned decomposition is optimized for. * @param needU Should it compute the U matrix. If not sure set to true. * @param needV Should it compute the V matrix. If not sure set to true. * @param compact Should it compute the SVD in compact form. If not sure set to false. * @return */ public static SingularValueDecomposition svd( int numRows , int numCols , boolean needU , boolean needV , boolean compact ) { // Don't allow the tall decomposition by default since it *might* be less stable return new SvdImplicitQrDecompose_D64(compact,needU,needV,false); } /** *

* Returns a {@link org.ejml.interfaces.decomposition.QRDecomposition} that has been optimized for the specified matrix size. *

* * @param numRows Number of rows the returned decomposition is optimized for. * @param numCols Number of columns that the returned decomposition is optimized for. * @return QRDecomposition */ public static QRDecomposition qr( int numRows , int numCols ) { return new QRDecompositionHouseholderColumn_D64(); } /** *

* Returns a {@link org.ejml.interfaces.decomposition.QRPDecomposition} that has been optimized for the specified matrix size. *

* * @param numRows Number of rows the returned decomposition is optimized for. * @param numCols Number of columns that the returned decomposition is optimized for. * @return QRPDecomposition */ public static QRPDecomposition qrp( int numRows , int numCols ) { return new QRColPivDecompositionHouseholderColumn_D64(); } /** *

* Returns an {@link EigenDecomposition} that has been optimized for the specified matrix size. * If the input matrix is symmetric within tolerance then the symmetric algorithm will be used, otherwise * a general purpose eigenvalue decomposition is used. *

* * @param matrixSize Number of rows and columns that the returned decomposition is optimized for. * @param needVectors Should eigenvectors be computed or not. If not sure set to true. * @return A new EigenDecomposition */ public static EigenDecomposition eig( int matrixSize , boolean needVectors ) { return new SwitchingEigenDecomposition(matrixSize,needVectors,1e-8); } /** *

* Returns an {@link EigenDecomposition} which is specialized for symmetric matrices or the general problem. *

* * @param matrixSize Number of rows and columns that the returned decomposition is optimized for. * @param computeVectors Should it compute the eigenvectors or just eigenvalues. * @param isSymmetric If true then the returned algorithm is specialized only for symmetric matrices, if false * then a general purpose algorithm is returned. * @return EVD for any matrix. */ public static EigenDecomposition eig( int matrixSize , boolean computeVectors , boolean isSymmetric ) { if( isSymmetric ) { TridiagonalSimilarDecomposition decomp = DecompositionFactory.tridiagonal(matrixSize); return new SymmetricQRAlgorithmDecomposition_D64(decomp,computeVectors); } else return new WatchedDoubleStepQRDecomposition_D64(computeVectors); } /** *

* Computes a metric which measures the the quality of a singular value decomposition. If a * value is returned that is close to or smaller than 1e-15 then it is within machine precision. *

* *

* SVD quality is defined as:
*
* Quality = || A - U W VT|| / || A ||
* where A is the original matrix , U W V is the decomposition, and ||A|| is the norm-f of A. *

* * @param orig The original matrix which was decomposed. Not modified. * @param svd The decomposition after processing 'orig'. Not modified. * @return The quality of the decomposition. */ public static double quality( DenseMatrix64F orig , SingularValueDecomposition svd ) { return quality(orig,svd.getU(null,false),svd.getW(null),svd.getV(null,true)); } public static double quality( DenseMatrix64F orig , DenseMatrix64F U , DenseMatrix64F W , DenseMatrix64F Vt ) { // foundA = U*W*Vt DenseMatrix64F UW = new DenseMatrix64F(U.numRows,W.numCols); CommonOps.mult(U,W,UW); DenseMatrix64F foundA = new DenseMatrix64F(UW.numRows,Vt.numCols); CommonOps.mult(UW,Vt,foundA); double normA = NormOps.normF(foundA); return SpecializedOps.diffNormF(orig,foundA)/normA; } /** *

* Computes a metric which measures the the quality of an eigen value decomposition. If a * value is returned that is close to or smaller than 1e-15 then it is within machine precision. *

*

* EVD quality is defined as:
*
* Quality = ||A*V - V*D|| / ||A*V||. *

* * @param orig The original matrix. Not modified. * @param eig EVD of the original matrix. Not modified. * @return The quality of the decomposition. */ public static double quality( DenseMatrix64F orig , EigenDecomposition eig ) { DenseMatrix64F A = orig; DenseMatrix64F V = EigenOps.createMatrixV(eig); DenseMatrix64F D = EigenOps.createMatrixD(eig); // L = A*V DenseMatrix64F L = new DenseMatrix64F(A.numRows,V.numCols); CommonOps.mult(A,V,L); // R = V*D DenseMatrix64F R = new DenseMatrix64F(V.numRows,D.numCols); CommonOps.mult(V,D,R); DenseMatrix64F diff = new DenseMatrix64F(L.numRows,L.numCols); CommonOps.subtract(L,R,diff); double top = NormOps.normF(diff); double bottom = NormOps.normF(L); double error = top/bottom; return error; } /** * Checks to see if the passed in tridiagonal decomposition is of the appropriate type * for the matrix of the provided size. Returns the same instance or a new instance. * * @param matrixSize Number of rows and columns that the returned decomposition is optimized for. */ public static TridiagonalSimilarDecomposition tridiagonal( int matrixSize ) { if( matrixSize >= 1800 ) { return new TridiagonalDecomposition_B64_to_D64(); } else { return new TridiagonalDecompositionHouseholder_D64(); } } /** * A simple convinience function that decomposes the matrix but automatically checks the input ti make * sure is not being modified. * * @param decomp Decomposition which is being wrapped * @param M THe matrix being decomposed. * @param Matrix type. * @return If the decomposition was successful or not. */ public static boolean decomposeSafe( DecompositionInterface decomp, T M ) { if( decomp.inputModified() ) { return decomp.decompose(M.copy()); } else { return decomp.decompose(M); } } } ejml-0.28/main/dense64/src/org/ejml/factory/LinearSolverFactory.java000066400000000000000000000174701256171534400253630ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.factory; import org.ejml.EjmlParameters; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionCommon_D64; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionInner_D64; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.decomposition.qr.QRColPivDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.linsol.AdjustableLinearSolver; import org.ejml.alg.dense.linsol.chol.LinearSolverChol_B64; import org.ejml.alg.dense.linsol.chol.LinearSolverChol_D64; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_D64; import org.ejml.alg.dense.linsol.qr.*; import org.ejml.alg.dense.linsol.svd.SolvePseudoInverseSvd; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * A factory for generating solvers for systems of the form A*x=b, where A and B are known and x is unknown. * * @author Peter Abeles */ public class LinearSolverFactory { /** * Creates a linear solver using LU decomposition */ public static LinearSolver lu( int numRows ) { return linear(numRows); } /** * Creates a linear solver using Cholesky decomposition */ public static LinearSolver chol( int numRows ) { return symmPosDef(numRows); } /** * Creates a linear solver using QR decomposition */ public static LinearSolver qr( int numRows , int numCols ) { return leastSquares(numRows,numCols); } /** * Creates a linear solver using QRP decomposition */ public static LinearSolver qrp( boolean computeNorm2, boolean computeQ ) { return leastSquaresQrPivot(computeNorm2,computeQ); } /** * Creates a general purpose solver. Use this if you are not sure what you need. * * @param numRows The number of rows that the decomposition is optimized for. * @param numCols The number of columns that the decomposition is optimized for. */ public static LinearSolver general( int numRows , int numCols ) { if( numRows == numCols ) return linear(numRows); else return leastSquares(numRows,numCols); } /** * Creates a solver for linear systems. The A matrix will have dimensions (m,m). * * @return A new linear solver. */ public static LinearSolver linear( int matrixSize ) { return new LinearSolverLu_D64(new LUDecompositionAlt_D64()); } /** * Creates a good general purpose solver for over determined systems and returns the optimal least-squares * solution. The A matrix will have dimensions (m,n) where m ≥ n. * * @param numRows The number of rows that the decomposition is optimized for. * @param numCols The number of columns that the decomposition is optimized for. * @return A new least-squares solver for over determined systems. */ public static LinearSolver leastSquares( int numRows , int numCols ) { if(numCols < EjmlParameters.SWITCH_BLOCK64_QR ) { return new LinearSolverQrHouseCol_D64(); } else { if( EjmlParameters.MEMORY == EjmlParameters.MemoryUsage.FASTER ) return new LinearSolverQrBlock64_D64(); else return new LinearSolverQrHouseCol_D64(); } } /** * Creates a solver for symmetric positive definite matrices. * * @return A new solver for symmetric positive definite matrices. */ public static LinearSolver symmPosDef( int matrixWidth ) { if(matrixWidth < EjmlParameters.SWITCH_BLOCK64_CHOLESKY ) { CholeskyDecompositionCommon_D64 decomp = new CholeskyDecompositionInner_D64(true); return new LinearSolverChol_D64(decomp); } else { if( EjmlParameters.MEMORY == EjmlParameters.MemoryUsage.FASTER ) return new LinearSolverChol_B64(); else { CholeskyDecompositionCommon_D64 decomp = new CholeskyDecompositionInner_D64(true); return new LinearSolverChol_D64(decomp); } } } /** *

* Linear solver which uses QR pivot decomposition. These solvers can handle singular systems * and should never fail. For singular systems, the solution might not be as accurate as a * pseudo inverse that uses SVD. *

* *

* For singular systems there are multiple correct solutions. The optimal 2-norm solution is the * solution vector with the minimal 2-norm and is unique. If the optimal solution is not computed * then the basic solution is returned. See {@link org.ejml.alg.dense.linsol.qr.BaseLinearSolverQrp_D64} * for details. There is only a runtime difference for small matrices, 2-norm solution is slower. *

* *

* Two different solvers are available. Compute Q will compute the Q matrix once then use it multiple times. * If the solution for a single vector is being found then this should be set to false. If the pseudo inverse * is being found or the solution matrix has more than one columns AND solve is being called numerous multiples * times then this should be set to true. *

* * @param computeNorm2 true to compute the minimum 2-norm solution for singular systems. Try true. * @param computeQ Should it precompute Q or use house holder. Try false; * @return Pseudo inverse type solver using QR with column pivots. */ public static LinearSolver leastSquaresQrPivot( boolean computeNorm2 , boolean computeQ ) { QRColPivDecompositionHouseholderColumn_D64 decomposition = new QRColPivDecompositionHouseholderColumn_D64(); if( computeQ ) return new SolvePseudoInverseQrp_D64(decomposition,computeNorm2); else return new LinearSolverQrpHouseCol_D64(decomposition,computeNorm2); } /** *

* Returns a solver which uses the pseudo inverse. Useful when a matrix * needs to be inverted which is singular. Two variants of pseudo inverse are provided. SVD * will tend to be the most robust but the slowest and QR decomposition with column pivots will * be faster, but less robust. *

* *

* See {@link #leastSquaresQrPivot} for additional options specific to QR decomposition based * pseudo inverse. These options allow for better runtime performance in different situations. *

* * @param useSVD If true SVD will be used, otherwise QR with column pivot will be used. * @return Solver for singular matrices. */ public static LinearSolver pseudoInverse( boolean useSVD ) { if( useSVD ) return new SolvePseudoInverseSvd(); else return leastSquaresQrPivot(true,false); } /** * Create a solver which can efficiently add and remove elements instead of recomputing * everything from scratch. */ public static AdjustableLinearSolver adjustable() { return new AdjLinearSolverQr_D64(); } } ejml-0.28/main/dense64/src/org/ejml/factory/SingularMatrixException.java000066400000000000000000000023441256171534400262500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.factory; /** * This exception is thrown if an operation can not be finished because the matrix is singular. * It is a RuntimeException to allow the code to be written cleaner and also because singular * matrices are not always detected. Forcing an exception to be caught provides a false sense * of security. * * @author Peter Abeles */ public class SingularMatrixException extends RuntimeException { public SingularMatrixException() { } public SingularMatrixException(String message) { super(message); } } ejml-0.28/main/dense64/src/org/ejml/ops/000077500000000000000000000000001256171534400177045ustar00rootroot00000000000000ejml-0.28/main/dense64/src/org/ejml/ops/CommonOps.java000066400000000000000000002123451256171534400224700ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.EjmlParameters; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_D64; import org.ejml.alg.dense.misc.*; import org.ejml.alg.dense.mult.MatrixMatrixMult; import org.ejml.alg.dense.mult.MatrixMultProduct; import org.ejml.alg.dense.mult.MatrixVectorMult; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RealMatrix64F; import org.ejml.data.RowD1Matrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.interfaces.linsol.ReducedRowEchelonForm; import java.util.Arrays; /** *

* Common matrix operations are contained here. Which specific underlying algorithm is used * is not specified just the out come of the operation. Nor should calls to these functions * reply on the underlying implementation. Which algorithm is used can depend on the matrix * being passed in. *

*

* For more exotic and specialized generic operations see {@link org.ejml.ops.SpecializedOps}. *

* @see org.ejml.alg.dense.mult.MatrixMatrixMult * @see org.ejml.alg.dense.mult.MatrixVectorMult * @see org.ejml.ops.SpecializedOps * @see org.ejml.ops.MatrixFeatures * * @author Peter Abeles */ @SuppressWarnings({"ForLoopReplaceableByForEach"}) public class CommonOps { /** *

Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( b.numCols == 1 ) { MatrixVectorMult.mult(a,b,c); } else if( b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.mult_reorder(a,b,c); } else { MatrixMatrixMult.mult_small(a,b,c); } } /** *

Performs the following operation:
*
* c = α * a * b
*
* cij = α ∑k=1:n { * aik * bkj} *

* * @param alpha Scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here if( b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.mult_reorder(alpha,a,b,c); } else { MatrixMatrixMult.mult_small(alpha,a,b,c); } } /** *

Performs the following operation:
*
* c = aT * b
*
* cij = ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( b.numCols == 1 ) { // todo check a.numCols == 1 and do inner product? // there are significantly faster algorithms when dealing with vectors if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixVectorMult.multTransA_reorder(a,b,c); } else { MatrixVectorMult.multTransA_small(a,b,c); } } else if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH || b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.multTransA_reorder(a,b,c); } else { MatrixMatrixMult.multTransA_small(a,b,c); } } /** *

Performs the following operation:
*
* c = α * aT * b
*
* cij = α ∑k=1:n { aki * bkj} *

* * @param alpha Scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransA( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH || b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.multTransA_reorder(alpha,a,b,c); } else { MatrixMatrixMult.multTransA_small(alpha,a,b,c); } } /** *

* Performs the following operation:
*
* c = a * bT
* cij = ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransB( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( b.numRows == 1 ) { MatrixVectorMult.mult(a,b,c); } else { MatrixMatrixMult.multTransB(a,b,c); } } /** *

* Performs the following operation:
*
* c = α * a * bT
* cij = α ∑k=1:n { aik * bjk} *

* * @param alpha Scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransB( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here MatrixMatrixMult.multTransB(alpha,a,b,c); } /** *

* Performs the following operation:
*
* c = aT * bT
* cij = ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransAB( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( b.numRows == 1) { // there are significantly faster algorithms when dealing with vectors if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixVectorMult.multTransA_reorder(a,b,c); } else { MatrixVectorMult.multTransA_small(a,b,c); } } else if( a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH ) { MatrixMatrixMult.multTransAB_aux(a,b,c,null); } else { MatrixMatrixMult.multTransAB(a,b,c); } } /** *

* Performs the following operation:
*
* c = α * aT * bT
* cij = α ∑k=1:n { aki * bjk} *

* * @param alpha Scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multTransAB( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here if( a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH ) { MatrixMatrixMult.multTransAB_aux(alpha,a,b,c,null); } else { MatrixMatrixMult.multTransAB(alpha,a,b,c); } } /** *

* Computes the dot product or inner product between two vectors. If the two vectors are columns vectors * then it is defined as:
* {@code dot(a,b) = aT * b}
* If the vectors are column or row or both is ignored by this function. *

* @param a Vector * @param b Vector * @return Dot product of the two vectors */ public static double dot( D1Matrix64F a , D1Matrix64F b ) { if( !MatrixFeatures.isVector(a) || !MatrixFeatures.isVector(b)) throw new RuntimeException("Both inputs must be vectors"); return VectorVectorMult.innerProd(a,b); } /** *

Computes the matrix multiplication inner product:
*
* c = aT * a
*
* cij = ∑k=1:n { aki * akj} *

* *

* Is faster than using a generic matrix multiplication by taking advantage of symmetry. For * vectors there is an even faster option, see {@link org.ejml.alg.dense.mult.VectorVectorMult#innerProd(org.ejml.data.D1Matrix64F, org.ejml.data.D1Matrix64F)} *

* * @param a The matrix being multiplied. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multInner( RowD1Matrix64F a , RowD1Matrix64F c ) { if( a.numCols != c.numCols || a.numCols != c.numRows ) throw new IllegalArgumentException("Rows and columns of 'c' must be the same as the columns in 'a'"); if( a.numCols >= EjmlParameters.MULT_INNER_SWITCH ) { MatrixMultProduct.inner_small(a, c); } else { MatrixMultProduct.inner_reorder(a, c); } } /** *

Computes the matrix multiplication outer product:
*
* c = a * aT
*
* cij = ∑k=1:m { aik * ajk} *

* *

* Is faster than using a generic matrix multiplication by taking advantage of symmetry. *

* * @param a The matrix being multiplied. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multOuter( RowD1Matrix64F a , RowD1Matrix64F c ) { if( a.numRows != c.numCols || a.numRows != c.numRows ) throw new IllegalArgumentException("Rows and columns of 'c' must be the same as the rows in 'a'"); MatrixMultProduct.outer(a, c); } /** *

* Performs the following operation:
*
* c = c + a * b
* cij = cij + ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( b.numCols == 1 ) { MatrixVectorMult.multAdd(a,b,c); } else { if( b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.multAdd_reorder(a,b,c); } else { MatrixMatrixMult.multAdd_small(a,b,c); } } } /** *

* Performs the following operation:
*
* c = c + α * a * b
* cij = cij + α * ∑k=1:n { aik * bkj} *

* * @param alpha scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here if( b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.multAdd_reorder(alpha,a,b,c); } else { MatrixMatrixMult.multAdd_small(alpha,a,b,c); } } /** *

* Performs the following operation:
*
* c = c + aT * b
* cij = cij + ∑k=1:n { aki * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( b.numCols == 1 ) { if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixVectorMult.multAddTransA_reorder(a,b,c); } else { MatrixVectorMult.multAddTransA_small(a,b,c); } } else { if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH || b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.multAddTransA_reorder(a,b,c); } else { MatrixMatrixMult.multAddTransA_small(a,b,c); } } } /** *

* Performs the following operation:
*
* c = c + α * aT * b
* cij =cij + α * ∑k=1:n { aki * bkj} *

* * @param alpha scaling factor * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransA( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH || b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult.multAddTransA_reorder(alpha,a,b,c); } else { MatrixMatrixMult.multAddTransA_small(alpha,a,b,c); } } /** *

* Performs the following operation:
*
* c = c + a * bT
* cij = cij + ∑k=1:n { aik * bjk} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransB( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { MatrixMatrixMult.multAddTransB(a,b,c); } /** *

* Performs the following operation:
*
* c = c + α * a * bT
* cij = cij + α * ∑k=1:n { aik * bjk} *

* * @param alpha Scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransB( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here MatrixMatrixMult.multAddTransB(alpha,a,b,c); } /** *

* Performs the following operation:
*
* c = c + aT * bT
* cij = cij + ∑k=1:n { aki * bjk} *

* * @param a The left matrix in the multiplication operation. Not Modified. * @param b The right matrix in the multiplication operation. Not Modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { if( b.numRows == 1 ) { // there are significantly faster algorithms when dealing with vectors if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixVectorMult.multAddTransA_reorder(a,b,c); } else { MatrixVectorMult.multAddTransA_small(a,b,c); } } else if( a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH ) { MatrixMatrixMult.multAddTransAB_aux(a,b,c,null); } else { MatrixMatrixMult.multAddTransAB(a,b,c); } } /** *

* Performs the following operation:
*
* c = c + α * aT * bT
* cij = cij + α * ∑k=1:n { aki * bjk} *

* * @param alpha Scaling factor. * @param a The left matrix in the multiplication operation. Not Modified. * @param b The right matrix in the multiplication operation. Not Modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAddTransAB( double alpha , RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c ) { // TODO add a matrix vectory multiply here if( a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH ) { MatrixMatrixMult.multAddTransAB_aux(alpha,a,b,c,null); } else { MatrixMatrixMult.multAddTransAB(alpha,a,b,c); } } /** *

* Solves for x in the following equation:
*
* A*x = b *

* *

* If the system could not be solved then false is returned. If it returns true * that just means the algorithm finished operating, but the results could still be bad * because 'A' is singular or nearly singular. *

* *

* If repeat calls to solve are being made then one should consider using {@link LinearSolverFactory} * instead. *

* *

* It is ok for 'b' and 'x' to be the same matrix. *

* * @param a A matrix that is m by n. Not modified. * @param b A matrix that is n by k. Not modified. * @param x A matrix that is m by k. Modified. * * @return true if it could invert the matrix false if it could not. */ public static boolean solve( DenseMatrix64F a , DenseMatrix64F b , DenseMatrix64F x ) { LinearSolver solver = LinearSolverFactory.general(a.numRows,a.numCols); // make sure the inputs 'a' and 'b' are not modified solver = new LinearSolverSafe(solver); if( !solver.setA(a) ) return false; solver.solve(b,x); return true; } /** *

Performs an "in-place" transpose.

* *

* For square matrices the transpose is truly in-place and does not require * additional memory. For non-square matrices, internally a temporary matrix is declared and * {@link #transpose(org.ejml.data.DenseMatrix64F, org.ejml.data.DenseMatrix64F)} is invoked. *

* * @param mat The matrix that is to be transposed. Modified. */ public static void transpose( DenseMatrix64F mat ) { if( mat.numCols == mat.numRows ){ TransposeAlgs.square(mat); } else { DenseMatrix64F b = new DenseMatrix64F(mat.numCols,mat.numRows); transpose(mat,b); mat.set(b); } } /** *

* Transposes matrix 'a' and stores the results in 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'. *

* * @param A The original matrix. Not modified. * @param A_tran Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static DenseMatrix64F transpose( DenseMatrix64F A, DenseMatrix64F A_tran) { if( A_tran == null ) { A_tran = new DenseMatrix64F(A.numCols,A.numRows); } else { if( A.numRows != A_tran.numCols || A.numCols != A_tran.numRows ) { throw new IllegalArgumentException("Incompatible matrix dimensions"); } } if( A.numRows > EjmlParameters.TRANSPOSE_SWITCH && A.numCols > EjmlParameters.TRANSPOSE_SWITCH ) TransposeAlgs.block(A,A_tran,EjmlParameters.BLOCK_WIDTH); else TransposeAlgs.standard(A,A_tran); return A_tran; } /** *

* This computes the trace of the matrix:
*
* trace = ∑i=1:n { aii }
* where n = min(numRows,numCols) *

* * @param a A square matrix. Not modified. */ public static double trace( RowD1Matrix64F a ) { int N = Math.min(a.numRows,a.numCols); double sum = 0; int index = 0; for( int i = 0; i < N; i++ ) { sum += a.get(index); index += 1 + a.numCols; } return sum; } /** * Returns the determinant of the matrix. If the inverse of the matrix is also * needed, then using {@link org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64} directly (or any * similar algorithm) can be more efficient. * * @param mat The matrix whose determinant is to be computed. Not modified. * @return The determinant. */ public static double det( DenseMatrix64F mat ) { int numCol = mat.getNumCols(); int numRow = mat.getNumRows(); if( numCol != numRow ) { throw new IllegalArgumentException("Must be a square matrix."); } else if( numCol <= UnrolledDeterminantFromMinor.MAX ) { // slight performance boost overall by doing it this way // when it was the case statement the VM did some strange optimization // and made case 2 about 1/2 the speed if( numCol >= 2 ) { return UnrolledDeterminantFromMinor.det(mat); } else { return mat.get(0); } } else { LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); if( alg.inputModified() ) { mat = mat.copy(); } if( !alg.decompose(mat) ) return 0.0; return alg.computeDeterminant().real; } } /** *

* Performs a matrix inversion operation on the specified matrix and stores the results * in the same matrix.
*
* a = a-1 *

* *

* If the algorithm could not invert the matrix then false is returned. If it returns true * that just means the algorithm finished. The results could still be bad * because the matrix is singular or nearly singular. *

* * @param mat The matrix that is to be inverted. Results are stored here. Modified. * @return true if it could invert the matrix false if it could not. */ public static boolean invert( DenseMatrix64F mat) { if( mat.numCols <= UnrolledInverseFromMinor.MAX ) { if( mat.numCols != mat.numRows ) { throw new IllegalArgumentException("Must be a square matrix."); } if( mat.numCols >= 2 ) { UnrolledInverseFromMinor.inv(mat,mat); } else { mat.set(0, 1.0/mat.get(0)); } } else { LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); LinearSolverLu_D64 solver = new LinearSolverLu_D64(alg); if( solver.setA(mat) ) { solver.invert(mat); } else { return false; } } return true; } /** *

* Performs a matrix inversion operation that does not modify the original * and stores the results in another matrix. The two matrices must have the * same dimension.
*
* b = a-1 *

* *

* If the algorithm could not invert the matrix then false is returned. If it returns true * that just means the algorithm finished. The results could still be bad * because the matrix is singular or nearly singular. *

* *

* For medium to large matrices there might be a slight performance boost to using * {@link LinearSolverFactory} instead. *

* * @param mat The matrix that is to be inverted. Not modified. * @param result Where the inverse matrix is stored. Modified. * @return true if it could invert the matrix false if it could not. */ public static boolean invert( DenseMatrix64F mat, DenseMatrix64F result ) { if( mat.numCols <= UnrolledInverseFromMinor.MAX ) { if( mat.numCols != mat.numRows ) { throw new IllegalArgumentException("Must be a square matrix."); } if( result.numCols >= 2 ) { UnrolledInverseFromMinor.inv(mat,result); } else { result.set(0, 1.0/mat.get(0)); } } else { LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); LinearSolverLu_D64 solver = new LinearSolverLu_D64(alg); if( solver.modifiesA() ) mat = mat.copy(); if( !solver.setA(mat)) return false; solver.invert(result); } return true; } /** *

* Computes the Moore-Penrose pseudo-inverse:
*
* pinv(A) = (ATA)-1 AT
* or
* pinv(A) = AT(AAT)-1
*

*

* Internally it uses {@link org.ejml.alg.dense.linsol.svd.SolvePseudoInverseSvd} to compute the inverse. For performance reasons, this should only * be used when a matrix is singular or nearly singular. *

* @param A A m by n Matrix. Not modified. * @param invA Where the computed pseudo inverse is stored. n by m. Modified. * @return */ public static void pinv( DenseMatrix64F A , DenseMatrix64F invA ) { LinearSolver solver = LinearSolverFactory.pseudoInverse(true); if( solver.modifiesA()) A = A.copy(); if( !solver.setA(A) ) throw new IllegalArgumentException("Invert failed, maybe a bug?"); solver.invert(invA); } /** * Converts the columns in a matrix into a set of vectors. * * @param A Matrix. Not modified. * @param v * @return An array of vectors. */ public static DenseMatrix64F[] columnsToVector(DenseMatrix64F A, DenseMatrix64F[] v) { DenseMatrix64F []ret; if( v == null || v.length < A.numCols ) { ret = new DenseMatrix64F[ A.numCols ]; } else { ret = v; } for( int i = 0; i < ret.length; i++ ) { if( ret[i] == null ) { ret[i] = new DenseMatrix64F(A.numRows,1); } else { ret[i].reshape(A.numRows,1, false); } DenseMatrix64F u = ret[i]; for( int j = 0; j < A.numRows; j++ ) { u.set(j,0, A.get(j,i)); } } return ret; } /** * Converts the rows in a matrix into a set of vectors. * * @param A Matrix. Not modified. * @param v * @return An array of vectors. */ public static DenseMatrix64F[] rowsToVector(DenseMatrix64F A, DenseMatrix64F[] v) { DenseMatrix64F []ret; if( v == null || v.length < A.numRows ) { ret = new DenseMatrix64F[ A.numRows ]; } else { ret = v; } for( int i = 0; i < ret.length; i++ ) { if( ret[i] == null ) { ret[i] = new DenseMatrix64F(A.numCols,1); } else { ret[i].reshape(A.numCols,1, false); } DenseMatrix64F u = ret[i]; for( int j = 0; j < A.numCols; j++ ) { u.set(j,0, A.get(i,j)); } } return ret; } /** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @see #identity(int) * * @param mat A square matrix. */ public static void setIdentity( RowD1Matrix64F mat ) { int width = mat.numRows < mat.numCols ? mat.numRows : mat.numCols; Arrays.fill(mat.data,0,mat.getNumElements(),0); int index = 0; for( int i = 0; i < width; i++ , index += mat.numCols + 1) { mat.data[index] = 1; } } /** *

* Creates an identity matrix of the specified size.
*
* aij = 0 if i ≠ j
* aij = 1 if i = j
*

* * @param width The width and height of the identity matrix. * @return A new instance of an identity matrix. */ public static DenseMatrix64F identity( int width ) { DenseMatrix64F ret = new DenseMatrix64F(width,width); for( int i = 0; i < width; i++ ) { ret.set(i,i,1.0); } return ret; } /** * Creates a rectangular matrix which is zero except along the diagonals. * * @param numRows Number of rows in the matrix. * @param numCols NUmber of columns in the matrix. * @return A matrix with diagonal elements equal to one. */ public static DenseMatrix64F identity( int numRows , int numCols ) { DenseMatrix64F ret = new DenseMatrix64F(numRows,numCols); int small = numRows < numCols ? numRows : numCols; for( int i = 0; i < small; i++ ) { ret.set(i,i,1.0); } return ret; } /** *

* Creates a new square matrix whose diagonal elements are specified by diagEl and all * the other elements are zero.
*
* aij = 0 if i ≤ j
* aij = diag[i] if i = j
*

* * @see #diagR * * @param diagEl Contains the values of the diagonal elements of the resulting matrix. * @return A new matrix. */ public static DenseMatrix64F diag( double ...diagEl ) { return diag(null,diagEl.length,diagEl); } /** * @see #diag(double...) */ public static DenseMatrix64F diag( DenseMatrix64F ret , int width , double ...diagEl ) { if( ret == null ) { ret = new DenseMatrix64F(width,width); } else { if( ret.numRows != width || ret.numCols != width ) throw new IllegalArgumentException("Unexpected matrix size"); CommonOps.fill(ret, 0); } for( int i = 0; i < width; i++ ) { ret.unsafe_set(i, i, diagEl[i]); } return ret; } /** *

* Creates a new rectangular matrix whose diagonal elements are specified by diagEl and all * the other elements are zero.
*
* aij = 0 if i ≤ j
* aij = diag[i] if i = j
*

* * @see #diag * * @param numRows Number of rows in the matrix. * @param numCols Number of columns in the matrix. * @param diagEl Contains the values of the diagonal elements of the resulting matrix. * @return A new matrix. */ public static DenseMatrix64F diagR( int numRows , int numCols , double ...diagEl ) { DenseMatrix64F ret = new DenseMatrix64F(numRows,numCols); int o = Math.min(numRows,numCols); for( int i = 0; i < o; i++ ) { ret.set(i,i,diagEl[i]); } return ret; } /** *

* The Kronecker product of two matrices is defined as:
* Cij = aijB
* where Cij is a sub matrix inside of C ∈ ℜ m*k × n*l, * A ∈ ℜ m × n, and B ∈ ℜ k × l. *

* * @param A The left matrix in the operation. Not modified. * @param B The right matrix in the operation. Not modified. * @param C Where the results of the operation are stored. Modified. * @return The results of the operation. */ public static void kron( DenseMatrix64F A , DenseMatrix64F B , DenseMatrix64F C ) { int numColsC = A.numCols*B.numCols; int numRowsC = A.numRows*B.numRows; if( C.numCols != numColsC || C.numRows != numRowsC) { throw new IllegalArgumentException("C does not have the expected dimensions"); } // TODO see comment below // this will work well for small matrices // but an alternative version should be made for large matrices for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { double a = A.get(i,j); for( int rowB = 0; rowB < B.numRows; rowB++ ) { for( int colB = 0; colB < B.numCols; colB++ ) { double val = a*B.get(rowB,colB); C.set(i*B.numRows+rowB,j*B.numCols+colB,val); } } } } } /** *

* Extracts a submatrix from 'src' and inserts it in a submatrix in 'dst'. *

*

* si-y0 , j-x0 = oij for all y0 ≤ i < y1 and x0 ≤ j < x1
*
* where 'sij' is an element in the submatrix and 'oij' is an element in the * original matrix. *

* * @param src The original matrix which is to be copied. Not modified. * @param srcX0 Start column. * @param srcX1 Stop column+1. * @param srcY0 Start row. * @param srcY1 Stop row+1. * @param dst Where the submatrix are stored. Modified. * @param dstY0 Start row in dst. * @param dstX0 start column in dst. */ public static void extract( RealMatrix64F src, int srcY0, int srcY1, int srcX0, int srcX1, RealMatrix64F dst , int dstY0, int dstX0 ) { if( srcY1 < srcY0 || srcY0 < 0 || srcY1 > src.getNumRows() ) throw new IllegalArgumentException("srcY1 < srcY0 || srcY0 < 0 || srcY1 > src.numRows"); if( srcX1 < srcX0 || srcX0 < 0 || srcX1 > src.getNumCols() ) throw new IllegalArgumentException("srcX1 < srcX0 || srcX0 < 0 || srcX1 > src.numCols"); int w = srcX1-srcX0; int h = srcY1-srcY0; if( dstY0+h > dst.getNumRows() ) throw new IllegalArgumentException("dst is too small in rows"); if( dstX0+w > dst.getNumCols() ) throw new IllegalArgumentException("dst is too small in columns"); // interestingly, the performance is only different for small matrices but identical for larger ones if( src instanceof DenseMatrix64F && dst instanceof DenseMatrix64F ) { ImplCommonOps_DenseMatrix64F.extract((DenseMatrix64F)src,srcY0,srcX0,(DenseMatrix64F)dst,dstY0,dstX0, h, w); } else { ImplCommonOps_Matrix64F.extract(src,srcY0,srcX0,dst,dstY0,dstX0, h, w); } } /** *

* Creates a new matrix which is the specified submatrix of 'src' *

*

* si-y0 , j-x0 = oij for all y0 ≤ i < y1 and x0 ≤ j < x1
*
* where 'sij' is an element in the submatrix and 'oij' is an element in the * original matrix. *

* * @param src The original matrix which is to be copied. Not modified. * @param srcX0 Start column. * @param srcX1 Stop column+1. * @param srcY0 Start row. * @param srcY1 Stop row+1. * @return Extracted submatrix. */ public static DenseMatrix64F extract( DenseMatrix64F src, int srcY0, int srcY1, int srcX0, int srcX1 ) { if( srcY1 <= srcY0 || srcY0 < 0 || srcY1 > src.numRows ) throw new IllegalArgumentException("srcY1 <= srcY0 || srcY0 < 0 || srcY1 > src.numRows"); if( srcX1 <= srcX0 || srcX0 < 0 || srcX1 > src.numCols ) throw new IllegalArgumentException("srcX1 <= srcX0 || srcX0 < 0 || srcX1 > src.numCols"); int w = srcX1-srcX0; int h = srcY1-srcY0; DenseMatrix64F dst = new DenseMatrix64F(h,w); ImplCommonOps_DenseMatrix64F.extract(src,srcY0,srcX0,dst,0,0, h, w); return dst; } /** *

* Extracts the diagonal elements 'src' write it to the 'dst' vector. 'dst' * can either be a row or column vector. *

* * @param src Matrix whose diagonal elements are being extracted. Not modified. * @param dst A vector the results will be written into. Modified. */ public static void extractDiag( DenseMatrix64F src, DenseMatrix64F dst ) { int N = Math.min(src.numRows, src.numCols); if( !MatrixFeatures.isVector(dst) ) { throw new IllegalArgumentException("Expected a vector for dst."); } else if( dst.getNumElements() != N ) { throw new IllegalArgumentException("Expected "+N+" elements in dst."); } for( int i = 0; i < N; i++ ) { dst.set( i , src.unsafe_get(i,i) ); } } /** * Extracts the row from a matrix. * @param a Input matrix * @param row Which row is to be extracted * @param out output. Storage for the extracted row. If null then a new vector will be returned. * @return The extracted row. */ public static DenseMatrix64F extractRow( DenseMatrix64F a , int row , DenseMatrix64F out ) { if( out == null) out = new DenseMatrix64F(1,a.numCols); else if( !MatrixFeatures.isVector(out) || out.getNumElements() != a.numCols ) throw new IllegalArgumentException("Output must be a vector of length "+a.numCols); System.arraycopy(a.data,a.getIndex(row,0),out.data,0,a.numCols); return out; } /** * Extracts the column from a matrix. * @param a Input matrix * @param column Which column is to be extracted * @param out output. Storage for the extracted column. If null then a new vector will be returned. * @return The extracted column. */ public static DenseMatrix64F extractColumn( DenseMatrix64F a , int column , DenseMatrix64F out ) { if( out == null) out = new DenseMatrix64F(a.numRows,1); else if( !MatrixFeatures.isVector(out) || out.getNumElements() != a.numRows ) throw new IllegalArgumentException("Output must be a vector of length "+a.numRows); int index = column; for (int i = 0; i < a.numRows; i++, index += a.numCols ) { out.data[i] = a.data[index]; } return out; } /** * Inserts matrix 'src' into matrix 'dest' with the (0,0) of src at (row,col) in dest. * This is equivalent to calling extract(src,0,src.numRows,0,src.numCols,dest,destY0,destX0). * * @param src matrix that is being copied into dest. Not modified. * @param dest Where src is being copied into. Modified. * @param destY0 Start row for the copy into dest. * @param destX0 Start column for the copy into dest. */ public static void insert( RealMatrix64F src, RealMatrix64F dest, int destY0, int destX0) { extract(src,0,src.getNumRows(),0,src.getNumCols(),dest,destY0,destX0); } /** *

* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMax( D1Matrix64F a ) { final int size = a.getNumElements(); double max = a.get(0); for( int i = 1; i < size; i++ ) { double val = a.get(i); if( val >= max ) { max = val; } } return max; } /** *

* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementMaxAbs( D1Matrix64F a ) { final int size = a.getNumElements(); double max = 0; for( int i = 0; i < size; i++ ) { double val = Math.abs(a.get( i )); if( val > max ) { max = val; } } return max; } /** *

* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The value of element in the matrix with the minimum value. */ public static double elementMin( D1Matrix64F a ) { final int size = a.getNumElements(); double min = a.get(0); for( int i = 1; i < size; i++ ) { double val = a.get(i); if( val < min ) { min = val; } } return min; } /** *

* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max element value of the matrix. */ public static double elementMinAbs( D1Matrix64F a ) { final int size = a.getNumElements(); double min = Double.MAX_VALUE; for( int i = 0; i < size; i++ ) { double val = Math.abs(a.get(i)); if( val < min ) { min = val; } } return min; } /** *

Performs the an element by element multiplication operation:
*
* aij = aij * bij
*

* @param a The left matrix in the multiplication operation. Modified. * @param b The right matrix in the multiplication operation. Not modified. */ public static void elementMult( D1Matrix64F a , D1Matrix64F b ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.times(i , b.get(i)); } } /** *

Performs the an element by element multiplication operation:
*
* cij = aij * bij
*

* @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementMult( D1Matrix64F a , D1Matrix64F b , D1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numRows != c.numRows || a.numCols != c.numCols ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set( i , a.get(i) * b.get(i) ); } } /** *

Performs the an element by element division operation:
*
* aij = aij / bij
*

* @param a The left matrix in the division operation. Modified. * @param b The right matrix in the division operation. Not modified. */ public static void elementDiv( D1Matrix64F a , D1Matrix64F b ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.div(i , b.get(i)); } } /** *

Performs the an element by element division operation:
*
* cij = aij / bij
*

* @param a The left matrix in the division operation. Not modified. * @param b The right matrix in the division operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void elementDiv( D1Matrix64F a , D1Matrix64F b , D1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numRows != c.numRows || a.numCols != c.numCols ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set( i , a.get(i) / b.get(i) ); } } /** *

* Computes the sum of all the elements in the matrix:
*
* sum(i=1:m , j=1:n ; aij) *

* * @param mat An m by n matrix. Not modified. * @return The sum of the elements. */ public static double elementSum( D1Matrix64F mat ) { double total = 0; int size = mat.getNumElements(); for( int i = 0; i < size; i++ ) { total += mat.get(i); } return total; } /** *

* Computes the sum of the absolute value all the elements in the matrix:
*
* sum(i=1:m , j=1:n ; |aij|) *

* * @param mat An m by n matrix. Not modified. * @return The sum of the absolute value of each element. */ public static double elementSumAbs( D1Matrix64F mat ) { double total = 0; int size = mat.getNumElements(); for( int i = 0; i < size; i++ ) { total += Math.abs(mat.get(i)); } return total; } /** *

* Element-wise power operation
* cij = aij ^ bij *

* * @param A left side * @param B right side * @param C output (modified) */ public static void elementPower( D1Matrix64F A , D1Matrix64F B , D1Matrix64F C ) { if( A.numRows != B.numRows || A.numRows != C.numRows || A.numCols != B.numCols || A.numCols != C.numCols ) { throw new IllegalArgumentException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = Math.pow(A.data[i],B.data[i]); } } /** *

* Element-wise power operation
* cij = a ^ bij *

* * @param a left scalar * @param B right side * @param C output (modified) */ public static void elementPower( double a , D1Matrix64F B , D1Matrix64F C ) { if( B.numRows != C.numRows || B.numCols != C.numCols ) { throw new IllegalArgumentException("All matrices must be the same shape"); } int size = B.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = Math.pow(a,B.data[i]); } } /** *

* Element-wise power operation
* cij = aij ^ b *

* * @param A left side * @param b right scalar * @param C output (modified) */ public static void elementPower( D1Matrix64F A , double b, D1Matrix64F C ) { if( A.numRows != C.numRows || A.numCols != C.numCols ) { throw new IllegalArgumentException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = Math.pow(A.data[i],b); } } /** *

* Element-wise log operation
* cij = Math.log(aij) *

* * @param A input * @param C output (modified) */ public static void elementLog( D1Matrix64F A , D1Matrix64F C ) { if( A.numCols != C.numCols || A.numRows != C.numRows ) { throw new IllegalArgumentException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = Math.log(A.data[i]); } } /** *

* Element-wise exp operation
* cij = Math.log(aij) *

* * @param A input * @param C output (modified) */ public static void elementExp( D1Matrix64F A , D1Matrix64F C ) { if( A.numCols != C.numCols || A.numRows != C.numRows ) { throw new IllegalArgumentException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = Math.exp(A.data[i]); } } /** *

* Computes the sum of each row in the input matrix and returns the results in a vector:
*
* bj = sum(i=1:n ; |aji|) *

* * @param input INput matrix whose rows are summed. * @param output Optional storage for output. Must be a vector. If null a row vector is returned. Modified. * @return Vector containing the sum of each row in the input. */ public static DenseMatrix64F sumRows( DenseMatrix64F input , DenseMatrix64F output ) { if( output == null ) { output = new DenseMatrix64F(input.numRows,1); } else if( output.getNumElements() != input.numRows ) throw new IllegalArgumentException("Output does not have enough elements to store the results"); for( int row = 0; row < input.numRows; row++ ) { double total = 0; int end = (row+1)*input.numCols; for( int index = row*input.numCols; index < end; index++ ) { total += input.data[index]; } output.set(row,total); } return output; } /** *

* Computes the sum of each column in the input matrix and returns the results in a vector:
*
* bj = sum(i=1:m ; |aij|) *

* * @param input INput matrix whose rows are summed. * @param output Optional storage for output. Must be a vector. If null a column vector is returned. Modified. * @return Vector containing the sum of each row in the input. */ public static DenseMatrix64F sumCols( DenseMatrix64F input , DenseMatrix64F output ) { if( output == null ) { output = new DenseMatrix64F(1,input.numCols); } else if( output.getNumElements() != input.numCols ) throw new IllegalArgumentException("Output does not have enough elements to store the results"); for( int cols = 0; cols < input.numCols; cols++ ) { double total = 0; int index = cols; int end = index + input.numCols*input.numRows; for( ; index < end; index += input.numCols ) { total += input.data[index]; } output.set(cols,total); } return output; } /** *

Performs the following operation:
*
* a = a + b
* aij = aij + bij
*

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals( D1Matrix64F a , D1Matrix64F b ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.plus(i, b.get(i)); } } /** *

Performs the following operation:
*
* a = a + β * b
* aij = aij + β * bij *

* * @param beta The number that matrix 'b' is multiplied by. * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals( D1Matrix64F a , double beta, D1Matrix64F b ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.plus(i, beta * b.get(i)); } } /** *

Performs the following operation:
*
* c = a + b
* cij = aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( final D1Matrix64F a , final D1Matrix64F b , final D1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numCols != c.numCols || a.numRows != c.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set( i , a.get(i)+b.get(i) ); } } /** *

Performs the following operation:
*
* c = a + β * b
* cij = aij + β * bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param beta Scaling factor for matrix b. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( D1Matrix64F a , double beta , D1Matrix64F b , D1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numCols != c.numCols || a.numRows != c.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set( i , a.get(i)+beta*b.get(i) ); } } /** *

Performs the following operation:
*
* c = α * a + β * b
* cij = α * aij + β * bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param alpha A scaling factor for matrix a. * @param a A Matrix. Not modified. * @param beta A scaling factor for matrix b. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( double alpha , D1Matrix64F a , double beta , D1Matrix64F b , D1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numCols != c.numCols || a.numRows != c.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set(i , alpha*a.get(i) + beta*b.get(i)); } } /** *

Performs the following operation:
*
* c = α * a + b
* cij = α * aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param alpha A scaling factor for matrix a. * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( double alpha , D1Matrix64F a , D1Matrix64F b , D1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numCols != c.numCols || a.numRows != c.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set( i , alpha*a.get(i) + b.get(i)); } } /** *

Performs an in-place scalar addition:
*
* a = a + val
* aij = aij + val
*

* * @param a A matrix. Modified. * @param val The value that's added to each element. */ public static void add( D1Matrix64F a , double val ) { final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.plus( i , val); } } /** *

Performs scalar addition:
*
* c = a + val
* cij = aij + val
*

* * @param a A matrix. Not modified. * @param c A matrix. Modified. * @param val The value that's added to each element. */ public static void add( D1Matrix64F a , double val , D1Matrix64F c ) { if( a.numRows != c.numRows || a.numCols != c.numCols ) { throw new IllegalArgumentException("Dimensions of a and c do not match."); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i] + val; } } /** *

Performs matrix scalar subtraction:
*
* c = a - val
* cij = aij - val
*

* * @param a (input) A matrix. Not modified. * @param val (input) The value that's subtracted to each element. * @param c (Output) A matrix. Modified. */ public static void subtract( D1Matrix64F a , double val , D1Matrix64F c ) { if( a.numRows != c.numRows || a.numCols != c.numCols ) { throw new IllegalArgumentException("Dimensions of a and c do not match."); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i] - val; } } /** *

Performs matrix scalar subtraction:
*
* c = val - a
* cij = val - aij
*

* * @param val (input) The value that's subtracted to each element. * @param a (input) A matrix. Not modified. * @param c (Output) A matrix. Modified. */ public static void subtract( double val , D1Matrix64F a , D1Matrix64F c ) { if( a.numRows != c.numRows || a.numCols != c.numCols ) { throw new IllegalArgumentException("Dimensions of a and c do not match."); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.data[i] = val - a.data[i]; } } /** *

Performs the following subtraction operation:
*
* a = a - b
* aij = aij - bij *

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void subtractEquals(D1Matrix64F a, D1Matrix64F b) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.data[i] -= b.data[i]; } } /** *

Performs the following subtraction operation:
*
* c = a - b
* cij = aij - bij *

*

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix. Modified. */ public static void subtract(D1Matrix64F a, D1Matrix64F b, D1Matrix64F c) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new IllegalArgumentException("The 'a' and 'b' matrices do not have compatible dimensions"); } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i] - b.data[i]; } } /** *

* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij *

* * @param a The matrix that is to be scaled. Modified. * @param alpha the amount each element is multiplied by. */ public static void scale( double alpha , D1Matrix64F a ) { // on very small matrices (2 by 2) the call to getNumElements() can slow it down // slightly compared to other libraries since it involves an extra multiplication. final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { a.data[i] *= alpha; } } /** *

* Performs an element by element scalar multiplication.
*
* bij = α*aij *

* * @param alpha the amount each element is multiplied by. * @param a The matrix that is to be scaled. Not modified. * @param b Where the scaled matrix is stored. Modified. */ public static void scale( double alpha , D1Matrix64F a , D1Matrix64F b) { if( a.numRows != b.numRows || a.numCols != b.numCols ) throw new IllegalArgumentException("Matrices must have the same shape"); final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { b.data[i] = a.data[i]*alpha; } } /** *

* Performs an in-place element by element scalar division with the scalar on top.
*
* aij = &alpha/aij; *

* * @param a The matrix whose elements are divide the scalar. Modified. * @param alpha top value in division */ public static void divide( double alpha , D1Matrix64F a ) { final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { a.data[i] = alpha/a.data[i]; } } /** *

* Performs an in-place element by element scalar division with the scalar on bottom.
*
* aij = aij/α *

* * @param a The matrix whose elements are to be divided. Modified. * @param alpha the amount each element is divided by. */ public static void divide( D1Matrix64F a , double alpha) { final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { a.data[i] /= alpha; } } /** *

* Performs an element by element scalar division with the scalar on top.
*
* bij = &alpha/aij; *

* * @param alpha The numerator. * @param a The matrix whose elements are the divisor. Not modified. * @param b Where the results are stored. Modified. */ public static void divide( double alpha , D1Matrix64F a , D1Matrix64F b) { if( a.numRows != b.numRows || a.numCols != b.numCols ) throw new IllegalArgumentException("Matrices must have the same shape"); final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { b.data[i] = alpha/a.data[i]; } } /** *

* Performs an element by element scalar division with the scalar on botton.
*
* bij = aij /α *

* * @param a The matrix whose elements are to be divided. Not modified. * @param alpha the amount each element is divided by. * @param b Where the results are stored. Modified. */ public static void divide( D1Matrix64F a , double alpha , D1Matrix64F b) { if( a.numRows != b.numRows || a.numCols != b.numCols ) throw new IllegalArgumentException("Matrices must have the same shape"); final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { b.data[i] = a.data[i]/alpha; } } /** *

* Changes the sign of every element in the matrix.
*
* aij = -aij *

* * @param a A matrix. Modified. */ public static void changeSign( D1Matrix64F a ) { final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { a.data[i] = -a.data[i]; } } /** *

* Changes the sign of every element in the matrix.
*
* outputij = -inputij *

* * @param input A matrix. Modified. */ public static void changeSign( D1Matrix64F input , D1Matrix64F output) { if( input.numRows != output.numRows || input.numCols != output.numCols ) throw new IllegalArgumentException("Matrices must have the same shape"); final int size = input.getNumElements(); for( int i = 0; i < size; i++ ) { output.data[i] = -input.data[i]; } } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param a A matrix whose elements are about to be set. Modified. * @param value The value each element will have. */ public static void fill(D1Matrix64F a, double value) { Arrays.fill(a.data,0,a.getNumElements(),value); } /** *

* Puts the augmented system matrix into reduced row echelon form (RREF) using Gauss-Jordan * elimination with row (partial) pivots. A matrix is said to be in RREF is the following conditions are true: *

* *
    *
  1. If a row has non-zero entries, then the first non-zero entry is 1. This is known as the leading one.
  2. *
  3. If a column contains a leading one then all other entries in that column are zero.
  4. *
  5. If a row contains a leading 1, then each row above contains a leading 1 further to the left.
  6. *
* *

* [1] Page 19 in, Otter Bretscherm "Linear Algebra with Applications" Prentice-Hall Inc, 1997 *

* * @see RrefGaussJordanRowPivot * * @param A Input matrix. Unmodified. * @param numUnknowns Number of unknowns/columns that are reduced. Set to -1 to default to * Math.min(A.numRows,A.numCols), which works for most systems. * @param reduced Storage for reduced echelon matrix. If null then a new matrix is returned. Modified. * @return Reduced echelon form of A */ public static DenseMatrix64F rref( DenseMatrix64F A , int numUnknowns, DenseMatrix64F reduced ) { if( reduced == null ) { reduced = new DenseMatrix64F(A.numRows,A.numCols); } else if( reduced.numCols != A.numCols || reduced.numRows != A.numRows ) throw new IllegalArgumentException("'re' must have the same shape as the original input matrix"); if( numUnknowns <= 0 ) numUnknowns = Math.min(A.numCols,A.numRows); ReducedRowEchelonForm alg = new RrefGaussJordanRowPivot(); alg.setTolerance(elementMaxAbs(A)* UtilEjml.EPS*Math.max(A.numRows,A.numCols)); reduced.set(A); alg.reduce(reduced, numUnknowns); return reduced; } } ejml-0.28/main/dense64/src/org/ejml/ops/CovarianceOps.java000066400000000000000000000104401256171534400233020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.alg.dense.misc.UnrolledInverseFromMinor; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import java.util.Random; /** * Contains operations specific to covariance matrices. * * @author Peter Abeles */ public class CovarianceOps { public static double TOL = 1e-9; /** * This is a fairly light weight check to see of a covariance matrix is valid. * It checks to see if the diagonal elements are all positive, which they should be * if it is valid. Not all invalid covariance matrices will be caught by this method. * * @return true if valid and false if invalid */ public static boolean isValidFast( DenseMatrix64F cov ) { return MatrixFeatures.isDiagonalPositive(cov); } /** * Performs a variety of tests to see if the provided matrix is a valid * covariance matrix. * * @return 0 = is valid 1 = failed positive diagonal, 2 = failed on symmetry, 2 = failed on positive definite */ public static int isValid( DenseMatrix64F cov ) { if( !MatrixFeatures.isDiagonalPositive(cov) ) return 1; if( !MatrixFeatures.isSymmetric(cov,TOL) ) return 2; if( !MatrixFeatures.isPositiveSemidefinite(cov) ) return 3; return 0; } /** * Performs a matrix inversion operations that takes advantage of the special * properties of a covariance matrix. * * @param cov On input it is a covariance matrix, on output it is the inverse. Modified. * @return true if it could invert the matrix false if it could not. */ public static boolean invert( DenseMatrix64F cov ) { return invert(cov,cov); } /** * Performs a matrix inversion operations that takes advantage of the special * properties of a covariance matrix. * * @param cov A covariance matrix. Not modified. * @param cov_inv The inverse of cov. Modified. * @return true if it could invert the matrix false if it could not. */ public static boolean invert( final DenseMatrix64F cov , final DenseMatrix64F cov_inv ) { if( cov.numCols <= 4 ) { if( cov.numCols != cov.numRows ) { throw new IllegalArgumentException("Must be a square matrix."); } if( cov.numCols >= 2 ) UnrolledInverseFromMinor.inv(cov,cov_inv); else cov_inv.data[0] = 1.0/cov_inv.data[0]; } else { LinearSolver solver = LinearSolverFactory.symmPosDef(cov.numRows); // wrap it to make sure the covariance is not modified. solver = new LinearSolverSafe(solver); if( !solver.setA(cov) ) return false; solver.invert(cov_inv); } return true; } /** * Sets vector to a random value based upon a zero-mean multivariate Gaussian distribution with * covariance 'cov'. If repeat calls are made to this class, consider using {@link CovarianceRandomDraw} instead. * * @param cov The distirbutions covariance. Not modified. * @param vector The random vector. Modified. * @param rand Random number generator. */ public static void randomVector( DenseMatrix64F cov , DenseMatrix64F vector , Random rand ) { CovarianceRandomDraw rng = new CovarianceRandomDraw(rand,cov); rng.next(vector); } } ejml-0.28/main/dense64/src/org/ejml/ops/CovarianceRandomDraw.java000066400000000000000000000050131256171534400245770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionInner_D64; import org.ejml.data.DenseMatrix64F; import java.util.Random; import static org.ejml.ops.CommonOps.multAdd; /** * Generates random vectors based on a zero mean multivariate Gaussian distribution. The covariance * matrix is provided in the constructor. */ public class CovarianceRandomDraw { private DenseMatrix64F A; private Random rand; private DenseMatrix64F r; /** * Creates a random distribution with the specified mean and covariance. The references * to the variables are not saved, their value are copied. * * @param rand Used to create the random numbers for the draw. Reference is saved. * @param cov The covariance of the distribution. Not modified. */ public CovarianceRandomDraw( Random rand , DenseMatrix64F cov ) { r = new DenseMatrix64F(cov.numRows,1); CholeskyDecompositionInner_D64 cholesky = new CholeskyDecompositionInner_D64( true); if( cholesky.inputModified() ) cov = cov.copy(); if( !cholesky.decompose(cov) ) throw new RuntimeException("Decomposition failed!"); A = cholesky.getT(); this.rand = rand; } /** * Makes a draw on the distribution. The results are added to parameter 'x' */ public void next( DenseMatrix64F x ) { for( int i = 0; i < r.numRows; i++ ) { r.set(i,0,rand.nextGaussian()); } multAdd(A,r,x); } /** * Computes the likelihood of the random draw * * @return The likelihood. */ public double computeLikelihoodP() { double ret = 1.0; for( int i = 0; i < r.numRows; i++ ) { double a = r.get(i,0); ret *= Math.exp(-a*a/2.0); } return ret; } }ejml-0.28/main/dense64/src/org/ejml/ops/EigenOps.java000066400000000000000000000240011256171534400222550ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.eig.EigenPowerMethod; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.Eigenpair64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.interfaces.linsol.LinearSolver; /** * Additional functions related to eigenvalues and eigenvectors of a matrix. * * @author Peter Abeles */ public class EigenOps { /** *

* Given matrix A and an eigen vector of A, compute the corresponding eigen value. This is * the Rayleigh quotient.
*
* xTAx / xTx *

* * * @param A Matrix. Not modified. * @param eigenVector An eigen vector of A. Not modified. * @return The corresponding eigen value. */ public static double computeEigenValue( DenseMatrix64F A , DenseMatrix64F eigenVector ) { double bottom = VectorVectorMult.innerProd(eigenVector,eigenVector); double top = VectorVectorMult.innerProdA(eigenVector,A,eigenVector); return top/bottom; } /** *

* Given an eigenvalue it computes an eigenvector using inverse iteration: *
* for i=1:MAX {
* (A - μI)z(i) = q(i-1)
* q(i) = z(i) / ||z(i)||
* λ(i) = q(i)T A q(i)
* }
*

*

* NOTE: If there is another eigenvalue that is very similar to the provided one then there * is a chance of it converging towards that one instead. The larger a matrix is the more * likely this is to happen. *

* @param A Matrix whose eigenvector is being computed. Not modified. * @param eigenvalue The eigenvalue in the eigen pair. * @return The eigenvector or null if none could be found. */ public static Eigenpair64F computeEigenVector( DenseMatrix64F A , double eigenvalue ) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("Must be a square matrix."); DenseMatrix64F M = new DenseMatrix64F(A.numRows,A.numCols); DenseMatrix64F x = new DenseMatrix64F(A.numRows,1); DenseMatrix64F b = new DenseMatrix64F(A.numRows,1); CommonOps.fill(b, 1); // perturb the eigenvalue slightly so that its not an exact solution the first time // eigenvalue -= eigenvalue*UtilEjml.EPS*10; double origEigenvalue = eigenvalue; SpecializedOps.addIdentity(A,M,-eigenvalue); double threshold = NormOps.normPInf(A)*UtilEjml.EPS; double prevError = Double.MAX_VALUE; boolean hasWorked = false; LinearSolver solver = LinearSolverFactory.linear(M.numRows); double perp = 0.0001; for( int i = 0; i < 200; i++ ) { boolean failed = false; // if the matrix is singular then the eigenvalue is within machine precision // of the true value, meaning that x must also be. if( !solver.setA(M) ) { failed = true; } else { solver.solve(b,x); } // see if solve silently failed if( MatrixFeatures.hasUncountable(x)) { failed = true; } if( failed ) { if( !hasWorked ) { // if it failed on the first trial try perturbing it some more double val = i % 2 == 0 ? 1.0-perp : 1.0 + perp; // maybe this should be turn into a parameter allowing the user // to configure the wise of each step eigenvalue = origEigenvalue * Math.pow(val,i/2+1); SpecializedOps.addIdentity(A,M,-eigenvalue); } else { // otherwise assume that it was so accurate that the matrix was singular // and return that result return new Eigenpair64F(eigenvalue,b); } } else { hasWorked = true; b.set(x); NormOps.normalizeF(b); // compute the residual CommonOps.mult(M,b,x); double error = NormOps.normPInf(x); if( error-prevError > UtilEjml.EPS*10) { // if the error increased it is probably converging towards a different // eigenvalue // CommonOps.set(b,1); prevError = Double.MAX_VALUE; hasWorked = false; double val = i % 2 == 0 ? 1.0-perp : 1.0 + perp; eigenvalue = origEigenvalue * Math.pow(val,1); } else { // see if it has converged if(error <= threshold || Math.abs(prevError-error) <= UtilEjml.EPS) return new Eigenpair64F(eigenvalue,b); // update everything prevError = error; eigenvalue = VectorVectorMult.innerProdA(b,A,b); } SpecializedOps.addIdentity(A,M,-eigenvalue); } } return null; } /** *

* Computes the dominant eigen vector for a matrix. The dominant eigen vector is an * eigen vector associated with the largest eigen value. *

* *

* WARNING: This function uses the power method. There are known cases where it will not converge. * It also seems to converge to non-dominant eigen vectors some times. Use at your own risk. *

* * @param A A matrix. Not modified. */ // TODO maybe do the regular power method, estimate the eigenvalue, then shift invert? public static Eigenpair64F dominantEigenpair( DenseMatrix64F A ) { EigenPowerMethod power = new EigenPowerMethod(A.numRows); // eh maybe 0.1 is a good value. who knows. if( !power.computeShiftInvert(A,0.1) ) return null; return null;//power.getEigenVector(); } /** *

* Generates a bound for the largest eigen value of the provided matrix using Perron-Frobenius * theorem. This function only applies to non-negative real matrices. *

* *

* For "stochastic" matrices (Markov process) this should return one for the upper and lower bound. *

* * @param A Square matrix with positive elements. Not modified. * @param bound Where the results are stored. If null then a matrix will be declared. Modified. * @return Lower and upper bound in the first and second elements respectively. */ public static double [] boundLargestEigenValue( DenseMatrix64F A , double []bound ) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("A must be a square matrix."); double min = Double.MAX_VALUE; double max = 0; int n = A.numRows; for( int i = 0; i < n; i++ ) { double total = 0; for( int j = 0; j < n; j++ ) { double v = A.get(i,j); if( v < 0 ) throw new IllegalArgumentException("Matrix must be positive"); total += v; } if( total < min ) { min = total; } if( total > max ) { max = total; } } if( bound == null ) bound = new double[2]; bound[0] = min; bound[1] = max; return bound; } /** *

* A diagonal matrix where real diagonal element contains a real eigenvalue. If an eigenvalue * is imaginary then zero is stored in its place. *

* * @param eig An eigenvalue decomposition which has already decomposed a matrix. * @return A diagonal matrix containing the eigenvalues. */ public static DenseMatrix64F createMatrixD( EigenDecomposition eig ) { int N = eig.getNumberOfEigenvalues(); DenseMatrix64F D = new DenseMatrix64F( N , N ); for( int i = 0; i < N; i++ ) { Complex64F c = eig.getEigenvalue(i); if( c.isReal() ) { D.set(i,i,c.real); } } return D; } /** *

* Puts all the real eigenvectors into the columns of a matrix. If an eigenvalue is imaginary * then the corresponding eigenvector will have zeros in its column. *

* * @param eig An eigenvalue decomposition which has already decomposed a matrix. * @return An m by m matrix containing eigenvectors in its columns. */ public static DenseMatrix64F createMatrixV( EigenDecomposition eig ) { int N = eig.getNumberOfEigenvalues(); DenseMatrix64F V = new DenseMatrix64F( N , N ); for( int i = 0; i < N; i++ ) { Complex64F c = eig.getEigenvalue(i); if( c.isReal() ) { DenseMatrix64F v = eig.getEigenVector(i); if( v != null ) { for( int j = 0; j < N; j++ ) { V.set(j,i,v.get(j,0)); } } } } return V; } } ejml-0.28/main/dense64/src/org/ejml/ops/EjmlUnitTests.java000066400000000000000000000216031256171534400233230ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.*; /** * Contains various functions related to unit testing matrix operations. * * @author Peter Abeles */ public class EjmlUnitTests { /** * Checks to see if every element in A is countable. A doesn't have any element with * a value of NaN or infinite. * * @param A Matrix */ public static void assertCountable( RealMatrix64F A ) { for( int i = 0; i < A.getNumRows(); i++ ){ for( int j = 0; j < A.getNumCols(); j++ ) { assertTrue( !Double.isNaN(A.get(i,j)) , "NaN found at "+i+" "+j ); assertTrue( !Double.isInfinite(A.get(i,j)) , "Infinite found at "+i+" "+j ); } } } /** *

* Checks to see if A and B have the same shape. *

* * @param A Matrix * @param B Matrix */ public static void assertShape( Matrix A , Matrix B ) { assertTrue( A.getNumRows() == B.getNumRows() , "Number of rows do not match"); assertTrue( A.getNumCols() == B.getNumCols() , "Number of columns do not match"); } /** *

* Checks to see if the matrix has the specified number of rows and columns. *

* * @param A Matrix * @param numRows expected number of rows in the matrix * @param numCols expected number of columns in the matrix */ public static void assertShape( RealMatrix64F A , int numRows , int numCols ) { assertTrue( A.getNumRows() == numRows , "Unexpected number of rows."); assertTrue( A.getNumCols() == numCols , "Unexpected number of columns."); } /** *

* Checks to see if each element in the matrix is within tolerance of each other: *

* *

* The two matrices are identical with in tolerance if:
* |aij - bij| ≤ tol *

* *

* In addition if an element is NaN or infinite in one matrix it must be the same in the other. *

* * @param A Matrix A * @param B Matrix B * @param tol Tolerance */ public static void assertEqualsUncountable( RealMatrix64F A , RealMatrix64F B , double tol ) { assertShape(A, B); for (int i = 0; i < A.getNumRows(); i++) { for (int j = 0; j < A.getNumCols(); j++) { double valA = A.get(i, j); double valB = B.get(i, j); if (Double.isNaN(valA)) { assertTrue(Double.isNaN(valB), "At (" + i + "," + j + ") A = " + valA + " B = " + valB); } else if (Double.isInfinite(valA)) { assertTrue(Double.isInfinite(valB), "At (" + i + "," + j + ") A = " + valA + " B = " + valB); } else { double diff = Math.abs(valA - valB); assertTrue(diff <= tol, "At (" + i + "," + j + ") A = " + valA + " B = " + valB); } } } } /** *

* Checks to see if each element in the matrices are within tolerance of each other and countable: *

* *

* The two matrices are identical with in tolerance if:
* |aij - bij| ≤ tol *

* *

* The test will fail if any element in either matrix is NaN or infinite. *

* * @param A Matrix A * @param B Matrix B * @param tol Tolerance */ public static void assertEquals( RealMatrix64F A , RealMatrix64F B , double tol ) { assertShape(A,B); for( int i = 0; i < A.getNumRows(); i++ ){ for( int j = 0; j < A.getNumCols(); j++ ) { double valA = A.get(i,j); double valB = B.get(i,j); assertTrue(!Double.isNaN(valA) && !Double.isNaN(valB) ,"At ("+i+","+j+") A = "+valA+" B = "+valB); assertTrue(!Double.isInfinite(valA) && !Double.isInfinite(valB) ,"At ("+i+","+j+") A = "+valA+" B = "+valB); assertTrue(Math.abs( valA-valB) <= tol,"At ("+i+","+j+") A = "+valA+" B = "+valB); } } } public static void assertEquals( RealMatrix32F A , RealMatrix32F B , float tol ) { assertShape(A,B); for( int i = 0; i < A.getNumRows(); i++ ){ for( int j = 0; j < A.getNumCols(); j++ ) { float valA = A.get(i,j); float valB = B.get(i,j); assertTrue(!Float.isNaN(valA) && !Float.isNaN(valB) ,"At ("+i+","+j+") A = "+valA+" B = "+valB); assertTrue(!Float.isInfinite(valA) && !Float.isInfinite(valB) ,"At ("+i+","+j+") A = "+valA+" B = "+valB); assertTrue(Math.abs( valA-valB) <= tol,"At ("+i+","+j+") A = "+valA+" B = "+valB); } } } public static void assertEquals( Complex64F a , Complex64F b , double tol ) { assertTrue(!Double.isNaN(a.real) && !Double.isNaN(b.real) ,"real a = "+a.real+" b = "+b.real); assertTrue(!Double.isInfinite(a.real) && !Double.isInfinite(b.real) ,"real a = "+a.real+" b = "+b.real); assertTrue(Math.abs( a.real-b.real) <= tol,"real a = "+a.real+" b = "+b.real); assertTrue(!Double.isNaN(a.imaginary) && !Double.isNaN(b.imaginary) ,"imaginary a = "+a.imaginary+" b = "+b.imaginary); assertTrue(!Double.isInfinite(a.imaginary) && !Double.isInfinite(b.imaginary) ,"imaginary a = "+a.imaginary+" b = "+b.imaginary); assertTrue(Math.abs( a.imaginary-b.imaginary) <= tol,"imaginary a = "+a.imaginary+" b = "+b.imaginary); } public static void assertEquals( ComplexMatrix64F A , ComplexMatrix64F B , double tol ) { assertShape(A,B); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); for( int i = 0; i < A.getNumRows(); i++ ){ for( int j = 0; j < A.getNumCols(); j++ ) { A.get(i, j, a); B.get(i, j, b); assertTrue(!Double.isNaN(a.real) && !Double.isNaN(b.real) ,"Real At ("+i+","+j+") A = "+a.real+" B = "+b.real); assertTrue(!Double.isInfinite(a.real) && !Double.isInfinite(b.real) ,"Real At ("+i+","+j+") A = "+a.real+" B = "+b.real); assertTrue(Math.abs( a.real-b.real) <= tol,"Real At ("+i+","+j+") A = "+a.real+" B = "+b.real); assertTrue(!Double.isNaN(a.imaginary) && !Double.isNaN(b.imaginary) ,"Img At ("+i+","+j+") A = "+a.imaginary+" B = "+b.imaginary); assertTrue(!Double.isInfinite(a.imaginary) && !Double.isInfinite(b.imaginary) ,"Img At ("+i+","+j+") A = "+a.imaginary+" B = "+b.imaginary); assertTrue(Math.abs( a.imaginary-b.imaginary) <= tol,"Img At ("+i+","+j+") A = "+a.imaginary+" B = "+b.imaginary); } } } /** *

* Checks to see if the transpose of B is equal to A and countable: *

* *

* |aij - bji| ≤ tol *

* *

* The test will fail if any element in either matrix is NaN or infinite. *

* * @param A Matrix A * @param B Matrix B * @param tol Tolerance */ public static void assertEqualsTrans( RealMatrix64F A , RealMatrix64F B , double tol ) { assertShape(A,B.getNumCols(),B.getNumRows()); for( int i = 0; i < A.getNumRows(); i++ ){ for( int j = 0; j < A.getNumCols(); j++ ) { double valA = A.get(i,j); double valB = B.get(j,i); assertTrue(!Double.isNaN(valA) && !Double.isNaN(valB) ,"A("+i+","+j+") = "+valA+") B("+j+","+i+") = "+valB); assertTrue(!Double.isInfinite(valA) && !Double.isInfinite(valB) ,"A("+i+","+j+") = "+valA+") B("+j+","+i+") = "+valB); assertTrue(Math.abs( valA-valB) <= tol,"A("+i+","+j+") = "+valA+") B("+j+","+i+") = "+valB); } } } @SuppressWarnings({"ConstantConditions"}) private static void assertTrue( boolean result , String message ) { // if turned on use asserts assert result : message; // otherwise throw an exception if( !result ) throw new TestException(message); } public static class TestException extends RuntimeException { public TestException(String message) { super(message); } } } ejml-0.28/main/dense64/src/org/ejml/ops/MatrixComponent.java000066400000000000000000000050411256171534400236760ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.D1Matrix64F; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; /** * Renders a matrix as an image. Positive elements are shades of red, negative shades of blue, 0 is black. * * @author Peter Abeles */ public class MatrixComponent extends JPanel { BufferedImage image; public MatrixComponent( int width , int height ) { image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); setPreferredSize(new Dimension(width,height)); setMinimumSize(new Dimension(width,height)); } public synchronized void setMatrix( D1Matrix64F A ) { double maxValue = CommonOps.elementMaxAbs(A); renderMatrix(A,image,maxValue); repaint(); } public static void renderMatrix( D1Matrix64F M , BufferedImage image , double maxValue ) { int w = image.getWidth(); int h = image.getHeight(); double widthStep = (double)M.numCols / image.getWidth(); double heightStep = (double)M.numRows / image.getHeight(); for( int i = 0; i < h; i++ ) { for( int j = 0; j < w; j++ ) { double value = M.get( (int)(i*heightStep) , (int)(j*widthStep) ); if( value == 0 ){ image.setRGB(j,i,255 << 24); } else if( value > 0 ) { int p = 255-(int)(255.0*(value/maxValue)); int rgb = 255 << 24 | 255 << 16 | p << 8 | p; image.setRGB(j,i,rgb); } else { int p = 255+(int)(255.0*(value/maxValue)); int rgb = 255 << 24 | p << 16 | p << 8 | 255; image.setRGB(j,i,rgb); } } } } @Override public synchronized void paint( Graphics g ) { g.drawImage(image,0,0,this); } } ejml-0.28/main/dense64/src/org/ejml/ops/MatrixFeatures.java000066400000000000000000000516661256171534400235300ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionInner_D64; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.*; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.interfaces.decomposition.SingularValueDecomposition; /** *

* Used to compute features that describe the structure of a matrix. *

* *

* Unless explicitly stated otherwise it is assumed that the elements of input matrices * contain only real numbers. If an element is NaN or infinite then the behavior is undefined. * See IEEE 754 for more information on this issue. *

* * @author Peter Abeles */ public class MatrixFeatures { /** * Checks to see if any element in the matrix is NaN. * * @param m A matrix. Not modified. * @return True if any element in the matrix is NaN. */ public static boolean hasNaN( D1Matrix64F m ) { int length = m.getNumElements(); for( int i = 0; i < length; i++ ) { if( Double.isNaN(m.get(i))) return true; } return false; } /** * Checks to see if any element in the matrix is NaN of Infinite. * * @param m A matrix. Not modified. * @return True if any element in the matrix is NaN of Infinite. */ public static boolean hasUncountable( D1Matrix64F m ) { int length = m.getNumElements(); for( int i = 0; i < length; i++ ) { double a = m.get(i); if( Double.isNaN(a) || Double.isInfinite(a)) return true; } return false; } /** * Checks to see all the elements in the matrix are zeros * * @param m A matrix. Not modified. * @return True if all elements are zeros or false if not */ public static boolean isZeros( D1Matrix64F m , double tol ) { int length = m.getNumElements(); for( int i = 0; i < length; i++ ) { if( Math.abs(m.get(i)) > tol ) return false; } return true; } /** * Checks to see if the matrix is a vector or not. * * @param mat A matrix. Not modified. * * @return True if it is a vector and false if it is not. */ public static boolean isVector( Matrix mat ) { return (mat.getNumCols() == 1 || mat.getNumRows() == 1); } /** *

* Checks to see if the matrix is positive definite. *

*

* xT A x > 0
* for all x where x is a non-zero vector and A is a symmetric matrix. *

* * @param A square symmetric matrix. Not modified. * * @return True if it is positive definite and false if it is not. */ public static boolean isPositiveDefinite( DenseMatrix64F A ) { if( !isSquare(A)) return false; CholeskyDecompositionInner_D64 chol = new CholeskyDecompositionInner_D64(true); if( chol.inputModified() ) A = A.copy(); return chol.decompose(A); } /** *

* Checks to see if the matrix is positive semidefinite: *

*

* xT A x >= 0
* for all x where x is a non-zero vector and A is a symmetric matrix. *

* * @param A square symmetric matrix. Not modified. * * @return True if it is positive semidefinite and false if it is not. */ public static boolean isPositiveSemidefinite( DenseMatrix64F A ) { if( !isSquare(A)) return false; EigenDecomposition eig = DecompositionFactory.eig(A.numCols,false); if( eig.inputModified() ) A = A.copy(); eig.decompose(A); for( int i = 0; i < A.numRows; i++ ) { Complex64F v = eig.getEigenvalue(i); if( v.getReal() < 0 ) return false; } return true; } /** * Checks to see if it is a square matrix. A square matrix has * the same number of rows and columns. * * @param mat A matrix. Not modified. * @return True if it is a square matrix and false if it is not. */ public static boolean isSquare( D1Matrix64F mat ) { return mat.numCols == mat.numRows; } /** *

* Returns true if the matrix is symmetric within the tolerance. Only square matrices can be * symmetric. *

*

* A matrix is symmetric if:
* |aij - aji| ≤ tol *

* * @param m A matrix. Not modified. * @param tol Tolerance for how similar two elements need to be. * @return true if it is symmetric and false if it is not. */ public static boolean isSymmetric( DenseMatrix64F m , double tol ) { if( m.numCols != m.numRows ) return false; double max = CommonOps.elementMaxAbs(m); for( int i = 0; i < m.numRows; i++ ) { for( int j = 0; j < i; j++ ) { double a = m.get(i,j)/max; double b = m.get(j,i)/max; double diff = Math.abs(a-b); if( !(diff <= tol) ) { return false; } } } return true; } /** *

* Returns true if the matrix is perfectly symmetric. Only square matrices can be symmetric. *

*

* A matrix is symmetric if:
* aij == aji *

* * @param m A matrix. Not modified. * @return true if it is symmetric and false if it is not. */ public static boolean isSymmetric( DenseMatrix64F m ) { return isSymmetric(m,0.0); } /** *

* Checks to see if a matrix is skew symmetric with in tolerance:
*
* -A = AT
* or
* |aij + aji| ≤ tol *

* * @param A The matrix being tested. * @param tol Tolerance for being skew symmetric. * @return True if it is skew symmetric and false if it is not. */ public static boolean isSkewSymmetric( DenseMatrix64F A , double tol ){ if( A.numCols != A.numRows ) return false; for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < i; j++ ) { double a = A.get(i,j); double b = A.get(j,i); double diff = Math.abs(a+b); if( !(diff <= tol) ) { return false; } } } return true; } /** * Checks to see if the two matrices are inverses of each other. * * @param a A matrix. Not modified. * @param b A matrix. Not modified. */ public static boolean isInverse( DenseMatrix64F a , DenseMatrix64F b , double tol ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { return false; } int numRows = a.numRows; int numCols = a.numCols; for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { double total = 0; for( int k = 0; k < numCols; k++ ) { total += a.get(i,k)*b.get(k,j); } if( i == j ) { if( !(Math.abs(total-1) <= tol) ) return false; } else if( !(Math.abs(total) <= tol) ) return false; } } return true; } /** *

* Checks to see if each element in the two matrices are within tolerance of * each other: tol ≥ |aij - bij|. *

* *

* NOTE: If any of the elements are not countable then false is returned.
* NOTE: If a tolerance of zero is passed in this is equivalent to calling * {@link #isEquals(org.ejml.data.D1Matrix64F, org.ejml.data.D1Matrix64F)} *

* * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @param tol How close to being identical each element needs to be. * @return true if equals and false otherwise. */ public static boolean isEquals( D1Matrix64F a , D1Matrix64F b , double tol ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { return false; } if( tol == 0.0 ) return isEquals(a,b); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { if( !(tol >= Math.abs(a.get(i) - b.get(i))) ) { return false; } } return true; } /** *

* Checks to see if each element in the upper or lower triangular portion of the two matrices are within tolerance of * each other: tol ≥ |aij - bij|. *

* *

* NOTE: If any of the elements are not countable then false is returned.
* NOTE: If a tolerance of zero is passed in this is equivalent to calling * {@link #isEquals(org.ejml.data.D1Matrix64F, org.ejml.data.D1Matrix64F)} *

* * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @param upper true of upper triangular and false for lower. * @param tol How close to being identical each element needs to be. * @return true if equals and false otherwise. */ public static boolean isEqualsTriangle(RealMatrix64F a, RealMatrix64F b, boolean upper, double tol) { if( a.getNumRows() != b.getNumRows() || a.getNumCols() != b.getNumCols() ) { return false; } if( upper ) { for( int i = 0; i < a.getNumRows(); i++ ) { for( int j = i; j < a.getNumCols(); j++ ) { if( Math.abs(a.get(i,j)-b.get(i,j)) > tol ) return false; } } } else { for( int i = 0; i < a.getNumRows(); i++ ) { int end = Math.min(i,a.getNumCols()-1); for( int j = 0; j <= end; j++ ) { if( Math.abs(a.get(i,j)-b.get(i,j)) > tol ) return false; } } } return true; } /** *

* Checks to see if each element in the two matrices are equal: * aij == bij *

* *

* NOTE: If any of the elements are NaN then false is returned. If two corresponding * elements are both positive or negative infinity then they are equal. *

* * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @return true if identical and false otherwise. */ public static boolean isEquals( D1Matrix64F a, D1Matrix64F b ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { return false; } final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { if( !(a.get(i) == b.get(i)) ) { return false; } } return true; } /** *

* Checks to see if each corresponding element in the two matrices are * within tolerance of each other or have the some symbolic meaning. This * can handle NaN and Infinite numbers. *

* *

* If both elements are countable then the following equality test is used:
* |aij - bij| ≤ tol.
* Otherwise both numbers must both be Double.NaN, Double.POSITIVE_INFINITY, or * Double.NEGATIVE_INFINITY to be identical. *

* * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @param tol Tolerance for equality. * @return true if identical and false otherwise. */ public static boolean isIdentical( D1Matrix64F a, D1Matrix64F b , double tol ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { return false; } if( tol < 0 ) throw new IllegalArgumentException("Tolerance must be greater than or equal to zero."); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { double valA = a.get(i); double valB = b.get(i); // if either is negative or positive infinity the result will be positive infinity // if either is NaN the result will be NaN double diff = Math.abs(valA-valB); // diff = NaN == false // diff = infinity == false if( tol >= diff ) continue; if( Double.isNaN(valA) ) { return Double.isNaN(valB); } else if( Double.isInfinite(valA) ) { return valA == valB; } else { return false; } } return true; } /** *

* Checks to see if a matrix is orthogonal or isometric. *

* * @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static boolean isOrthogonal( DenseMatrix64F Q , double tol ) { if( Q.numRows < Q.numCols ) { throw new IllegalArgumentException("The number of rows must be more than or equal to the number of columns"); } DenseMatrix64F u[] = CommonOps.columnsToVector(Q, null); for( int i = 0; i < u.length; i++ ) { DenseMatrix64F a = u[i]; for( int j = i+1; j < u.length; j++ ) { double val = VectorVectorMult.innerProd(a,u[j]); if( !(Math.abs(val) <= tol)) return false; } } return true; } /** * Checks to see if the rows of the provided matrix are linearly independent. * * @param A Matrix whose rows are being tested for linear independence. * @return true if linearly independent and false otherwise. */ public static boolean isRowsLinearIndependent( DenseMatrix64F A ) { // LU decomposition LUDecomposition lu = DecompositionFactory.lu(A.numRows,A.numCols); if( lu.inputModified() ) A = A.copy(); if( !lu.decompose(A)) throw new RuntimeException("Decompositon failed?"); // if they are linearly independent it should not be singular return !lu.isSingular(); } /** * Checks to see if the provided matrix is within tolerance to an identity matrix. * * @param mat Matrix being examined. Not modified. * @param tol Tolerance. * @return True if it is within tolerance to an identify matrix. */ public static boolean isIdentity( DenseMatrix64F mat , double tol ) { // see if the result is an identity matrix int index = 0; for( int i = 0; i < mat.numRows; i++ ) { for( int j = 0; j < mat.numCols; j++ ) { if( i == j ) { if( !(Math.abs(mat.get(index++)-1) <= tol) ) return false; } else { if( !(Math.abs(mat.get(index++)) <= tol) ) return false; } } } return true; } /** * Checks to see if every value in the matrix is the specified value. * * @param mat The matrix being tested. Not modified. * @param val Checks to see if every element in the matrix has this value. * @param tol True if all the elements are within this tolerance. * @return true if the test passes. */ public static boolean isConstantVal( DenseMatrix64F mat , double val , double tol ) { // see if the result is an identity matrix int index = 0; for( int i = 0; i < mat.numRows; i++ ) { for( int j = 0; j < mat.numCols; j++ ) { if( !(Math.abs(mat.get(index++)-val) <= tol) ) return false; } } return true; } /** * Checks to see if all the diagonal elements in the matrix are positive. * * @param a A matrix. Not modified. * @return true if all the diagonal elements are positive, false otherwise. */ public static boolean isDiagonalPositive( DenseMatrix64F a ) { for( int i = 0; i < a.numRows; i++ ) { if( !(a.get(i,i) >= 0) ) return false; } return true; } // TODO write this public static boolean isFullRank( DenseMatrix64F a ) { throw new RuntimeException("Implement"); } /** *

* Checks to see if the two matrices are the negative of each other:
*
* aij = -bij *

* * @param a First matrix. Not modified. * @param b Second matrix. Not modified. * @param tol Numerical tolerance. * @return True if they are the negative of each other within tolerance. */ public static boolean isNegative(D1Matrix64F a, D1Matrix64F b, double tol) { if( a.numRows != b.numRows || a.numCols != b.numCols ) throw new IllegalArgumentException("Matrix dimensions must match"); int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { if( !(Math.abs(a.get(i)+b.get(i)) <= tol) ) return false; } return true; } /** *

* Checks to see if a matrix is upper triangular or Hessenberg. A Hessenberg matrix of degree N * has the following property:
*
* aij ≤ 0 for all i < j+N
*
* A triangular matrix is a Hessenberg matrix of degree 0. *

* @param A Matrix being tested. Not modified. * @param hessenberg The degree of being hessenberg. * @param tol How close to zero the lower left elements need to be. * @return If it is an upper triangular/hessenberg matrix or not. */ public static boolean isUpperTriangle(DenseMatrix64F A , int hessenberg , double tol ) { if( A.numRows != A.numCols ) return false; for( int i = hessenberg+1; i < A.numRows; i++ ) { for( int j = 0; j < i-hessenberg; j++ ) { if( !(Math.abs(A.get(i,j)) <= tol) ) { return false; } } } return true; } /** * Computes the rank of a matrix using a default tolerance. * * @param A Matrix whose rank is to be calculated. Not modified. * @return The matrix's rank. */ public static int rank( DenseMatrix64F A ) { return rank(A, UtilEjml.EPS*100); } /** * Computes the rank of a matrix using the specified tolerance. * * @param A Matrix whose rank is to be calculated. Not modified. * @param threshold The numerical threshold used to determine a singular value. * @return The matrix's rank. */ public static int rank( DenseMatrix64F A , double threshold ) { SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows,A.numCols,false,false,true); if( svd.inputModified() ) A = A.copy(); if( !svd.decompose(A) ) throw new RuntimeException("Decomposition failed"); return SingularOps.rank(svd, threshold); } /** * Computes the nullity of a matrix using the default tolerance. * * @param A Matrix whose rank is to be calculated. Not modified. * @return The matrix's nullity. */ public static int nullity( DenseMatrix64F A ) { return nullity(A, UtilEjml.EPS*100); } /** * Computes the nullity of a matrix using the specified tolerance. * * @param A Matrix whose rank is to be calculated. Not modified. * @param threshold The numerical threshold used to determine a singular value. * @return The matrix's nullity. */ public static int nullity( DenseMatrix64F A , double threshold ) { SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows,A.numCols,false,false,true); if( svd.inputModified() ) A = A.copy(); if( !svd.decompose(A) ) throw new RuntimeException("Decomposition failed"); return SingularOps.nullity(svd,threshold); } } ejml-0.28/main/dense64/src/org/ejml/ops/MatrixVisualization.java000066400000000000000000000035651256171534400246060ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.D1Matrix64F; import javax.swing.*; import java.awt.*; /** *

* Functions for visualizing matrices in a GUI matrices. *

* *

* NOTE: In some embedded applications there is no GUI or AWT is not supported (like in Android) so excluding * this class is necessary. *

* * @author Peter Abeles */ public class MatrixVisualization { /** * Creates a window visually showing the matrix's state. Block means an element is zero. * Red positive and blue negative. More intense the color larger the element's absolute value * is. * * @param A A matrix. * @param title Name of the window. */ public static void show( D1Matrix64F A , String title ) { JFrame frame = new JFrame(title); int width = 300; int height = 300; if( A.numRows > A.numCols) { width = width*A.numCols/A.numRows; } else { height = height*A.numRows/A.numCols; } MatrixComponent panel = new MatrixComponent(width,height); panel.setMatrix(A); frame.add(panel, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); } } ejml-0.28/main/dense64/src/org/ejml/ops/NormOps.java000066400000000000000000000321301256171534400221430ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.UtilEjml; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.SingularValueDecomposition; /** *

* Norms are a measure of the size of a vector or a matrix. One typical application is in error analysis. *

*

* Vector norms have the following properties: *

    *
  1. ||x|| > 0 if x ≠ 0 and ||0|| = 0
  2. *
  3. ||αx|| = |α| ||x||
  4. *
  5. ||x+y|| ≤ ||x|| + ||y||
  6. *
*

* *

* Matrix norms have the following properties: *

    *
  1. ||A|| > 0 if A ≠ 0 where A ∈ ℜ m × n
  2. *
  3. || α A || = |α| ||A|| where A ∈ ℜ m × n
  4. *
  5. ||A+B|| ≤ ||A|| + ||B|| where A and B are ∈ ℜ m × n
  6. *
  7. ||AB|| ≤ ||A|| ||B|| where A and B are ∈ ℜ m × m
  8. *
* Note that the last item in the list only applies to square matrices. *

* *

* Matrix norms can be induced from vector norms as is shown below:
*
* ||A||M = maxx≠0||Ax||v/||x||v
*
* where ||.||M is the induced matrix norm for the vector norm ||.||v. *

* *

* By default implementations that try to mitigate overflow/underflow are used. If the word fast is * found before a function's name that means it does not mitigate those issues, but runs a bit faster. *

* * @author Peter Abeles */ public class NormOps { /** * Normalizes the matrix such that the Frobenius norm is equal to one. * * @param A The matrix that is to be normalized. */ public static void normalizeF( DenseMatrix64F A ) { double val = normF(A); if( val == 0 ) return; int size = A.getNumElements(); for( int i = 0; i < size; i++) { A.div(i , val); } } /** *

* The condition number of a matrix is used to measure the sensitivity of the linear * system Ax=b. A value near one indicates that it is a well conditioned matrix.
*
* κp = ||A||p||A-1||p *

*

* If the matrix is not square then the condition of either ATA or AAT is computed. *

* @param A The matrix. * @param p p-norm * @return The condition number. */ public static double conditionP( DenseMatrix64F A , double p ) { if( p == 2 ) { return conditionP2(A); } else if( A.numRows == A.numCols ){ // square matrices are the typical case DenseMatrix64F A_inv = new DenseMatrix64F(A.numRows,A.numCols); if( !CommonOps.invert(A,A_inv) ) throw new IllegalArgumentException("A can't be inverted."); return normP(A,p) * normP(A_inv,p); } else { DenseMatrix64F pinv = new DenseMatrix64F(A.numCols,A.numRows); CommonOps.pinv(A,pinv); return normP(A,p) * normP(pinv,p); } } /** *

* The condition p = 2 number of a matrix is used to measure the sensitivity of the linear * system Ax=b. A value near one indicates that it is a well conditioned matrix.
*
* κ2 = ||A||2||A-1||2 *

*

* This is also known as the spectral condition number. *

* * @param A The matrix. * @return The condition number. */ public static double conditionP2( DenseMatrix64F A ) { SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows,A.numCols,false,false,true); svd.decompose(A); double[] singularValues = svd.getSingularValues(); int n = SingularOps.rank(svd,1e-12); if( n == 0 ) return 0; double smallest = Double.MAX_VALUE; double largest = Double.MIN_VALUE; for( double s : singularValues ) { if( s < smallest ) smallest = s; if( s > largest ) largest = s; } return largest/smallest; } /** *

* This implementation of the Frobenius norm is a straight forward implementation and can * be susceptible for overflow/underflow issues. A more resilient implementation is * {@link #normF}. *

* * @param a The matrix whose norm is computed. Not modified. */ public static double fastNormF( D1Matrix64F a ) { double total = 0; int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { double val = a.get(i); total += val*val; } return Math.sqrt(total); } /** *

* Computes the Frobenius matrix norm:
*
* normF = Sqrt{ ∑i=1:mj=1:n { aij2} } *

*

* This is equivalent to the element wise p=2 norm. See {@link #fastNormF} for another implementation * that is faster, but more prone to underflow/overflow errors. *

* * @param a The matrix whose norm is computed. Not modified. * @return The norm's value. */ public static double normF( D1Matrix64F a ) { double total = 0; double scale = CommonOps.elementMaxAbs(a); if( scale == 0.0 ) return 0.0; final int size = a.getNumElements(); for( int i = 0; i < size; i++ ) { double val = a.get(i)/scale; total += val*val; } return scale*Math.sqrt(total); } /** *

* Element wise p-norm:
*
* norm = {∑i=1:mj=1:n { |aij|p}}1/p *

* *

* This is not the same as the induced p-norm used on matrices, but is the same as the vector p-norm. *

* * @param A Matrix. Not modified. * @param p p value. * @return The norm's value. */ public static double elementP( RowD1Matrix64F A , double p ) { if( p == 1 ) { return CommonOps.elementSumAbs(A); } if( p == 2 ) { return normF(A); } else { double max = CommonOps.elementMaxAbs(A); if( max == 0.0 ) return 0.0; double total = 0; int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { double a = A.get(i)/max; total += Math.pow(Math.abs(a),p); } return max*Math.pow(total,1.0/p); } } /** * Same as {@link #elementP} but runs faster by not mitigating overflow/underflow related problems. * * @param A Matrix. Not modified. * @param p p value. * @return The norm's value. */ public static double fastElementP( D1Matrix64F A , double p ) { if( p == 2 ) { return fastNormF(A); } else { double total = 0; int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { double a = A.get(i); total += Math.pow(Math.abs(a),p); } return Math.pow(total,1.0/p); } } /** * Computes either the vector p-norm or the induced matrix p-norm depending on A * being a vector or a matrix respectively. * * @param A Vector or matrix whose norm is to be computed. * @param p The p value of the p-norm. * @return The computed norm. */ public static double normP( DenseMatrix64F A , double p ) { if( p == 1 ) { return normP1(A); } else if( p == 2 ) { return normP2(A); } else if( Double.isInfinite(p)) { return normPInf(A); } if( MatrixFeatures.isVector(A) ) { return elementP(A,p); } else { throw new IllegalArgumentException("Doesn't support induced norms yet."); } } /** * An unsafe but faster version of {@link #normP} that calls routines which are faster * but more prone to overflow/underflow problems. * * @param A Vector or matrix whose norm is to be computed. * @param p The p value of the p-norm. * @return The computed norm. */ public static double fastNormP( DenseMatrix64F A , double p ) { if( p == 1 ) { return normP1(A); } else if( p == 2 ) { return fastNormP2(A); } else if( Double.isInfinite(p)) { return normPInf(A); } if( MatrixFeatures.isVector(A) ) { return fastElementP(A,p); } else { throw new IllegalArgumentException("Doesn't support induced norms yet."); } } /** * Computes the p=1 norm. If A is a matrix then the induced norm is computed. * * @param A Matrix or vector. * @return The norm. */ public static double normP1( DenseMatrix64F A ) { if( MatrixFeatures.isVector(A)) { return CommonOps.elementSumAbs(A); } else { return inducedP1(A); } } /** * Computes the p=2 norm. If A is a matrix then the induced norm is computed. * * @param A Matrix or vector. * @return The norm. */ public static double normP2( DenseMatrix64F A ) { if( MatrixFeatures.isVector(A)) { return normF(A); } else { return inducedP2(A); } } /** * Computes the p=2 norm. If A is a matrix then the induced norm is computed. This * implementation is faster, but more prone to buffer overflow or underflow problems. * * @param A Matrix or vector. * @return The norm. */ public static double fastNormP2( DenseMatrix64F A ) { if( MatrixFeatures.isVector(A)) { return fastNormF(A); } else { return inducedP2(A); } } /** * Computes the p=∞ norm. If A is a matrix then the induced norm is computed. * * @param A Matrix or vector. * @return The norm. */ public static double normPInf( DenseMatrix64F A ) { if( MatrixFeatures.isVector(A)) { return CommonOps.elementMaxAbs(A); } else { return inducedPInf(A); } } /** *

* Computes the induced p = 1 matrix norm.
*
* ||A||1= max(j=1 to n; sum(i=1 to m; |aij|)) *

* * @param A Matrix. Not modified. * @return The norm. */ public static double inducedP1( DenseMatrix64F A ) { double max = 0; int m = A.numRows; int n = A.numCols; for( int j = 0; j < n; j++ ) { double total = 0; for( int i = 0; i < m; i++ ) { total += Math.abs(A.get(i,j)); } if( total > max ) { max = total; } } return max; } /** *

* Computes the induced p = 2 matrix norm, which is the largest singular value. *

* * @param A Matrix. Not modified. * @return The norm. */ public static double inducedP2( DenseMatrix64F A ) { SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows,A.numCols,false,false,true); if( !svd.decompose(A) ) throw new RuntimeException("Decomposition failed"); double[] singularValues = svd.getSingularValues(); // the largest singular value is the induced p2 norm return UtilEjml.max(singularValues,0,singularValues.length); } /** *

* Induced matrix p = infinity norm.
*
* ||A|| = max(i=1 to m; sum(j=1 to n; |aij|)) *

* * @param A A matrix. * @return the norm. */ public static double inducedPInf( DenseMatrix64F A ) { double max = 0; int m = A.numRows; int n = A.numCols; for( int i = 0; i < m; i++ ) { double total = 0; for( int j = 0; j < n; j++ ) { total += Math.abs(A.get(i,j)); } if( total > max ) { max = total; } } return max; } } ejml-0.28/main/dense64/src/org/ejml/ops/RandomMatrices.java000066400000000000000000000411651256171534400234660ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.SubmatrixOps; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import java.util.Random; /** * Contains a list of functions for creating random dense real matrices and vectors with different structures. * * @author Peter Abeles */ public class RandomMatrices { /** *

* Creates a randomly generated set of orthonormal vectors. At most it can generate the same * number of vectors as the dimension of the vectors. *

* *

* This is done by creating random vectors then ensuring that they are orthogonal * to all the ones previously created with reflectors. *

* *

* NOTE: This employs a brute force O(N3) algorithm. *

* * @param dimen dimension of the space which the vectors will span. * @param numVectors How many vectors it should generate. * @param rand Used to create random vectors. * @return Array of N random orthogonal vectors of unit length. */ // is there a faster algorithm out there? This one is a bit sluggish public static DenseMatrix64F[] createSpan( int dimen, int numVectors , Random rand ) { if( dimen < numVectors ) throw new IllegalArgumentException("The number of vectors must be less than or equal to the dimension"); DenseMatrix64F u[] = new DenseMatrix64F[numVectors]; u[0] = RandomMatrices.createRandom(dimen,1,-1,1,rand); NormOps.normalizeF(u[0]); for( int i = 1; i < numVectors; i++ ) { // System.out.println(" i = "+i); DenseMatrix64F a = new DenseMatrix64F(dimen,1); DenseMatrix64F r=null; for( int j = 0; j < i; j++ ) { // System.out.println("j = "+j); if( j == 0 ) r = RandomMatrices.createRandom(dimen,1,-1,1,rand); // find a vector that is normal to vector j // u[i] = (1/2)*(r + Q[j]*r) a.set(r); VectorVectorMult.householder(-2.0,u[j],r,a); CommonOps.add(r,a,a); CommonOps.scale(0.5,a); // UtilEjml.print(a); DenseMatrix64F t = a; a = r; r = t; // normalize it so it doesn't get too small double val = NormOps.normF(r); if( val == 0 || Double.isNaN(val) || Double.isInfinite(val)) throw new RuntimeException("Failed sanity check"); CommonOps.divide(r,val); } u[i] = r; } return u; } /** * Creates a random vector that is inside the specified span. * * @param span The span the random vector belongs in. * @param rand RNG * @return A random vector within the specified span. */ public static DenseMatrix64F createInSpan( DenseMatrix64F[] span , double min , double max , Random rand ) { DenseMatrix64F A = new DenseMatrix64F(span.length,1); DenseMatrix64F B = new DenseMatrix64F(span[0].getNumElements(),1); for( int i = 0; i < span.length; i++ ) { B.set(span[i]); double val = rand.nextDouble()*(max-min)+min; CommonOps.scale(val,B); CommonOps.add(A,B,A); } return A; } /** *

* Creates a random orthogonal or isometric matrix, depending on the number of rows and columns. * The number of rows must be more than or equal to the number of columns. *

* * @param numRows Number of rows in the generated matrix. * @param numCols Number of columns in the generated matrix. * @param rand Random number generator used to create matrices. * @return A new isometric matrix. */ public static DenseMatrix64F createOrthogonal( int numRows , int numCols , Random rand ) { if( numRows < numCols ) { throw new IllegalArgumentException("The number of rows must be more than or equal to the number of columns"); } DenseMatrix64F u[] = createSpan(numRows,numCols,rand); DenseMatrix64F ret = new DenseMatrix64F(numRows,numCols); for( int i = 0; i < numCols; i++ ) { SubmatrixOps.setSubMatrix(u[i],ret,0,0,0,i,numRows,1); } return ret; } /** * Creates a random diagonal matrix where the diagonal elements are selected from a uniform * distribution that goes from min to max. * * @param N Dimension of the matrix. * @param min Minimum value of a diagonal element. * @param max Maximum value of a diagonal element. * @param rand Random number generator. * @return A random diagonal matrix. */ public static DenseMatrix64F createDiagonal( int N , double min , double max , Random rand ) { return createDiagonal(N,N,min,max,rand); } /** * Creates a random matrix where all elements are zero but diagonal elements. Diagonal elements * randomly drawn from a uniform distribution from min to max, inclusive. * * @param numRows Number of rows in the returned matrix.. * @param numCols Number of columns in the returned matrix. * @param min Minimum value of a diagonal element. * @param max Maximum value of a diagonal element. * @param rand Random number generator. * @return A random diagonal matrix. */ public static DenseMatrix64F createDiagonal( int numRows , int numCols , double min , double max , Random rand ) { if( max < min ) throw new IllegalArgumentException("The max must be >= the min"); DenseMatrix64F ret = new DenseMatrix64F(numRows,numCols); int N = Math.min(numRows,numCols); double r = max-min; for( int i = 0; i < N; i++ ) { ret.set(i,i, rand.nextDouble()*r+min); } return ret; } /** *

* Creates a random matrix which will have the provided singular values. The length of sv * is assumed to be the rank of the matrix. This can be useful for testing purposes when one * needs to ensure that a matrix is not singular but randomly generated. *

* * @param numRows Number of rows in generated matrix. * @param numCols NUmber of columns in generated matrix. * @param rand Random number generator. * @param sv Singular values of the matrix. * @return A new matrix with the specified singular values. */ public static DenseMatrix64F createSingularValues(int numRows, int numCols, Random rand, double ...sv) { DenseMatrix64F U = RandomMatrices.createOrthogonal(numRows,numRows,rand); DenseMatrix64F V = RandomMatrices.createOrthogonal(numCols,numCols,rand); DenseMatrix64F S = new DenseMatrix64F(numRows,numCols); int min = Math.min(numRows,numCols); min = Math.min(min,sv.length); for( int i = 0; i < min; i++ ) { S.set(i,i,sv[i]); } DenseMatrix64F tmp = new DenseMatrix64F(numRows,numCols); CommonOps.mult(U,S,tmp); CommonOps.multTransB(tmp,V,S); return S; } /** * Creates a new random symmetric matrix that will have the specified real eigenvalues. * * @param num Dimension of the resulting matrix. * @param rand Random number generator. * @param eigenvalues Set of real eigenvalues that the matrix will have. * @return A random matrix with the specified eigenvalues. */ public static DenseMatrix64F createEigenvaluesSymm( int num, Random rand , double ...eigenvalues ) { DenseMatrix64F V = RandomMatrices.createOrthogonal(num,num,rand); DenseMatrix64F D = CommonOps.diag(eigenvalues); DenseMatrix64F temp = new DenseMatrix64F(num,num); CommonOps.mult(V,D,temp); CommonOps.multTransB(temp,V,D); return D; } /** * Returns a matrix where all the elements are selected independently from * a uniform distribution between 0 and 1 inclusive. * * @param numRow Number of rows in the new matrix. * @param numCol Number of columns in the new matrix. * @param rand Random number generator used to fill the matrix. * @return The randomly generated matrix. */ public static DenseMatrix64F createRandom( int numRow , int numCol , Random rand ) { DenseMatrix64F mat = new DenseMatrix64F(numRow,numCol); setRandom(mat,0,1,rand); return mat; } /** *

* Adds random values to each element in the matrix from an uniform distribution.
*
* aij = aij + U(min,max)
*

* * @param A The matrix who is to be randomized. Modified * @param min The minimum value each element can be. * @param max The maximum value each element can be.. * @param rand Random number generator used to fill the matrix. */ public static void addRandom( DenseMatrix64F A , double min , double max , Random rand ) { double d[] = A.getData(); int size = A.getNumElements(); double r = max-min; for( int i = 0; i < size; i++ ) { d[i] += r*rand.nextDouble()+min; } } /** *

* Returns a matrix where all the elements are selected independently from * a uniform distribution between 'min' and 'max' inclusive. *

* * @param numRow Number of rows in the new matrix. * @param numCol Number of columns in the new matrix. * @param min The minimum value each element can be. * @param max The maximum value each element can be. * @param rand Random number generator used to fill the matrix. * @return The randomly generated matrix. */ public static DenseMatrix64F createRandom( int numRow , int numCol , double min , double max , Random rand ) { DenseMatrix64F mat = new DenseMatrix64F(numRow,numCol); setRandom(mat,min,max,rand); return mat; } /** *

* Sets each element in the matrix to a value drawn from an uniform distribution from 0 to 1 inclusive. *

* * @param mat The matrix who is to be randomized. Modified. * @param rand Random number generator used to fill the matrix. */ public static void setRandom( DenseMatrix64F mat , Random rand ) { setRandom(mat,0,1,rand); } /** *

* Sets each element in the matrix to a value drawn from an uniform distribution from 'min' to 'max' inclusive. *

* * @param min The minimum value each element can be. * @param max The maximum value each element can be. * @param mat The matrix who is to be randomized. Modified. * @param rand Random number generator used to fill the matrix. */ public static void setRandom( D1Matrix64F mat , double min , double max , Random rand ) { double d[] = mat.getData(); int size = mat.getNumElements(); double r = max-min; for( int i = 0; i < size; i++ ) { d[i] = r*rand.nextDouble()+min; } } /** *

* Sets each element in the matrix to a value drawn from an Gaussian distribution with the specified mean and * standard deviation *

* * * @param numRow Number of rows in the new matrix. * @param numCol Number of columns in the new matrix. * @param mean Mean value in the distribution * @param stdev Standard deviation in the distribution * @param rand Random number generator used to fill the matrix. */ public static DenseMatrix64F createGaussian( int numRow , int numCol , double mean , double stdev , Random rand ) { DenseMatrix64F m = new DenseMatrix64F(numRow,numCol); setGaussian(m,mean,stdev,rand); return m; } /** *

* Sets each element in the matrix to a value drawn from an Gaussian distribution with the specified mean and * standard deviation *

* * @param mat The matrix who is to be randomized. Modified. * @param mean Mean value in the distribution * @param stdev Standard deviation in the distribution * @param rand Random number generator used to fill the matrix. */ public static void setGaussian( D1Matrix64F mat , double mean , double stdev , Random rand ) { double d[] = mat.getData(); int size = mat.getNumElements(); for( int i = 0; i < size; i++ ) { d[i] = mean + stdev*rand.nextGaussian(); } } /** * Creates a random symmetric positive definite matrix. * * @param width The width of the square matrix it returns. * @param rand Random number generator used to make the matrix. * @return The random symmetric positive definite matrix. */ public static DenseMatrix64F createSymmPosDef(int width, Random rand) { // This is not formally proven to work. It just seems to work. DenseMatrix64F a = new DenseMatrix64F(width,1); DenseMatrix64F b = new DenseMatrix64F(width,width); for( int i = 0; i < width; i++ ) { a.set(i,0,rand.nextDouble()); } CommonOps.multTransB(a,a,b); for( int i = 0; i < width; i++ ) { b.add(i,i,1); } return b; } /** * Creates a random symmetric matrix whose values are selected from an uniform distribution * from min to max, inclusive. * * @param length Width and height of the matrix. * @param min Minimum value an element can have. * @param max Maximum value an element can have. * @param rand Random number generator. * @return A symmetric matrix. */ public static DenseMatrix64F createSymmetric(int length, double min, double max, Random rand) { DenseMatrix64F A = new DenseMatrix64F(length,length); createSymmetric(A,min,max,rand); return A; } /** * Sets the provided square matrix to be a random symmetric matrix whose values are selected from an uniform distribution * from min to max, inclusive. * * @param A The matrix that is to be modified. Must be square. Modified. * @param min Minimum value an element can have. * @param max Maximum value an element can have. * @param rand Random number generator. */ public static void createSymmetric(DenseMatrix64F A, double min, double max, Random rand) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("A must be a square matrix"); double range = max-min; int length = A.numRows; for( int i = 0; i < length; i++ ) { for( int j = i; j < length; j++ ) { double val = rand.nextDouble()*range + min; A.set(i,j,val); A.set(j,i,val); } } } /** * Creates an upper triangular matrix whose values are selected from a uniform distribution. If hessenberg * is greater than zero then a hessenberg matrix of the specified degree is created instead. * * @param dimen Number of rows and columns in the matrix.. * @param hessenberg 0 for triangular matrix and > 0 for hessenberg matrix. * @param min minimum value an element can be. * @param max maximum value an element can be. * @param rand random number generator used. * @return The randomly generated matrix. */ public static DenseMatrix64F createUpperTriangle( int dimen , int hessenberg , double min , double max , Random rand ) { if( hessenberg < 0 ) throw new RuntimeException("hessenberg must be more than or equal to 0"); double range = max-min; DenseMatrix64F A = new DenseMatrix64F(dimen,dimen); for( int i = 0; i < dimen; i++ ) { int start = i <= hessenberg ? 0 : i-hessenberg; for( int j = start; j < dimen; j++ ) { A.set(i,j, rand.nextDouble()*range+min); } } return A; } } ejml-0.28/main/dense64/src/org/ejml/ops/SingularOps.java000066400000000000000000000352711256171534400230250ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.SingularValueDecomposition; /** * Operations related to singular value decomposition. * * @author Peter Abeles */ public class SingularOps { /** *

* Adjusts the matrices so that the singular values are in descending order. *

* *

* In most implementations of SVD the singular values are automatically arranged in in descending * order. In EJML this is not the case since it is often not needed and some computations can * be saved by not doing that. *

* * @param U Matrix. Modified. * @param tranU is U transposed or not. * @param W Diagonal matrix with singular values. Modified. * @param V Matrix. Modified. * @param tranV is V transposed or not. */ // TODO the number of copies can probably be reduced here public static void descendingOrder( DenseMatrix64F U , boolean tranU , DenseMatrix64F W , DenseMatrix64F V , boolean tranV ) { int numSingular = Math.min(W.numRows,W.numCols); checkSvdMatrixSize(U, tranU, W, V, tranV); for( int i = 0; i < numSingular; i++ ) { double bigValue=-1; int bigIndex=-1; // find the smallest singular value in the submatrix for( int j = i; j < numSingular; j++ ) { double v = W.get(j,j); if( v > bigValue ) { bigValue = v; bigIndex = j; } } // only swap if the current index is not the smallest if( bigIndex == i) continue; if( bigIndex == -1 ) { // there is at least one uncountable singular value. just stop here break; } double tmp = W.get(i,i); W.set(i,i,bigValue); W.set(bigIndex,bigIndex,tmp); if( V != null ) { swapRowOrCol(V, tranV, i, bigIndex); } if( U != null ) { swapRowOrCol(U, tranU, i, bigIndex); } } } /** *

* Similar to {@link #descendingOrder(org.ejml.data.DenseMatrix64F, boolean, org.ejml.data.DenseMatrix64F, org.ejml.data.DenseMatrix64F, boolean)} * but takes in an array of singular values instead. *

* * @param U Matrix. Modified. * @param tranU is U transposed or not. * @param singularValues Array of singular values. Modified. * @param numSingularValues Number of elements in singularValues array * @param V Matrix. Modified. * @param tranV is V transposed or not. */ public static void descendingOrder( DenseMatrix64F U , boolean tranU , double singularValues[] , int numSingularValues , DenseMatrix64F V , boolean tranV ) { // checkSvdMatrixSize(U, tranU, W, V, tranV); for( int i = 0; i < numSingularValues; i++ ) { double bigValue=-1; int bigIndex=-1; // find the smallest singular value in the submatrix for( int j = i; j < numSingularValues; j++ ) { double v = singularValues[j]; if( v > bigValue ) { bigValue = v; bigIndex = j; } } // only swap if the current index is not the smallest if( bigIndex == i) continue; if( bigIndex == -1 ) { // there is at least one uncountable singular value. just stop here break; } double tmp = singularValues[i]; singularValues[i] = bigValue; singularValues[bigIndex] = tmp; if( V != null ) { swapRowOrCol(V, tranV, i, bigIndex); } if( U != null ) { swapRowOrCol(U, tranU, i, bigIndex); } } } /** * Checks to see if all the provided matrices are the expected size for an SVD. If an error is encountered * then an exception is thrown. This automatically handles compact and non-compact formats */ public static void checkSvdMatrixSize(DenseMatrix64F U, boolean tranU, DenseMatrix64F W, DenseMatrix64F V, boolean tranV ) { int numSingular = Math.min(W.numRows,W.numCols); boolean compact = W.numRows == W.numCols; if( compact ) { if( U != null ) { if( tranU && U.numRows != numSingular ) throw new IllegalArgumentException("Unexpected size of matrix U"); else if( !tranU && U.numCols != numSingular ) throw new IllegalArgumentException("Unexpected size of matrix U"); } if( V != null ) { if( tranV && V.numRows != numSingular ) throw new IllegalArgumentException("Unexpected size of matrix V"); else if( !tranV && V.numCols != numSingular ) throw new IllegalArgumentException("Unexpected size of matrix V"); } } else { if( U != null && U.numRows != U.numCols ) throw new IllegalArgumentException("Unexpected size of matrix U"); if( V != null && V.numRows != V.numCols ) throw new IllegalArgumentException("Unexpected size of matrix V"); if( U != null && U.numRows != W.numRows ) throw new IllegalArgumentException("Unexpected size of W"); if( V != null && V.numRows != W.numCols ) throw new IllegalArgumentException("Unexpected size of W"); } } private static void swapRowOrCol(DenseMatrix64F M, boolean tran, int i, int bigIndex) { double tmp; if( tran ) { // swap the rows for( int col = 0; col < M.numCols; col++ ) { tmp = M.get(i,col); M.set(i,col,M.get(bigIndex,col)); M.set(bigIndex,col,tmp); } } else { // swap the columns for( int row = 0; row < M.numRows; row++ ) { tmp = M.get(row,i); M.set(row,i,M.get(row,bigIndex)); M.set(row,bigIndex,tmp); } } } /** *

* Returns the null-space from the singular value decomposition. The null space is a set of non-zero vectors that * when multiplied by the original matrix return zero. *

* *

* The null space is found by extracting the columns in V that are associated singular values less than * or equal to the threshold. In some situations a non-compact SVD is required. *

* * @param svd A precomputed decomposition. Not modified. * @param nullSpace Storage for null space. Will be reshaped as needed. Modified. * @param tol Threshold for selecting singular values. Try UtilEjml.EPS. * @return The null space. */ public static DenseMatrix64F nullSpace( SingularValueDecomposition svd , DenseMatrix64F nullSpace , double tol ) { int N = svd.numberOfSingularValues(); double s[] = svd.getSingularValues(); DenseMatrix64F V = svd.getV(null,true); if( V.numRows != svd.numCols() ) { throw new IllegalArgumentException("Can't compute the null space using a compact SVD for a matrix of this size."); } // first determine the size of the null space int numVectors = svd.numCols()-N; for( int i = 0; i < N; i++ ) { if( s[i] <= tol ) { numVectors++; } } // declare output data if( nullSpace == null ) { nullSpace = new DenseMatrix64F(numVectors,svd.numCols()); } else { nullSpace.reshape(numVectors,svd.numCols()); } // now extract the vectors int count = 0; for( int i = 0; i < N; i++ ) { if( s[i] <= tol ) { CommonOps.extract(V, i,i+1,0, V.numCols,nullSpace,count++,0); } } for( int i = N; i < svd.numCols(); i++ ) { CommonOps.extract(V, i,i+1,0, V.numCols,nullSpace,count++,0); } CommonOps.transpose(nullSpace); return nullSpace; } /** *

* The vector associated will the smallest singular value is returned as the null space * of the decomposed system. A right null space is returned if 'isRight' is set to true, * and a left null space if false. *

* * @param svd A precomputed decomposition. Not modified. * @param isRight true for right null space and false for left null space. Right is more commonly used. * @param nullVector Optional storage for a vector for the null space. Modified. * @return Vector in V associated with smallest singular value.. */ public static DenseMatrix64F nullVector( SingularValueDecomposition svd , boolean isRight , DenseMatrix64F nullVector ) { int N = svd.numberOfSingularValues(); double s[] = svd.getSingularValues(); DenseMatrix64F A = isRight ? svd.getV(null,true) : svd.getU(null,false); if( isRight ) { if( A.numRows != svd.numCols() ) { throw new IllegalArgumentException("Can't compute the null space using a compact SVD for a matrix of this size."); } if( nullVector == null ) { nullVector = new DenseMatrix64F(svd.numCols(),1); } } else { if( A.numCols != svd.numRows() ) { throw new IllegalArgumentException("Can't compute the null space using a compact SVD for a matrix of this size."); } if( nullVector == null ) { nullVector = new DenseMatrix64F(svd.numRows(),1); } } int smallestIndex = -1; if( isRight && svd.numCols() > svd.numRows() ) smallestIndex = svd.numCols()-1; else if( !isRight && svd.numCols() < svd.numRows() ) smallestIndex = svd.numRows()-1; else { // find the smallest singular value double smallestValue = Double.MAX_VALUE; for( int i = 0; i < N; i++ ) { if( s[i] < smallestValue ) { smallestValue = s[i]; smallestIndex = i; } } } // extract the null space if( isRight ) SpecializedOps.subvector(A,smallestIndex,0,A.numRows,true,0,nullVector); else SpecializedOps.subvector(A,0,smallestIndex,A.numRows,false,0,nullVector); return nullVector; } /** * Returns a reasonable threshold for singular values.

* * tol = max (size (A)) * largest sigma * eps; * * @param svd A precomputed decomposition. Not modified. * @return threshold for singular values */ public static double singularThreshold( SingularValueDecomposition svd ) { double largest = 0; double w[]= svd.getSingularValues(); int N = svd.numberOfSingularValues(); for( int j = 0; j < N; j++ ) { if( w[j] > largest) largest = w[j]; } int M = Math.max(svd.numCols(),svd.numRows()); return M*largest* UtilEjml.EPS; } /** * Extracts the rank of a matrix using a preexisting decomposition and default threshold. * * @see #singularThreshold(org.ejml.interfaces.decomposition.SingularValueDecomposition) * * @param svd A precomputed decomposition. Not modified. * @return The rank of the decomposed matrix. */ public static int rank( SingularValueDecomposition svd ) { double threshold = singularThreshold(svd); return rank(svd,threshold); } /** * Extracts the rank of a matrix using a preexisting decomposition. * * @see #singularThreshold(org.ejml.interfaces.decomposition.SingularValueDecomposition) * * @param svd A precomputed decomposition. Not modified. * @param threshold Tolerance used to determine of a singular value is singular. * @return The rank of the decomposed matrix. */ public static int rank( SingularValueDecomposition svd , double threshold ) { int numRank=0; double w[]= svd.getSingularValues(); int N = svd.numberOfSingularValues(); for( int j = 0; j < N; j++ ) { if( w[j] > threshold) numRank++; } return numRank; } /** * Extracts the nullity of a matrix using a preexisting decomposition and default threshold. * * @see #singularThreshold(org.ejml.interfaces.decomposition.SingularValueDecomposition) * * @param svd A precomputed decomposition. Not modified. * @return The nullity of the decomposed matrix. */ public static int nullity( SingularValueDecomposition svd ) { double threshold = singularThreshold(svd); return nullity(svd, threshold); } /** * Extracts the nullity of a matrix using a preexisting decomposition. * * @see #singularThreshold(org.ejml.interfaces.decomposition.SingularValueDecomposition) * * @param svd A precomputed decomposition. Not modified. * @param threshold Tolerance used to determine of a singular value is singular. * @return The nullity of the decomposed matrix. */ public static int nullity( SingularValueDecomposition svd , double threshold ) { int ret = 0; double w[]= svd.getSingularValues(); int N = svd.numberOfSingularValues(); int numCol = svd.numCols(); for( int j = 0; j < N; j++ ) { if( w[j] <= threshold) ret++; } return ret + numCol-N; } } ejml-0.28/main/dense64/src/org/ejml/ops/SpecializedOps.java000066400000000000000000000344071256171534400234750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; /** * This contains less common or more specialized matrix operations. * * @author Peter Abeles */ public class SpecializedOps { /** *

* Creates a reflector from the provided vector.
*
* Q = I - γ u uT
* γ = 2/||u||2 *

* *

* In practice {@link org.ejml.alg.dense.mult.VectorVectorMult#householder(double, org.ejml.data.D1Matrix64F, org.ejml.data.D1Matrix64F, org.ejml.data.D1Matrix64F)} multHouseholder} * should be used for performance reasons since there is no need to calculate Q explicitly. *

* * @param u A vector. Not modified. * @return An orthogonal reflector. */ public static DenseMatrix64F createReflector( RowD1Matrix64F u ) { if( !MatrixFeatures.isVector(u)) throw new IllegalArgumentException("u must be a vector"); double norm = NormOps.fastNormF(u); double gamma = -2.0/(norm*norm); DenseMatrix64F Q = CommonOps.identity(u.getNumElements()); CommonOps.multAddTransB(gamma,u,u,Q); return Q; } /** *

* Creates a reflector from the provided vector and gamma.
*
* Q = I - γ u uT
*

* *

* In practice {@link org.ejml.alg.dense.mult.VectorVectorMult#householder(double, org.ejml.data.D1Matrix64F, org.ejml.data.D1Matrix64F, org.ejml.data.D1Matrix64F)} multHouseholder} * should be used for performance reasons since there is no need to calculate Q explicitly. *

* * @param u A vector. Not modified. * @param gamma To produce a reflector gamma needs to be equal to 2/||u||. * @return An orthogonal reflector. */ public static DenseMatrix64F createReflector( DenseMatrix64F u , double gamma) { if( !MatrixFeatures.isVector(u)) throw new IllegalArgumentException("u must be a vector"); DenseMatrix64F Q = CommonOps.identity(u.getNumElements()); CommonOps.multAddTransB(-gamma,u,u,Q); return Q; } /** * Creates a copy of a matrix but swaps the rows as specified by the order array. * * @param order Specifies which row in the dest corresponds to a row in the src. Not modified. * @param src The original matrix. Not modified. * @param dst A Matrix that is a row swapped copy of src. Modified. */ public static DenseMatrix64F copyChangeRow( int order[] , DenseMatrix64F src , DenseMatrix64F dst ) { if( dst == null ) { dst = new DenseMatrix64F(src.numRows,src.numCols); } else if( src.numRows != dst.numRows || src.numCols != dst.numCols ) { throw new IllegalArgumentException("src and dst must have the same dimensions."); } for( int i = 0; i < src.numRows; i++ ) { int indexDst = i*src.numCols; int indexSrc = order[i]*src.numCols; System.arraycopy(src.data,indexSrc,dst.data,indexDst,src.numCols); } return dst; } /** * Copies just the upper or lower triangular portion of a matrix. * * @param src Matrix being copied. Not modified. * @param dst Where just a triangle from src is copied. If null a new one will be created. Modified. * @param upper If the upper or lower triangle should be copied. * @return The copied matrix. */ public static DenseMatrix64F copyTriangle( DenseMatrix64F src , DenseMatrix64F dst , boolean upper ) { if( dst == null ) { dst = new DenseMatrix64F(src.numRows,src.numCols); } else if( src.numRows != dst.numRows || src.numCols != dst.numCols ) { throw new IllegalArgumentException("src and dst must have the same dimensions."); } if( upper ) { int N = Math.min(src.numRows,src.numCols); for( int i = 0; i < N; i++ ) { int index = i*src.numCols+i; System.arraycopy(src.data,index,dst.data,index,src.numCols-i); } } else { for( int i = 0; i < src.numRows; i++ ) { int length = Math.min(i+1,src.numCols); int index = i*src.numCols; System.arraycopy(src.data,index,dst.data,index,length); } } return dst; } /** *

* Computes the F norm of the difference between the two Matrices:
*
* Sqrt{∑i=1:mj=1:n ( aij - bij)2} *

*

* This is often used as a cost function. *

* * @see NormOps#fastNormF * * @param a m by n matrix. Not modified. * @param b m by n matrix. Not modified. * * @return The F normal of the difference matrix. */ public static double diffNormF( D1Matrix64F a , D1Matrix64F b ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { throw new IllegalArgumentException("Both matrices must have the same shape."); } final int size = a.getNumElements(); DenseMatrix64F diff = new DenseMatrix64F(size,1); for( int i = 0; i < size; i++ ) { diff.set(i , b.get(i) - a.get(i)); } return NormOps.normF(diff); } public static double diffNormF_fast( D1Matrix64F a , D1Matrix64F b ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { throw new IllegalArgumentException("Both matrices must have the same shape."); } final int size = a.getNumElements(); double total=0; for( int i = 0; i < size; i++ ) { double diff = b.get(i) - a.get(i); total += diff*diff; } return Math.sqrt(total); } /** *

* Computes the p=1 p-norm of the difference between the two Matrices:
*
* ∑i=1:mj=1:n | aij - bij|
*
* where |x| is the absolute value of x. *

*

* This is often used as a cost function. *

* * @param a m by n matrix. Not modified. * @param b m by n matrix. Not modified. * * @return The p=1 p-norm of the difference matrix. */ public static double diffNormP1( D1Matrix64F a , D1Matrix64F b ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { throw new IllegalArgumentException("Both matrices must have the same shape."); } final int size = a.getNumElements(); double total=0; for( int i = 0; i < size; i++ ) { total += Math.abs(b.get(i) - a.get(i)); } return total; } /** *

* Performs the following operation:
*
* B = A + αI *

* * @param A A square matrix. Not modified. * @param B A square matrix that the results are saved to. Modified. * @param alpha Scaling factor for the identity matrix. */ public static void addIdentity( RowD1Matrix64F A , RowD1Matrix64F B , double alpha ) { if( A.numCols != A.numRows ) throw new IllegalArgumentException("A must be square"); if( B.numCols != A.numCols || B.numRows != A.numRows ) throw new IllegalArgumentException("B must be the same shape as A"); int n = A.numCols; int index = 0; for( int i = 0; i < n; i++ ) { for( int j = 0; j < n; j++ , index++) { if( i == j ) { B.set( index , A.get(index) + alpha); } else { B.set( index , A.get(index) ); } } } } /** *

* Extracts a row or column vector from matrix A. The first element in the matrix is at element (rowA,colA). * The next 'length' elements are extracted along a row or column. The results are put into vector 'v' * start at its element v0. *

* * @param A Matrix that the vector is being extracted from. Not modified. * @param rowA Row of the first element that is extracted. * @param colA Column of the first element that is extracted. * @param length Length of the extracted vector. * @param row If true a row vector is extracted, otherwise a column vector is extracted. * @param offsetV First element in 'v' where the results are extracted to. * @param v Vector where the results are written to. Modified. */ public static void subvector(RowD1Matrix64F A, int rowA, int colA, int length , boolean row, int offsetV, RowD1Matrix64F v) { if( row ) { for( int i = 0; i < length; i++ ) { v.set( offsetV +i , A.get(rowA,colA+i) ); } } else { for( int i = 0; i < length; i++ ) { v.set( offsetV +i , A.get(rowA+i,colA)); } } } /** * Takes a matrix and splits it into a set of row or column vectors. * * @param A original matrix. * @param column If true then column vectors will be created. * @return Set of vectors. */ public static DenseMatrix64F[] splitIntoVectors( RowD1Matrix64F A , boolean column ) { int w = column ? A.numCols : A.numRows; int M = column ? A.numRows : 1; int N = column ? 1 : A.numCols; int o = Math.max(M,N); DenseMatrix64F[] ret = new DenseMatrix64F[w]; for( int i = 0; i < w; i++ ) { DenseMatrix64F a = new DenseMatrix64F(M,N); if( column ) subvector(A,0,i,o,false,0,a); else subvector(A,i,0,o,true,0,a); ret[i] = a; } return ret; } /** *

* Creates a pivot matrix that exchanges the rows in a matrix: *
* A' = P*A
*

*

* For example, if element 0 in 'pivots' is 2 then the first row in A' will be the 3rd row in A. *

* * @param ret If null then a new matrix is declared otherwise the results are written to it. Is modified. * @param pivots Specifies the new order of rows in a matrix. * @param numPivots How many elements in pivots are being used. * @param transposed If the transpose of the matrix is returned. * @return A pivot matrix. */ public static DenseMatrix64F pivotMatrix(DenseMatrix64F ret, int pivots[], int numPivots, boolean transposed ) { if( ret == null ) { ret = new DenseMatrix64F(numPivots, numPivots); } else { if( ret.numCols != numPivots || ret.numRows != numPivots ) throw new IllegalArgumentException("Unexpected matrix dimension"); CommonOps.fill(ret, 0); } if( transposed ) { for( int i = 0; i < numPivots; i++ ) { ret.set(pivots[i],i,1); } } else { for( int i = 0; i < numPivots; i++ ) { ret.set(i,pivots[i],1); } } return ret; } /** * Computes the product of the diagonal elements. For a diagonal or triangular * matrix this is the determinant. * * @param T A matrix. * @return product of the diagonal elements. */ public static double diagProd( RowD1Matrix64F T ) { double prod = 1.0; int N = Math.min(T.numRows,T.numCols); for( int i = 0; i < N; i++ ) { prod *= T.unsafe_get(i,i); } return prod; } /** *

* Returns the absolute value of the digonal element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementDiagonalMaxAbs( D1Matrix64F a ) { final int size = Math.min(a.numRows,a.numCols); double max = 0; for( int i = 0; i < size; i++ ) { double val = Math.abs(a.get( i,i )); if( val > max ) { max = val; } } return max; } /** * Computes the quality of a triangular matrix, where the quality of a matrix * is defined in {@link org.ejml.interfaces.linsol.LinearSolver#quality()}. In * this situation the quality os the absolute value of the product of * each diagonal element divided by the magnitude of the largest diagonal element. * If all diagonal elements are zero then zero is returned. * * @param T A matrix. @return product of the diagonal elements. * @return the quality of the system. */ public static double qualityTriangular(D1Matrix64F T) { int N = Math.min(T.numRows,T.numCols); // TODO make faster by just checking the upper triangular portion double max = elementDiagonalMaxAbs(T); if( max == 0.0d ) return 0.0d; double quality = 1.0; for( int i = 0; i < N; i++ ) { quality *= T.unsafe_get(i,i)/max; } return Math.abs(quality); } /** * Sums up the square of each element in the matrix. This is equivalent to the * Frobenius norm squared. * * @param m Matrix. * @return Sum of elements squared. */ public static double elementSumSq( D1Matrix64F m ) { double total = 0; int N = m.getNumElements(); for( int i = 0; i < N; i++ ) { double d = m.data[i]; total += d*d; } return total; } } ejml-0.28/main/dense64/src/overview.html000066400000000000000000000013071256171534400201220ustar00rootroot00000000000000 A fast and easy to use dense matrix linear algebra library written in Java. Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating dense matrices. Its design goals are; 1) to be as computationally and memory efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime, clean API, and multiple interfaces. EJML is free, written in 100% Java and has been released under an Apache v2.0 license. ejml-0.28/main/dense64/test/000077500000000000000000000000001256171534400155555ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/000077500000000000000000000000001256171534400163445ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/000077500000000000000000000000001256171534400172735ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/000077500000000000000000000000001256171534400200365ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/000077500000000000000000000000001256171534400211305ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/TestBlockInnerMultiplication.java000066400000000000000000000132341256171534400276020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** * @author Peter Abeles */ public class TestBlockInnerMultiplication { private static Random rand = new Random(234234); private static final int BLOCK_LENGTH = 4; /** * Check the inner block multiplication functions against various shapes of inputs */ @Test public void testAllBlockMult() { checkBlockMultCase(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH); checkBlockMultCase(BLOCK_LENGTH -1, BLOCK_LENGTH, BLOCK_LENGTH); checkBlockMultCase(BLOCK_LENGTH -1, BLOCK_LENGTH -1, BLOCK_LENGTH); checkBlockMultCase(BLOCK_LENGTH -1, BLOCK_LENGTH -1, BLOCK_LENGTH -1); checkBlockMultCase(BLOCK_LENGTH, BLOCK_LENGTH -1, BLOCK_LENGTH -1); checkBlockMultCase(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH -1); } /** * Searches for all inner block matrix operations and tests their correctness. */ private void checkBlockMultCase(final int heightA, final int widthA, final int widthB) { Method methods[] = BlockInnerMultiplication.class.getDeclaredMethods(); int numFound = 0; for( Method m : methods) { String name = m.getName(); // System.out.println("name = "+name); boolean transA = false; boolean transB = false; if( name.contains("TransA")) transA = true; if( name.contains("TransB")) transB = true; // See if the results are added, subtracted, or set to the output matrix int operationType = 0; if( name.contains("Plus")) operationType = 1; else if ( name.contains("Minus")) operationType = -1; else if( name.contains("Set")) operationType = 0; checkBlockMult(operationType,transA,transB,m,heightA,widthA,widthB); numFound++; } // make sure all the functions were in fact tested assertEquals(15,numFound); } /** * The inner block multiplication is in a row major format. Test it against * operations for DenseMatrix64F */ private void checkBlockMult( int operationType , boolean transA , boolean transB , Method method, final int heightA, final int widthA, final int widthB ) { boolean hasAlpha = method.getParameterTypes().length == 10; if( hasAlpha && operationType == -1 ) fail("No point to minus and alpha"); DenseMatrix64F A = RandomMatrices.createRandom(heightA,widthA,rand); DenseMatrix64F B = RandomMatrices.createRandom(widthA,widthB,rand); DenseMatrix64F C = new DenseMatrix64F(heightA,widthB); if( operationType == -1 ) CommonOps.mult(-1,A,B,C); else CommonOps.mult(A,B,C); DenseMatrix64F C_found = new DenseMatrix64F(heightA,widthB); // if it is set then it should overwrite everything just fine if( operationType == 0) RandomMatrices.setRandom(C_found,rand); if( transA ) CommonOps.transpose(A); if( transB ) CommonOps.transpose(B); double alpha = 2.0; if( hasAlpha ) { CommonOps.scale(alpha,C); } invoke(method,alpha,A.data,B.data,C_found.data,0,0,0,A.numRows,A.numCols,C_found.numCols); if( !MatrixFeatures.isIdentical(C,C_found,1e-10) ) { C.print(); C_found.print(); System.out.println("Method "+method.getName()); System.out.println("transA " +transA); System.out.println("transB " +transB); System.out.println("type " +operationType); System.out.println("alpha " +hasAlpha); fail("Not identical"); } } public static void invoke(Method func, double alpha , double[] dataA, double []dataB, double []dataC, int indexA, int indexB, int indexC, final int heightA, final int widthA, final int widthB ) { try { if( func.getParameterTypes().length == 9 ) { func.invoke(null, dataA, dataB, dataC, indexA,indexB,indexC, heightA,widthA,widthB); } else { func.invoke(null, alpha , dataA, dataB, dataC, indexA,indexB,indexC, heightA,widthA,widthB); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } } ejml-0.28/main/dense64/test/org/ejml/alg/block/TestBlockInnerRankUpdate.java000066400000000000000000000114531256171534400266440ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestBlockInnerRankUpdate { Random rand = new Random(234234); int N = 4; /** * Tests rankNUpdate with various sized input matrices */ @Test public void rankNUpdate() { // the matrix being updated is a whole block checkRankNUpdate(N, N-2); // the matrix being updated is multiple blocks + a fraction checkRankNUpdate(N*2+1, N-2); // matrix being updated is less than a block checkRankNUpdate(N-1, N-2); } private void checkRankNUpdate(int lengthA, int heightB) { double alpha = -2.0; SimpleMatrix origA = SimpleMatrix.random(lengthA,lengthA,-1,1,rand); SimpleMatrix origB = SimpleMatrix.random(heightB,lengthA,-1,1,rand); BlockMatrix64F blockA = BlockMatrixOps.convert(origA.getMatrix(),N); BlockMatrix64F blockB = BlockMatrixOps.convert(origB.getMatrix(),N); D1Submatrix64F subA = new D1Submatrix64F(blockA,0, origA.numRows(), 0, origA.numCols()); D1Submatrix64F subB = new D1Submatrix64F(blockB,0, origB.numRows(), 0, origB.numCols()); SimpleMatrix expected = origA.plus(origB.transpose().mult(origB).scale(alpha)); BlockInnerRankUpdate.rankNUpdate(N,alpha,subA,subB); assertTrue(GenericMatrixOps.isEquivalent(expected.getMatrix(),blockA,1e-8)); } /** * Tests symmRankNMinus_U with various sized input matrices */ @Test public void symmRankNMinus_U() { // the matrix being updated is a whole block checkSymmRankNMinus_U(N, N-2); // the matrix being updated is multiple blocks + a fraction checkSymmRankNMinus_U(N*2+1, N-2); // matrix being updated is less than a block checkSymmRankNMinus_U(N-1, N-2); } private void checkSymmRankNMinus_U(int lengthA, int heightB) { SimpleMatrix origA = SimpleMatrix.wrap(RandomMatrices.createSymmPosDef(lengthA,rand)); SimpleMatrix origB = SimpleMatrix.random(heightB,lengthA,-1,1,rand); BlockMatrix64F blockA = BlockMatrixOps.convert(origA.getMatrix(),N); BlockMatrix64F blockB = BlockMatrixOps.convert(origB.getMatrix(),N); D1Submatrix64F subA = new D1Submatrix64F(blockA,0, origA.numRows(), 0, origA.numCols()); D1Submatrix64F subB = new D1Submatrix64F(blockB,0, origB.numRows(), 0, origB.numCols()); SimpleMatrix expected = origA.plus(origB.transpose().mult(origB).scale(-1)); BlockInnerRankUpdate.symmRankNMinus_U(N,subA,subB); assertTrue(GenericMatrixOps.isEquivalentTriangle(true,expected.getMatrix(),blockA,1e-8)); } @Test public void symmRankNMinus_L() { // the matrix being updated is a whole block checkSymmRankNMinus_L(N, N-2); // the matrix being updated is multiple blocks + a fraction checkSymmRankNMinus_L(N*2+1, N-2); // matrix being updated is less than a block checkSymmRankNMinus_L(N-1, N-2); } private void checkSymmRankNMinus_L(int lengthA, int widthB) { SimpleMatrix origA = SimpleMatrix.wrap(RandomMatrices.createSymmPosDef(lengthA,rand)); SimpleMatrix origB = SimpleMatrix.random(lengthA,widthB,-1,1,rand); BlockMatrix64F blockA = BlockMatrixOps.convert(origA.getMatrix(),N); BlockMatrix64F blockB = BlockMatrixOps.convert(origB.getMatrix(),N); D1Submatrix64F subA = new D1Submatrix64F(blockA,0, origA.numRows(), 0, origA.numCols()); D1Submatrix64F subB = new D1Submatrix64F(blockB,0, origB.numRows(), 0, origB.numCols()); SimpleMatrix expected = origA.plus(origB.mult(origB.transpose()).scale(-1)); BlockInnerRankUpdate.symmRankNMinus_L(N,subA,subB); // expected.print(); // blockA.print(); assertTrue(GenericMatrixOps.isEquivalentTriangle(false,expected.getMatrix(),blockA,1e-8)); } } ejml-0.28/main/dense64/test/org/ejml/alg/block/TestBlockInnerTriangularSolver.java000066400000000000000000000124671256171534400301170ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.alg.dense.misc.UnrolledInverseFromMinor; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestBlockInnerTriangularSolver { Random rand = new Random(234534); @Test public void testInvertLower_two() { DenseMatrix64F A = RandomMatrices.createUpperTriangle(5,0,-1,1,rand); CommonOps.transpose(A); DenseMatrix64F A_inv = A.copy(); BlockInnerTriangularSolver.invertLower(A.data,A_inv.data,5,0,0); DenseMatrix64F S = new DenseMatrix64F(5,5); CommonOps.mult(A,A_inv,S); assertTrue(GenericMatrixOps.isIdentity(S,1e-8)); // see if it works with the same input matrix BlockInnerTriangularSolver.invertLower(A.data,A.data,5,0,0); assertTrue(MatrixFeatures.isIdentical(A,A_inv,1e-8)); } @Test public void testInvertLower_one() { DenseMatrix64F A = RandomMatrices.createUpperTriangle(5,0,-1,1,rand); CommonOps.transpose(A); DenseMatrix64F A_inv = A.copy(); BlockInnerTriangularSolver.invertLower(A_inv.data,5,0); DenseMatrix64F S = new DenseMatrix64F(5,5); CommonOps.mult(A,A_inv,S); assertTrue(GenericMatrixOps.isIdentity(S,1e-8)); } /** * Test all inner block solvers using reflections to look up the functions */ @Test public void testSolveArray() { Method methods[] = BlockInnerTriangularSolver.class.getMethods(); int numFound = 0; for( Method m : methods) { String name = m.getName(); if( !name.contains("solve") || name.compareTo("solve") == 0 || name.compareTo("solveBlock") == 0 ) continue; // System.out.println("name = "+name); boolean solveL = name.contains("L"); boolean transT; boolean transB = name.contains("TransB"); if( solveL ) transT = name.contains("TransL"); else transT = name.contains("TransU"); check_solve_array(m,solveL,transT,transB); numFound++; } // make sure all the functions were in fact tested assertEquals(5,numFound); } /** * Checks to see if solve functions that use arrays as input work correctly. */ private void check_solve_array(Method m, boolean solveL, boolean transT, boolean transB) { int offsetL = 2; int offsetB = 3; DenseMatrix64F L = createRandomLowerTriangular(3); if( !solveL ) { CommonOps.transpose(L); } if( transT ) { CommonOps.transpose(L); } DenseMatrix64F L_inv = L.copy(); UnrolledInverseFromMinor.inv(L_inv,L_inv); DenseMatrix64F B = RandomMatrices.createRandom(3,4,rand); DenseMatrix64F expected = RandomMatrices.createRandom(3,4,rand); DenseMatrix64F found = B.copy(); // compute the expected solution CommonOps.mult(L_inv,B,expected); if( transT ) { CommonOps.transpose(L); } if( transB ) { CommonOps.transpose(found); CommonOps.transpose(expected); } // create arrays that are offset from the original // use two different offsets to make sure it doesn't confuse them internally double dataL[] = offsetArray(L.data,offsetL); double dataB[] = offsetArray(found.data,offsetB); try { m.invoke(null,dataL,dataB,3,4,3,offsetL,offsetB); } catch (IllegalAccessException e) { fail("invoke failed"); } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } // put the solution into B, minus the offset System.arraycopy(dataB,offsetB,found.data,0,found.data.length); assertTrue(MatrixFeatures.isIdentical(expected,found,1e-8)); } private DenseMatrix64F createRandomLowerTriangular( int N ) { DenseMatrix64F U = RandomMatrices.createUpperTriangle(N,0,-1,1,rand); CommonOps.transpose(U); return U; } private double[] offsetArray( double[] orig , int offset ) { double[] ret = new double[ orig.length + offset ]; System.arraycopy(orig,0,ret,offset,orig.length); return ret; } } ejml-0.28/main/dense64/test/org/ejml/alg/block/TestBlockMatrixOps.java000066400000000000000000000436311256171534400255430ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.ejml.simple.UtilSimpleMatrix; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestBlockMatrixOps { final static int BLOCK_LENGTH = 10; Random rand = new Random(234); @Test public void convert_dense_to_block() { checkConvert_dense_to_block(10,10); checkConvert_dense_to_block(5,8); checkConvert_dense_to_block(12,16); checkConvert_dense_to_block(16,12); checkConvert_dense_to_block(21,27); checkConvert_dense_to_block(28,5); checkConvert_dense_to_block(5,28); checkConvert_dense_to_block(20,20); } private void checkConvert_dense_to_block( int m , int n ) { DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); BlockMatrix64F B = new BlockMatrix64F(A.numRows,A.numCols,BLOCK_LENGTH); BlockMatrixOps.convert(A,B); assertTrue( GenericMatrixOps.isEquivalent(A,B,1e-8)); } @Test public void convertInline_dense_to_block() { for( int i = 2; i < 30; i += 5 ) { for( int j = 2; j < 30; j += 5 ) { checkConvertInline_dense_to_block(i,j); } } } private void checkConvertInline_dense_to_block( int m , int n ) { double tmp[] = new double[BLOCK_LENGTH*n]; DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DenseMatrix64F A_orig = A.copy(); BlockMatrixOps.convertRowToBlock(m,n,BLOCK_LENGTH,A.data,tmp); BlockMatrix64F B = BlockMatrix64F.wrap(A.data,A.numRows,A.numCols,BLOCK_LENGTH); assertTrue( GenericMatrixOps.isEquivalent(A_orig,B,1e-8)); } @Test public void convert_block_to_dense() { checkBlockToDense(10,10); checkBlockToDense(5,8); checkBlockToDense(12,16); checkBlockToDense(16,12); checkBlockToDense(21,27); checkBlockToDense(28,5); checkBlockToDense(5,28); checkBlockToDense(20,20); } private void checkBlockToDense( int m , int n ) { DenseMatrix64F A = new DenseMatrix64F(m,n); BlockMatrix64F B = BlockMatrixOps.createRandom(m,n,-1,1,rand); BlockMatrixOps.convert(B,A); assertTrue( GenericMatrixOps.isEquivalent(A,B,1e-8)); } @Test public void convertInline_block_to_dense() { for( int i = 2; i < 30; i += 5 ) { for( int j = 2; j < 30; j += 5 ) { checkConvertInline_block_to_dense(i,j); } } } private void checkConvertInline_block_to_dense( int m , int n ) { double tmp[] = new double[BLOCK_LENGTH*n]; BlockMatrix64F A = BlockMatrixOps.createRandom(m,n,-1,1,rand,BLOCK_LENGTH); BlockMatrix64F A_orig = A.copy(); BlockMatrixOps.convertBlockToRow(m,n,BLOCK_LENGTH,A.data,tmp); DenseMatrix64F B = DenseMatrix64F.wrap(A.numRows,A.numCols,A.data); assertTrue( GenericMatrixOps.isEquivalent(A_orig,B,1e-8)); } /** * Makes sure the bounds check on input matrices for mult() is done correctly */ @Test public void testMultInputChecks() { Method methods[] = BlockMatrixOps.class.getDeclaredMethods(); int numFound = 0; for( Method m : methods) { String name = m.getName(); if( !name.contains("mult")) continue; boolean transA = false; boolean transB = false; if( name.contains("TransA")) transA = true; if( name.contains("TransB")) transB = true; checkMultInput(m,transA,transB); numFound++; } // make sure all the functions were in fact tested assertEquals(3,numFound); } /** * Makes sure exceptions are thrown for badly shaped input matrices. */ private void checkMultInput( Method func, boolean transA , boolean transB ) { // bad block size BlockMatrix64F A = new BlockMatrix64F(5,4,3); BlockMatrix64F B = new BlockMatrix64F(4,6,3); BlockMatrix64F C = new BlockMatrix64F(5,6,4); invokeErrorCheck(func, transA , transB , A, B, C); C.blockLength = 3; B.blockLength = 4; invokeErrorCheck(func, transA , transB ,A, B, C); B.blockLength = 3; A.blockLength = 4; invokeErrorCheck(func, transA , transB , A, B, C); A.blockLength = 3; // check for bad size C C.numCols = 7; invokeErrorCheck(func,transA , transB ,A,B,C); C.numCols = 6; C.numRows = 4; invokeErrorCheck(func,transA , transB ,A,B,C); // make A and B incompatible A.numCols = 3; invokeErrorCheck(func,transA , transB ,A,B,C); } private void invokeErrorCheck(Method func, boolean transA , boolean transB , BlockMatrix64F a, BlockMatrix64F b, BlockMatrix64F c) { if( transA ) a = BlockMatrixOps.transpose(a,null); if( transB ) b = BlockMatrixOps.transpose(b,null); try { func.invoke(null, a, b, c); fail("No exception"); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { if( !(e.getCause() instanceof IllegalArgumentException) ) fail("Unexpected exception: "+e.getCause().getMessage()); } } /** * Tests for correctness multiplication of an entire matrix for all multiplication operations. */ @Test public void testMultSolution() { Method methods[] = BlockMatrixOps.class.getDeclaredMethods(); int numFound = 0; for( Method m : methods) { String name = m.getName(); if( !name.contains("mult")) continue; // System.out.println("name = "+name); boolean transA = false; boolean transB = false; if( name.contains("TransA")) transA = true; if( name.contains("TransB")) transB = true; checkMult(m,transA,transB); numFound++; } // make sure all the functions were in fact tested assertEquals(3,numFound); } /** * Test the method against various matrices of different sizes and shapes which have partial * blocks. */ private void checkMult( Method func, boolean transA , boolean transB ) { // trivial case checkMult(func,transA,transB,BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH); // stuff larger than the block size checkMult(func,transA,transB,BLOCK_LENGTH+1, BLOCK_LENGTH, BLOCK_LENGTH); checkMult(func,transA,transB,BLOCK_LENGTH, BLOCK_LENGTH+1, BLOCK_LENGTH); checkMult(func,transA,transB,BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH+1); checkMult(func,transA,transB,BLOCK_LENGTH+1, BLOCK_LENGTH+1, BLOCK_LENGTH+1); // stuff smaller than the block size checkMult(func,transA,transB,BLOCK_LENGTH-1, BLOCK_LENGTH, BLOCK_LENGTH); checkMult(func,transA,transB,BLOCK_LENGTH, BLOCK_LENGTH-1, BLOCK_LENGTH); checkMult(func,transA,transB,BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH-1); checkMult(func,transA,transB,BLOCK_LENGTH-1, BLOCK_LENGTH-1, BLOCK_LENGTH-1); // stuff multiple blocks checkMult(func,transA,transB,BLOCK_LENGTH*2, BLOCK_LENGTH, BLOCK_LENGTH); checkMult(func,transA,transB,BLOCK_LENGTH, BLOCK_LENGTH*2, BLOCK_LENGTH); checkMult(func,transA,transB,BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH*2); checkMult(func,transA,transB,BLOCK_LENGTH*2, BLOCK_LENGTH*2, BLOCK_LENGTH*2); checkMult(func,transA,transB,BLOCK_LENGTH*2+4, BLOCK_LENGTH*2+3, BLOCK_LENGTH*2+2); } private void checkMult( Method func, boolean transA , boolean transB , int m, int n, int o) { DenseMatrix64F A_d = RandomMatrices.createRandom(m, n,rand); DenseMatrix64F B_d = RandomMatrices.createRandom(n, o,rand); DenseMatrix64F C_d = new DenseMatrix64F(m, o); BlockMatrix64F A_b = BlockMatrixOps.convert(A_d,BLOCK_LENGTH); BlockMatrix64F B_b = BlockMatrixOps.convert(B_d,BLOCK_LENGTH); BlockMatrix64F C_b = BlockMatrixOps.createRandom(m, o, -1 , 1 , rand , BLOCK_LENGTH); if( transA ) A_b=BlockMatrixOps.transpose(A_b,null); if( transB ) B_b=BlockMatrixOps.transpose(B_b,null); CommonOps.mult(A_d,B_d,C_d); try { func.invoke(null,A_b,B_b,C_b); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } // C_d.print(); // C_b.print(); assertTrue( GenericMatrixOps.isEquivalent(C_d,C_b,1e-8)); } @Test public void convertTranSrc_block_to_dense() { checkTranSrcBlockToDense(10,10); checkTranSrcBlockToDense(5,8); checkTranSrcBlockToDense(12,16); checkTranSrcBlockToDense(16,12); checkTranSrcBlockToDense(21,27); checkTranSrcBlockToDense(28,5); checkTranSrcBlockToDense(5,28); checkTranSrcBlockToDense(20,20); } private void checkTranSrcBlockToDense( int m , int n ) { DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DenseMatrix64F A_t = new DenseMatrix64F(n,m); BlockMatrix64F B = new BlockMatrix64F(n,m,BLOCK_LENGTH); CommonOps.transpose(A,A_t); BlockMatrixOps.convertTranSrc(A,B); assertTrue( GenericMatrixOps.isEquivalent(A_t,B,1e-8)); } @Test public void transpose() { checkTranspose(10,10); checkTranspose(5,8); checkTranspose(12,16); checkTranspose(16,12); checkTranspose(21,27); checkTranspose(28,5); checkTranspose(5,28); checkTranspose(20,20); } private void checkTranspose( int m , int n ) { DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DenseMatrix64F A_t = new DenseMatrix64F(n,m); BlockMatrix64F B = new BlockMatrix64F(A.numRows,A.numCols,BLOCK_LENGTH); BlockMatrix64F B_t = new BlockMatrix64F(n,m,BLOCK_LENGTH); BlockMatrixOps.convert(A,B); CommonOps.transpose(A,A_t); BlockMatrixOps.transpose(B,B_t); assertTrue( GenericMatrixOps.isEquivalent(A_t,B_t,1e-8)); } @Test public void zeroTriangle_upper() { int r = 3; for( int numRows = 2; numRows <= 6; numRows += 2 ){ for( int numCols = 2; numCols <= 6; numCols += 2 ){ BlockMatrix64F B = BlockMatrixOps.createRandom(numRows,numCols,-1,1,rand,r); BlockMatrixOps.zeroTriangle(true,B); for( int i = 0; i < B.numRows; i++ ) { for( int j = 0; j < B.numCols; j++ ) { if( j <= i ) assertTrue(B.get(i,j) != 0 ); else assertTrue(B.get(i,j) == 0 ); } } } } } @Test public void zeroTriangle_lower() { int r = 3; for( int numRows = 2; numRows <= 6; numRows += 2 ){ for( int numCols = 2; numCols <= 6; numCols += 2 ){ BlockMatrix64F B = BlockMatrixOps.createRandom(numRows,numCols,-1,1,rand,r); BlockMatrixOps.zeroTriangle(false,B); for( int i = 0; i < B.numRows; i++ ) { for( int j = 0; j < B.numCols; j++ ) { if( j >= i ) assertTrue(B.get(i,j) != 0 ); else assertTrue(B.get(i,j) == 0 ); } } } } } @Test public void copyTriangle() { int r = 3; // test where src and dst are the same size for( int numRows = 2; numRows <= 6; numRows += 2 ){ for( int numCols = 2; numCols <= 6; numCols += 2 ){ BlockMatrix64F A = BlockMatrixOps.createRandom(numRows,numCols,-1,1,rand,r); BlockMatrix64F B = new BlockMatrix64F(numRows,numCols,r); BlockMatrixOps.copyTriangle(true,A,B); for( int i = 0; i < numRows; i++) { for( int j = 0; j < numCols; j++ ) { if( j >= i ) assertTrue(A.get(i,j) == B.get(i,j)); else assertTrue( 0 == B.get(i,j)); } } CommonOps.fill(B, 0); BlockMatrixOps.copyTriangle(false,A,B); for( int i = 0; i < numRows; i++) { for( int j = 0; j < numCols; j++ ) { if( j <= i ) assertTrue(A.get(i,j) == B.get(i,j)); else assertTrue( 0 == B.get(i,j)); } } } } // now the dst will be smaller than the source BlockMatrix64F B = new BlockMatrix64F(r+1,r+1,r); for( int numRows = 4; numRows <= 6; numRows += 1 ){ for( int numCols = 4; numCols <= 6; numCols += 1 ){ BlockMatrix64F A = BlockMatrixOps.createRandom(numRows,numCols,-1,1,rand,r); CommonOps.fill(B, 0); BlockMatrixOps.copyTriangle(true,A,B); for( int i = 0; i < B.numRows; i++) { for( int j = 0; j < B.numCols; j++ ) { if( j >= i ) assertTrue(A.get(i,j) == B.get(i,j)); else assertTrue( 0 == B.get(i,j)); } } CommonOps.fill(B, 0); BlockMatrixOps.copyTriangle(false,A,B); for( int i = 0; i < B.numRows; i++) { for( int j = 0; j < B.numCols; j++ ) { if( j <= i ) assertTrue(A.get(i,j) == B.get(i,j)); else assertTrue( 0 == B.get(i,j)); } } } } } @Test public void setIdentity() { int r = 3; for( int numRows = 2; numRows <= 6; numRows += 2 ){ for( int numCols = 2; numCols <= 6; numCols += 2 ){ BlockMatrix64F A = BlockMatrixOps.createRandom(numRows,numCols,-1,1,rand,r); BlockMatrixOps.setIdentity(A); for( int i = 0; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { if( i == j ) assertEquals(1.0,A.get(i,j),1e-8); else assertEquals(0.0,A.get(i,j),1e-8); } } } } } @Test public void convertSimple() { BlockMatrix64F A = BlockMatrixOps.createRandom(4,6,-1,1,rand,3); SimpleMatrix S = UtilSimpleMatrix.convertSimple(A); assertEquals(A.numRows,S.numRows()); assertEquals(A.numCols,S.numCols()); for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { assertEquals(A.get(i,j),S.get(i,j),1e-8); } } } @Test public void identity() { // test square BlockMatrix64F A = BlockMatrixOps.identity(4,4,3); assertTrue(GenericMatrixOps.isIdentity(A,1e-8)); // test wide A = BlockMatrixOps.identity(4,5,3); assertTrue(GenericMatrixOps.isIdentity(A,1e-8)); // test tall A = BlockMatrixOps.identity(5,4,3); assertTrue(GenericMatrixOps.isIdentity(A,1e-8)); } @Test public void extractAligned() { BlockMatrix64F A = BlockMatrixOps.createRandom(10,11,-1,1,rand,3); BlockMatrix64F B = new BlockMatrix64F(9,11,3); BlockMatrixOps.extractAligned(A,B); for( int i = 0; i < B.numRows; i++ ) { for( int j = 0; j < B.numCols; j++ ) { assertEquals(A.get(i,j),B.get(i,j),1e-8); } } } @Test public void blockAligned() { int r = 3; BlockMatrix64F A = BlockMatrixOps.createRandom(10,11,-1,1,rand,r); D1Submatrix64F S = new D1Submatrix64F(A); assertTrue(BlockMatrixOps.blockAligned(r,S)); S.row0 = r; S.col0 = 2*r; assertTrue(BlockMatrixOps.blockAligned(r,S)); // test negative cases S.row0 = r-1; assertFalse(BlockMatrixOps.blockAligned(r,S)); S.row0 = 0; S.col0 = 1; assertFalse(BlockMatrixOps.blockAligned(r,S)); S.col0 = 0; S.row1 = 8; assertFalse(BlockMatrixOps.blockAligned(r,S)); S.row1 = 10; S.col0 = 10; assertFalse(BlockMatrixOps.blockAligned(r,S)); } } ejml-0.28/main/dense64/test/org/ejml/alg/block/TestBlockMultiplication.java000066400000000000000000000160321256171534400266050ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** * @author Peter Abeles */ public class TestBlockMultiplication { private static Random rand = new Random(234234); private static final int BLOCK_LENGTH = 4; private static final int numRows = 10; private static final int numCols = 13; /** * Checks to see if matrix multiplication variants handles submatrices correctly */ @Test public void mult_submatrix() { Method methods[] = BlockMultiplication.class.getDeclaredMethods(); int numFound = 0; for( Method m : methods) { String name = m.getName(); if( name.contains("Block") || !name.contains("mult") ) continue; // System.out.println("name = "+name); boolean transA = name.contains("TransA"); boolean transB = name.contains("TransB"); int operationType = 0; if( name.contains("Plus")) operationType = 1; else if ( name.contains("Minus")) operationType = -1; else if( name.contains("Set")) operationType = 0; checkMult_submatrix(m,operationType,transA,transB); numFound++; } // make sure all the functions were in fact tested assertEquals(7,numFound); } private static void checkMult_submatrix( Method func , int operationType , boolean transA , boolean transB ) { // the submatrix is the same size as the originals checkMult_submatrix( func , operationType , transA , transB , sub(0,0,numRows,numCols),sub(0,0,numCols,numRows)); // submatrix has a size in multiples of the block checkMult_submatrix( func , operationType , transA , transB , sub(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH *2, BLOCK_LENGTH *2), sub(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH *2, BLOCK_LENGTH *2)); // submatrix row and column ends at a fraction of a block checkMult_submatrix( func , operationType , transA , transB , sub(BLOCK_LENGTH, BLOCK_LENGTH,numRows,numCols), sub(BLOCK_LENGTH, BLOCK_LENGTH,numCols,numRows)); // the previous tests have some symmetry in it which can mask errors checkMult_submatrix( func , operationType , transA , transB , sub(0, BLOCK_LENGTH,BLOCK_LENGTH,2*BLOCK_LENGTH), sub(0, BLOCK_LENGTH,BLOCK_LENGTH,numRows)); } /** * Multiplies the two sub-matrices together. Checks to see if the same result * is found when multiplied using the normal algorithm versus the submatrix one. */ private static void checkMult_submatrix( Method func , int operationType , boolean transA , boolean transB , D1Submatrix64F A , D1Submatrix64F B ) { if( A.col0 % BLOCK_LENGTH != 0 || A.row0 % BLOCK_LENGTH != 0) throw new IllegalArgumentException("Submatrix A is not block aligned"); if( B.col0 % BLOCK_LENGTH != 0 || B.row0 % BLOCK_LENGTH != 0) throw new IllegalArgumentException("Submatrix B is not block aligned"); BlockMatrix64F origA = BlockMatrixOps.createRandom(numRows,numCols,-1,1, rand, BLOCK_LENGTH); BlockMatrix64F origB = BlockMatrixOps.createRandom(numCols,numRows,-1,1, rand, BLOCK_LENGTH); A.original = origA; B.original = origB; int w = B.col1-B.col0; int h = A.row1-A.row0; // offset it to make the test harder // randomize to see if its set or adding BlockMatrix64F subC = BlockMatrixOps.createRandom(BLOCK_LENGTH +h, BLOCK_LENGTH +w, -1,1,rand, BLOCK_LENGTH); D1Submatrix64F C = new D1Submatrix64F(subC, BLOCK_LENGTH, subC.numRows, BLOCK_LENGTH, subC.numCols); DenseMatrix64F rmC = multByExtract(operationType,A,B,C); if( transA ) { origA = BlockMatrixOps.transpose(origA,null); transposeSub(A); A.original = origA; } if( transB ) { origB = BlockMatrixOps.transpose(origB,null); transposeSub(B); B.original = origB; } try { func.invoke(null,BLOCK_LENGTH,A,B,C); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } for( int i = C.row0; i < C.row1; i++ ) { for( int j = C.col0; j < C.col1; j++ ) { // System.out.println(i+" "+j); double diff = Math.abs(subC.get(i,j) - rmC.get(i-C.row0,j-C.col0)); // System.out.println(subC.get(i,j)+" "+rmC.get(i-C.row0,j-C.col0)); if( diff >= 1e-12) { subC.print(); rmC.print(); System.out.println(func.getName()); System.out.println("transA "+transA); System.out.println("transB "+transB); System.out.println("type "+operationType); fail("Error too large"); } } } } public static void transposeSub(D1Submatrix64F A) { int temp = A.col0; A.col0 = A.row0; A.row0 = temp; temp = A.col1; A.col1 = A.row1; A.row1 = temp; } private static D1Submatrix64F sub( int row0 , int col0 , int row1 , int col1 ) { return new D1Submatrix64F(null,row0, row1, col0, col1); } private static DenseMatrix64F multByExtract( int operationType , D1Submatrix64F subA , D1Submatrix64F subB , D1Submatrix64F subC ) { SimpleMatrix A = SimpleMatrix.wrap(subA.extract()); SimpleMatrix B = SimpleMatrix.wrap(subB.extract()); SimpleMatrix C = SimpleMatrix.wrap(subC.extract()); if( operationType > 0 ) return A.mult(B).plus(C).getMatrix(); else if( operationType < 0 ) return C.minus(A.mult(B)).getMatrix(); else return A.mult(B).getMatrix(); } } ejml-0.28/main/dense64/test/org/ejml/alg/block/TestBlockTriangularSolver.java000066400000000000000000000204701256171534400271140ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestBlockTriangularSolver { Random rand = new Random(234534); @Test public void invert_two() { // block size int r = 3; double temp[] = new double[r*r]; for( int size = 1; size <= 9; size++ ) { BlockMatrix64F T = BlockMatrixOps.createRandom(size,size,-1,1,rand,r); BlockMatrixOps.zeroTriangle(true,T); BlockMatrix64F T_inv = T.copy(); BlockTriangularSolver.invert(r,false,new D1Submatrix64F(T),new D1Submatrix64F(T_inv),temp); BlockMatrix64F C = new BlockMatrix64F(size,size,r); BlockMatrixOps.mult(T,T_inv,C); assertTrue(GenericMatrixOps.isIdentity(C,1e-8)); // see if passing in the same matrix instance twice messes it up or not BlockTriangularSolver.invert(r,false,new D1Submatrix64F(T),new D1Submatrix64F(T),temp); assertTrue(BlockMatrixOps.isEquals(T,T_inv,1e-8)); } } @Test public void invert_one() { // block size int r = 3; double temp[] = new double[r*r]; for( int size = 1; size <= 9; size++ ) { BlockMatrix64F T = BlockMatrixOps.createRandom(size,size,-1,1,rand,r); BlockMatrixOps.zeroTriangle(true,T); BlockMatrix64F T_inv = T.copy(); BlockTriangularSolver.invert(r,false,new D1Submatrix64F(T_inv),temp); BlockMatrix64F C = new BlockMatrix64F(size,size,r); BlockMatrixOps.mult(T,T_inv,C); assertTrue(GenericMatrixOps.isIdentity(C,1e-8)); } } /** * Test solving several different triangular systems with different sizes. * All matrices begin and end along block boundaries. */ @Test public void testSolve() { // block size int r = 3; for( int dir = 0; dir < 2; dir++ ) { boolean upper = dir == 0; for( int triangleSize = 1; triangleSize <= 9; triangleSize++ ) { for( int cols = 1; cols <= 9; cols++ ) { // System.out.println("triangle "+triangleSize+" cols "+cols); BlockMatrix64F T = BlockMatrixOps.createRandom(triangleSize,triangleSize,-1,1,rand,r); BlockMatrixOps.zeroTriangle(true,T); if( upper ) { T=BlockMatrixOps.transpose(T,null); } BlockMatrix64F B = BlockMatrixOps.createRandom(triangleSize,cols,-1,1,rand,r); BlockMatrix64F Y = new BlockMatrix64F(B.numRows,B.numCols,r); checkSolve(T,B,Y,r,upper,false); checkSolve(T,B,Y,r,upper,true); // test cases where the submatrix is not aligned with the inner // blocks checkSolveUnaligned(T,B,Y,r,upper,false); checkSolveUnaligned(T,B,Y,r,upper,true); } } } } /** * Checks to see if BlockTriangularSolver.solve produces the expected output given * these inputs. The solution is computed directly. */ private void checkSolve( BlockMatrix64F T , BlockMatrix64F B , BlockMatrix64F Y , int r , boolean upper , boolean transT ) { if( transT ) { BlockMatrix64F T_tran = BlockMatrixOps.transpose(T,null); // Compute Y directly from the expected result B BlockMatrixOps.mult(T_tran,B,Y); } else { // Compute Y directly from the expected result B BlockMatrixOps.mult(T,B,Y); } // Y is overwritten with the solution BlockTriangularSolver.solve(r,upper,new D1Submatrix64F(T),new D1Submatrix64F(Y),transT); assertTrue( BlockMatrixOps.isEquals(B,Y,1e-8)); } /** * Checks to see if BlockTriangularSolver.solve produces the expected output given * these inputs. The solution is computed directly. */ private void checkSolveUnaligned( BlockMatrix64F T , BlockMatrix64F B , BlockMatrix64F Y , int r , boolean upper , boolean transT ) { BlockMatrix64F T2; if( upper ) T2 = BlockMatrixOps.createRandom(T.numRows+1,T.numCols,-1,1,rand,T.blockLength); else T2 = BlockMatrixOps.createRandom(T.numRows,T.numCols+1,-1,1,rand,T.blockLength); CommonOps.insert(T,T2,0,0); if( transT ) { BlockMatrix64F T_tran = BlockMatrixOps.transpose(T,null); // Compute Y directly from the expected result B BlockMatrixOps.mult(T_tran,B,Y); } else { // Compute Y directly from the expected result B BlockMatrixOps.mult(T,B,Y); } int size = T.numRows; // Y is overwritten with the solution BlockTriangularSolver.solve(r,upper,new D1Submatrix64F(T2,0,size,0,size),new D1Submatrix64F(Y),transT); assertTrue( "Failed upper = "+upper+" transT = "+transT+" T.length "+T.numRows+" B.cols "+B.numCols, BlockMatrixOps.isEquals(B,Y,1e-8)); } /** * Check all permutations of solve for submatrices */ @Test public void testSolveBlock() { check_solveBlock_submatrix(false,false,false); check_solveBlock_submatrix(true,false,false); check_solveBlock_submatrix(false,true,false); check_solveBlock_submatrix(true,true,false); // check_solveBlock_submatrix(false,false,true); check_solveBlock_submatrix(true,false,true); // check_solveBlock_submatrix(false,true,true); // check_solveBlock_submatrix(false,true,true); } /** * Checks to see if solve functions that use sub matrices as input work correctly */ private void check_solveBlock_submatrix( boolean solveL , boolean transT , boolean transB ) { // compute expected solution DenseMatrix64F L = createRandomLowerTriangular(3); DenseMatrix64F B = RandomMatrices.createRandom(3,5,rand); DenseMatrix64F X = new DenseMatrix64F(3,5); if( !solveL ) { CommonOps.transpose(L); } if( transT ) { CommonOps.transpose(L); } CommonOps.solve(L,B,X); // do it again using block matrices BlockMatrix64F b_L = BlockMatrixOps.convert(L,3); BlockMatrix64F b_B = BlockMatrixOps.convert(B,3); D1Submatrix64F sub_L = new D1Submatrix64F(b_L,0, 3, 0, 3); D1Submatrix64F sub_B = new D1Submatrix64F(b_B,0, 3, 0, 5); if( transT ) { sub_L.original = BlockMatrixOps.transpose((BlockMatrix64F)sub_L.original,null); TestBlockMultiplication.transposeSub(sub_L); } if( transB ) { sub_B.original = b_B = BlockMatrixOps.transpose((BlockMatrix64F)sub_B.original,null); TestBlockMultiplication.transposeSub(sub_B); CommonOps.transpose(X); } // sub_L.original.print(); // sub_B.original.print(); BlockTriangularSolver.solveBlock(3,!solveL,sub_L,sub_B,transT,transB); assertTrue(GenericMatrixOps.isEquivalent(X,b_B,1e-10)); } private DenseMatrix64F createRandomLowerTriangular( int N ) { DenseMatrix64F U = RandomMatrices.createUpperTriangle(N,0,-1,1,rand); CommonOps.transpose(U); return U; } } ejml-0.28/main/dense64/test/org/ejml/alg/block/TestBlockVectorOps.java000066400000000000000000000157351256171534400255450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestBlockVectorOps { Random rand = new Random(234); int r = 3; @Test public void scale_row() { int rowA=0; int rowB=1; double alpha = 1.5; for( int width = 1; width <= 3*r; width++ ) { // System.out.println("width "+width); int end = width; int offset = width > 1 ? 1 : 0; SimpleMatrix A = SimpleMatrix.random(r,width,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Bb = Ab.copy(); SimpleMatrix b = A.extractVector(true,rowA).scale(alpha); BlockVectorOps.scale_row(r,new D1Submatrix64F(Ab),rowA, alpha, new D1Submatrix64F(Bb),rowB,offset,end); checkVector_row(rowB, end, offset, A, Bb, b); } } @Test public void div_row() { int rowA=0; int rowB=1; double alpha = 1.5; for( int width = 1; width <= 3*r; width++ ) { // System.out.println("width "+width); int end = width; int offset = width > 1 ? 1 : 0; SimpleMatrix A = SimpleMatrix.random(r,width,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Bb = Ab.copy(); SimpleMatrix b = A.extractVector(true,rowA).divide(alpha); BlockVectorOps.div_row(r,new D1Submatrix64F(Ab),rowA, alpha, new D1Submatrix64F(Bb),rowB,offset,end); checkVector_row(rowB, end, offset, A, Bb, b); } } @Test public void add_row() { int rowA=0; int rowB=1; int rowC=2; double alpha = 1.5; double beta = -0.7; for( int width = 1; width <= 3*r; width++ ) { // System.out.println("width "+width); int end = width; int offset = width > 1 ? 1 : 0; SimpleMatrix A = SimpleMatrix.random(r,width,-1,1,rand); SimpleMatrix B = SimpleMatrix.random(r,width,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Bb = BlockMatrixOps.convert(B.getMatrix(),r); BlockMatrix64F Cb = Ab.copy(); SimpleMatrix a = A.extractVector(true,rowA).scale(alpha); SimpleMatrix b = B.extractVector(true,rowB).scale(beta); SimpleMatrix c = a.plus(b); BlockVectorOps.add_row(r, new D1Submatrix64F(Ab),rowA, alpha, new D1Submatrix64F(Bb),rowB, beta , new D1Submatrix64F(Cb),rowC, offset,end); checkVector_row(rowC, end, offset, A, Cb, c); } } @Test public void dot_row() { int rowA=0; int rowB=1; for( int width = 1; width <= 3*r; width++ ) { // System.out.println("width "+width); int end = width; int offset = width > 1 ? 1 : 0; SimpleMatrix A = SimpleMatrix.random(r,width,-1,1,rand); SimpleMatrix a = A.extractMatrix(rowA,rowA+1,offset,SimpleMatrix.END); SimpleMatrix B = SimpleMatrix.random(r,width,-1,1,rand); SimpleMatrix b = B.extractMatrix(rowB,rowB+1,offset,SimpleMatrix.END); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Bb = BlockMatrixOps.convert(B.getMatrix(),r); double expected = a.dot(b); double found = BlockVectorOps.dot_row(r,new D1Submatrix64F(Ab),rowA, new D1Submatrix64F(Bb),rowB,offset,end); assertEquals(expected,found,1e-8); } } @Test public void dot_row_col() { int rowA=0; int colB=1; for( int width = 1; width <= 3*r; width++ ) { // System.out.println("width "+width); int end = width; int offset = width > 1 ? 1 : 0; if( colB >= width) colB = 0; SimpleMatrix A = SimpleMatrix.random(width,width,-1,1,rand); SimpleMatrix a = A.extractMatrix(rowA,rowA+1,offset,SimpleMatrix.END); SimpleMatrix B = SimpleMatrix.random(width,width,-1,1,rand); SimpleMatrix b = B.extractMatrix(offset,SimpleMatrix.END,colB,colB+1); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Bb = BlockMatrixOps.convert(B.getMatrix(),r); double expected = a.dot(b); double found = BlockVectorOps.dot_row_col(r, new D1Submatrix64F(Ab),rowA, new D1Submatrix64F(Bb),colB, offset,end); assertEquals(expected,found,1e-8); } } /** * Checks to see if only the anticipated parts of the matrix have been modified and that * they are the anticipated values. * * @param row The row modified in modMatrix. * @param end end of the vector. * @param offset start of the vector. * @param untouched Original values of the modMatrix. * @param modMatrix The matrix which have been modified by the function being tested. * @param modVector Vector that contains the anticipated values. */ public static void checkVector_row(int row, int end, int offset, SimpleMatrix untouched, BlockMatrix64F modMatrix, SimpleMatrix modVector) { for( int i = 0; i < modMatrix.numRows; i++ ) { if( i == row ) { for( int j = 0; j < offset; j++ ) { assertEquals(untouched.get(i,j), modMatrix.get(i,j),1e-8); } for( int j = offset; j < end; j++ ) { assertEquals(modVector.get(j), modMatrix.get(i,j),1e-8); } for( int j = end; j < modMatrix.numCols; j++ ) { assertEquals(untouched.get(i,j), modMatrix.get(i,j),1e-8); } } else { for( int j = 0; j < modMatrix.numCols; j++ ) { assertEquals(i+" "+j, untouched.get(i,j), modMatrix.get(i,j),1e-8); } } } } } ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/000077500000000000000000000000001256171534400240045ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/bidiagonal/000077500000000000000000000000001256171534400260755ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/bidiagonal/TestBidiagonalHelper.java000066400000000000000000000036431256171534400327770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.bidiagonal; import org.junit.Test; import java.util.Random; /** * @author Peter Abeles */ public class TestBidiagonalHelper { final static int r = 3; Random rand = new Random(234); @Test public void bidiagOuterBlocks() { // SimpleMatrix A = SimpleMatrix.random(r*2+r-1,r*2+r-1,-1,1,rand); // BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); // // A.print(); // BidiagonalDecompositionRow decompTest = new BidiagonalDecompositionRow(); // assertTrue( decompTest.decompose(A.getMatrix()) ); // // double gammasU[] = new double[ r*3 ]; // double gammasV[] = new double[ r*3 ]; // // BidiagonalHelper.bidiagOuterBlocks(r,new D1Submatrix64F(Ab),gammasU,gammasV); // // for( int i = 0; i < r; i++ ) { // assertEquals(decompTest.getGammasU()[i],gammasU[i],1e-8); // assertEquals(decompTest.getGammasV()[i],gammasV[i],1e-8); // } // // for( int i = 0; i < A.numRows(); i++ ) { // for( int j = 0; j < A.numCols(); j++ ) { // if( i < r && j < r ) { // assertEquals(A.get(i,j),Ab.get(i,j),1e-8); // } // } // } } } ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/chol/000077500000000000000000000000001256171534400247315ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/chol/TestCholeskyOuterForm_B64.java000066400000000000000000000065061256171534400325020ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.chol; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCholeskyOuterForm_B64 { Random rand = new Random(1231); // size of a block int bl = 5; /** * Test upper cholesky decomposition for upper triangular. */ @Test public void testUpper() { // test against various different sizes for( int N = bl-2; N <= 13; N += 2 ) { DenseMatrix64F A = RandomMatrices.createSymmPosDef(N,rand); CholeskyDecomposition chol = DecompositionFactory.chol(1,false); assertTrue(DecompositionFactory.decomposeSafe(chol,A)); DenseMatrix64F expectedT = chol.getT(null); BlockMatrix64F blockA = BlockMatrixOps.convert(A,bl); CholeskyOuterForm_B64 blockChol = new CholeskyOuterForm_B64(false); assertTrue(DecompositionFactory.decomposeSafe(blockChol,blockA)); assertTrue(GenericMatrixOps.isEquivalent(expectedT,blockChol.getT(null),1e-8)); double blockDet = blockChol.computeDeterminant().real; double expectedDet = chol.computeDeterminant().real; assertEquals(expectedDet,blockDet,1e-8); } } /** * Test upper cholesky decomposition for upper triangular. */ @Test public void testLower() { // test against various different sizes for( int N = bl-2; N <= 13; N += 2 ) { DenseMatrix64F A = RandomMatrices.createSymmPosDef(N,rand); CholeskyDecomposition chol = DecompositionFactory.chol(1,true); assertTrue(DecompositionFactory.decomposeSafe(chol, A)); DenseMatrix64F expectedT = chol.getT(null); BlockMatrix64F blockA = BlockMatrixOps.convert(A,bl); CholeskyOuterForm_B64 blockChol = new CholeskyOuterForm_B64(true); assertTrue(DecompositionFactory.decomposeSafe(blockChol,blockA)); assertTrue(GenericMatrixOps.isEquivalent(expectedT,blockChol.getT(null),1e-8)); double blockDet = blockChol.computeDeterminant().real; double expectedDet = chol.computeDeterminant().real; assertEquals(expectedDet,blockDet,1e-8); } } } ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/chol/TestInnerCholesky_B64.java000066400000000000000000000063731256171534400316350ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.chol; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestInnerCholesky_B64 { Random rand = new Random(234234); @Test public void upper() { checkDecompose(5, false); checkNotPositiveDefinite(5,true); } @Test public void lower() { checkDecompose(5, true); checkNotPositiveDefinite(5,true); } /** * Test a positive case where it should be able to decompose the matrix */ private void checkDecompose(int n, boolean lower) { DenseMatrix64F A = RandomMatrices.createSymmPosDef(n,rand); // decompose a DenseMatrix64F to find expected solution CholeskyDecomposition chol = DecompositionFactory.chol(n,lower); assertTrue(DecompositionFactory.decomposeSafe(chol,A)); DenseMatrix64F expected = chol.getT(null); // copy the original data by an offset double data[] = new double[ A.getNumElements() + 2 ]; System.arraycopy(A.data,0,data,2,A.getNumElements()); // decompose using the algorithm if( lower ) assertTrue(InnerCholesky_B64.lower(data, 2, n)); else assertTrue(InnerCholesky_B64.upper(data, 2, n)); DenseMatrix64F found = new DenseMatrix64F(n, n); System.arraycopy(data,2,found.data,0,found.data.length); // set lower triangular potion to be zero so that it is exactly the same assertTrue(GenericMatrixOps.isEquivalentTriangle(!lower,expected,found,1e-10)); } /** * See if it fails when the matrix is not positive definite. */ private void checkNotPositiveDefinite(int n, boolean lower) { DenseMatrix64F A = new DenseMatrix64F(n,n); for( int i = 0; i < n; i++ ) { for( int j = 0; j < n; j++ ) { A.set(i,j,1); } } // copy the original data by an offset double data[] = new double[ A.getNumElements() + 2 ]; System.arraycopy(A.data,0,data,2,A.getNumElements()); // decompose using the algorithm if( lower ) assertFalse(InnerCholesky_B64.lower(data, 2, n)); else assertFalse(InnerCholesky_B64.upper(data, 2, n)); } } ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/hessenberg/000077500000000000000000000000001256171534400261315ustar00rootroot00000000000000TestTridiagonalDecompositionHouseholder_B64.java000066400000000000000000000107751256171534400373760ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.hessenberg; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecompositionHouseholderOrig_D64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestTridiagonalDecompositionHouseholder_B64 { Random rand = new Random(23423); int r = 3; @Test public void compareToSimple() { for( int width = 1; width <= r*3; width++ ) { // System.out.println("width = "+width); DenseMatrix64F A = RandomMatrices.createSymmetric(width,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A,r); TridiagonalDecompositionHouseholderOrig_D64 decomp = new TridiagonalDecompositionHouseholderOrig_D64(); decomp.decompose(A); DenseMatrix64F expected = decomp.getQT(); TridiagonalDecompositionHouseholder_B64 decompB = new TridiagonalDecompositionHouseholder_B64(); assertTrue(decompB.decompose(Ab)); // expected.print(); // Ab.print(); // see if the decomposed matrix is the same for( int i = 0; i < width; i++ ) { for( int j = i; j < width; j++ ) { assertEquals(i+" "+j,expected.get(i,j),Ab.get(i,j),1e-8); } } // check the gammas for( int i = 0; i < width-1; i++ ) { assertEquals(decomp.getGamma(i+1),decompB.gammas[i],1e-8); } DenseMatrix64F Q = decomp.getQ(null); BlockMatrix64F Qb = decompB.getQ(null,false); EjmlUnitTests.assertEquals(Q,Qb,1e-8); } } @Test public void fullTest() { for( int width = 1; width <= r*3; width++ ) { SimpleMatrix A = SimpleMatrix.wrap(RandomMatrices.createSymmetric(width,-1,1,rand)); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); TridiagonalDecompositionHouseholder_B64 alg = new TridiagonalDecompositionHouseholder_B64(); assertTrue(alg.decompose(Ab)); BlockMatrix64F Qb = alg.getQ(null,false); BlockMatrix64F Tb = alg.getT(null); SimpleMatrix Q = new SimpleMatrix(Qb); SimpleMatrix T = new SimpleMatrix(Tb); // reconstruct the original matrix SimpleMatrix A_found = Q.mult(T).mult(Q.transpose()); assertTrue(MatrixFeatures.isIdentical(A.getMatrix(),A_found.getMatrix(),1e-8)); } } @Test public void multPlusTransA() { for( int width = r+1; width <= r*3; width++ ) { SimpleMatrix A = SimpleMatrix.random(width,width,-1,1,rand); SimpleMatrix U = SimpleMatrix.random(r,width,-1,1,rand); SimpleMatrix V = SimpleMatrix.random(r,width,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Ub = BlockMatrixOps.convert(U.getMatrix(),r); BlockMatrix64F Vb = BlockMatrixOps.convert(V.getMatrix(),r); SimpleMatrix expected = A.plus(U.transpose().mult(V)); TridiagonalDecompositionHouseholder_B64.multPlusTransA(r, new D1Submatrix64F(Ub) , new D1Submatrix64F(Vb), new D1Submatrix64F(Ab)); for( int i = r; i < width; i++ ) { for( int j = i; j < width; j++ ) { assertEquals(i+" "+j,expected.get(i,j),Ab.get(i,j),1e-8); } } } } } TestTridiagonalHelper_B64.java000066400000000000000000000236711256171534400335760ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.hessenberg; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecompositionHouseholderOrig_D64; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestTridiagonalHelper_B64 { Random rand = new Random(234324); int r = 3; /** * Compare against a simple tridiagonalization implementation */ @Test public void tridiagUpperRow() { int offX = 0; int offY = 0; // test it out on a variety of sizes for( int width = 1; width <= 3*r; width++ ) { // System.out.println("********* width "+width); // create a random symmetric matrix SimpleMatrix A = SimpleMatrix.wrap(RandomMatrices.createSymmetric(width,-1,1,rand)); TridiagonalDecompositionHouseholderOrig_D64 decomp = new TridiagonalDecompositionHouseholderOrig_D64(); decomp.decompose(A.getMatrix()); D1Submatrix64F Ab = insertIntoBlock(offX,offY,A,r); D1Submatrix64F V = new D1Submatrix64F(new BlockMatrix64F(r,offX+A.numCols(),r)); V.col0 = offX; V.row1 = Ab.row1-Ab.row0; int gammaOffset = offX; double gammas[] = new double[gammaOffset+A.numCols()]; TridiagonalHelper_B64.tridiagUpperRow(r, Ab, gammas, V); DenseMatrix64F expected = decomp.getQT(); // see if the decomposed matrix is the same for( int i = 0; i < r; i++ ) { for( int j = i; j < width; j++ ) { assertEquals(i+" "+j,expected.get(i,j),Ab.get(i,j),1e-8); } } // check the gammas for( int i = 0; i < Math.min(width-1,r); i++ ) { assertEquals(decomp.getGamma(i+1),gammas[i+gammaOffset],1e-8); } } } @Test public void computeW_row() { for( int width = r; width <= 3*r; width++ ) { // System.out.println("width!!! "+width); double betas[] = new double[ r ]; for( int i = 0; i < r; i++ ) betas[i] = i + 0.5; SimpleMatrix A = SimpleMatrix.random(r,width,-1,1,rand); // Compute W directly using SimpleMatrix SimpleMatrix v = A.extractVector(true,0); v.set(0,0); v.set(1,1); SimpleMatrix Y = v; SimpleMatrix W = v.scale(-betas[0]); for( int i = 1; i < A.numRows(); i++ ) { v = A.extractVector(true,i); for( int j = 0; j <= i; j++ ) v.set(j,0); if( i+1 < A.numCols()) v.set(i+1,1); SimpleMatrix z = v.transpose().plus(W.transpose().mult(Y.mult(v.transpose()))).scale(-betas[i]); W = W.combine(i,0,z.transpose()); Y = Y.combine(i,0,v); } // now compute it using the block matrix stuff BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Wb = new BlockMatrix64F(Ab.numRows,Ab.numCols,r); D1Submatrix64F Ab_sub = new D1Submatrix64F(Ab); D1Submatrix64F Wb_sub = new D1Submatrix64F(Wb); TridiagonalHelper_B64.computeW_row(r, Ab_sub, Wb_sub, betas, 0); // see if the result is the same assertTrue(GenericMatrixOps.isEquivalent(Wb,W.getMatrix(),1e-8)); } } @Test public void applyReflectorsToRow() { // try different offsets to make sure there are no implicit assumptions for( int offX = 0; offX <= r; offX += r) { for( int offY = 0; offY <= r; offY += r) { SimpleMatrix A = SimpleMatrix.random(2*r+2,2*r+2,-1,1,rand); A = A.mult(A.transpose()); SimpleMatrix A_orig = A.copy(); SimpleMatrix V = SimpleMatrix.random(r,A.numCols(),-1,1,rand); D1Submatrix64F Ab = insertIntoBlock(offY,offX,A,r); D1Submatrix64F Vb = insertIntoBlock(0,offX,V,r); int row = r-1; // manually apply "reflectors" to A for( int i = 0; i < row; i++ ) { SimpleMatrix u = A_orig.extractVector(true,i).transpose(); SimpleMatrix v = V.extractVector(true,i).transpose(); for( int j = 0; j <= i; j++ ) { u.set(j,0.0); } u.set(i+1,1.0); A = A.plus(u.mult(v.transpose())).plus(v.mult(u.transpose())); } // apply the reflector to that row TridiagonalHelper_B64.applyReflectorsToRow(r, Ab, Vb, row); // compare to manually computed solution for( int i = row; i < A.numCols(); i++ ) { assertEquals(A.get(row,i),Ab.get(row,i),1e-8); } } } } private static D1Submatrix64F insertIntoBlock( int offRow , int offCol , SimpleMatrix A , int r ) { DenseMatrix64F B = new DenseMatrix64F(offRow+A.numRows(),offCol+A.numCols()); CommonOps.insert(A.getMatrix(),B,offRow,offCol); BlockMatrix64F C = BlockMatrixOps.convert(B,r); return new D1Submatrix64F(C,offRow,C.numRows,offCol,C.numCols); } @Test public void multA_u() { SimpleMatrix A = SimpleMatrix.random(2*r+2,2*r+2,-1,1,rand); // make a symmetric so that this mult will work A = A.transpose().mult(A); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F V = new BlockMatrix64F(r,Ab.numCols,r); int row = 1; SimpleMatrix u = A.extractVector(true,row).transpose(); for( int i = 0; i <= row; i++ ) { u.set(i,0); } u.set(row+1,1); SimpleMatrix v = A.mult(u).transpose(); TridiagonalHelper_B64.multA_u(r, new D1Submatrix64F(Ab), new D1Submatrix64F(V), row); for( int i = row+1; i < A.numCols(); i++ ) { assertEquals(v.get(i),V.get(row,i),1e-8); } } /** * Check by performing the calculation manually */ @Test public void computeY() { SimpleMatrix A = SimpleMatrix.random(2*r+2,2*r+2,-1,1,rand); A = A.transpose().mult(A); // needs to be symmetric to pass SimpleMatrix Vo = SimpleMatrix.random(r,A.numCols(),-1,1,rand); for( int row = 0; row < r; row++ ) { SimpleMatrix AA = A.copy(); SimpleMatrix u = A.extractVector(true,row).transpose(); SimpleMatrix y; double gamma = 1.3; // zero elements that should already be zero for( int i = 0; i < row; i++ ) { u.set(i,0); for( int j = i+2; j < A.numRows(); j++ ) { AA.set(i,j,0); AA.set(j,i,0); } } u.set(row,0); u.set(row+1,1); if( row > 0 ) { SimpleMatrix U = A.extractMatrix(0,row,0,A.numCols()).transpose(); SimpleMatrix V = Vo.extractMatrix(0,row,0,A.numCols()).transpose(); for( int i = 0; i < row; i++ ) { for( int j = 0; j <= i; j++ ) { U.set(j,i,0); } U.set(i+1,i,1); } y = AA.plus(U.mult(V.transpose())).plus(V.mult(U.transpose())).mult(u); } else { y = AA.mult(u); } y = y.scale(-gamma); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Vb = BlockMatrixOps.convert(Vo.getMatrix(),r); TridiagonalHelper_B64.computeY(r, new D1Submatrix64F(Ab), new D1Submatrix64F(Vb), row, gamma); for( int i = row+1; i < A.numCols(); i++ ) { assertEquals(Vb.get(row,i),y.get(i),1e-8); } } } @Test public void computeRowOfV() { SimpleMatrix A = SimpleMatrix.random(2*r+2,2*r+2,-1,1,rand); SimpleMatrix V = SimpleMatrix.random(r,A.numCols(),-1,1,rand); double gamma = 2.3; for( int row = 0; row < r; row++ ) { SimpleMatrix u = A.extractVector(true,row).transpose(); SimpleMatrix y = V.extractVector(true,row).transpose(); for( int i = 0; i <= row; i++ ) { u.set(i,0); } u.set(row+1,1); SimpleMatrix v = y.plus(u.scale(-(gamma/2.0)*u.dot(y))); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Vb = BlockMatrixOps.convert(V.getMatrix(),r); TridiagonalHelper_B64.computeRowOfV(r, new D1Submatrix64F(Ab), new D1Submatrix64F(Vb), row, gamma); for( int i = row+1; i < A.numCols(); i++ ) { assertEquals(Vb.get(row,i),v.get(i),1e-8); } } } } ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/qr/000077500000000000000000000000001256171534400244265ustar00rootroot00000000000000GenericBlock64QrDecompositionTests.java000066400000000000000000000122561256171534400340040ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.qr; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderTran_D64; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import java.util.Random; import static org.junit.Assert.assertTrue; /** * Generic tests that test the compliance of an implementation of QRDecomposition(BlockMatrix64F). * * @author Peter Abeles */ public class GenericBlock64QrDecompositionTests { Random rand = new Random(324); int r = 3; QRDecompositionHouseholder_B64 alg; public GenericBlock64QrDecompositionTests(QRDecompositionHouseholder_B64 alg) { this.alg = alg; } /** * Runs all the tests. */ public void allTests() { applyQ(); applyQTran(); checkInternalData(); fullDecomposition(); } /** * Test applyQTran() by explicitly computing Q and compare the results of multiplying * a matrix by QT and applying Q to it. */ public void applyQTran() { for( int i = 1; i <= 3*r; i++ ) { for( int j = 1; j <= 3*r; j++ ) { BlockMatrix64F A = BlockMatrixOps.createRandom(i,j,-1,1,rand,r); assertTrue(alg.decompose(A.copy())); BlockMatrix64F Q = alg.getQ(null,false); BlockMatrix64F B = BlockMatrixOps.createRandom(i,j,-1,1,rand,r); BlockMatrix64F expected = new BlockMatrix64F(i,j,r); BlockMatrixOps.multTransA(Q,B,expected); alg.applyQTran(B); assertTrue(MatrixFeatures.isIdentical(expected,B,1e-8)); } } } /** * Test applyQ() by explicitly computing Q and compare the results of multiplying * a matrix by Q and applying Q to it. */ public void applyQ() { for( int i = 1; i <= 3*r; i++ ) { for( int j = 1; j <= 3*r; j++ ) { BlockMatrix64F A = BlockMatrixOps.createRandom(i,j,-1,1,rand,r); assertTrue(alg.decompose(A.copy())); BlockMatrix64F Q = alg.getQ(null,false); BlockMatrix64F B = BlockMatrixOps.createRandom(i,j,-1,1,rand,r); BlockMatrix64F expected = new BlockMatrix64F(i,j,r); BlockMatrixOps.mult(Q,B,expected); alg.applyQ(B); assertTrue(MatrixFeatures.isIdentical(expected,B,1e-8)); } } } /** * Decomposes the matrix and checks the internal data structure for correctness. */ public void checkInternalData() { for( int i = 1; i <= 3*r; i++ ) { for( int j = 1; j <= 3*r; j++ ) { // System.out.println("i = "+i+" j = "+j); checkSize(i,j); } } } private void checkSize( int numRows , int numCols ) { DenseMatrix64F A = RandomMatrices.createRandom(numRows,numCols,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A,r); QRDecompositionHouseholderTran_D64 algCheck = new QRDecompositionHouseholderTran_D64(); assertTrue(algCheck.decompose(A)); assertTrue(alg.decompose(Ab)); DenseMatrix64F expected = CommonOps.transpose(algCheck.getQR(),null); // expected.print(); // Ab.print(); EjmlUnitTests.assertEquals(expected,Ab,1e-8); } /** * Decomposes the matrix and computes Q and R. Verifies the results by * multiplying Q and R together and seeing if it gets A. */ public void fullDecomposition() { for( int i = 1; i <= 3*r; i++ ) { for( int j = 1; j <= 3*r; j++ ) { // i=4;j=4; // System.out.println("i = "+i+" j = "+j); checkFullDecomposition(i,j,true); checkFullDecomposition(i,j,false); } } } private void checkFullDecomposition( int numRows , int numCols , boolean compact ) { BlockMatrix64F A = BlockMatrixOps.createRandom(numRows,numCols,-1,1,rand,r); assertTrue(alg.decompose(A.copy())); BlockMatrix64F Q = alg.getQ(null,compact); BlockMatrix64F R = alg.getR(null,compact); BlockMatrix64F found = new BlockMatrix64F(numRows,numCols,r); BlockMatrixOps.mult(Q,R,found); assertTrue(GenericMatrixOps.isEquivalent(A,found,1e-8)); } } ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/qr/TestBlockHouseHolder.java000066400000000000000000000370321256171534400313320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.qr; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderTran_D64; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Submatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestBlockHouseHolder { Random rand = new Random(234); // the block length int r = 3; SimpleMatrix A, Y,V,W; @Test public void decomposeQR_block_col() { DenseMatrix64F A = RandomMatrices.createRandom(r*2+r-1,r,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A,r); QRDecompositionHouseholderTran_D64 algTest = new QRDecompositionHouseholderTran_D64(); assertTrue(algTest.decompose(A)); double gammas[] = new double[A.numCols]; BlockHouseHolder.decomposeQR_block_col(r,new D1Submatrix64F(Ab),gammas); DenseMatrix64F expected = CommonOps.transpose(algTest.getQR(),null); assertTrue(GenericMatrixOps.isEquivalent(expected,Ab,1e-8)); } @Test public void rank1UpdateMultR_Col() { // check various sized matrices double gamma = 2.5; A = SimpleMatrix.random(r*2+r-1,r*2-1,-1,1,rand); SimpleMatrix U = A.extractMatrix(0,A.numRows(),1,2); U.set(0,0,0); U.set(1,0,1); SimpleMatrix V = A.extractMatrix(0,A.numRows(),2,3); SimpleMatrix expected = V.minus(U.mult(U.transpose().mult(V)).scale(gamma)); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockHouseHolder.rank1UpdateMultR_Col(r,new D1Submatrix64F(Ab),1,gamma); for( int i = 1; i < expected.numRows(); i++ ) { assertEquals(expected.get(i,0),Ab.get(i,2),1e-8); } } @Test public void rank1UpdateMultR_TopRow() { double gamma = 2.5; A = SimpleMatrix.random(r*2+r-1,r*2-1,-1,1,rand); SimpleMatrix U = A.extractMatrix(0,A.numRows(),1,2); U.set(0,0,0); U.set(1,0,1); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockHouseHolder.rank1UpdateMultR_TopRow(r,new D1Submatrix64F(Ab),1,gamma); // check all the columns now for( int i = 0; i < r; i++ ) { for( int j = r; j < A.numCols(); j++ ) { SimpleMatrix V = A.extractMatrix(0,A.numRows(),j,j+1); SimpleMatrix expected = V.minus(U.mult(U.transpose().mult(V)).scale(gamma)); assertEquals(i+" "+j,expected.get(i,0),Ab.get(i,j),1e-8); } } } @Test public void rank1UpdateMultL_Row() { double gamma = 2.5; A = SimpleMatrix.random(r*2+r-1,r*2+r-1,-1,1,rand); SimpleMatrix U = A.extractMatrix(1,2,0,A.numCols()).transpose(); U.set(0,0); U.set(1,1); SimpleMatrix expected = A.minus( A.mult(U).mult(U.transpose()).scale(gamma) ); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockHouseHolder.rank1UpdateMultL_Row(r,new D1Submatrix64F(Ab),1,1,gamma); for( int j = 1; j < expected.numCols(); j++ ) { assertEquals(expected.get(2,j),Ab.get(2,j),1e-8); } } @Test public void rank1UpdateMultL_LeftCol() { double gamma = 2.5; A = SimpleMatrix.random(r*2+r-1,r*2+r-1,-1,1,rand); int row = 0; int zeroOffset = 1; SimpleMatrix U = A.extractMatrix(row,row+1,0,A.numCols()).transpose(); for( int i = 0; i < row+zeroOffset; i++ ) U.set(i,0); U.set(row+zeroOffset,1); SimpleMatrix expected = A.minus( A.mult(U).mult(U.transpose()).scale(gamma) ); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockHouseHolder.rank1UpdateMultL_LeftCol(r,new D1Submatrix64F(Ab),row,gamma,zeroOffset); for( int i = r; i < A.numRows(); i++ ) { for( int j = 0; j < r; j++ ) { assertEquals(expected.get(i,j),Ab.get(i,j),1e-8); } } } /** * Check inner product when column blocks have two different widths */ @Test public void innerProdCol() { DenseMatrix64F A = RandomMatrices.createRandom(r*2+r-1,r*3-1,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A,r); int row = 0; int innerCol = 1; for( int colBlock = 0; colBlock < r*2; colBlock+=r) { int colA = colBlock+innerCol; int colB = colA+innerCol+1; int widthA = Math.min(r,A.numCols - (colA-colA%r)); int widthB = Math.min(r,A.numCols - (colB-colB%r)); DenseMatrix64F v0 = CommonOps.extract(A,row,A.numRows,colA,colA+1); DenseMatrix64F v1 = CommonOps.extract(A,row,A.numRows,colB,colB+1); for( int j = 0; j < innerCol; j++ ) { v0.set(j,0.0); } v0.set(innerCol,1.0); double expected = VectorVectorMult.innerProd(v0,v1); D1Submatrix64F subAb = new D1Submatrix64F(Ab,row,A.numRows,colBlock,A.numCols); double found = BlockHouseHolder.innerProdCol(r,subAb,colA-colBlock,widthA,colB-colBlock,widthB); assertEquals(expected,found,1e-8); } } @Test public void innerProdRow() { DenseMatrix64F A = RandomMatrices.createRandom(r*3-1,r*2+r-1,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A,r); int zeroOffset = 1; for( int rowBlock = 0; rowBlock < r*2; rowBlock+=r) { int rowA = 2; int rowB = 1; DenseMatrix64F v0 = CommonOps.extract(A,rowBlock+rowA,rowBlock+rowA+1,0,A.numCols); DenseMatrix64F v1 = CommonOps.extract(A,rowBlock+rowB,rowBlock+rowB+1,0,A.numCols); for( int j = 0; j < rowA+zeroOffset; j++ ) { v0.set(j,0.0); } v0.set(rowA+zeroOffset,1.0); double expected = VectorVectorMult.innerProd(v0,v1); D1Submatrix64F subAb = new D1Submatrix64F(Ab,rowBlock,A.numRows,0,A.numCols); double found = BlockHouseHolder.innerProdRow(r, subAb,rowA,subAb,rowB,zeroOffset); assertEquals(expected,found,1e-8); } } @Test public void divideElementsCol() { double div = 1.5; int col = 1; BlockMatrix64F A = BlockMatrixOps.createRandom(r*2+r-1,r,-1,1,rand,r); BlockMatrix64F A_orig = A.copy(); BlockHouseHolder.divideElementsCol(r,new D1Submatrix64F(A),col,div); for( int i = col+1; i < A.numRows; i++ ) { assertEquals(A_orig.get(i,col)/div , A.get(i,col),1e-8); } } @Test public void scale_row() { double div = 1.5; int row = 1; BlockMatrix64F A = BlockMatrixOps.createRandom(r*2+r-1,r*2+1,-1,1,rand,r); BlockMatrix64F A_orig = A.copy(); BlockHouseHolder.scale_row(r,new D1Submatrix64F(A),new D1Submatrix64F(A),row,1,div); // check the one assertEquals(div,A.get(row,row+1),1e-8); // check the rest for( int i = row+2; i < A.numCols; i++ ) { assertEquals(A_orig.get(row,i)*div , A.get(row,i),1e-8); } } @Test public void add_row() { int rowA=0; int rowB=1; int rowC=2; double alpha = 1.5; double beta = -0.7; for( int width = 1; width <= 3*r; width++ ) { // System.out.println("width "+width); int end = width; SimpleMatrix A = SimpleMatrix.random(r,width,-1,1,rand); SimpleMatrix B = SimpleMatrix.random(r,width,-1,1,rand); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Bb = BlockMatrixOps.convert(B.getMatrix(),r); BlockMatrix64F Cb = Ab.copy(); // turn A into householder vectors for( int i = 0; i < A.numRows(); i++ ) { for( int j = 0; j <= i; j++ ) { if( A.isInBounds(i,j)) A.set(i,j,0); } if( A.isInBounds(i,i+1) ) A.set(i,i+1,1); } SimpleMatrix a = A.extractVector(true,rowA).scale(alpha); SimpleMatrix b = B.extractVector(true,rowB).scale(beta); SimpleMatrix c = a.plus(b); BlockHouseHolder.add_row(r, new D1Submatrix64F(Ab),rowA, alpha, new D1Submatrix64F(Bb),rowB, beta , new D1Submatrix64F(Cb),rowC, 1,end); // skip over the zeros for( int j = rowA+1; j < end; j++ ) { assertEquals(c.get(j), Cb.get(rowC,j),1e-8); } } } @Test public void computeTauAndDivideCol() { double max = 1.5; int col = 1; BlockMatrix64F A = BlockMatrixOps.createRandom(r*2+r-1,r,-1,1,rand,r); BlockMatrix64F A_orig = A.copy(); // manual alg double expected = 0; for( int i = col; i < A.numRows; i++ ) { double val = A.get(i,col)/max; expected += val*val; } expected = Math.sqrt(expected); double found = BlockHouseHolder.computeTauAndDivideCol(r,new D1Submatrix64F(A),col,max); assertEquals(expected,found,1e-8); for( int i = col; i < A.numRows; i++ ) { assertEquals(A_orig.get(i,col)/max , A.get(i,col),1e-8); } } @Test public void computeTauAndDivideRow() { double max = 1.5; int row = 1; int colStart = row+1; BlockMatrix64F A = BlockMatrixOps.createRandom(r*2+r-1,r*2+1,-1,1,rand,r); BlockMatrix64F A_orig = A.copy(); // manual alg double expected = 0; for( int j = colStart; j < A.numCols; j++ ) { double val = A.get(row,j)/max; expected += val*val; } expected = Math.sqrt(expected); double found = BlockHouseHolder.computeTauAndDivideRow(r,new D1Submatrix64F(A),row,colStart,max); assertEquals(expected,found,1e-8); for( int j = colStart; j < A.numCols; j++ ) { assertEquals(A_orig.get(row,j)/max , A.get(row,j),1e-8); } } @Test public void testFindMaxCol() { BlockMatrix64F A = BlockMatrixOps.createRandom(r*2+r-1,r,-1,1,rand,r); // make sure it ignores the first element A.set(0,1,100000); A.set(5,1,-2346); double max = BlockHouseHolder.findMaxCol(r,new D1Submatrix64F(A),1); assertEquals(2346,max,1e-8); } @Test public void testFindMaxRow() { BlockMatrix64F A = BlockMatrixOps.createRandom(r*2+r-1,r*2-1,-1,1,rand,r); // make sure it ignores the first element A.set(1,1,100000); A.set(1,4,-2346); double max = BlockHouseHolder.findMaxRow(r,new D1Submatrix64F(A),1,2); assertEquals(2346,max,1e-8); } @Test public void computeW_Column() { double betas[] = new double[]{1.2,2,3}; A = SimpleMatrix.random(r*2+r-1,r,-1,1,rand); // Compute W directly using SimpleMatrix SimpleMatrix V = A.extractMatrix(0,A.numRows(),0,1); V.set(0,0,1); SimpleMatrix Y = V; SimpleMatrix W = V.scale(-betas[0]); for( int i = 1; i < A.numCols(); i++ ) { V = A.extractMatrix(0,A.numRows(),i,i+1); for( int j = 0; j < i; j++ ) V.set(j,0,0); V.set(i,0,1); SimpleMatrix z = V.plus(W.mult(Y.transpose().mult(V))).scale(-betas[i]); W = W.combine(0,i,z); Y = Y.combine(0,i,V); } // now compute it using the block matrix stuff double temp[] = new double[ r ]; BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Wb = new BlockMatrix64F(Ab.numRows,Ab.numCols,r); D1Submatrix64F Ab_sub = new D1Submatrix64F(Ab); D1Submatrix64F Wb_sub = new D1Submatrix64F(Wb); BlockHouseHolder.computeW_Column(r,Ab_sub,Wb_sub,temp,betas,0); // see if the result is the same assertTrue(GenericMatrixOps.isEquivalent(Wb,W.getMatrix(),1e-8)); } @Test public void initializeW() { initMatrices(r-1); double beta = 1.5; BlockMatrix64F Wb = BlockMatrixOps.convert(W.getMatrix(),r); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); D1Submatrix64F Wb_sub = new D1Submatrix64F(Wb,0, W.numRows(), 0, r); D1Submatrix64F Yb_sub = new D1Submatrix64F(Ab,0, A.numRows(), 0, r); BlockHouseHolder.initializeW(r,Wb_sub,Yb_sub,r,beta); assertEquals(-beta,Wb.get(0,0),1e-8); for( int i = 1; i < Wb.numRows; i++ ) { assertEquals(-beta*Ab.get(i,0),Wb.get(i,0),1e-8); } } @Test public void computeZ() { int M = r-1; initMatrices(M); double beta = 2.5; BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); BlockMatrix64F Aw = BlockMatrixOps.convert(W.getMatrix(),r); // need to extract only the elements in W that are currently being used when // computing the expected Z W = W.extractMatrix(0,W.numRows(),0,M); SimpleMatrix T = SimpleMatrix.random(M,1,-1,1,rand); // -beta * (V + W*T) SimpleMatrix expected = V.plus(W.mult(T)).scale(-beta); BlockHouseHolder.computeZ(r,new D1Submatrix64F(Ab,0, A.numRows(), 0, r),new D1Submatrix64F(Aw,0, A.numRows(), 0, r), M,T.getMatrix().data,beta); for( int i = 0; i < A.numRows(); i++ ) { assertEquals(expected.get(i),Aw.get(i,M),1e-8); } } @Test public void computeY_t_V() { int M = r-2; initMatrices(M); // Y'*V SimpleMatrix expected = Y.transpose().mult(V); BlockMatrix64F Ab = BlockMatrixOps.convert(A.getMatrix(),r); double found[] = new double[ M ]; BlockHouseHolder.computeY_t_V(r,new D1Submatrix64F(Ab,0, A.numRows(), 0, r),M,found); for( int i = 0; i < M; i++ ) { assertEquals(expected.get(i),found[i],1e-8); } } private void initMatrices( int M ) { A = SimpleMatrix.random(r*2+r-1,r,-1,1,rand); // create matrices that are used to test Y = A.extractMatrix(0,A.numRows(),0,M); V = A.extractMatrix(0,A.numRows(),M,M+1); // add in zeros and ones setZerosY(); for( int i = 0; i < M; i++ ) { V.set(i,0); } V.set(M,1); W = SimpleMatrix.random(r*2+r-1,r,-1,1,rand); } private void setZerosY() { for( int j = 0; j < Y.numCols(); j++ ) { for( int i = 0; i < j; i++ ) { Y.set(i,j,0); } Y.set(j,j,1); } } } TestQRDecompositionHouseholder_B64.java000066400000000000000000000026241256171534400337520ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.decomposition.qr; import org.junit.Test; /** * @author Peter Abeles */ public class TestQRDecompositionHouseholder_B64 { @Test public void generic() { QRDecompositionHouseholder_B64 decomp = new QRDecompositionHouseholder_B64(); GenericBlock64QrDecompositionTests tests; tests = new GenericBlock64QrDecompositionTests(decomp); tests.allTests(); } @Test public void genericSaveW() { QRDecompositionHouseholder_B64 decomp = new QRDecompositionHouseholder_B64(); decomp.setSaveW(true); GenericBlock64QrDecompositionTests tests; tests = new GenericBlock64QrDecompositionTests(decomp); tests.allTests(); } } ejml-0.28/main/dense64/test/org/ejml/alg/block/linsol/000077500000000000000000000000001256171534400224305ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/linsol/chol/000077500000000000000000000000001256171534400233555ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/linsol/chol/TestBlockCholeskyOuterSolver.java000066400000000000000000000134651256171534400320370ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.linsol.chol; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.linsol.qr.BlockQrHouseHolderSolver; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestBlockCholeskyOuterSolver { protected Random rand = new Random(234234); protected int r = 3; /** * Test positive examples against a variety of different inputs shapes. */ @Test public void testPositiveSolve() { BlockCholeskyOuterSolver solver = new BlockCholeskyOuterSolver(); for( int i = 1; i <= r*3; i++ ) { for( int j = 1; j <= r*3; j++ ) { BlockMatrix64F A = createMatrixSPD(i); BlockMatrix64F X = BlockMatrixOps.createRandom(i,j,-1,1,rand,r); BlockMatrix64F Y = new BlockMatrix64F(i,j,r); BlockMatrix64F X_found = new BlockMatrix64F(i,j,r); // compute the expected solution directly BlockMatrixOps.mult(A,X,Y); assertTrue(solver.setA(A.copy())); solver.solve(Y,X_found); assertTrue(BlockMatrixOps.isEquals(X,X_found,1e-8)); } } } /** * Give it a matrix which is not SPD and see if it fails */ @Test public void testNegativeSolve() { BlockCholeskyOuterSolver solver = new BlockCholeskyOuterSolver(); BlockMatrix64F X = BlockMatrixOps.createRandom(7,7,-1,1,rand,r); assertFalse(solver.setA(X)); } @Test public void testInvert() { BlockCholeskyOuterSolver solver = new BlockCholeskyOuterSolver(); for( int i = 1; i <= r*3; i++ ) { BlockMatrix64F A = createMatrixSPD(i); BlockMatrix64F A_inv = BlockMatrixOps.createRandom(i,i,-1,1,rand,r); assertTrue(solver.setA(A.copy())); solver.invert(A_inv); BlockMatrix64F B = new BlockMatrix64F(i,i,r); BlockMatrixOps.mult(A,A_inv,B); assertTrue(GenericMatrixOps.isIdentity(B,1e-8)); } } @Test public void testQuality() { BlockCholeskyOuterSolver solver = new BlockCholeskyOuterSolver(); DenseMatrix64F A = CommonOps.diag(5,3,2,1); DenseMatrix64F B = CommonOps.diag(5,3,2,0.001); assertTrue(solver.setA(BlockMatrixOps.convert(A,r))); double qualityA = solver.quality(); assertTrue(solver.setA(BlockMatrixOps.convert(B,r))); double qualityB = solver.quality(); assertTrue(qualityB < qualityA); assertTrue(qualityB*10.0 < qualityA); } @Test public void testQuality_scale() { BlockCholeskyOuterSolver solver = new BlockCholeskyOuterSolver(); DenseMatrix64F A = CommonOps.diag(5,3,2,1); DenseMatrix64F B = A.copy(); CommonOps.scale(0.001,B); assertTrue(solver.setA(BlockMatrixOps.convert(A,r))); double qualityA = solver.quality(); assertTrue(solver.setA(BlockMatrixOps.convert(B,r))); double qualityB = solver.quality(); assertEquals(qualityB,qualityA,1e-8); } @Test public void testPositiveSolveNull() { BlockCholeskyOuterSolver solver = new BlockCholeskyOuterSolver(); for( int i = 1; i <= r*3; i++ ) { for( int j = 1; j <= r*3; j++ ) { BlockMatrix64F A = createMatrixSPD(i); BlockMatrix64F X = BlockMatrixOps.createRandom(i,j,-1,1,rand,r); BlockMatrix64F Y = new BlockMatrix64F(i,j,r); BlockMatrix64F X_found = new BlockMatrix64F(i,j,r); // compute the expected solution directly BlockMatrixOps.mult(A,X,Y); assertTrue(solver.setA(A.copy())); solver.solve(Y,null); assertTrue(BlockMatrixOps.isEquals(X,Y,1e-8)); } } } @Test public void modifiesA(){ BlockMatrix64F A = createMatrixSPD(4); BlockMatrix64F A_orig = A.copy(); BlockQrHouseHolderSolver solver = new BlockQrHouseHolderSolver(); assertTrue(solver.setA(A)); boolean modified = !MatrixFeatures.isEquals(A,A_orig); assertTrue(modified == solver.modifiesA()); } @Test public void modifiesB(){ BlockMatrix64F A = createMatrixSPD(4); BlockQrHouseHolderSolver solver = new BlockQrHouseHolderSolver(); assertTrue(solver.setA(A)); BlockMatrix64F B = BlockMatrixOps.createRandom(4,2,-1,1,rand,3); BlockMatrix64F B_orig = B.copy(); BlockMatrix64F X = new BlockMatrix64F(A.numRows,B.numCols,3); solver.solve(B,X); boolean modified = !MatrixFeatures.isEquals(B_orig,B); assertTrue(modified == solver.modifiesB()); } protected BlockMatrix64F createMatrixSPD( int width ) { DenseMatrix64F A = RandomMatrices.createSymmPosDef(width,rand); return BlockMatrixOps.convert(A,r); } } ejml-0.28/main/dense64/test/org/ejml/alg/block/linsol/qr/000077500000000000000000000000001256171534400230525ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/block/linsol/qr/TestBlockQrHouseHolderSolver.java000066400000000000000000000117571256171534400314620ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block.linsol.qr; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestBlockQrHouseHolderSolver { Random rand = new Random(23423); /** * Test positive examples against a variety of different inputs shapes. */ @Test public void testPositiveSolve() { int r = 3; BlockQrHouseHolderSolver solver = new BlockQrHouseHolderSolver(); for( int i = 1; i <= r*3; i++ ) { for( int j = i; j <= r*3; j++ ) { for( int k = 1; k <= r*3; k++ ) { // System.out.println("i = "+i+" j = "+j+" k = "+k); BlockMatrix64F A = BlockMatrixOps.createRandom(j,i,-1,1,rand,r); BlockMatrix64F X = BlockMatrixOps.createRandom(i,k,-1,1,rand,r); BlockMatrix64F Y = new BlockMatrix64F(j,k,r); BlockMatrix64F X_found = new BlockMatrix64F(i,k,r); // compute the expected solution directly BlockMatrixOps.mult(A,X,Y); assertTrue(solver.setA(A.copy())); solver.solve(Y,X_found); assertTrue(BlockMatrixOps.isEquals(X,X_found,1e-8)); } } } } @Test public void testInvert() { int r = 3; BlockQrHouseHolderSolver solver = new BlockQrHouseHolderSolver(); for( int i = 1; i <= r*3; i++ ) { BlockMatrix64F A = BlockMatrixOps.createRandom(i,i,-1,1,rand,r); BlockMatrix64F A_orig = A.copy(); BlockMatrix64F I = new BlockMatrix64F(i,i,r); assertTrue(solver.setA(A.copy())); solver.invert(A); // A times its inverse is an identity matrix BlockMatrixOps.mult(A,A_orig,I); assertTrue(GenericMatrixOps.isIdentity(I,1e-8)); } } @Test public void testQuality() { BlockMatrix64F A = BlockMatrixOps.convert(CommonOps.diag(4,3,2,1),3); BlockMatrix64F B = BlockMatrixOps.convert(CommonOps.diag(4,3,2,0.1),3); // see if a matrix with smaller singular value has a worse quality BlockQrHouseHolderSolver solver = new BlockQrHouseHolderSolver(); assertTrue(solver.setA(A.copy())); double qualityA = solver.quality(); assertTrue(solver.setA(B.copy())); double qualityB = solver.quality(); assertTrue(qualityB { @Override public boolean decompose(BlockMatrix64F orig) { // see if the input was correctly converted int val = 0; for (int i = 0; i < orig.numRows; i++) { for (int j = 0; j < orig.numCols; j++,val++) { assertEquals(val,orig.get(i,j),1e-8); } } // modify it now Arrays.fill(orig.data,1); return true; } @Override public boolean inputModified() { return true; } } private static class DoNotModifyBlock implements DecompositionInterface { @Override public boolean decompose(BlockMatrix64F orig) { return true; } @Override public boolean inputModified() { return false; } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/TestTriangularSolver.java000066400000000000000000000133661256171534400310270ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition; import org.ejml.alg.dense.misc.UnrolledInverseFromMinor; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestTriangularSolver { Random rand = new Random(0xff); @Test public void invert_inplace() { DenseMatrix64F L = createRandomLowerTriangular(); DenseMatrix64F L_inv = L.copy(); TriangularSolver.invertLower(L_inv.data,L.numRows); DenseMatrix64F I = new DenseMatrix64F(L.numRows,L.numCols); CommonOps.mult(L,L_inv,I); assertTrue(MatrixFeatures.isIdentity(I,1e-8)); } @Test public void invert() { DenseMatrix64F L = createRandomLowerTriangular(); DenseMatrix64F L_inv = L.copy(); TriangularSolver.invertLower(L.data,L_inv.data,L.numRows); DenseMatrix64F I = new DenseMatrix64F(L.numRows,L.numCols); CommonOps.mult(L,L_inv,I); assertTrue(MatrixFeatures.isIdentity(I,1e-8)); } @Test public void solveL_vector() { DenseMatrix64F L = createRandomLowerTriangular(); DenseMatrix64F L_inv = L.copy(); UnrolledInverseFromMinor.inv(L_inv,L_inv); DenseMatrix64F B = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F expected = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F found = B.copy(); TriangularSolver.solveL(L.data,found.data,3); CommonOps.mult(L_inv,B,expected); assertTrue(MatrixFeatures.isIdentical(expected,found,1e-8)); } private DenseMatrix64F createRandomLowerTriangular() { DenseMatrix64F L = RandomMatrices.createRandom(3,3,rand); for( int i = 0; i < L.numRows; i++ ) { for( int j = i+1; j < L.numCols; j++ ) { L.set(i,j,0); } } return L; } @Test public void solveL_matrix() { DenseMatrix64F L = createRandomLowerTriangular(); DenseMatrix64F L_inv = L.copy(); UnrolledInverseFromMinor.inv(L_inv,L_inv); DenseMatrix64F B = RandomMatrices.createRandom(3,4,rand); DenseMatrix64F expected = RandomMatrices.createRandom(3,4,rand); DenseMatrix64F found = B.copy(); TriangularSolver.solveL(L.data,found.data,3,4); CommonOps.mult(L_inv,B,expected); assertTrue(MatrixFeatures.isIdentical(expected,found,1e-8)); } @Test public void solveTranL() { DenseMatrix64F L = createRandomLowerTriangular(); DenseMatrix64F B = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F expected = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F found = B.copy(); TriangularSolver.solveTranL(L.data,found.data,3); CommonOps.transpose(L); DenseMatrix64F L_inv = L.copy(); UnrolledInverseFromMinor.inv(L_inv,L_inv); CommonOps.mult(L_inv,B,expected); assertTrue(MatrixFeatures.isIdentical(expected,found,1e-8)); } @Test public void solveU() { DenseMatrix64F U = RandomMatrices.createRandom(3,3,rand); for( int i = 0; i < U.numRows; i++ ) { for( int j = 0; j < i; j++ ) { U.set(i,j,0); } } DenseMatrix64F U_inv = U.copy(); UnrolledInverseFromMinor.inv(U_inv,U_inv); DenseMatrix64F B = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F expected = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F found = B.copy(); TriangularSolver.solveU(U.data,found.data,3); CommonOps.mult(U_inv,B,expected); assertTrue(MatrixFeatures.isIdentical(expected,found,1e-8)); } @Test public void solveU_submatrix() { // create U and B. Insert into a larger matrix DenseMatrix64F U_orig = RandomMatrices.createRandom(3,3,rand); for( int i = 0; i < U_orig.numRows; i++ ) { for( int j = 0; j < i; j++ ) { U_orig.set(i,j,0); } } DenseMatrix64F U = new DenseMatrix64F(6,7); CommonOps.insert(U_orig,U,2,3); DenseMatrix64F B_orig = RandomMatrices.createRandom(3,2,rand); DenseMatrix64F B = new DenseMatrix64F(4,5); CommonOps.insert(B_orig,B,1,2); // compute expected solution DenseMatrix64F U_inv = U_orig.copy(); UnrolledInverseFromMinor.inv(U_inv,U_inv); DenseMatrix64F expected = RandomMatrices.createRandom(3,2,rand); int startU = 2*U.numCols+3; int strideU = U.numCols; int widthU = U_orig.numCols; int startB = 1*B.numCols+2; int strideB = B.numCols; int widthB = B_orig.numCols; TriangularSolver.solveU(U.data,startU,strideU,widthU,B.data,startB,strideB,widthB); DenseMatrix64F found = CommonOps.extract(B,1,4,2,4); CommonOps.mult(U_inv,B_orig,expected); assertTrue(MatrixFeatures.isIdentical(expected,found,1e-8)); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/bidiagonal/000077500000000000000000000000001256171534400261015ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/bidiagonal/GenericBidiagonalCheck.java000066400000000000000000000107151256171534400332340ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.bidiagonal; import org.ejml.alg.dense.decomposition.CheckDecompositionInterface; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.BidiagonalDecomposition; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public abstract class GenericBidiagonalCheck { protected Random rand = new Random(0xff); abstract protected BidiagonalDecomposition createQRDecomposition(); @Test public void testModifiedInput() { CheckDecompositionInterface.checkModifiedInput(createQRDecomposition()); } @Test public void testRandomMatrices() { BidiagonalDecomposition decomp = createQRDecomposition(); for( int i = 0; i < 10; i++ ) { for( int N = 2; N <= 10; N++ ) { for( int tall = 0; tall <= 2; tall++ ) { DenseMatrix64F A = RandomMatrices.createRandom(N+tall,N,rand); assertTrue(decomp.decompose(A.copy())); checkGeneric(A, decomp); } for( int wide = 1; wide <= 2; wide++ ) { DenseMatrix64F A = RandomMatrices.createRandom(N,N+wide,rand); assertTrue(decomp.decompose(A.copy())); checkGeneric(A, decomp); } } } } @Test public void testIdentity() { SimpleMatrix A = SimpleMatrix.identity(5); BidiagonalDecomposition decomp = createQRDecomposition(); assertTrue(decomp.decompose(A.getMatrix().copy())); checkGeneric(A.getMatrix(), decomp); } @Test public void testZero() { SimpleMatrix A = new SimpleMatrix(5,5); BidiagonalDecomposition decomp = createQRDecomposition(); assertTrue(decomp.decompose(A.getMatrix().copy())); checkGeneric(A.getMatrix(), decomp); } /** * Checks to see if the decomposition will reconstruct the original input matrix */ protected void checkGeneric(DenseMatrix64F a, BidiagonalDecomposition decomp) { // check the full version SimpleMatrix U = SimpleMatrix.wrap(decomp.getU(null,false,false)); SimpleMatrix B = SimpleMatrix.wrap(decomp.getB(null,false)); SimpleMatrix V = SimpleMatrix.wrap(decomp.getV(null,false,false)); DenseMatrix64F foundA = U.mult(B).mult(V.transpose()).getMatrix(); assertTrue(MatrixFeatures.isIdentical(a,foundA,1e-8)); // check with transpose SimpleMatrix Ut = SimpleMatrix.wrap(decomp.getU(null,true,false)); assertTrue(U.transpose().isIdentical(Ut,1e-8)); SimpleMatrix Vt = SimpleMatrix.wrap(decomp.getV(null,true,false)); assertTrue(V.transpose().isIdentical(Vt,1e-8)); // U.print(); // V.print(); // B.print(); // System.out.println("------------------------"); // now test compact U = SimpleMatrix.wrap(decomp.getU(null,false,true)); B = SimpleMatrix.wrap(decomp.getB(null,true)); V = SimpleMatrix.wrap(decomp.getV(null,false,true)); // U.print(); // V.print(); // B.print(); foundA = U.mult(B).mult(V.transpose()).getMatrix(); assertTrue(MatrixFeatures.isIdentical(a,foundA,1e-8)); // check with transpose Ut = SimpleMatrix.wrap(decomp.getU(null,true,true)); Vt = SimpleMatrix.wrap(decomp.getV(null,true,true)); assertTrue(U.transpose().isIdentical(Ut,1e-8)); assertTrue(V.transpose().isIdentical(Vt,1e-8)); } } TestBidiagonalDecompositionRow_D64.java000066400000000000000000000130731256171534400354240ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/bidiagonal/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.bidiagonal; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; import org.ejml.interfaces.decomposition.BidiagonalDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.ops.SpecializedOps; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestBidiagonalDecompositionRow_D64 extends GenericBidiagonalCheck { /** * See if the naive implementation and this version produce the same results. */ @Test public void testAgainstNaive() { for( int i = 1; i <= 5; i++ ) { for( int j = 1; j <= 5; j++ ) { checkNaive(i,j); } } } private void checkNaive(int m, int n) { SimpleMatrix A = SimpleMatrix.wrap(RandomMatrices.createRandom(m,n,rand)); BidiagonalDecompositionRow_D64 decomp = new BidiagonalDecompositionRow_D64(); BidiagonalDecompositionNaive_D64 naive = new BidiagonalDecompositionNaive_D64(); assertTrue(decomp.decompose(A.getMatrix().copy())); assertTrue(naive.decompose(A.getMatrix())); SimpleMatrix U = SimpleMatrix.wrap(decomp.getU(null,false,false)); SimpleMatrix B = SimpleMatrix.wrap(decomp.getB(null,false)); SimpleMatrix V = SimpleMatrix.wrap(decomp.getV(null,false,false)); // U.print(); // B.print(); // naive.getB().print(); // V.print(); // naive.getV().print(); // naive.getVTran().print(); assertTrue(naive.getB().isIdentical(B,1e-8)); assertTrue(naive.getU().isIdentical(U,1e-8)); assertTrue(naive.getV().isIdentical(V,1e-8)); // check the decomposition DenseMatrix64F foundA = U.mult(B).mult(V.transpose()).getMatrix(); // A.print(); // foundA.print(); assertTrue(MatrixFeatures.isIdentical(A.getMatrix(),foundA,1e-8)); } @Test public void testComputeU() { int m = 7; int n = 5; DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DebugBidiagonal alg = new DebugBidiagonal(A); DenseMatrix64F B = new DenseMatrix64F(A); DenseMatrix64F C = new DenseMatrix64F(m,n); DenseMatrix64F u = new DenseMatrix64F(m,1); RowD1Matrix64F UBV = alg.getUBV(); for( int i = 0; i < n; i++ ) { alg.computeU(i); SpecializedOps.subvector(UBV,i+1,i,m-i-1,false,i+1,u); u.data[i] = 1; DenseMatrix64F Q = SpecializedOps.createReflector(u,alg.getGammasU()[i]); CommonOps.mult(Q,B,C); // u.print(); // B.print(); // UBV.print(); // C.print(); B.set(C); // make sure everything is as expected for( int j = i+1; j < m; j++ ) { assertEquals(0,C.get(j,i),1e-8); } for( int j = i+1; j < n; j++ ) { assertEquals(UBV.get(i,j),C.get(i,j),1e-8); } u.data[i] = 0; } } @Test public void testComputeV() { int m = 7; int n = 5; DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DebugBidiagonal alg = new DebugBidiagonal(A); DenseMatrix64F B = new DenseMatrix64F(A); DenseMatrix64F C = new DenseMatrix64F(m,n); DenseMatrix64F u = new DenseMatrix64F(n,1); RowD1Matrix64F UBV = alg.getUBV(); // A.print(); for( int i = 0; i < n-2; i++ ) { alg.computeV(i); u.zero(); SpecializedOps.subvector(UBV,i,i+2,n-i-2,true,i+2,u); u.data[i+1] = 1; DenseMatrix64F Q = SpecializedOps.createReflector(u,alg.getGammasV()[i]); // Q.print(); CommonOps.mult(B,Q,C); // u.print(); // B.print(); // UBV.print(); // C.print(); B.set(C); // make sure everything is as expected for( int j = i+2; j < n; j++ ) { assertEquals(0,C.get(i,j),1e-8); } for( int j = i+2; j < m; j++ ) { assertEquals(UBV.get(j,i),C.get(j,i),1e-8); } u.data[i] = 0; } } @Override protected BidiagonalDecomposition createQRDecomposition() { return new BidiagonalDecompositionRow_D64(); } private static class DebugBidiagonal extends BidiagonalDecompositionRow_D64 { public DebugBidiagonal( DenseMatrix64F A ) { init(A.copy()); } @Override protected void computeU(int k) { super.computeU(k); } @Override protected void computeV(int k) { super.computeV(k); } } } TestBidiagonalDecompositionTall_D64.java000066400000000000000000000021411256171534400355430ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/bidiagonal/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.bidiagonal; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.BidiagonalDecomposition; /** * @author Peter Abeles */ public class TestBidiagonalDecompositionTall_D64 extends GenericBidiagonalCheck { @Override protected BidiagonalDecomposition createQRDecomposition() { return new BidiagonalDecompositionTall_D64(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/chol/000077500000000000000000000000001256171534400247355ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/chol/GenericCholeskyTests_D64.java000066400000000000000000000125131256171534400323200ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public abstract class GenericCholeskyTests_D64 { Random rand = new Random(0x45478); boolean canL = true; boolean canR = true; public abstract CholeskyDecomposition create( boolean lower ); @Test public void testDecomposeL() { if( !canL ) return; DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 4, 2, 13, 23, 4, 23, 90); DenseMatrix64F L = new DenseMatrix64F(3,3, true, 1, 0, 0, 2, 3, 0, 4, 5, 7); CholeskyDecomposition cholesky = create(true); assertTrue(cholesky.decompose(A)); DenseMatrix64F foundL = cholesky.getT(null); EjmlUnitTests.assertEquals(L,foundL,1e-8); } @Test public void testDecomposeR() { if( !canR ) return; DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 4, 2, 13, 23, 4, 23, 90); DenseMatrix64F R = new DenseMatrix64F(3,3, true, 1, 2, 4, 0, 3, 5, 0, 0, 7); CholeskyDecomposition cholesky = create(false); assertTrue(cholesky.decompose(A)); DenseMatrix64F foundR = cholesky.getT(null); EjmlUnitTests.assertEquals(R,foundR,1e-8); } /** * If it is not positive definate it should fail */ @Test public void testNotPositiveDefinite() { DenseMatrix64F A = new DenseMatrix64F(2,2, true, 1, -1, -1, -2); CholeskyDecomposition alg = create(true); assertFalse(alg.decompose(A)); } /** * The correctness of getT(null) has been tested else where effectively. This * checks to see if it handles the case where an input is provided correctly. */ @Test public void getT() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 4, 2, 13, 23, 4, 23, 90); CholeskyDecomposition cholesky = create(true); assertTrue(cholesky.decompose(A)); DenseMatrix64F L_null = cholesky.getT(null); DenseMatrix64F L_provided = RandomMatrices.createRandom(3,3,rand); assertTrue( L_provided == cholesky.getT(L_provided)); assertTrue(MatrixFeatures.isEquals(L_null,L_provided)); } /** * Test across several different matrix sizes and upper/lower decompositions using * the definition of cholesky. */ @Test public void checkWithDefinition() { for( int i = 0; i < 2; i++ ) { boolean lower = i == 0; if( lower && !canL ) continue; if( !lower && !canR ) continue; for( int size = 1; size < 10; size++ ) { checkWithDefinition(lower, size); } } } private void checkWithDefinition(boolean lower, int size) { SimpleMatrix A = SimpleMatrix.wrap( RandomMatrices.createSymmPosDef(size,rand)); CholeskyDecomposition cholesky = create(lower); assertTrue(DecompositionFactory.decomposeSafe(cholesky,A.getMatrix())); SimpleMatrix T = SimpleMatrix.wrap(cholesky.getT(null)); SimpleMatrix found; if( lower ) { found = T.mult(T.transpose()); } else { found = T.transpose().mult(T); } assertTrue(A.isIdentical(found,1e-8)); } @Test public void checkDeterminant() { for( int i = 0; i < 2; i++ ) { boolean lower = i == 0; if( lower && !canL ) continue; if( !lower && !canR ) continue; for( int size = 1; size < 20; size += 2 ) { checkDeterminant(lower, size); } } } public void checkDeterminant( boolean lower , int size ) { LUDecomposition lu = DecompositionFactory.lu(size,size); CholeskyDecomposition cholesky = create(lower); DenseMatrix64F A = RandomMatrices.createSymmPosDef(size,rand); assertTrue(DecompositionFactory.decomposeSafe(lu,A)); assertTrue(DecompositionFactory.decomposeSafe(cholesky,A)); double expected = lu.computeDeterminant().real; double found = cholesky.computeDeterminant().real; assertEquals(expected,found,1e-8); } } TestCholeskyDecompositionBlock_D64.java000066400000000000000000000065161256171534400342770ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.alg.dense.linsol.chol.LinearSolverChol_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; import static org.ejml.alg.dense.decomposition.CheckDecompositionInterface.checkModifiedInput; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCholeskyDecompositionBlock_D64 extends GenericCholeskyTests_D64 { public TestCholeskyDecompositionBlock_D64(){ canR = false; } @Test public void checkModifyInput() { checkModifiedInput(new CholeskyDecompositionBlock_D64(2)); } @Override public CholeskyDecomposition create(boolean lower) { if( !lower ) throw new IllegalArgumentException("Doesn't support upper form"); return new CholeskyDecompositionBlock_D64(1); } /** * * L = * * 2 0 0 0 * 1 5 0 0 * 3 2 4 0 * 7 1 6 3 * */ @Test public void testWithBlocks() { int W = 4; int B = 2; checkBlockMatrix(W, B); } /** * The block size and the matrix width are not perfectly divisible. see if this is handled correctly. */ @Test public void testWithBlocksNotDivisible() { int W = 4; int B = 3; checkBlockMatrix(W, B); } /** * The block size is bigger than the matrix. */ @Test public void testWithBlocksBiggerThanMatrix() { int W = 4; int B = 10; checkBlockMatrix(W, B); } private void checkBlockMatrix(int w, int b) { DenseMatrix64F A = new DenseMatrix64F(w, w, true, 4, 2, 6, 14, 2, 26, 13, 12, 6, 13, 29, 47, 14, 12, 47, 95); DenseMatrix64F A_inv = new DenseMatrix64F(w, w); DenseMatrix64F A_inv_block = new DenseMatrix64F(w, w); CholeskyDecompositionBlock_D64 algBlock = new CholeskyDecompositionBlock_D64(b); LinearSolver solver = new LinearSolverChol_D64(algBlock); solver = new LinearSolverSafe(solver); assertTrue(solver.setA(A)); solver.invert(A_inv_block); CholeskyDecompositionInner_D64 alg = new CholeskyDecompositionInner_D64(true); solver = new LinearSolverChol_D64(alg); solver = new LinearSolverSafe(solver); assertTrue(solver.setA(A)); solver.invert(A_inv); EjmlUnitTests.assertEquals(A_inv,A_inv_block,1e-5); } }TestCholeskyDecompositionInner_D64.java000066400000000000000000000026221256171534400343120ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.junit.Test; import static org.ejml.alg.dense.decomposition.CheckDecompositionInterface.checkModifiedInput; /** * @author Peter Abeles */ public class TestCholeskyDecompositionInner_D64 extends GenericCholeskyTests_D64 { @Override public CholeskyDecomposition create(boolean lower) { return new CholeskyDecompositionInner_D64(lower); } @Test public void checkModifyInput() { checkModifiedInput(new CholeskyDecompositionInner_D64(true)); checkModifiedInput(new CholeskyDecompositionInner_D64(false)); } } TestCholeskyDecompositionLDL_D64.java000066400000000000000000000042001256171534400336440ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; import java.util.Random; import static org.ejml.alg.dense.decomposition.CheckDecompositionInterface.checkModifiedInput; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestCholeskyDecompositionLDL_D64 { Random rand = new Random(0x45478); @Test public void checkModifyInput() { checkModifiedInput(new CholeskyDecompositionLDL_D64()); } @Test public void testDecompose() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 4, 2, 7, 23, 4, 23, 98); DenseMatrix64F L = new DenseMatrix64F(3,3, true, 1, 0, 0, 2, 1, 0, 4, 5, 1); double D[] = new double[]{1,3,7}; CholeskyDecompositionLDL_D64 cholesky = new CholeskyDecompositionLDL_D64(); assertTrue(cholesky.decompose(A)); DenseMatrix64F foundL = cholesky.getL(); EjmlUnitTests.assertEquals(L,foundL,1e-8); for( int i = 0; i < D.length; i++ ) { assertEquals(D[i],cholesky.getDiagonal()[i],1e-8); } } /** * If it is not positive definate it should fail */ @Test public void testNotPositiveDefinate() { DenseMatrix64F A = new DenseMatrix64F(2,2, true, 1, -1, -1, -2); CholeskyDecompositionLDL_D64 alg = new CholeskyDecompositionLDL_D64(); assertFalse(alg.decompose(A)); } }TestCholeskyDecomposition_B64_to_D64.java000066400000000000000000000026311256171534400344330ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.junit.Test; import static org.ejml.alg.dense.decomposition.CheckDecompositionInterface.checkModifiedInput; /** * @author Peter Abeles */ public class TestCholeskyDecomposition_B64_to_D64 extends GenericCholeskyTests_D64 { @Test public void checkModifyInput() { checkModifiedInput(new CholeskyDecomposition_B64_to_D64(true)); checkModifiedInput(new CholeskyDecomposition_B64_to_D64(false)); } @Override public CholeskyDecomposition create(boolean lower) { return new CholeskyDecomposition_B64_to_D64(lower); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/000077500000000000000000000000001256171534400245545ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/GeneralEigenDecompositionCheck.java000066400000000000000000000474401256171534400334500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.UtilEjml; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.Eigenpair64F; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.ops.*; import org.ejml.simple.SimpleMatrix; import java.util.Random; import static org.ejml.alg.dense.decomposition.CheckDecompositionInterface.safeDecomposition; import static org.junit.Assert.*; /** * @author Peter Abeles */ public abstract class GeneralEigenDecompositionCheck { Random rand = new Random(895723); public abstract EigenDecomposition createDecomposition(); boolean computeVectors; public void allTests() { computeVectors = true; checkSizeZero(); checkRandom(); checkKnownReal(); checkKnownComplex(); checkCompanionMatrix(); checkRandomSymmetric(); checkExceptional(); checkIdentity(); checkAllZeros(); rand = new Random(2934); checkWithSomeRepeatedValuesSymm(); checkWithSingularSymm(); checkSmallValue(false); checkSmallValue(true); checkLargeValue(false); checkLargeValue(true); } /** * Tests for when it just computes eigenvalues */ public void justEigenValues() { computeVectors = false; checkKnownReal_JustValue(); checkKnownSymmetric_JustValue(); checkCompanionMatrix(); } public void checkSizeZero() { EigenDecomposition alg = createDecomposition(); assertFalse(alg.decompose(new DenseMatrix64F(0,0))); } /** * Create a variety of different random matrices of different sizes and sees if they pass the standard * eigen decompositions tests. */ public void checkRandom() { int sizes[] = new int[]{1,2,5,10,20,50,100,200}; EigenDecomposition alg = createDecomposition(); for( int s = 2; s < sizes.length; s++ ) { int N = sizes[s]; // System.out.println("N = "+N); for( int i = 0; i < 2; i++ ) { DenseMatrix64F A = RandomMatrices.createRandom(N,N,-1,1,rand); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,-1); } } } /** * Compare results against a simple matrix with known results where all the eigenvalues * are real. Octave was used to test the known values. */ public void checkKnownReal() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0.907265, 0.832472, 0.255310, 0.667810, 0.871323, 0.612657, 0.025059, 0.126475, 0.427002); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,-1); testForEigenpair(alg,1.686542,0,-0.739990,-0.667630,-0.081761); testForEigenpair(alg,0.079014,0,-0.658665,0.721163,-0.214673); testForEigenpair(alg,0.440034,0,-0.731422,0.211711,0.648229); } /** * Found to be a stressing case that broke a version of the general EVD algorithm. It is a companion matrix * for a polynomial used to find the zeros. * * Discovered by exratt@googlema*l.com */ public void checkCompanionMatrix() { // double[] polynomial = { // 5.392104631674957e7, // -7.717841412372049e8, // -1.4998803087543774e7, // -30110.074181432814, // -16.0 // }; // //// double polynomial[] = new double[]{ //// 0.0817011296749115, //// -0.8100357949733734, //// -0.8667608685791492, //// 2.2995666563510895, //// 0.8879469335079193, //// -4.16266793012619, //// -1.527034044265747, //// 2.201415002346039, //// 0.5391231775283813, //// -0.41334158182144165}; // // // build companion matrix // int n = polynomial.length - 1; // DenseMatrix64F companion = new DenseMatrix64F(n, n); // for (int i = 0; i < n; i++) { // companion.set(i, n - 1, -polynomial[i] / polynomial[n]); // } // for (int i = 1; i < n; i++) { // companion.set(i, i - 1, 1); // } // // // the eigenvalues of the companion matrix matches the roots of the polynomial // EigenDecomposition alg = createDecomposition(); // assertTrue(safeDecomposition(alg,companion)); // // // see if the roots are zero // for( int i = 0; i < alg.getNumberOfEigenvalues(); i++ ) { // Complex64F c = alg.getEigenvalue(i); // // if( !c.isReal() ) { // continue; // } // // double total = 0; // for( int j = 0; j < polynomial.length; j++ ) { // total += polynomial[j]*Math.pow(c.real,j); // } // // assertEquals(0,total,1e-12); // } // // // performStandardTests(alg,companion,n); } /** * Sees if it correctly computed the eigenvalues. Does not check eigenvectors. */ public void checkKnownReal_JustValue() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0.907265, 0.832472, 0.255310, 0.667810, 0.871323, 0.612657, 0.025059, 0.126475, 0.427002); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); testForEigenvalue(alg,A,1.686542,0,1); testForEigenvalue(alg,A,0.079014,0,1); testForEigenvalue(alg,A,0.440034,0,1); } /** * Sees if it correctly computed the eigenvalues. Does not check eigenvectors. */ public void checkKnownSymmetric_JustValue() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0.98139, 0.78650, 0.78564, 0.78650, 1.03207, 0.29794, 0.78564, 0.29794, 0.91926); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); testForEigenvalue(alg,A,0.00426,0,1); testForEigenvalue(alg,A,0.67856,0,1); testForEigenvalue(alg,A,2.24989,0,1); } /** * Compare results against a simple matrix with known results where some the eigenvalues * are real and some are complex. */ public void checkKnownComplex() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, -0.418284, 0.279875, 0.452912, -0.093748, -0.045179, 0.310949, 0.250513, -0.304077, -0.031414); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,-1); testForEigenpair(alg,-0.39996,0,0.87010,0.43425,-0.23314); testForEigenpair(alg,-0.04746,0.02391); testForEigenpair(alg,-0.04746,-0.02391); } /** * Check results against symmetric matrices that are randomly generated */ public void checkRandomSymmetric() { for( int N = 1; N <= 15; N++ ) { for( int i = 0; i < 20; i++ ) { DenseMatrix64F A = RandomMatrices.createSymmetric(N,-1,1,rand); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,N); } } } /** * For some eigenvector algorithms this is a difficult matrix that requires a special * check for. If it fails that check it will either loop forever or exit before converging. */ public void checkExceptional() { DenseMatrix64F A = new DenseMatrix64F(5,5, true, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,1); } public void checkIdentity() { DenseMatrix64F I = CommonOps.identity(4); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,I)); performStandardTests(alg,I,4); testForEigenpair(alg,1,0,1,0,0,0); testForEigenpair(alg,1,0,0,1,0,0); testForEigenpair(alg,1,0,0,0,1,0); testForEigenpair(alg,1,0,0,0,0,1); } public void checkAllZeros() { DenseMatrix64F A = new DenseMatrix64F(5,5); EigenDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,5); testEigenvalues(alg,0); } public void checkWithSomeRepeatedValuesSymm() { EigenDecomposition alg = createDecomposition(); checkSymmetricMatrix(alg,2,-3,-3,-3); checkSymmetricMatrix(alg,2,-3,2,2); checkSymmetricMatrix(alg,1,1,1,2); } public void checkWithSingularSymm() { EigenDecomposition alg = createDecomposition(); checkSymmetricMatrix(alg,1,0,1,2); } /** * Creates a random symmetric matrix with the specified eigenvalues. It then * checks to see if it has the expected results. */ private void checkSymmetricMatrix(EigenDecomposition alg , double ...ev ) { int numRepeated[] = new int[ ev.length ]; for( int i = 0; i < ev.length ; i++ ) { int num = 0; for (double anEv : ev) { if (ev[i] == anEv) num++; } numRepeated[i] = num; } for( int i = 0; i < 200; i++ ) { DenseMatrix64F A = RandomMatrices.createEigenvaluesSymm(ev.length,rand,ev); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,ev.length); for( int j = 0; j < ev.length; j++ ) { testForEigenvalue(alg,A,ev[j],0,numRepeated[j]); } } } public void checkSmallValue( boolean symmetric) { // System.out.println("Symmetric = "+symmetric); EigenDecomposition alg = createDecomposition(); for( int i = 0; i < 20; i++ ) { DenseMatrix64F A = symmetric ? RandomMatrices.createSymmetric(4,-1,1,rand) : RandomMatrices.createRandom(4,4,-1,1,rand); CommonOps.scale(1e-200,A); assertTrue(safeDecomposition(alg,A)); // A.print("%15.13e"); performStandardTests(alg,A,-1); } } public void checkLargeValue( boolean symmetric) { EigenDecomposition alg = createDecomposition(); for( int i = 0; i < 20; i++ ) { DenseMatrix64F A = symmetric ? RandomMatrices.createSymmetric(4,-1,1,rand) : RandomMatrices.createRandom(4,4,-1,1,rand); CommonOps.scale(1e100,A); assertTrue(safeDecomposition(alg,A)); performStandardTests(alg,A,-1); } } /** * If the eigenvalues are all known, real, and the same this can be used to check them. */ public void testEigenvalues( EigenDecomposition alg , double expected ) { for( int i = 0; i < alg.getNumberOfEigenvalues(); i++ ) { Complex64F c = alg.getEigenvalue(i); assertTrue(c.isReal()); assertEquals(expected,c.real,1e-8); } } /** * Preforms standard tests that can be performed on any decomposition without prior knowledge of * what the results should be. */ public void performStandardTests( EigenDecomposition alg , DenseMatrix64F A , int numReal ) { // basic sanity tests assertEquals(A.numRows,alg.getNumberOfEigenvalues()); if( numReal >= 0 ) { for( int i = 0; i < A.numRows; i++ ) { Complex64F v = alg.getEigenvalue(i); assertFalse( Double.isNaN(v.getReal() )); if( v.isReal() ) numReal--; else if( Math.abs(v.getImaginary()) < 10*UtilEjml.EPS) numReal--; } // if there are more than the expected number of real eigenvalues this will // be negative assertEquals(0,numReal); } // checkCharacteristicEquation(alg,A); if( computeVectors ) { testPairsConsistent(alg,A); testVectorsLinearlyIndependent(alg); } else { testEigenvalueConsistency(alg,A); } } /** * Checks to see if an eigenvalue is complex then the eigenvector is null. If it is real it * then checks to see if the equation A*v = lambda*v holds true. */ public void testPairsConsistent( EigenDecomposition alg , DenseMatrix64F A ) { // System.out.println("-------------------------------------------------------------------------"); int N = alg.getNumberOfEigenvalues(); DenseMatrix64F tempA = new DenseMatrix64F(N,1); DenseMatrix64F tempB = new DenseMatrix64F(N,1); for( int i = 0; i < N; i++ ) { Complex64F c = alg.getEigenvalue(i); DenseMatrix64F v = alg.getEigenVector(i); if( Double.isInfinite(c.real) || Double.isNaN(c.real) || Double.isInfinite(c.imaginary) || Double.isNaN(c.imaginary)) fail("Uncountable eigenvalue"); if( !c.isReal() ) { assertTrue(v==null); } else { assertTrue(v != null ); // if( MatrixFeatures.hasUncountable(v)) { // throw new RuntimeException("Egads"); // } assertFalse(MatrixFeatures.hasUncountable(v)); CommonOps.mult(A,v,tempA); CommonOps.scale(c.real,v,tempB); double max = NormOps.normPInf(A); if( max == 0 ) max = 1; double error = SpecializedOps.diffNormF(tempA,tempB)/max; if( error > 1e-12 ) { System.out.println("Original matrix:"); A.print(); System.out.println("Eigenvalue = "+c.real); Eigenpair64F p = EigenOps.computeEigenVector(A,c.real); p.vector.print(); v.print(); CommonOps.mult(A,p.vector,tempA); CommonOps.scale(c.real,p.vector,tempB); max = NormOps.normPInf(A); System.out.println("error before = "+error); error = SpecializedOps.diffNormF(tempA,tempB)/max; System.out.println("error after = "+error); A.print("%f"); System.out.println(); fail("Error was too large"); } assertTrue(error <= 1e-12); } } } /** * Takes a real eigenvalue and computes its eigenvector. then sees if it is similar to the adjusted * eigenvalue */ public void testEigenvalueConsistency( EigenDecomposition alg , DenseMatrix64F A ) { int N = alg.getNumberOfEigenvalues(); DenseMatrix64F AV = new DenseMatrix64F(N,1); DenseMatrix64F LV = new DenseMatrix64F(N,1); for( int i = 0; i < N; i++ ) { Complex64F c = alg.getEigenvalue(i); if( c.isReal() ) { Eigenpair64F p = EigenOps.computeEigenVector(A,c.getReal()); if( p != null ) { CommonOps.mult(A,p.vector,AV); CommonOps.scale(c.getReal(),p.vector,LV); double error = SpecializedOps.diffNormF(AV,LV); // System.out.println("error = "+error); assertTrue(error<1e-12); } } } } /** * See if eigenvalues cause the characteristic equation to have a value of zero */ public void checkCharacteristicEquation( EigenDecomposition alg , DenseMatrix64F A ) { int N = alg.getNumberOfEigenvalues(); SimpleMatrix a = SimpleMatrix.wrap(A); for( int i = 0; i < N; i++ ) { Complex64F c = alg.getEigenvalue(i); if( c.isReal() ) { // test using the characteristic equation double det = SimpleMatrix.identity(A.numCols).scale(c.real).minus(a).determinant(); // extremely crude test. given perfect data this is probably considered a failure... However, // its hard to tell what a good test value actually is. assertEquals(0, det, 0.1); } } } /** * Checks to see if all the real eigenvectors are linearly independent of each other. */ public void testVectorsLinearlyIndependent( EigenDecomposition alg ) { int N = alg.getNumberOfEigenvalues(); // create a matrix out of the eigenvectors DenseMatrix64F A = new DenseMatrix64F(N,N); int off = 0; for( int i = 0; i < N; i++ ) { DenseMatrix64F v = alg.getEigenVector(i); // it can only handle real eigenvectors if( v == null ) off++; else { for( int j = 0; j < N; j++ ) { A.set(i-off,j,v.get(j)); } } } // see if there are any real eigenvectors if( N == off ) return; A.reshape(N-off,N, false); assertTrue(MatrixFeatures.isRowsLinearIndependent(A)); } /** * Sees if the pair of eigenvalue and eigenvector was found in the decomposition. */ public void testForEigenpair( EigenDecomposition alg , double valueReal , double valueImg , double... vector ) { int N = alg.getNumberOfEigenvalues(); int numMatched = 0; for( int i = 0; i < N; i++ ) { Complex64F c = alg.getEigenvalue(i); if( Math.abs(c.real-valueReal) < 1e-4 && Math.abs(c.imaginary-valueImg) < 1e-4) { if( c.isReal() ) { if( vector.length > 0 ) { DenseMatrix64F v = alg.getEigenVector(i); DenseMatrix64F e = new DenseMatrix64F(N,1, true, vector); double error = SpecializedOps.diffNormF(e,v); CommonOps.changeSign(e); double error2 = SpecializedOps.diffNormF(e,v); if(error < 1e-3 || error2 < 1e-3) numMatched++; } else { numMatched++; } } else if( !c.isReal() ) { numMatched++; } } } assertEquals(1,numMatched); } public void testForEigenvalue( EigenDecomposition alg , DenseMatrix64F A, double valueReal , double valueImg , int numMatched ) { int N = alg.getNumberOfEigenvalues(); int numFound = 0; for( int i = 0; i < N; i++ ) { Complex64F c = alg.getEigenvalue(i); if( Math.abs(c.real-valueReal) < 1e-4 && Math.abs(c.imaginary-valueImg) < 1e-4) { numFound++; } } assertEquals(numMatched,numFound); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/TestEigenPowerMethod.java000066400000000000000000000062361256171534400314730ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.NormOps; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestEigenPowerMethod { Random rand = new Random(0x34234); /** * Test it against a case */ @Test public void computeDirect() { double dataA[] = new double[]{ 0.499765 , 0.626231 , 0.759554, 0.850879 , 0.104374 , 0.247645 , 0.069614 , 0.155754 , 0.380435 }; DenseMatrix64F A = new DenseMatrix64F(3,3, true, dataA); EigenPowerMethod power = new EigenPowerMethod(3); power.setOptions(100,1e-10); assertTrue(power.computeDirect(A)); DenseMatrix64F v = power.getEigenVector(); NormOps.normalizeF(v); assertEquals(0.75678,v.get(0,0),1e-6); assertEquals(0.62755,v.get(1,0),1e-5); assertEquals(0.18295,v.get(2,0),1e-5); } @Test public void computeShiftDirect() { double dataA[] = new double[]{ 0.499765 , 0.626231 , 0.759554, 0.850879 , 0.104374 , 0.247645 , 0.069614 , 0.155754 , 0.380435 }; DenseMatrix64F A = new DenseMatrix64F(3,3, true, dataA); EigenPowerMethod power = new EigenPowerMethod(3); power.setOptions(100,1e-10); assertTrue(power.computeShiftDirect(A,0.2)); DenseMatrix64F v = power.getEigenVector(); NormOps.normalizeF(v); assertEquals(0.75678,v.get(0,0),1e-6); assertEquals(0.62755,v.get(1,0),1e-5); assertEquals(0.18295,v.get(2,0),1e-5); } @Test public void computeShiftInvert() { double dataA[] = new double[]{ 0.499765 , 0.626231 , 0.759554, 0.850879 , 0.104374 , 0.247645 , 0.069614 , 0.155754 , 0.380435 }; DenseMatrix64F A = new DenseMatrix64F(3,3, true, dataA); EigenPowerMethod power = new EigenPowerMethod(3); power.setOptions(100,1e-10); // a tried a few values for psi until I found one that converged assertTrue(power.computeShiftInvert(A,1.1)); DenseMatrix64F v = power.getEigenVector(); NormOps.normalizeF(v); assertEquals(0.75678,v.get(0,0),1e-6); assertEquals(0.62755,v.get(1,0),1e-5); assertEquals(0.18295,v.get(2,0),1e-5); } } TestSwitchingEigenDecomposition.java000066400000000000000000000022521256171534400336450ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.junit.Test; /** * @author Peter Abeles */ public class TestSwitchingEigenDecomposition extends GeneralEigenDecompositionCheck { @Override public EigenDecomposition createDecomposition() { return new SwitchingEigenDecomposition(0,computeVectors,1e-8); } @Test public void allTests() { super.allTests(); super.justEigenValues(); } }TestSymmetricQRAlgorithmDecomposition_D64.java000066400000000000000000000041471256171534400354460ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.junit.Test; /** * @author Peter Abeles */ public class TestSymmetricQRAlgorithmDecomposition_D64 extends GeneralEigenDecompositionCheck { boolean together; @Override public EigenDecomposition createDecomposition() { SymmetricQRAlgorithmDecomposition_D64 alg = new SymmetricQRAlgorithmDecomposition_D64(computeVectors); if( computeVectors ) alg.setComputeVectorsWithValues(together); return alg; } @Test public void justSymmetricTests_separate() { together = false; computeVectors = true; checkSizeZero(); checkRandomSymmetric(); checkIdentity(); checkAllZeros(); checkWithSomeRepeatedValuesSymm(); checkWithSingularSymm(); checkSmallValue(true); checkLargeValue(true); computeVectors = false; checkKnownSymmetric_JustValue(); } @Test public void justSymmetricTests_together() { together = true; computeVectors = true; checkSizeZero(); checkRandomSymmetric(); checkIdentity(); checkAllZeros(); checkWithSomeRepeatedValuesSymm(); checkWithSingularSymm(); checkSmallValue(true); checkLargeValue(true); computeVectors = false; checkKnownSymmetric_JustValue(); } } TestWatchedDoubleStepQRDecomposition_D64.java000066400000000000000000000022661256171534400351710ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.junit.Test; /** * @author Peter Abeles */ public class TestWatchedDoubleStepQRDecomposition_D64 extends GeneralEigenDecompositionCheck { @Override public EigenDecomposition createDecomposition() { return new WatchedDoubleStepQRDecomposition_D64(computeVectors); } @Test public void allTests() { super.allTests(); super.justEigenValues(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/symm/000077500000000000000000000000001256171534400255415ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/eig/symm/TestSymmetricQrAlgorithm.java000066400000000000000000000104711256171534400333750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.symm; import org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecompositionHouseholder_D64; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestSymmetricQrAlgorithm { /** * There should no need to do anything in this case. */ @Test public void shouldNotChange() { double diag[] = new double[]{2,3,4,5,6}; double off[] = new double[diag.length-1]; SymmetricQrAlgorithm alg = new SymmetricQrAlgorithm(); assertTrue(alg.process(diag.length,diag,off)); for( int i = 0; i < diag.length; i++ ) { assertEquals(1,countNumFound(alg,diag[i],1e-4)); } } /** * The tridiagonal matrix has off diagonal terms now */ @Test public void hasOffDiagonal() { double diag[] = new double[]{2,3,4,5,6}; double off[] = new double[diag.length-1]; for( int i = 1; i < diag.length; i++ ) { off[i-1] = i+0.5; } SymmetricQrAlgorithm alg = new SymmetricQrAlgorithm(); assertTrue(alg.process(diag.length,diag,off)); assertEquals(1,countNumFound(alg,-1.26677,1e-4)); assertEquals(1,countNumFound(alg,0.93171,1e-4)); assertEquals(1,countNumFound(alg,3.11320,1e-4)); assertEquals(1,countNumFound(alg,6.20897,1e-4)); assertEquals(1,countNumFound(alg,11.01290,1e-4)); } /** * Test it against a matrix that has zeros along the diagonal but non zero values along * the off diagonal elements. */ @Test public void zeroDiagonalNotZeroOff() { int N = 5; double diag[] = new double[N]; double off[] = new double[N-1]; for( int i = 0; i < N-1; i++ ) { off[i] = i+0.5; } // A.print(); SymmetricQrAlgorithm alg = new SymmetricQrAlgorithm(); assertTrue(alg.process(N,diag,off)); assertEquals(1,countNumFound(alg,-4.39719,1e-4)); assertEquals(1,countNumFound(alg,-1.29023,1e-4)); assertEquals(1,countNumFound(alg,0,1e-4)); assertEquals(1,countNumFound(alg,1.29023,1e-4)); assertEquals(1,countNumFound(alg,4.39719,1e-4)); } /** * Provide a test case where the same eigenvalue is repeated a few times */ @Test public void multipleEigenvalues() { DenseMatrix64F A = new DenseMatrix64F(5,5, true, 2.191140, -0.098491, -0.397037, 0.367426, -0.208338, -0.098491, 2.776741, 0.623341, 0.624798, 0.401906, -0.397037, 0.623341, 3.571302, -0.239631, -0.264573, 0.367426, 0.624798, -0.239631, 3.625034, -0.162896, -0.208338, 0.401906, -0.264573, -0.162896, 3.835783); TridiagonalDecompositionHouseholder_D64 tridiag = new TridiagonalDecompositionHouseholder_D64(); tridiag.decompose(A); double diag[] = new double[5]; double off[] = new double[4]; tridiag.getDiagonal(diag,off); SymmetricQrAlgorithm alg = new SymmetricQrAlgorithm(); assertTrue(alg.process(5,diag,off)); assertEquals(3,countNumFound(alg,4,1e-4)); assertEquals(2,countNumFound(alg,2,1e-4)); } /** * Counts the number of times the specified eigenvalue appears. */ public int countNumFound( SymmetricQrAlgorithm alg , double val , double tol ) { int total = 0; for( int i = 0; i < alg.getNumberOfEigenvalues(); i++ ) { double a = alg.getEigenvalue(i); if( Math.abs(a-val) <= tol ) { total++; } } return total; } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/hessenberg/000077500000000000000000000000001256171534400261355ustar00rootroot00000000000000StandardTridiagonalTests.java000066400000000000000000000067561256171534400337000ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.ejml.alg.dense.decomposition.CheckDecompositionInterface.safeDecomposition; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public abstract class StandardTridiagonalTests { protected Random rand = new Random(2344); protected abstract TridiagonalSimilarDecomposition createDecomposition(); @Test public void fullTest() { for( int width = 1; width < 20; width += 2 ) { SimpleMatrix A = SimpleMatrix.wrap(RandomMatrices.createSymmetric(width,-1,1,rand)); TridiagonalSimilarDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A.getMatrix())); // test the results using the decomposition's definition SimpleMatrix Q = SimpleMatrix.wrap(alg.getQ(null,false)); SimpleMatrix T = SimpleMatrix.wrap(alg.getT(null)); SimpleMatrix A_found = Q.mult(T).mult(Q.transpose()); assertTrue("width = "+width,MatrixFeatures.isIdentical(A.getMatrix(),A_found.getMatrix(),1e-8)); } } @Test public void getDiagonal() { for( int width = 1; width < 20; width += 2 ) { DenseMatrix64F A = RandomMatrices.createSymmetric(width,-1,1,rand); TridiagonalSimilarDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); DenseMatrix64F T = alg.getT(null); double diag[] = new double[width]; double off[] = new double[width]; alg.getDiagonal(diag,off); assertEquals(T.get(0,0),diag[0],1e-8); for( int i = 1; i < width; i++ ) { assertEquals(T.get(i,i),diag[i],1e-8); assertEquals(T.get(i-1,i),off[i-1],1e-8); } } } @Test public void transposeFlagForQ() { for( int width = 1; width < 20; width += 2 ) { DenseMatrix64F A = RandomMatrices.createSymmetric(width,-1,1,rand); TridiagonalSimilarDecomposition alg = createDecomposition(); assertTrue(safeDecomposition(alg,A)); DenseMatrix64F Q = alg.getQ(null,false); DenseMatrix64F Q_t = alg.getQ(null,true); for( int i = 0; i < Q.numRows; i++ ) { for( int j = 0; j < Q.numCols; j++ ) { assertEquals(Q.get(i,j),Q_t.get(j,i),1e-8); } } } } } TestHessenbergSimilarDecomposition_D64.java000066400000000000000000000152451256171534400363500ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.ops.SpecializedOps; import org.junit.Test; import java.util.Random; import static org.ejml.alg.dense.decomposition.CheckDecompositionInterface.safeDecomposition; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class TestHessenbergSimilarDecomposition_D64 { Random rand = new Random(5745784); /** * Decomposes the matrix, extracts H and Q, then sees if it can recompute A using similar matrix stuff. */ @Test public void testItAllTogether() { DenseMatrix64F A = RandomMatrices.createRandom(5,5,rand); checkItAll(A); } private void checkItAll(DenseMatrix64F A) { HessenbergSimilarDecomposition_D64 decomp = new HessenbergSimilarDecomposition_D64(A.numRows); assertTrue(safeDecomposition(decomp,A)); DenseMatrix64F Q = decomp.getQ(null); DenseMatrix64F H = decomp.getH(null); // System.out.println("-------- H ---------"); // UtilEjml.print(H,"%8.2e"); // System.out.println("-------- Q ---------"); // UtilEjml.print(Q,"%8.2e"); assertTrue(MatrixFeatures.isOrthogonal(Q, UtilEjml.TOLERANCE)); DenseMatrix64F temp0 = new DenseMatrix64F(5,5); CommonOps.mult(Q,H,temp0); CommonOps.multTransB(temp0,Q,H); // System.out.println("------- A ----------"); // UtilEjml.print(A,"%8.2e"); // System.out.println("----- Found A ------"); // UtilEjml.print(H,"%8.2e"); assertTrue(!MatrixFeatures.hasUncountable(H)); assertTrue(MatrixFeatures.isIdentical(A,H,UtilEjml.TOLERANCE)); } /** * Make sure it doesn't change the input */ @Test public void testInputUnmodified() { DenseMatrix64F A = RandomMatrices.createRandom(4,4,rand); DenseMatrix64F B = A.copy(); HessenbergSimilarDecomposition_D64 decomp = new HessenbergSimilarDecomposition_D64(A.numRows); assertTrue(safeDecomposition(decomp,A)); assertTrue(MatrixFeatures.isIdentical(A,B,0)); } /** * Give it a matrix that is already a Hessenberg matrix and see if its comes out the same. */ // @Test // public void testNoChange() { // DenseMatrix64F A = RandomMatrices.createUpperTriangle(4,1,-1,1,rand); // // HessenbergSimilarDecomposition decomp = new HessenbergSimilarDecomposition(A.numRows); // // assertTrue(decomp.decompose(A)); // // DenseMatrix64F H = decomp.getH(null); // // assertTrue(MatrixFeatures.isIdentical(A,H,0)); // } /** * This checks to see the gammas and if the householder vectors stored in QH are correct. This * is done by extracting the vectors, computing reflectors, and multipling them by A and seeing * if it has the expected response. */ @Test public void testHouseholderVectors() { int N = 5; DenseMatrix64F A = RandomMatrices.createRandom(N,N,rand); DenseMatrix64F B = new DenseMatrix64F(N,N); HessenbergSimilarDecomposition_D64 decomp = new HessenbergSimilarDecomposition_D64(A.numRows); assertTrue(safeDecomposition(decomp,A)); DenseMatrix64F QH = decomp.getQH(); // System.out.println("------------ QH -----------"); // UtilEjml.print(QH); double gammas[] = decomp.getGammas(); DenseMatrix64F u = new DenseMatrix64F(N,1); // UtilEjml.print(A); // System.out.println("-------------------"); for( int i = 0; i < N-1; i++ ) { u.zero(); u.data[i+1] = 1; for( int j = i+2; j < N; j++ ) { u.data[j] = QH.get(j,i); } DenseMatrix64F Q = SpecializedOps.createReflector(u,gammas[i]); CommonOps.mult(Q,A,B); // System.out.println("----- u ------"); // UtilEjml.print(u); // System.out.println("----- Q ------"); // UtilEjml.print(Q); // System.out.println("----- B ------"); // UtilEjml.print(B); for( int j = 0; j < i+2; j++ ) { assertTrue(Math.abs(B.get(j,i))>UtilEjml.TOLERANCE); } for( int j = i+2; j < N; j++ ) { assertEquals(0,B.get(j,i),UtilEjml.TOLERANCE); } CommonOps.mult(B,Q,A); // System.out.println("-------------------"); // UtilEjml.print(A); // System.out.println("-------------------"); } } /** * Compute the overall Q matrix from the stored u vectors. See if the extract H is the same as the expected H. */ @Test public void testH() { int N = 5; DenseMatrix64F A = RandomMatrices.createRandom(N,N,rand); HessenbergSimilarDecomposition_D64 decomp = new HessenbergSimilarDecomposition_D64(A.numRows); assertTrue(safeDecomposition(decomp,A)); DenseMatrix64F QH = decomp.getQH(); double gammas[] = decomp.getGammas(); DenseMatrix64F u = new DenseMatrix64F(N,1); DenseMatrix64F Q = CommonOps.identity(N); DenseMatrix64F temp = new DenseMatrix64F(N,N); for( int i = N-2; i >= 0; i-- ) { u.zero(); u.data[i+1] = 1; for( int j = i+2; j < N; j++ ) { u.data[j] = QH.get(j,i); } DenseMatrix64F Qi = SpecializedOps.createReflector(u,gammas[i]); CommonOps.mult(Qi,Q,temp); Q.set(temp); } DenseMatrix64F expectedH = new DenseMatrix64F(N,N); CommonOps.multTransA(Q,A,temp); CommonOps.mult(temp,Q,expectedH); // UtilEjml.print(expectedH); DenseMatrix64F foundH = decomp.getH(null); // UtilEjml.print(foundH); assertTrue(MatrixFeatures.isIdentical(expectedH,foundH,UtilEjml.TOLERANCE)); System.out.println(); } } TestTridiagonalDecompositionHouseholder_D64.java000066400000000000000000000022031256171534400373670ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; /** * @author Peter Abeles */ public class TestTridiagonalDecompositionHouseholder_D64 extends StandardTridiagonalTests { @Override protected TridiagonalSimilarDecomposition createDecomposition() { return new TridiagonalDecompositionHouseholder_D64(); } } TestTridiagonalDecomposition_B64_to_D64.java000066400000000000000000000021741256171534400363110ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; /** * @author Peter Abeles */ public class TestTridiagonalDecomposition_B64_to_D64 extends StandardTridiagonalTests { @Override protected TridiagonalSimilarDecomposition createDecomposition() { return new TridiagonalDecomposition_B64_to_D64(3); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/lu/000077500000000000000000000000001256171534400244305ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/lu/GeneralLuDecompositionChecks.java000066400000000000000000000144041256171534400330320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.lu; import org.ejml.alg.dense.decomposition.CheckDecompositionInterface; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public abstract class GeneralLuDecompositionChecks { Random rand = new Random(0xff); public abstract LUDecomposition create( int numRows , int numCols ); @Test public void testModifiedInput() { CheckDecompositionInterface.checkModifiedInput(create(0,0)); } /** * Uses the decomposition returned from octave, which uses LAPACK */ @Test public void testDecomposition() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 5, 2, 3, 1.5, -2, 8, -3, 4.7, -0.5); DenseMatrix64F octLower = new DenseMatrix64F(3,3, true, 1, 0, 0, -0.6, 1, 0, 0.3, -0.44068, 1); DenseMatrix64F octUpper = new DenseMatrix64F(3,3, true, 5, 2, 3, 0, 5.9, 1.3, 0, 0, 7.67288); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A)); assertFalse(alg.isSingular()); SimpleMatrix L = SimpleMatrix.wrap(alg.getLower(null)); SimpleMatrix U = SimpleMatrix.wrap(alg.getUpper(null)); SimpleMatrix P = SimpleMatrix.wrap(alg.getPivot(null)); EjmlUnitTests.assertEquals(octLower,L.getMatrix(),1e-5); EjmlUnitTests.assertEquals(octUpper,U.getMatrix(),1e-5); DenseMatrix64F A_found = P.mult(L).mult(U).getMatrix(); assertTrue(MatrixFeatures.isIdentical(A_found,A,1e-8)); } @Test public void testDecomposition2() { for( int i = 2; i <= 20; i++ ) { DenseMatrix64F A = RandomMatrices.createRandom(i,i,-1,1,rand); LUDecomposition alg = create(i,i); assertTrue(alg.decompose(A)); assertFalse(alg.isSingular()); SimpleMatrix L = SimpleMatrix.wrap(alg.getLower(null)); SimpleMatrix U = SimpleMatrix.wrap(alg.getUpper(null)); SimpleMatrix P = SimpleMatrix.wrap(alg.getPivot(null)); DenseMatrix64F A_found = P.transpose().mult(L).mult(U).getMatrix(); assertTrue(MatrixFeatures.isIdentical(A_found,A,1e-8)); } } @Test public void zeroMatrix() { DenseMatrix64F A = new DenseMatrix64F(3,3); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A)); assertTrue(alg.isSingular()); DenseMatrix64F L = alg.getLower(null); DenseMatrix64F U = alg.getUpper(null); DenseMatrix64F A_found = new DenseMatrix64F(3,3); CommonOps.mult(L,U,A_found); assertFalse(MatrixFeatures.hasUncountable(A_found)); assertTrue(MatrixFeatures.isIdentical(A_found,A,1e-8)); } @Test public void testSingular(){ DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 3, 2, 4, 6, 4, 4, 0); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A)); assertTrue(alg.isSingular()); } @Test public void testNearlySingular(){ DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 3, 2, 4, 6.1, 4, 4, 0); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A)); assertFalse(alg.isSingular()); } /** * Checks to see how it handles getLower getUpper functions with and without * a matrix being provided. */ @Test public void getLower_getUpper() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 5, 2, 3, 1.5, -2, 8, -3, 4.7, -0.5); LUDecomposition alg = create(3,3); alg.decompose(A); DenseMatrix64F L_provided = RandomMatrices.createRandom(3,3,rand); DenseMatrix64F U_provided = RandomMatrices.createRandom(3,3,rand); assertTrue(L_provided == alg.getLower(L_provided)); assertTrue(U_provided == alg.getUpper(U_provided)); DenseMatrix64F L_ret = alg.getLower(null); DenseMatrix64F U_ret = alg.getUpper(null); assertTrue(MatrixFeatures.isEquals(L_provided,L_ret)); assertTrue(MatrixFeatures.isEquals(U_provided,U_ret)); } @Test public void testFat() { DenseMatrix64F A = new DenseMatrix64F(2,3, true, 1, 2, 3, 2, 4, 6.1); LUDecomposition alg = create(2,3); assertTrue(alg.decompose(A)); // assertFalse(alg.isSingular()); SimpleMatrix L = SimpleMatrix.wrap(alg.getLower(null)); SimpleMatrix U = SimpleMatrix.wrap(alg.getUpper(null)); SimpleMatrix P = SimpleMatrix.wrap(alg.getPivot(null)); DenseMatrix64F A_found = P.mult(L).mult(U).getMatrix(); assertTrue(MatrixFeatures.isIdentical(A_found,A,1e-8)); } @Test public void testTall() { DenseMatrix64F A = new DenseMatrix64F(3,2, true, 1, 2, 3, 2, 4, 6.1); LUDecomposition alg = create(3,2); assertTrue(alg.decompose(A)); // assertFalse(alg.isSingular()); SimpleMatrix L = SimpleMatrix.wrap(alg.getLower(null)); SimpleMatrix U = SimpleMatrix.wrap(alg.getUpper(null)); SimpleMatrix P = SimpleMatrix.wrap(alg.getPivot(null)); DenseMatrix64F A_found = P.transpose().mult(L).mult(U).getMatrix(); assertTrue(MatrixFeatures.isIdentical(A_found,A,1e-8)); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/lu/TestLUDecompositionAlt_D64.java000066400000000000000000000020331256171534400322640ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.lu; import java.util.Random; /** * @author Peter Abeles */ public class TestLUDecompositionAlt_D64 extends GeneralLuDecompositionChecks { Random rand = new Random(0x3344); @Override public LUDecompositionBase_D64 create(int numRows, int numCols) { return new LUDecompositionAlt_D64(); } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/lu/TestLUDecompositionBase_D64.java000066400000000000000000000065511256171534400324270ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.lu; import org.ejml.alg.dense.misc.DeterminantFromMinor; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestLUDecompositionBase_D64 { Random rand = new Random(0x3344); /** * Compare the determinant computed from LU to the value computed from the minor * matrix method. */ @Test public void testDeterminant() { Random rand = new Random(0xfff); int width = 10; DenseMatrix64F A = RandomMatrices.createRandom(width,width,rand); DeterminantFromMinor minor = new DeterminantFromMinor(width); double minorVal = minor.compute(A); LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); alg.decompose(A); double luVal = alg.computeDeterminant().real; assertEquals(minorVal,luVal,1e-6); } @Test public void _solveVectorInternal() { int width = 10; DenseMatrix64F LU = RandomMatrices.createRandom(width,width,rand); DenseMatrix64F L = new DenseMatrix64F(width,width); DenseMatrix64F U = new DenseMatrix64F(width,width); for (int i = 0; i < width; i++) { for (int j = 0; j < width; j++) { double real = LU.get(i, j); if( j <= i ) { if( j == i ) L.set(i,j,1); else L.set(i,j,real); } if( i <= j ) { U.set(i,j,real); } } } DenseMatrix64F x = RandomMatrices.createRandom(width, 1, -1, 1, rand); DenseMatrix64F tmp = new DenseMatrix64F(width,1); DenseMatrix64F b = new DenseMatrix64F(width,1); CommonOps.mult(U, x, tmp); CommonOps.mult(L,tmp,b); DebugDecompose alg = new DebugDecompose(width); for( int i = 0; i < width; i++ ) alg.getIndx()[i] = i; alg.setLU(LU); alg._solveVectorInternal(b.data); for( int i = 0; i < width; i++ ) { assertEquals(x.data[i],b.data[i],1e-6); } } private static class DebugDecompose extends LUDecompositionBase_D64 { public DebugDecompose(int width) { setExpectedMaxSize(width, width); m = n = width; } void setLU( DenseMatrix64F LU ) { this.LU = LU; this.dataLU = LU.data; } @Override public boolean decompose(DenseMatrix64F orig) { return false; } } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/000077500000000000000000000000001256171534400244325ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/GenericQrCheck_D64.java000066400000000000000000000137221256171534400305340ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.alg.dense.decomposition.CheckDecompositionInterface; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * @author Peter Abeles */ public abstract class GenericQrCheck_D64 { Random rand = new Random(0xff); abstract protected QRDecomposition createQRDecomposition(); @Test public void testModifiedInput() { CheckDecompositionInterface.checkModifiedInput(createQRDecomposition()); } /** * See if it correctly decomposes a square, tall, or wide matrix. */ @Test public void decompositionShape() { checkDecomposition(5, 5 ,false); checkDecomposition(10, 5,false); checkDecomposition(5, 10,false); checkDecomposition(5, 5 ,true); checkDecomposition(10, 5,true); checkDecomposition(5, 10,true); } private void checkDecomposition(int height, int width, boolean compact ) { QRDecomposition alg = createQRDecomposition(); SimpleMatrix A = new SimpleMatrix(height,width); RandomMatrices.setRandom(A.getMatrix(),rand); assertTrue(alg.decompose(A.copy().getMatrix())); int minStride = Math.min(height,width); SimpleMatrix Q = new SimpleMatrix(height,compact ? minStride : height); alg.getQ(Q.getMatrix(), compact); SimpleMatrix R = new SimpleMatrix(compact ? minStride : height,width); alg.getR(R.getMatrix(), compact); // see if Q has the expected properties assertTrue(MatrixFeatures.isOrthogonal(Q.getMatrix(),1e-6)); // UtilEjml.print(alg.getQR()); // Q.print(); // R.print(); // see if it has the expected properties DenseMatrix64F A_found = Q.mult(R).getMatrix(); EjmlUnitTests.assertEquals(A.getMatrix(),A_found,1e-6); assertTrue(Q.transpose().mult(A).isIdentical(R,1e-6)); } /** * See if passing in a matrix or not providing one to getQ and getR functions * has the same result */ @Test public void checkGetNullVersusNot() { int width = 5; int height = 10; QRDecomposition alg = createQRDecomposition(); SimpleMatrix A = new SimpleMatrix(height,width); RandomMatrices.setRandom(A.getMatrix(),rand); alg.decompose(A.getMatrix()); // get the results from a provided matrix DenseMatrix64F Q_provided = RandomMatrices.createRandom(height,height,rand); DenseMatrix64F R_provided = RandomMatrices.createRandom(height,width,rand); assertTrue(R_provided == alg.getR(R_provided, false)); assertTrue(Q_provided == alg.getQ(Q_provided, false)); // get the results when no matrix is provided DenseMatrix64F Q_null = alg.getQ(null, false); DenseMatrix64F R_null = alg.getR(null,false); // see if they are the same assertTrue(MatrixFeatures.isEquals(Q_provided,Q_null)); assertTrue(MatrixFeatures.isEquals(R_provided,R_null)); } /** * Depending on if setZero being true or not the size of the R matrix changes */ @Test public void checkGetRInputSize() { int width = 5; int height = 10; QRDecomposition alg = createQRDecomposition(); SimpleMatrix A = new SimpleMatrix(height,width); RandomMatrices.setRandom(A.getMatrix(),rand); alg.decompose(A.getMatrix()); // check the case where it creates the matrix first assertTrue(alg.getR(null,true).numRows == width); assertTrue(alg.getR(null,false).numRows == height); // check the case where a matrix is provided alg.getR(new DenseMatrix64F(width,width),true); alg.getR(new DenseMatrix64F(height,width),false); // check some negative cases try { alg.getR(new DenseMatrix64F(height,width),true); fail("Should have thrown an exception"); } catch( IllegalArgumentException e ) {} try { alg.getR(new DenseMatrix64F(width-1,width),false); fail("Should have thrown an exception"); } catch( IllegalArgumentException e ) {} } /** * See if the compact format for Q works */ @Test public void checkCompactFormat() { int height = 10; int width = 5; QRDecomposition alg = createQRDecomposition(); SimpleMatrix A = new SimpleMatrix(height,width); RandomMatrices.setRandom(A.getMatrix(),rand); alg.decompose(A.getMatrix()); SimpleMatrix Q = new SimpleMatrix(height,width); alg.getQ(Q.getMatrix(), true); // see if Q has the expected properties assertTrue(MatrixFeatures.isOrthogonal(Q.getMatrix(),1e-6)); // try to extract it with the wrong dimensions Q = new SimpleMatrix(height,height); try { alg.getQ(Q.getMatrix(), true); fail("Didn't fail"); } catch( RuntimeException e ) {} } } TestQRColPivDecompositionHouseholderColumn_D64.java000066400000000000000000000124321256171534400362510ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRColPivDecompositionHouseholderColumn_D64 { Random rand = new Random(234); /** * Test it against a specially created matrix which should not require pivots * and is full rank. */ @Test public void noPivot() { DenseMatrix64F A = RandomMatrices.createOrthogonal(6, 3, rand); // make sure the columns have norms in descending magnitude for( int i = 0; i < A.numCols; i++ ) { double scale = (A.numCols-i)*3; for( int j = 0; j < A.numRows; j++ ) { A.set(j,i,scale*A.get(j,i)); } } // because no pivots are happening this should be equivalent of the normal QR QRColPivDecompositionHouseholderColumn_D64 alg = new QRColPivDecompositionHouseholderColumn_D64(); assertTrue(alg.decompose(A)); DenseMatrix64F Q = alg.getQ(null, false); DenseMatrix64F R = alg.getR(null, false); DenseMatrix64F found = new DenseMatrix64F(A.numRows,A.numCols); CommonOps.mult(Q,R,found); assertTrue(MatrixFeatures.isIdentical(A,found,1e-8)); // check the pivots int pivots[] = alg.getPivots(); for( int i = 0; i < A.numCols; i++ ) { assertEquals(i,pivots[i]); } DenseMatrix64F P = alg.getPivotMatrix(null); assertTrue(MatrixFeatures.isIdentity(P, 1e-8)); } /** * Test it against a rank deficient matrix */ @Test public void testRankDeficient() { int numRows = 10; for( int numSingular = 0; numSingular < numRows-1; numSingular++ ) { // construct a singular matrix from its SVD decomposition SimpleMatrix U = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numRows,numRows,rand)); SimpleMatrix S = SimpleMatrix.diag(1,2,3,4,5,6,7,8,9,10); SimpleMatrix V = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numRows,numRows,rand)); for( int i = 0; i < numSingular; i++ ) { S.set(i,i,0); } SimpleMatrix A = U.mult(S).mult(V.transpose()); QRColPivDecompositionHouseholderColumn_D64 alg = new QRColPivDecompositionHouseholderColumn_D64(); assertTrue(alg.decompose(A.getMatrix())); checkDecomposition(false,A.getMatrix(),alg); } } /** * See how the decomposition goes against various matrices of different sizes */ @Test public void testRandomMatrix() { checkDecomposition(5, 5 ,false); checkDecomposition(10, 5,false); checkDecomposition(5, 10,false); checkDecomposition(5, 5 ,true); checkDecomposition(10, 5,true); checkDecomposition(5, 10,true); } /** * See if a zero matrix is gracefully handled */ @Test public void testZeroMatrix() { DenseMatrix64F A = new DenseMatrix64F(5,5); QRColPivDecompositionHouseholderColumn_D64 alg = new QRColPivDecompositionHouseholderColumn_D64(); assertTrue(alg.decompose(A)); checkDecomposition(false, A, alg); checkDecomposition(true, A, alg); } private void checkDecomposition( int numRows , int numCols , boolean compact ) { for( int i = 0; i < 10; i++ ) { DenseMatrix64F A = RandomMatrices.createRandom(numRows, numCols, rand); QRColPivDecompositionHouseholderColumn_D64 alg = new QRColPivDecompositionHouseholderColumn_D64(); assertTrue(alg.decompose(A)); checkDecomposition(compact, A, alg); } } private void checkDecomposition(boolean compact, DenseMatrix64F a, QRColPivDecompositionHouseholderColumn_D64 alg) { SimpleMatrix Q = SimpleMatrix.wrap(alg.getQ(null, compact)); SimpleMatrix R = SimpleMatrix.wrap(alg.getR(null, compact)); SimpleMatrix P = SimpleMatrix.wrap(alg.getPivotMatrix(null)); SimpleMatrix AA = SimpleMatrix.wrap(a); SimpleMatrix expected = AA.mult(P); SimpleMatrix found = Q.mult(R); // Q.print(); // R.print(); // P.print(); // System.out.println("asdfasdf"); // expected.print(); // found.print(); assertTrue(expected.isIdentical(found,1e-8)); } } TestQRDecompositionHouseholderColumn_D64.java000066400000000000000000000117061256171534400351370ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRDecompositionHouseholderColumn_D64 extends GenericQrCheck_D64 { Random rand = new Random(0xff); @Override protected QRDecomposition createQRDecomposition() { return new QRDecompositionHouseholderColumn_D64(); } /** * Internal several householder operations are performed. This * checks to see if the householder operations and the expected result for all the * submatrices. */ @Test public void householder() { int width = 5; for( int i = 0; i < width; i++ ) { checkSubHouse(i , width); } } private void checkSubHouse(int w , int width) { DebugQR qr = new DebugQR(width,width); SimpleMatrix A = new SimpleMatrix(width,width); RandomMatrices.setRandom(A.getMatrix(),rand); qr.householder(w,A.getMatrix()); SimpleMatrix U = new SimpleMatrix(width,1, true, qr.getQR()[w]).extractMatrix(w,width,0,1); U.set(0,0,1); // this is not explicity set and is assumed to be 1 SimpleMatrix I = SimpleMatrix.identity(width-w); SimpleMatrix Q = I.minus(U.mult(U.transpose()).scale(qr.getGamma())); // check the expected properties of Q assertTrue(Q.isIdentical(Q.transpose(),1e-6)); assertTrue(Q.isIdentical(Q.invert(),1e-6)); SimpleMatrix result = Q.mult(A.extractMatrix(w,width,w,width)); for( int i = 1; i < width-w; i++ ) { assertEquals(0,result.get(i,0),1e-5); } } /** * Check the results of this function against basic matrix operations * which are equivalent. */ @Test public void updateA() { int width = 5; for( int i = 0; i < width; i++ ) checkSubMatrix(width,i); } private void checkSubMatrix(int width , int w ) { DebugQR qr = new DebugQR(width,width); double gamma = 0.2; double tau = 0.75; SimpleMatrix U = new SimpleMatrix(width,1); SimpleMatrix A = new SimpleMatrix(width,width); RandomMatrices.setRandom(U.getMatrix(),rand); RandomMatrices.setRandom(A.getMatrix(),rand); qr.convertToColumnMajor(A.getMatrix()); // compute the results using standard matrix operations SimpleMatrix I = SimpleMatrix.identity(width-w); SimpleMatrix u_sub = U.extractMatrix(w,width,0,1); u_sub.set(0,0,1);// assumed to be 1 in the algorithm SimpleMatrix A_sub = A.extractMatrix(w,width,w,width); SimpleMatrix expected = I.minus(u_sub.mult(u_sub.transpose()).scale(gamma)).mult(A_sub); qr.updateA(w,U.getMatrix().getData(),gamma,tau); double[][] found = qr.getQR(); for( int i = w+1; i < width; i++ ) { assertEquals(U.get(i,0),found[w][i],1e-8); } // the right should be the same for( int i = w; i < width; i++ ) { for( int j = w+1; j < width; j++ ) { double a = expected.get(i-w,j-w); double b = found[j][i]; assertEquals(a,b,1e-6); } } } private static class DebugQR extends QRDecompositionHouseholderColumn_D64 { public DebugQR( int numRows , int numCols ) { setExpectedMaxSize(numRows,numCols); this.numCols = numCols; this.numRows = numRows; } public void householder( int j , DenseMatrix64F A ) { convertToColumnMajor(A); super.householder(j); } protected void convertToColumnMajor(DenseMatrix64F A) { super.convertToColumnMajor(A); } public void updateA( int w , double u[] , double gamma , double tau ) { System.arraycopy(u,0,this.dataQR[w],0,u.length); this.gamma = gamma; this.tau = tau; super.updateA(w); } public double getGamma() { return gamma; } } }TestQRDecompositionHouseholderTran_D64.java000066400000000000000000000143301256171534400346020ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRDecompositionHouseholderTran_D64 extends GenericQrCheck_D64 { Random rand = new Random(0xff); @Override protected QRDecomposition createQRDecomposition() { return new QRDecompositionHouseholderTran_D64(); } /** * Sees if computing Q explicitly and applying Q produces the same results */ @Test public void applyQ() { DenseMatrix64F A = RandomMatrices.createRandom(5,4,rand); QRDecompositionHouseholderTran_D64 alg = new QRDecompositionHouseholderTran_D64(); assertTrue(alg.decompose(A)); DenseMatrix64F Q = alg.getQ(null,false); DenseMatrix64F B = RandomMatrices.createRandom(5,2,rand); DenseMatrix64F expected = new DenseMatrix64F(B.numRows,B.numCols); CommonOps.mult(Q,B,expected); alg.applyQ(B); assertTrue(MatrixFeatures.isIdentical(expected,B,1e-8)); } /** * Sees if computing Q^T explicitly and applying Q^T produces the same results */ @Test public void applyTranQ() { DenseMatrix64F A = RandomMatrices.createRandom(5,4,rand); QRDecompositionHouseholderTran_D64 alg = new QRDecompositionHouseholderTran_D64(); assertTrue(alg.decompose(A)); DenseMatrix64F Q = alg.getQ(null,false); DenseMatrix64F B = RandomMatrices.createRandom(5,2,rand); DenseMatrix64F expected = new DenseMatrix64F(B.numRows,B.numCols); CommonOps.multTransA(Q,B,expected); alg.applyTranQ(B); assertTrue(MatrixFeatures.isIdentical(expected,B,1e-8)); } /** * A focused check to see if the internal house holder operations are performed correctly. */ @Test public void householder() { int width = 5; for( int i = 0; i < width; i++ ) { checkSubHouse(i , width); } } private void checkSubHouse(int w , int width) { DebugQR qr = new DebugQR(width,width); SimpleMatrix A = new SimpleMatrix(width,width); RandomMatrices.setRandom(A.getMatrix(),rand); qr.householder(w,A.getMatrix()); SimpleMatrix U = new SimpleMatrix(width,1, true, qr.getU(w)).extractMatrix(w,width,0,1); SimpleMatrix I = SimpleMatrix.identity(width-w); SimpleMatrix Q = I.minus(U.mult(U.transpose()).scale(qr.getGamma())); // check the expected properties of Q assertTrue(Q.isIdentical(Q.transpose(),1e-6)); assertTrue(Q.isIdentical(Q.invert(),1e-6)); SimpleMatrix result = Q.mult(A.extractMatrix(w,width,w,width)); for( int i = 1; i < width-w; i++ ) { assertEquals(0,result.get(i,0),1e-5); } } /** * Check the results of this function against basic matrix operations * which are equivalent. */ @Test public void updateA() { int width = 5; for( int i = 0; i < width; i++ ) checkSubMatrix(width,i); } private void checkSubMatrix(int width , int w ) { DebugQR qr = new DebugQR(width,width); double gamma = 0.2; double tau = 0.75; SimpleMatrix U = new SimpleMatrix(width,1); SimpleMatrix A = new SimpleMatrix(width,width); RandomMatrices.setRandom(U.getMatrix(),rand); RandomMatrices.setRandom(A.getMatrix(),rand); CommonOps.transpose(A.getMatrix(),qr.getQR()); // compute the results using standard matrix operations SimpleMatrix I = SimpleMatrix.identity(width-w); SimpleMatrix u_sub = U.extractMatrix(w,width,0,1); u_sub.set(0,0,1);// assumed to be 1 in the algorithm SimpleMatrix A_sub = A.extractMatrix(w,width,w,width); SimpleMatrix expected = I.minus(u_sub.mult(u_sub.transpose()).scale(gamma)).mult(A_sub); qr.updateA(w,U.getMatrix().getData(),gamma,tau); DenseMatrix64F found = qr.getQR(); for( int i = w+1; i < width; i++ ) { assertEquals(U.get(i,0),found.get(w,i),1e-8); } // the right should be the same for( int i = w; i < width; i++ ) { for( int j = w+1; j < width; j++ ) { double a = expected.get(i-w,j-w); double b = found.get(j,i); assertEquals(a,b,1e-6); } } } private static class DebugQR extends QRDecompositionHouseholderTran_D64 { public DebugQR(int numRows, int numCols) { setExpectedMaxSize(numRows,numCols); this.numRows = numRows; this.numCols = numCols; } public void householder( int j , DenseMatrix64F A ) { CommonOps.transpose(A,QR); super.householder(j); } public void updateA( int w , double u[] , double gamma , double tau ) { System.arraycopy(u,0,this.QR.data,w*QR.numRows,u.length); this.gamma = gamma; this.tau = tau; super.updateA(w); } public double[] getU( int w ) { System.arraycopy(QR.data,w*numRows,v,0,numRows); v[w] = 1; return v; } public double getGamma() { return gamma; } } } TestQRDecompositionHouseholder_D64.java000066400000000000000000000115201256171534400337530ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRDecompositionHouseholder_D64 extends GenericQrCheck_D64 { Random rand = new Random(0xff); @Override protected QRDecomposition createQRDecomposition() { return new QRDecompositionHouseholder_D64(); } /** * Internall several house holder operations are performed. This * checks to see if the householder operations and the expected result for all the * submatrices. */ @Test public void householder() { int width = 5; for( int i = 0; i < width; i++ ) { checkSubHouse(i , width); } } private void checkSubHouse(int w , int width) { DebugQR qr = new DebugQR(width,width); SimpleMatrix A = new SimpleMatrix(width,width); RandomMatrices.setRandom(A.getMatrix(),rand); qr.householder(w,A.getMatrix()); SimpleMatrix U = new SimpleMatrix(width,1, true, qr.getU()).extractMatrix(w,width,0,1); SimpleMatrix I = SimpleMatrix.identity(width-w); SimpleMatrix Q = I.minus(U.mult(U.transpose()).scale(qr.getGamma())); // check the expected properties of Q assertTrue(Q.isIdentical(Q.transpose(),1e-6)); assertTrue(Q.isIdentical(Q.invert(),1e-6)); SimpleMatrix result = Q.mult(A.extractMatrix(w,width,w,width)); assertEquals(-qr.tau,result.get(0,0),1e-8); for( int i = 1; i < width-w; i++ ) { assertEquals(0,result.get(i,0),1e-5); } } /** * Check the results of this function against basic matrix operations * which are equivalent. */ @Test public void updateA() { int width = 5; for( int i = 0; i < width; i++ ) checkSubMatrix(width,i); } private void checkSubMatrix(int width , int w ) { DebugQR qr = new DebugQR(width,width); double gamma = 0.2; double tau = 0.75; SimpleMatrix U = new SimpleMatrix(width,1); SimpleMatrix A = new SimpleMatrix(width,width); RandomMatrices.setRandom(U.getMatrix(),rand); RandomMatrices.setRandom(A.getMatrix(),rand); qr.getQR().set(A.getMatrix()); // compute the results using standard matrix operations SimpleMatrix I = SimpleMatrix.identity(width-w); SimpleMatrix u_sub = U.extractMatrix(w,width,0,1); SimpleMatrix A_sub = A.extractMatrix(w,width,w,width); SimpleMatrix expected = I.minus(u_sub.mult(u_sub.transpose()).scale(gamma)).mult(A_sub); qr.updateA(w,U.getMatrix().getData(),gamma,tau); DenseMatrix64F found = qr.getQR(); assertEquals(-tau,found.get(w,w),1e-8); for( int i = w+1; i < width; i++ ) { assertEquals(U.get(i,0),found.get(i,w),1e-8); } // the right should be the same for( int i = w; i < width; i++ ) { for( int j = w+1; j < width; j++ ) { double a = expected.get(i-w,j-w); double b = found.get(i,j); assertEquals(a,b,1e-6); } } } private static class DebugQR extends QRDecompositionHouseholder_D64 { public DebugQR(int numRows, int numCols) { setExpectedMaxSize(numRows,numCols); this.numRows = numRows; this.numCols = numCols; } public void householder( int j , DenseMatrix64F A ) { this.QR.set(A); super.householder(j); } public void updateA( int w , double u[] , double gamma , double tau ) { System.arraycopy(u,0,this.u,0,this.u.length); this.gamma = gamma; this.tau = tau; super.updateA(w); } public double[] getU() { return u; } public double getGamma() { return gamma; } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/TestQRDecomposition_B64_to_D64.java000066400000000000000000000020071256171534400327450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.interfaces.decomposition.QRDecomposition; /** * @author Peter Abeles */ public class TestQRDecomposition_B64_to_D64 extends GenericQrCheck_D64 { @Override protected QRDecomposition createQRDecomposition() { return new QRDecomposition_B64_to_D64(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/qr/TestQrUpdate.java000066400000000000000000000117321256171534400276660ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.alg.dense.mult.SubmatrixOps; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQrUpdate { Random rand = new Random(0x345345); /** * Adds a row to a matrix at various points and updates the QR decomposition. * This is then checked by multiplying Q by R and seeing if the augmented A matrix * is the result */ @Test public void testInsertRow() { int n = 3; for( int m = 3; m < 6; m++ ) { for( int insert = 0; insert < m; insert++ ) { checkInsert(m, n, insert); } } } @Test public void testRemoveRow() { int n = 3; for( int m = 4; m < 6; m++ ) { for( int remove = 0; remove < m; remove++ ) { checkRemove(m, n, remove); } } } private void checkRemove(int m, int n, int remove) { DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DenseMatrix64F Q = RandomMatrices.createRandom(m,m,rand); DenseMatrix64F R = new DenseMatrix64F(m,n); // compute what the A matrix would look like without the row DenseMatrix64F A_e = RandomMatrices.createRandom(m-1,n,rand); SubmatrixOps.setSubMatrix(A,A_e,0,0,0,0,remove,n); SubmatrixOps.setSubMatrix(A,A_e,remove+1,0,remove,0,m-remove-1,n); QRDecomposition decomp = new QRDecompositionHouseholderColumn_D64(); // now compute the results by removing elements from A decomp.decompose(A); Q.reshape(m,m, false); decomp.getQ(Q,false); decomp.getR(R,false); QrUpdate update = new QrUpdate(m,n); update.deleteRow(Q,R,remove,true); assertTrue(MatrixFeatures.isOrthogonal(update.getU_tran(),1e-6)); DenseMatrix64F A_r = RandomMatrices.createRandom(m-1,n,rand); CommonOps.mult(Q,R,A_r); // see if the augmented A matrix is correct extracted from the adjusted Q and R matrices assertTrue(MatrixFeatures.isIdentical(A_e,A_r,1e-6)); } private void checkInsert(int m, int n, int insert) { DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DenseMatrix64F Q = RandomMatrices.createRandom(m+1,m+1,rand); DenseMatrix64F R = new DenseMatrix64F(m+1,n); // the row that is to be inserted double row[] = new double[]{1,2,3}; // create the modified A DenseMatrix64F A_e = RandomMatrices.createRandom(m+1,n,rand); SubmatrixOps.setSubMatrix(A,A_e,0,0,0,0,insert,n); System.arraycopy(row, 0, A_e.data, insert * n, n); SubmatrixOps.setSubMatrix(A,A_e,insert,0,insert+1,0,m-insert,n); QRDecomposition decomp = new QRDecompositionHouseholderColumn_D64(); decomp.decompose(A); Q.reshape(m,m, false); decomp.getQ(Q,false); R.reshape(m,n,false); decomp.getR(R,false); DenseMatrix64F Qmod = createQMod(Q,insert); QrUpdate update = new QrUpdate(m+1,n); update.addRow(Q,R,row,insert,true); DenseMatrix64F Z = new DenseMatrix64F(m+1,m+1); CommonOps.multTransB(Qmod,update.getU_tran(),Z); // see if the U matrix has the expected features assertTrue(MatrixFeatures.isOrthogonal(Z,1e-6)); // see if the process that updates Q from U is valid assertTrue(MatrixFeatures.isIdentical(Q,Z,1e-6)); DenseMatrix64F A_r = RandomMatrices.createRandom(m+1,n,rand); CommonOps.mult(Q,R,A_r); // see if the augmented A matrix is correct extracted from the adjusted Q and R matrices assertTrue(MatrixFeatures.isIdentical(A_e,A_r,1e-6)); } public static DenseMatrix64F createQMod( DenseMatrix64F Q , int insertRow ) { DenseMatrix64F Qmod = new DenseMatrix64F(Q.numRows+1,Q.numCols+1); SubmatrixOps.setSubMatrix(Q,Qmod,0,0,0,1,insertRow,Q.numCols); Qmod.set(insertRow,0,1); SubmatrixOps.setSubMatrix(Q,Qmod,insertRow,0,insertRow+1,1,Q.numRows-insertRow,Q.numCols); return Qmod; } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/svd/000077500000000000000000000000001256171534400246045ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/svd/StandardSvdChecks.java000066400000000000000000000244631256171534400310160ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.ejml.data.UtilTestMatrix; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.ops.SingularOps; import org.ejml.simple.SimpleMatrix; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public abstract class StandardSvdChecks { Random rand = new Random(73675); public abstract SingularValueDecomposition createSvd(); boolean omitVerySmallValues = false; public void allTests() { testSizeZero(); testDecompositionOfTrivial(); testWide(); testTall(); checkGetU_Transpose(); checkGetU_Storage(); checkGetV_Transpose(); checkGetV_Storage(); if( !omitVerySmallValues ) testVerySmallValue(); testZero(); testLargeToSmall(); testIdentity(); testLarger(); testLots(); } public void testSizeZero() { SingularValueDecomposition alg = createSvd(); assertFalse(alg.decompose(new DenseMatrix64F(0, 0))); assertFalse(alg.decompose(new DenseMatrix64F(0,2))); assertFalse(alg.decompose(new DenseMatrix64F(2,0))); } public void testDecompositionOfTrivial() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 5, 2, 3, 1.5, -2, 8, -3, 4.7, -0.5); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); assertEquals(3, SingularOps.rank(alg, UtilEjml.EPS)); assertEquals(0, SingularOps.nullity(alg, UtilEjml.EPS)); double []w = alg.getSingularValues(); UtilTestMatrix.checkNumFound(1,1e-5,9.59186,w); UtilTestMatrix.checkNumFound(1,1e-5,5.18005,w); UtilTestMatrix.checkNumFound(1,1e-5,4.55558,w); checkComponents(alg,A); } public void testWide() { DenseMatrix64F A = RandomMatrices.createRandom(5,20,-1,1,rand); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); checkComponents(alg,A); } public void testTall() { DenseMatrix64F A = RandomMatrices.createRandom(21,5,-1,1,rand); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); checkComponents(alg,A); } public void testZero() { for( int i = 1; i <= 16; i += 5 ) { for( int j = 1; j <= 16; j += 5 ) { DenseMatrix64F A = new DenseMatrix64F(i,j); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); int min = Math.min(i,j); assertEquals(min,checkOccurrence(0,alg.getSingularValues(),min),UtilEjml.EPS); checkComponents(alg,A); } } } public void testIdentity() { DenseMatrix64F A = CommonOps.identity(6,6); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); assertEquals(6,checkOccurrence(1,alg.getSingularValues(),6),1e-5); checkComponents(alg,A); } public void testLarger() { DenseMatrix64F A = RandomMatrices.createRandom(200,200,-1,1,rand); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); checkComponents(alg,A); } /** * See if it can handle very small values and not blow up. This can some times * cause a zero to appear unexpectedly and thus a divided by zero. */ public void testVerySmallValue() { DenseMatrix64F A = RandomMatrices.createRandom(5,5,-1,1,rand); CommonOps.scale(1e-200,A); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); checkComponents(alg,A); } public void testLots() { SingularValueDecomposition alg = createSvd(); for( int i = 1; i < 10; i++ ) { for( int j = 1; j < 10; j++ ) { DenseMatrix64F A = RandomMatrices.createRandom(i,j,-1,1,rand); assertTrue(alg.decompose(A)); checkComponents(alg,A); } } } /** * Makes sure transposed flag is correctly handled. */ public void checkGetU_Transpose() { DenseMatrix64F A = RandomMatrices.createRandom(5, 7, -1, 1, rand); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); DenseMatrix64F U = alg.getU(null,false); DenseMatrix64F Ut = alg.getU(null,true); DenseMatrix64F found = new DenseMatrix64F(U.numCols,U.numRows); CommonOps.transpose(U,found); assertTrue( MatrixFeatures.isEquals(Ut,found)); } /** * Makes sure the optional storage parameter is handled correctly */ public void checkGetU_Storage() { DenseMatrix64F A = RandomMatrices.createRandom(5,7,-1,1,rand); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); // test positive cases DenseMatrix64F U = alg.getU(null,false); DenseMatrix64F storage = new DenseMatrix64F(U.numRows,U.numCols); alg.getU(storage,false); assertTrue( MatrixFeatures.isEquals(U,storage)); U = alg.getU(null,true); storage = new DenseMatrix64F(U.numRows,U.numCols); alg.getU(storage,true); assertTrue( MatrixFeatures.isEquals(U,storage)); // give it an incorrect sign try { alg.getU(new DenseMatrix64F(10,20),true); fail("Exception should have been thrown"); } catch( RuntimeException e ){} try { alg.getU(new DenseMatrix64F(10,20),false); fail("Exception should have been thrown"); } catch( RuntimeException e ){} } /** * Makes sure transposed flag is correctly handled. */ public void checkGetV_Transpose() { DenseMatrix64F A = RandomMatrices.createRandom(5,7,-1,1,rand); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); DenseMatrix64F V = alg.getV(null,false); DenseMatrix64F Vt = alg.getV(null,true); DenseMatrix64F found = new DenseMatrix64F(V.numCols,V.numRows); CommonOps.transpose(V,found); assertTrue( MatrixFeatures.isEquals(Vt,found)); } /** * Makes sure the optional storage parameter is handled correctly */ public void checkGetV_Storage() { DenseMatrix64F A = RandomMatrices.createRandom(5,7,-1,1,rand); SingularValueDecomposition alg = createSvd(); assertTrue(alg.decompose(A)); // test positive cases DenseMatrix64F V = alg.getV(null, false); DenseMatrix64F storage = new DenseMatrix64F(V.numRows,V.numCols); alg.getV(storage, false); assertTrue(MatrixFeatures.isEquals(V, storage)); V = alg.getV(null, true); storage = new DenseMatrix64F(V.numRows,V.numCols); alg.getV(storage, true); assertTrue( MatrixFeatures.isEquals(V,storage)); // give it an incorrect sign try { alg.getV(new DenseMatrix64F(10, 20), true); fail("Exception should have been thrown"); } catch( RuntimeException e ){} try { alg.getV(new DenseMatrix64F(10, 20), false); fail("Exception should have been thrown"); } catch( RuntimeException e ){} } /** * Makes sure arrays are correctly set when it first computers a larger matrix * then a smaller one. When going from small to large its often forces to declare * new memory, this way it actually uses memory. */ public void testLargeToSmall() { SingularValueDecomposition alg = createSvd(); // first the larger one DenseMatrix64F A = RandomMatrices.createRandom(10,10,-1,1,rand); assertTrue(alg.decompose(A)); checkComponents(alg,A); // then the smaller one A = RandomMatrices.createRandom(5,5,-1,1,rand); assertTrue(alg.decompose(A)); checkComponents(alg,A); } private int checkOccurrence( double check , double[]values , int numSingular ) { int num = 0; for( int i = 0; i < numSingular; i++ ) { if( Math.abs(values[i]-check)<1e-8) num++; } return num; } private void checkComponents( SingularValueDecomposition svd , DenseMatrix64F expected ) { SimpleMatrix U = SimpleMatrix.wrap(svd.getU(null,false)); SimpleMatrix Vt = SimpleMatrix.wrap(svd.getV(null,true)); SimpleMatrix W = SimpleMatrix.wrap(svd.getW(null)); assertTrue( !U.hasUncountable() ); assertTrue( !Vt.hasUncountable() ); assertTrue( !W.hasUncountable() ); if( svd.isCompact() ) { assertEquals(W.numCols(),W.numRows()); assertEquals(U.numCols(),W.numRows()); assertEquals(Vt.numRows(),W.numCols()); } else { assertEquals(U.numCols(),W.numRows()); assertEquals(W.numCols(),Vt.numRows()); assertEquals(U.numCols(),U.numRows()); assertEquals(Vt.numCols(),Vt.numRows()); } DenseMatrix64F found = U.mult(W).mult(Vt).getMatrix(); // found.print(); // expected.print(); assertTrue(MatrixFeatures.isIdentical(expected,found,1e-8)); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/svd/TestSafeSvd.java000066400000000000000000000102311256171534400276370ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RealMatrix64F; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.junit.Test; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestSafeSvd { @Test public void getSafety() { DenseMatrix64F A = new DenseMatrix64F(3,4); // it will need to create a copy in this case Dummy dummy = new Dummy(2,true,true,2,3); SingularValueDecomposition decomp = new SafeSvd(dummy); assertFalse(decomp.inputModified()); decomp.decompose(A); assertTrue(A != dummy.passedInMatrix); // now no need to make a copy dummy = new Dummy(2,true,false,2,3); decomp = new SafeSvd(dummy); assertFalse(decomp.inputModified()); decomp.decompose(A); assertTrue(A == dummy.passedInMatrix); } @Test public void checkOtherFunctions() { Dummy dummy = new Dummy(2,true,true,2,3); SingularValueDecomposition decomp = new SafeSvd(dummy); assertTrue(decomp.isCompact()); assertEquals(2, decomp.numberOfSingularValues()); assertFalse(dummy.getU_called); assertFalse(dummy.getV_called); assertFalse(dummy.getW_called); decomp.getU(null,false); assertTrue(dummy.getU_called); decomp.getV(null, false); assertTrue(dummy.getV_called); decomp.getW(null); assertTrue(dummy.getW_called); assertEquals(2,decomp.numCols()); assertEquals(3,decomp.numRows()); } protected static class Dummy implements SingularValueDecomposition { RealMatrix64F passedInMatrix; boolean compact; double singular[]; boolean getU_called; boolean getV_called; boolean getW_called; int numRow,numCol; boolean inputModified; private Dummy( int numSingular , boolean compact, boolean inputModified, int numCol, int numRow) { singular = new double[ numSingular ]; this.compact = compact; this.inputModified = inputModified; this.numCol = numCol; this.numRow = numRow; } @Override public double[] getSingularValues() { return singular; } @Override public int numberOfSingularValues() { return singular.length; } @Override public boolean isCompact() { return compact; } @Override public DenseMatrix64F getU(DenseMatrix64F U, boolean transposed) { getU_called = true; return null; } @Override public DenseMatrix64F getV(DenseMatrix64F V, boolean transposed) { getV_called = true; return null; } @Override public DenseMatrix64F getW(DenseMatrix64F W) { getW_called = true; return null; } @Override public int numRows() { return numRow; } @Override public int numCols() { return numCol; } @Override public boolean decompose(DenseMatrix64F orig) { this.passedInMatrix = orig; return true; } @Override public boolean inputModified() { return inputModified; } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/svd/TestSvdImplicitQrDecompose_D64.java000066400000000000000000000105131256171534400333150ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.data.DenseMatrix64F; import org.ejml.data.UtilTestMatrix; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestSvdImplicitQrDecompose_D64 extends StandardSvdChecks { boolean compact; boolean needU; boolean needV; @Override public SingularValueDecomposition createSvd() { return new SvdImplicitQrDecompose_D64(compact,needU,needV,false); } @Test public void checkCompact() { compact = true; needU = true; needV = true; allTests(); } @Test public void checkNotCompact() { compact = false; needU = true; needV = true; allTests(); } /** * This SVD can be configured to compute or not compute different components * Checks to see if it has the expected behavior no matter how it is configured */ @Test public void checkAllPermutations() { // test matrices with different shapes. // this ensure that transposed and non-transposed are handled correctly checkAllPermutations(5, 5); checkAllPermutations(7, 5); checkAllPermutations(5, 7); // // for much taller or wider matrices different algs might be used checkAllPermutations(30, 5); checkAllPermutations(5, 30); } private void checkAllPermutations(int numRows, int numCols) { for( int a = 0; a < 2; a++ ) { boolean singular = a == 0; for( int k = 0; k < 2; k++ ) { compact = k == 0; SingularValueDecomposition alg = new SvdImplicitQrDecompose_D64(compact,true,true,false); DenseMatrix64F A; if( singular ) { double sv[] = new double[ Math.min(numRows,numCols)]; // for( int i = 0; i < sv.length; i++ ) // sv[i] = rand.nextDouble()*2; // sv[0] = 0; A = RandomMatrices.createSingularValues(numRows,numCols,rand,sv); // A = new DenseMatrix64F(numRows,numCols); } else { A = RandomMatrices.createRandom(numRows,numCols,-1,1,rand); } assertTrue(alg.decompose(A.copy())); DenseMatrix64F origU = alg.getU(null,false); double sv[] = alg.getSingularValues(); DenseMatrix64F origV = alg.getV(null,false); for( int i = 0; i < 2; i++ ) { needU = i == 0; for( int j = 0; j < 2; j++ ) { needV = j==0; testPartial(A,origU,sv,origV,needU,needV); } } } } } public void testPartial( DenseMatrix64F A , DenseMatrix64F U , double sv[] , DenseMatrix64F V , boolean checkU , boolean checkV ) { SingularValueDecomposition alg = new SvdImplicitQrDecompose_D64(compact,checkU,checkV,false); assertTrue(alg.decompose(A.copy())); UtilTestMatrix.checkSameElements(1e-10,sv.length,sv,alg.getSingularValues()); if( checkU ) { assertTrue(MatrixFeatures.isIdentical(U,alg.getU(null,false),1e-10)); } if( checkV ) assertTrue(MatrixFeatures.isIdentical(V,alg.getV(null,false),1e-10)); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/svd/implicitqr/000077500000000000000000000000001256171534400267615ustar00rootroot00000000000000TestSvdImplicitQrAlgorithm.java000066400000000000000000000170151256171534400350120ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/decomposition/svd/implicitqr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd.implicitqr; import org.ejml.UtilEjml; import org.ejml.alg.dense.decomposition.bidiagonal.BidiagonalDecompositionRow_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestSvdImplicitQrAlgorithm { private Random rand = new Random(234234); /** * Computes the singular values of a bidiagonal matrix that is all ones. * From exercise 5.9.45 in Fundamentals of Matrix Computations. * */ @Test public void oneBidiagonalMatrix() { SvdImplicitQrAlgorithm svd = new SvdImplicitQrAlgorithm(true); for( int N = 5; N < 10; N++ ) { double diag[] = new double[N]; double off[] = new double[N-1]; diag[0]=1; for( int i = 0; i < N-1; i++ ) { diag[i+1]=1; off[i] = 1; } svd.setMatrix(N,N,diag,off); assertTrue(svd.process()); for( int i = 0; i < N; i++ ) { double val = 2.0*Math.cos( (i+1)*Math.PI/(2.0*N+1.0)); assertEquals(1,countNumFound(svd,val,1e-8)); } } } /** * A trivial case where all the elements are diagonal. It should do nothing here. */ @Test public void knownDiagonal() { double diag[] = new double[]{1,2,3,4,5}; double off[] = new double[diag.length-1]; SvdImplicitQrAlgorithm svd = new SvdImplicitQrAlgorithm(true); svd.setMatrix(diag.length,diag.length,diag,off); assertTrue(svd.process()); assertEquals(1,countNumFound(svd,5,1e-8)); assertEquals(1,countNumFound(svd,4,1e-8)); assertEquals(1,countNumFound(svd,3,1e-8)); assertEquals(1,countNumFound(svd,2,1e-8)); assertEquals(1,countNumFound(svd,1,1e-8)); } /** * Sees if it handles the case where there is a zero on the diagonal */ @Test public void zeroOnDiagonal() { double diag[] = new double[]{1,2,3,4,5,6}; double off[] = new double[]{2,2,2,2,2}; diag[2] = 0; // A.print(); SvdImplicitQrAlgorithm svd = new SvdImplicitQrAlgorithm(false); svd.setMatrix(6,6,diag,off); assertTrue(svd.process()); assertEquals(1,countNumFound(svd,6.82550,1e-4)); assertEquals(1,countNumFound(svd,5.31496,1e-4)); assertEquals(1,countNumFound(svd,3.76347,1e-4)); assertEquals(1,countNumFound(svd,3.28207,1e-4)); assertEquals(1,countNumFound(svd,1.49265,1e-4)); assertEquals(1,countNumFound(svd,0.00000,1e-4)); } @Test public void knownCaseSquare() { DenseMatrix64F A = UtilEjml.parseMatrix("-3 1 3 -3 0\n" + " 2 -4 0 -2 0\n" + " 1 -4 4 1 -3\n" + " -1 -3 2 2 -4\n" + " -5 3 1 3 1",5); // A.print(); SvdImplicitQrAlgorithm svd = createHelper(A); assertTrue(svd.process()); assertEquals(1,countNumFound(svd,9.3431,1e-3)); assertEquals(1,countNumFound(svd,7.4856,1e-3)); assertEquals(1,countNumFound(svd,4.9653,1e-3)); assertEquals(1,countNumFound(svd,1.8178,1e-3)); assertEquals(1,countNumFound(svd,1.6475,1e-3)); } /** * This makes sure the U and V matrices are being correctly by the push code. */ @Test public void zeroOnDiagonalFull() { for( int where = 0; where < 6; where++ ) { double diag[] = new double[]{1,2,3,4,5,6}; double off[] = new double[]{2,2,2,2,2}; diag[where] = 0; checkFullDecomposition(6, diag, off ); } } /** * Decomposes a random matrix and see if the decomposition can reconstruct the original * */ @Test public void randomMatricesFullDecompose() { for( int N = 2; N <= 20; N++ ) { double diag[] = new double[N]; double off[] = new double[N]; diag[0] = rand.nextDouble(); for( int i = 1; i < N; i++ ) { diag[i]=rand.nextDouble(); off[i-1] = rand.nextDouble(); } checkFullDecomposition(N, diag,off); } } /** * Checks the full decomposing my multiplying the components together and seeing if it * gets the original matrix again. */ private void checkFullDecomposition(int n, double diag[] , double off[] ) { // a.print(); SvdImplicitQrAlgorithm svd = createHelper(n,n,diag.clone(),off.clone()); svd.setFastValues(true); assertTrue(svd.process()); // System.out.println("Value total steps = "+svd.totalSteps); svd.setFastValues(false); double values[] = svd.diag.clone(); svd.setMatrix(n,n,diag.clone(),off.clone()); svd.setUt(CommonOps.identity(n)); svd.setVt(CommonOps.identity(n)); assertTrue(svd.process(values)); // System.out.println("Vector total steps = "+svd.totalSteps); SimpleMatrix Ut = SimpleMatrix.wrap(svd.getUt()); SimpleMatrix Vt = SimpleMatrix.wrap(svd.getVt()); SimpleMatrix W = SimpleMatrix.diag(svd.diag); // // Ut.mult(W).mult(V).print(); SimpleMatrix A_found = Ut.transpose().mult(W).mult(Vt); // A_found.print(); assertEquals(diag[0],A_found.get(0,0),1e-8); for( int i = 0; i < n-1; i++ ) { assertEquals(diag[i+1],A_found.get(i+1,i+1),1e-8); assertEquals(off[i],A_found.get(i,i+1),1e-8); } } public static SvdImplicitQrAlgorithm createHelper( DenseMatrix64F a ) { BidiagonalDecompositionRow_D64 bidiag = new BidiagonalDecompositionRow_D64(); assertTrue(bidiag.decompose(a.copy())); double diag[] = new double[a.numRows]; double off[] = new double[ diag.length-1 ]; bidiag.getDiagonal(diag,off); return createHelper(a.numRows,a.numCols,diag,off); } public static SvdImplicitQrAlgorithm createHelper( int numRows , int numCols , double diag[] , double off[] ) { SvdImplicitQrAlgorithm helper = new SvdImplicitQrAlgorithm(); helper.setMatrix(numRows,numCols,diag,off); return helper; } /** * Counts the number of times the specified eigenvalue appears. */ public int countNumFound( SvdImplicitQrAlgorithm alg , double val , double tol ) { int total = 0; for( int i = 0; i < alg.getNumberOfSingularValues(); i++ ) { double a = Math.abs(alg.getSingularValue(i)); if( Math.abs(a-val) <= tol ) { total++; } } return total; } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/000077500000000000000000000000001256171534400224345ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/GenericLinearSolverChecks.java000066400000000000000000000215641256171534400303320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * Contains a series of tests where it solves equations from a known set problems. * * @author Peter Abeles */ public abstract class GenericLinearSolverChecks { protected Random rand = new Random(0xff); // by default have everything run protected boolean shouldFailSingular = true; protected boolean shouldWorkRectangle = true; protected double tol = 1e-8; @Test public void solve_dimensionCheck() { DenseMatrix64F A = RandomMatrices.createRandom(10,4,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); try { DenseMatrix64F x = RandomMatrices.createRandom(4,2,rand); DenseMatrix64F b = RandomMatrices.createRandom(9,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { DenseMatrix64F x = RandomMatrices.createRandom(4,3,rand); DenseMatrix64F b = RandomMatrices.createRandom(10,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { DenseMatrix64F x = RandomMatrices.createRandom(5,2,rand); DenseMatrix64F b = RandomMatrices.createRandom(10,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { DenseMatrix64F x = RandomMatrices.createRandom(4,2,rand); DenseMatrix64F b = RandomMatrices.createRandom(10,1,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } /** * Checks to see if the modifyA() flag is set correctly */ @Test public void modifiesA() { DenseMatrix64F A_orig = RandomMatrices.createRandom(4,4,rand); DenseMatrix64F A = A_orig.copy(); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); boolean modified = !MatrixFeatures.isEquals(A_orig,A); assertTrue(modified == solver.modifiesA()); } /** * Checks to see if the modifyB() flag is set correctly */ @Test public void modifiesB() { DenseMatrix64F A = RandomMatrices.createRandom(4, 4, rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); DenseMatrix64F B = RandomMatrices.createRandom(4,2,rand); DenseMatrix64F B_orig = B.copy(); DenseMatrix64F X = new DenseMatrix64F(A.numRows,B.numCols); solver.solve(B, X); boolean modified = !MatrixFeatures.isEquals(B_orig,B); assertTrue(modified == solver.modifiesB()); } /** * See if a matrix that is more singular has a lower quality. */ @Test public void checkQuality() { DenseMatrix64F A_good = CommonOps.diag(4,3,2,1); DenseMatrix64F A_bad = CommonOps.diag(4, 3, 2, 0.1); LinearSolver solver = createSafeSolver(A_good); assertTrue(solver.setA(A_good)); double q_good; try { q_good = solver.quality(); } catch( IllegalArgumentException e ) { // quality is not supported return; } assertTrue(solver.setA(A_bad)); double q_bad = solver.quality(); assertTrue(q_bad < q_good); assertEquals(q_bad*10.0,q_good,1e-8); } /** * See if quality is scale invariant */ @Test public void checkQuality_scale() { DenseMatrix64F A = CommonOps.diag(4,3,2,1); DenseMatrix64F Asmall = A.copy(); CommonOps.scale(0.01,Asmall); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); double q; try { q = solver.quality(); } catch( IllegalArgumentException e ) { // quality is not supported return; } assertTrue(solver.setA(Asmall)); double q_small = solver.quality(); assertEquals(q_small, q, 1e-8); } /** * A very easy matrix to decompose */ @Test public void square_trivial() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 5, 2, 3, 1.5, -2, 8, -3, 4.7, -0.5); DenseMatrix64F b = new DenseMatrix64F(3,1, true, 18, 21.5, 4.9000); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.solve(b,x); DenseMatrix64F x_expected = new DenseMatrix64F(3,1, true, 1, 2, 3); EjmlUnitTests.assertEquals(x_expected,x,1e-8); } /** * This test checks to see if it can solve a system that will require some algorithms to * perform a pivot. Pivots can change the data structure and can cause solve to fail if not * handled correctly. */ @Test public void square_pivot() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0, 1, 2, -2, 4, 9, 0.5, 0, 5); DenseMatrix64F b = new DenseMatrix64F(3,1, true, 8, 33, 15.5); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.solve(b,x); DenseMatrix64F x_expected = new DenseMatrix64F(3,1, true, 1, 2, 3); EjmlUnitTests.assertEquals(x_expected, x, 1e-8); } @Test public void square_singular() { DenseMatrix64F A = new DenseMatrix64F(3,3); LinearSolver solver = createSafeSolver(A); assertTrue(shouldFailSingular == !solver.setA(A)); } /** * Have it solve for the coefficients in a polynomial */ @Test public void rectangular() { if( !shouldWorkRectangle ) { // skip this test return; } double t[] = new double[]{-1,-0.75,-0.5,0,0.25,0.5,0.75}; double vals[] = new double[7]; double a=1,b=1.5,c=1.7; for( int i = 0; i < t.length; i++ ) { vals[i] = a + b*t[i] + c*t[i]*t[i]; } DenseMatrix64F B = new DenseMatrix64F(7,1, true, vals); DenseMatrix64F A = createPolyA(t,3); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.solve(B,x); assertEquals(a,x.get(0,0),tol); assertEquals(b,x.get(1,0),tol); assertEquals(c,x.get(2,0),tol); } private DenseMatrix64F createPolyA( double t[] , int dof ) { DenseMatrix64F A = new DenseMatrix64F(t.length,3); for( int j = 0; j < t.length; j++ ) { double val = t[j]; for( int i = 0; i < dof; i++ ) { A.set(j,i,Math.pow(val,i)); } } return A; } @Test public void inverse() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0, 1, 2, -2, 4, 9, 0.5, 0, 5); DenseMatrix64F A_inv = RandomMatrices.createRandom(3, 3, rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.invert(A_inv); DenseMatrix64F I = RandomMatrices.createRandom(3,3,rand); CommonOps.mult(A,A_inv,I); for( int i = 0; i < I.numRows; i++ ) { for( int j = 0; j < I.numCols; j++ ) { if( i == j ) assertEquals(1,I.get(i,j),tol); else assertEquals(0,I.get(i,j),tol); } } } protected LinearSolver createSafeSolver( DenseMatrix64F A ) { return new LinearSolverSafe( createSolver(A)); } protected abstract LinearSolver createSolver( DenseMatrix64F A ); } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/GenericSolvePseudoInverseChecks.java000066400000000000000000000130341256171534400315220ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import java.util.Random; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * Tests the ability of a solver to handle different type of rank deficient matrices * * @author Peter Abeles */ public class GenericSolvePseudoInverseChecks { Random rand = new Random(234); LinearSolver solver; public GenericSolvePseudoInverseChecks(LinearSolver solver) { this.solver = new LinearSolverSafe( solver ); } public void all() { zeroMatrix(); underDetermined_wide_solve(); underDetermined_wide_inv(); underDetermined_tall_solve(); singular_solve(); singular_inv(); } /** * Shouldn't blow if it the input matrix is zero. But there is no solution... */ public void zeroMatrix() { DenseMatrix64F A = new DenseMatrix64F(3,3); DenseMatrix64F y = new DenseMatrix64F(3,1,true,4,7,8); assertTrue(solver.setA(A)); DenseMatrix64F x = new DenseMatrix64F(3,1); solver.solve(y, x); assertFalse(MatrixFeatures.hasUncountable(x)); } /** * Compute a solution for a system with more variables than equations */ public void underDetermined_wide_solve() { // create a matrix where two rows are linearly dependent DenseMatrix64F A = new DenseMatrix64F(2,3,true,1,2,3,2,3,4); DenseMatrix64F y = new DenseMatrix64F(2,1,true,4,7); assertTrue(solver.setA(A)); DenseMatrix64F x = new DenseMatrix64F(3,1); solver.solve(y,x); DenseMatrix64F found = new DenseMatrix64F(2,1); CommonOps.mult(A, x, found); // there are multiple 'x' which will generate the same solution, see if this is one of them assertTrue(MatrixFeatures.isEquals(y, found, 1e-8)); } /** * Compute the pseudo inverse a system with more variables than equations */ public void underDetermined_wide_inv() { // create a matrix where two rows are linearly dependent DenseMatrix64F A = new DenseMatrix64F(2,3,true,1,2,3,2,3,4); DenseMatrix64F y = new DenseMatrix64F(2,1,true,4,7); assertTrue(solver.setA(A)); DenseMatrix64F x = new DenseMatrix64F(3,1); solver.solve(y,x); // now test the pseudo inverse DenseMatrix64F A_pinv = new DenseMatrix64F(3,2); DenseMatrix64F found = new DenseMatrix64F(3,1); solver.invert(A_pinv); CommonOps.mult(A_pinv,y,found); assertTrue(MatrixFeatures.isEquals(x, found,1e-8)); } /** * Compute a solution for a system with more variables than equations */ public void underDetermined_tall_solve() { // create a matrix where two rows are linearly dependent DenseMatrix64F A = new DenseMatrix64F(3,2,true,1,2,1,2,2,4); DenseMatrix64F y = new DenseMatrix64F(3,1,true,4,4,8); assertTrue(solver.setA(A)); DenseMatrix64F x = new DenseMatrix64F(2,1); solver.solve(y,x); DenseMatrix64F found = new DenseMatrix64F(3,1); CommonOps.mult(A, x, found); // there are multiple 'x' which will generate the same solution, see if this is one of them assertTrue(MatrixFeatures.isEquals(y, found, 1e-8)); } /** * Compute a solution for a system with more variables than equations */ public void singular_solve() { // create a matrix where two rows are linearly dependent DenseMatrix64F A = new DenseMatrix64F(3,3,true,1,2,3,2,3,4,2,3,4); DenseMatrix64F y = new DenseMatrix64F(3,1,true,4,7,7); assertTrue(solver.setA(A)); DenseMatrix64F x = new DenseMatrix64F(3,1); solver.solve(y,x); DenseMatrix64F found = new DenseMatrix64F(3,1); CommonOps.mult(A, x, found); // there are multiple 'x' which will generate the same solution, see if this is one of them assertTrue(MatrixFeatures.isEquals(y, found, 1e-8)); } /** * Compute the pseudo inverse a system with more variables than equations */ public void singular_inv() { // create a matrix where two rows are linearly dependent DenseMatrix64F A = new DenseMatrix64F(3,3,true,1,2,3,2,3,4,2,3,4); DenseMatrix64F y = new DenseMatrix64F(3,1,true,4,7,7); assertTrue(solver.setA(A)); DenseMatrix64F x = new DenseMatrix64F(3,1); solver.solve(y,x); // now test the pseudo inverse DenseMatrix64F A_pinv = new DenseMatrix64F(3,3); DenseMatrix64F found = new DenseMatrix64F(3,1); solver.invert(A_pinv); CommonOps.mult(A_pinv,y,found); assertTrue(MatrixFeatures.isEquals(x, found,1e-8)); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/TestInvertUsingSolve.java000066400000000000000000000040701256171534400274260ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestInvertUsingSolve { Random rand = new Random(0xff); double tol = 1e-8; /** * See if it can invert a matrix that is known to be invertable. */ @Test public void invert() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0, 1, 2, -2, 4, 9, 0.5, 0, 5); DenseMatrix64F A_inv = RandomMatrices.createRandom(3,3,rand); LUDecompositionAlt_D64 decomp = new LUDecompositionAlt_D64(); LinearSolver solver = new LinearSolverLu_D64(decomp); solver.setA(A); InvertUsingSolve.invert(solver,A,A_inv); DenseMatrix64F I = RandomMatrices.createRandom(3,3,rand); CommonOps.mult(A,A_inv,I); for( int i = 0; i < I.numRows; i++ ) { for( int j = 0; j < I.numCols; j++ ) { if( i == j ) assertEquals(1,I.get(i,j),tol); else assertEquals(0,I.get(i,j),tol); } } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/TestLinearSolverAbstract.java000066400000000000000000000043701256171534400302340ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.junit.Test; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestLinearSolverAbstract { @Test public void setA_getA() { DenseMatrix64F A = new DenseMatrix64F(1,1); MySolver s = new MySolver(); s.setA(A); assertTrue(A==s.getA()); } /** * Checks to see if solve is called by the default invert. */ @Test public void invert() { MySolver solver = new MySolver(); DenseMatrix64F A = new DenseMatrix64F(1,1); solver.setA(A); solver.invert(A); assertTrue(solver.solveCalled); } private static class MySolver extends LinearSolverAbstract_D64 { boolean solveCalled = false; @Override public boolean setA(DenseMatrix64F A) { _setA(A); return true; } @Override public double quality() { throw new IllegalArgumentException("Not supported by this solver."); } @Override public void solve(DenseMatrix64F B, DenseMatrix64F X) { solveCalled = true; } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public D getDecomposition() { return null; } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/TestLinearSolver_B64_to_D64.java000066400000000000000000000024621256171534400303020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.block.linsol.qr.BlockQrHouseHolderSolver; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * Test the wrapper by running it through the usual linear solver checks * * @author Peter Abeles */ public class TestLinearSolver_B64_to_D64 extends GenericLinearSolverChecks { @Override protected LinearSolver createSolver(DenseMatrix64F A) { LinearSolver solver = new BlockQrHouseHolderSolver(); return new LinearSolver_B64_to_D64(solver); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/chol/000077500000000000000000000000001256171534400233615ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/chol/BaseCholeskySolveTests_D64.java000066400000000000000000000121711256171534400312530ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public abstract class BaseCholeskySolveTests_D64 { Random rand = new Random(0x45); public void standardTests() { solve_dimensionCheck(); testSolve(); testInvert(); testQuality(); testQuality_scale(); } public abstract LinearSolver createSolver(); public LinearSolver createSafeSolver() { LinearSolver solver = createSolver(); return new LinearSolverSafe(solver); } @Test public void setA_dimensionCheck() { LinearSolver solver = createSafeSolver(); try { DenseMatrix64F A = RandomMatrices.createRandom(4,5,rand); assertTrue(solver.setA(A)); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } @Test public void solve_dimensionCheck() { LinearSolver solver = createSafeSolver(); DenseMatrix64F A = RandomMatrices.createSymmPosDef(4, rand); assertTrue(solver.setA(A)); try { DenseMatrix64F x = RandomMatrices.createRandom(4,3,rand); DenseMatrix64F b = RandomMatrices.createRandom(4,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { DenseMatrix64F x = RandomMatrices.createRandom(5,2,rand); DenseMatrix64F b = RandomMatrices.createRandom(4,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { DenseMatrix64F x = RandomMatrices.createRandom(5,2,rand); DenseMatrix64F b = RandomMatrices.createRandom(5,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } @Test public void testSolve() { LinearSolver solver = createSafeSolver(); DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 4, 2, 13, 23, 4, 23, 90); DenseMatrix64F b = new DenseMatrix64F(3,1, true, 17, 97, 320); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F A_orig = A.copy(); DenseMatrix64F B_orig = b.copy(); assertTrue(solver.setA(A)); solver.solve(b,x); // see if the input got modified EjmlUnitTests.assertEquals(A,A_orig,1e-5); EjmlUnitTests.assertEquals(b,B_orig,1e-5); DenseMatrix64F x_expected = new DenseMatrix64F(3,1, true, 1, 2, 3); EjmlUnitTests.assertEquals(x_expected,x,1e-6); } @Test public void testInvert() { LinearSolver solver = createSafeSolver(); DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 4, 2, 13, 23, 4, 23, 90); DenseMatrix64F found = new DenseMatrix64F(A.numRows,A.numCols); assertTrue(solver.setA(A)); solver.invert(found); DenseMatrix64F A_inv = new DenseMatrix64F(3,3, true, 1.453515, -0.199546, -0.013605, -0.199546, 0.167800, -0.034014, -0.013605, -0.034014, 0.020408); EjmlUnitTests.assertEquals(A_inv,found,1e-5); } @Test public void testQuality() { LinearSolver solver = createSafeSolver(); DenseMatrix64F A = CommonOps.diag(3,2,1); DenseMatrix64F B = CommonOps.diag(3,2,0.001); assertTrue(solver.setA(A)); double qualityA = solver.quality(); assertTrue(solver.setA(B)); double qualityB = solver.quality(); assertTrue(qualityB < qualityA); } @Test public void testQuality_scale() { LinearSolver solver = createSafeSolver(); DenseMatrix64F A = CommonOps.diag(3,2,1); DenseMatrix64F B = A.copy(); CommonOps.scale(0.001,B); assertTrue(solver.setA(A)); double qualityA = solver.quality(); assertTrue(solver.setA(B)); double qualityB = solver.quality(); assertEquals(qualityB,qualityA,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/chol/TestLinearSolverCholLDL_D64.java000066400000000000000000000034551256171534400312570ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestLinearSolverCholLDL_D64 { Random rand = new Random(3466); @Test public void testInverseAndSolve() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 4, 2, 13, 23, 4, 23, 90); DenseMatrix64F b = new DenseMatrix64F(3,1, true, 17, 97, 320); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); LinearSolverCholLDL_D64 solver = new LinearSolverCholLDL_D64(); assertTrue(solver.setA(A)); solver.invert(A); solver.solve(b,x); DenseMatrix64F A_inv = new DenseMatrix64F(3,3, true, 1.453515, -0.199546, -0.013605, -0.199546, 0.167800, -0.034014, -0.013605, -0.034014, 0.020408); DenseMatrix64F x_expected = new DenseMatrix64F(3,1, true, 1, 2, 3); EjmlUnitTests.assertEquals(A_inv,A,1e-5); EjmlUnitTests.assertEquals(x_expected,x,1e-6); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/chol/TestLinearSolverChol_B64.java000066400000000000000000000020321256171534400307070ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverChol_B64 extends BaseCholeskySolveTests_D64 { @Override public LinearSolver createSolver() { return new LinearSolverChol_B64(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/chol/TestLinearSolverChol_D64.java000066400000000000000000000023021256171534400307110ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionInner_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverChol_D64 extends BaseCholeskySolveTests_D64 { @Override public LinearSolver createSolver() { CholeskyDecompositionInner_D64 alg = new CholeskyDecompositionInner_D64(true); return new LinearSolverChol_D64(alg); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/lu/000077500000000000000000000000001256171534400230545ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/lu/TestLinearSolverLuBase_D64.java000066400000000000000000000037411256171534400307020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestLinearSolverLuBase_D64 { Random rand = new Random(0x334); /** * Make sure that improve solution doesn't make things worse. This test does * not realy test to see if it makes things better. */ @Test public void testImproveSol_noharm() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0, 1, 2, -2, 4, 9, 0.5, 0, 5); DenseMatrix64F b = new DenseMatrix64F(3,1, true, 8, 33, 15.5); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F x_improved = new DenseMatrix64F(3,1); LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); x_improved.set(x); LinearSolverLu_D64 solver = new LinearSolverLu_D64(alg); assertTrue(solver.setA(A)); solver.solve(x,b); solver.improveSol(x_improved,b); // DenseMatrix64F x_truth = new DenseMatrix64F(3,1,new double[]{1,2,3}); EjmlUnitTests.assertEquals(x,x_improved,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/lu/TestLinearSolverLuKJI_D64.java000066400000000000000000000025621256171534400304450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverLuKJI_D64 extends GenericLinearSolverChecks { public TestLinearSolverLuKJI_D64() { shouldWorkRectangle = false; shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { LUDecompositionAlt_D64 decomp = new LUDecompositionAlt_D64(); return new LinearSolverLuKJI_D64(decomp); } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/lu/TestLinearSolverLu_D64.java000066400000000000000000000025521256171534400301060ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverLu_D64 extends GenericLinearSolverChecks { public TestLinearSolverLu_D64() { shouldWorkRectangle = false; shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { LUDecompositionAlt_D64 decomp = new LUDecompositionAlt_D64(); return new LinearSolverLu_D64(decomp); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/000077500000000000000000000000001256171534400230565ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestAdjLinearSolverQr_D64.java000066400000000000000000000075211256171534400305320ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.AdjustableLinearSolver; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.alg.dense.mult.SubmatrixOps; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestAdjLinearSolverQr_D64 extends GenericLinearSolverChecks { @Test public void addRowToA() { int insert = 2; int m = 5; int n = 3; DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); double row[] = new double[]{1,2,3}; // create the modified A DenseMatrix64F A_e = RandomMatrices.createRandom(m+1,n,rand); SubmatrixOps.setSubMatrix(A,A_e,0,0,0,0,insert,n); System.arraycopy(row, 0, A_e.data, insert * n, n); SubmatrixOps.setSubMatrix(A,A_e,insert,0,insert+1,0,m-insert,n); // Compute the solution to the modified system DenseMatrix64F X = RandomMatrices.createRandom(n,2,rand); DenseMatrix64F Y = new DenseMatrix64F(A_e.numRows,X.numCols); CommonOps.mult(A_e,X,Y); // create the solver from A then add a A. The solver // should be equivalent to one created from A_e AdjustableLinearSolver adjSolver = new AdjLinearSolverQr_D64(); assertTrue(adjSolver.setA(A)); adjSolver.addRowToA(row,insert); // solve the system and see if it gets the expected solution DenseMatrix64F X_found = RandomMatrices.createRandom(X.numRows,X.numCols,rand); adjSolver.solve(Y,X_found); // see if they produce the same results assertTrue(MatrixFeatures.isIdentical(X_found,X,1e-8)); } @Test public void removeRowFromA() { int remove = 2; int m = 5; int n = 3; DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); // create the modified A DenseMatrix64F A_e = RandomMatrices.createRandom(m-1,n,rand); SubmatrixOps.setSubMatrix(A,A_e,0,0,0,0,remove,n); SubmatrixOps.setSubMatrix(A,A_e,remove+1,0,remove,0,m-remove-1,n); // Compute the solution to the modified system DenseMatrix64F X = RandomMatrices.createRandom(n,2,rand); DenseMatrix64F Y = new DenseMatrix64F(A_e.numRows,X.numCols); CommonOps.mult(A_e,X,Y); // create the solver from the original system then modify it AdjustableLinearSolver adjSolver = new AdjLinearSolverQr_D64(); adjSolver.setA(A); adjSolver.removeRowFromA(remove); // see if it produces the epected results // solve the system and see if it gets the expected solution DenseMatrix64F X_found = RandomMatrices.createRandom(X.numRows,X.numCols,rand); adjSolver.solve(Y,X_found); // see if they produce the same results assertTrue(MatrixFeatures.isIdentical(X_found,X,1e-8)); } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new AdjLinearSolverQr_D64(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQrBlock64_D64.java000066400000000000000000000021611256171534400312330ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQrBlock64_D64 extends GenericLinearSolverChecks { @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new LinearSolverQrBlock64_D64(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQrHouseCol_D64.java000066400000000000000000000023171256171534400315530ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQrHouseCol_D64 extends GenericLinearSolverChecks { public TestLinearSolverQrHouseCol_D64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new LinearSolverQrHouseCol_D64(); } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQrHouseTran_D64.java000066400000000000000000000023221256171534400317360ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQrHouseTran_D64 extends GenericLinearSolverChecks { public TestLinearSolverQrHouseTran_D64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new LinearSolverQrHouseTran_D64(); } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQrHouse_D64.java000066400000000000000000000023071256171534400311140ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQrHouse_D64 extends GenericLinearSolverChecks { public TestLinearSolverQrHouse_D64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new LinearSolverQrHouse_D64(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQr_D64.java000066400000000000000000000024621256171534400301120ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQr_D64 extends GenericLinearSolverChecks { public TestLinearSolverQr_D64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new LinearSolverQr_D64(new QRDecompositionHouseholderColumn_D64()); } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestSolveLinearSolverQrpHouseCol_D64.java000066400000000000000000000041051256171534400327410ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.qr.QRColPivDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.alg.dense.linsol.GenericSolvePseudoInverseChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.junit.Test; /** * @author Peter Abeles */ public class TestSolveLinearSolverQrpHouseCol_D64 extends GenericLinearSolverChecks { public TestSolveLinearSolverQrpHouseCol_D64() { shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new LinearSolverQrpHouseCol_D64(new QRColPivDecompositionHouseholderColumn_D64(),true); } @Test public void checkSingularBasic() { LinearSolver solver = new LinearSolverQrpHouseCol_D64(new QRColPivDecompositionHouseholderColumn_D64(),true); GenericSolvePseudoInverseChecks checks = new GenericSolvePseudoInverseChecks(solver); checks.all(); } @Test public void checkSingularFull() { LinearSolver solver = new LinearSolverQrpHouseCol_D64(new QRColPivDecompositionHouseholderColumn_D64(),false); GenericSolvePseudoInverseChecks checks = new GenericSolvePseudoInverseChecks(solver); checks.all(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/qr/TestSolvePseudoInverseQrp_D64.java000066400000000000000000000040611256171534400314660ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decomposition.qr.QRColPivDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.alg.dense.linsol.GenericSolvePseudoInverseChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.junit.Test; /** * @author Peter Abeles */ public class TestSolvePseudoInverseQrp_D64 extends GenericLinearSolverChecks { public TestSolvePseudoInverseQrp_D64() { shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new SolvePseudoInverseQrp_D64(new QRColPivDecompositionHouseholderColumn_D64(),true); } @Test public void checkSingularBasic() { LinearSolver solver = new SolvePseudoInverseQrp_D64(new QRColPivDecompositionHouseholderColumn_D64(),true); GenericSolvePseudoInverseChecks checks = new GenericSolvePseudoInverseChecks(solver); checks.all(); } @Test public void checkSingularFull() { LinearSolver solver = new SolvePseudoInverseQrp_D64(new QRColPivDecompositionHouseholderColumn_D64(),false); GenericSolvePseudoInverseChecks checks = new GenericSolvePseudoInverseChecks(solver); checks.all(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/svd/000077500000000000000000000000001256171534400232305ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/linsol/svd/TestSolvePseudoInverseSvd.java000066400000000000000000000030541256171534400312160ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.svd; import org.ejml.alg.dense.linsol.GenericLinearSolverChecks; import org.ejml.alg.dense.linsol.GenericSolvePseudoInverseChecks; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.junit.Test; /** * @author Peter Abeles */ public class TestSolvePseudoInverseSvd extends GenericLinearSolverChecks { public TestSolvePseudoInverseSvd() { this.shouldFailSingular = false; } @Override protected LinearSolver createSolver( DenseMatrix64F A ) { return new SolvePseudoInverseSvd(A.numRows,A.numCols); } @Test public void checkSingularBasic() { LinearSolver solver = new SolvePseudoInverseSvd(10,10); GenericSolvePseudoInverseChecks checks = new GenericSolvePseudoInverseChecks(solver); checks.all(); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400220675ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/GeneralReducedRowEchelonFormChecks.java000066400000000000000000000114661256171534400315460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.ReducedRowEchelonForm; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * Generalized checks for Gauss-Jordan implementations * * @author Peter Abeles */ public abstract class GeneralReducedRowEchelonFormChecks { Random rand = new Random(234); ReducedRowEchelonForm alg; public GeneralReducedRowEchelonFormChecks(ReducedRowEchelonForm alg) { this.alg = alg; } /** * See if it is reducing systems into RREF */ @Test public void testFormat() { for( int i = 1; i < 10; i++ ) { // test square checkFormatRandom(1+i,1+i); // test wide checkFormatRandom(3 + i, 4 + i * 2); // test tall checkFormatRandom(4 + i * 2,3 + i); } } /** * Solve several linear systems and check against solution */ @Test public void testSolution() { checkSolutionRandom(3,4,3); checkSolutionRandom(3,5,3); // Tall won't work because with this test because the system is inconsistent // checkSolutionRandom(10,4,3); } @Test public void testSingular() { DenseMatrix64F A = new DenseMatrix64F(3,4,true,1,2,3,4,3,5,6,7,2,4,6,8,-3,4,9,3); DenseMatrix64F found = A.copy(); alg.reduce(found,3); checkRref(found,3); DenseMatrix64F A1 = CommonOps.extract(A,0,3,0,3); DenseMatrix64F X = CommonOps.extract(found,0,3,3,4); DenseMatrix64F B = new DenseMatrix64F(3,1); CommonOps.mult(A1,X,B); for( int i = 0; i < 3; i++ ) assertEquals(A.get(i,3),B.get(i,0),1e-8); } /** * Feed it specific matrices and see if it dies a horrible death */ @Test public void spotTests() { DenseMatrix64F A = new DenseMatrix64F(4,6,true, 0,0,1,-1,-1,4, 2,4,2,4,2,4, 2,4,3,3,3,4, 3,6,6,3,6,6); alg.reduce(A,5); checkRref(A,5); } private void checkFormatRandom(int numRows, int numCols) { DenseMatrix64F A = RandomMatrices.createRandom(numRows,numCols,-1,1,rand); DenseMatrix64F found = A.copy(); alg.reduce(found,numCols); checkRref(found, numCols); } private void checkSolutionRandom(int numRows, int numCols , int solWidth ) { DenseMatrix64F A = RandomMatrices.createRandom(numRows,numCols,-1,1,rand); DenseMatrix64F found = A.copy(); alg.reduce(found,solWidth); checkRref(found,solWidth); DenseMatrix64F A1 = CommonOps.extract(A,0,numRows,0,solWidth); DenseMatrix64F X = CommonOps.extract(found,0,solWidth,solWidth,numCols); DenseMatrix64F B = new DenseMatrix64F(numRows,numCols-solWidth); CommonOps.mult(A1,X,B); for( int i = 0; i < numRows; i++ ) for( int j = 0; j < numCols-solWidth; j++ ) assertEquals(A.get(i,j+solWidth),B.get(i,j),1e-8); } /** * Checks to see if the provided matrix is in reduced row echelon format * @param A */ private void checkRref( DenseMatrix64F A , int systemWidth ) { int prevLeading = -1; for( int row = 0; row < A.numRows; row++ ) { // find the next leading for( int col = 0; col < systemWidth; col++ ) { double val = A.get(row,col); if( val == 1 ) { if( prevLeading > col ) fail("The next leading one should be at a later column than the previous"); prevLeading = col; for( int i = 0; i < A.numRows; i++ ) { if( i == row ) continue; assertTrue("Column should be all zeros, except at the leading",0==A.get(i,col)); } break; } else { assertEquals("Should be all zeros before the leading 1", 0, val, 1e-8); } } } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/TestDeterminantFromMinor.java000066400000000000000000000100351256171534400276740ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; /** * @author Peter Abeles */ public class TestDeterminantFromMinor { /** * Compare it against the algorithm for 4 by 4 matrices. */ @Test public void compareTo4x4() { double[] mat = new double[]{5 ,-2 ,-4 ,0.5, 0.1, 91, 8, 66, 1, -2, 10, -4, -0.2, 7, -4, 0.8}; double val = NaiveDeterminant.recursive(new DenseMatrix64F(4,4,true,mat)); DeterminantFromMinor minor = new DeterminantFromMinor(4,3); double minorVal = minor.compute(new DenseMatrix64F(4,4, true, mat)); assertEquals(val,minorVal,1e-6); } /** * Compare it against the results found using Octave. */ @Test public void compareTo5x5() { double[] mat = new double[]{5 ,-2, -4, 0.5, -0.3, 0.1, 91, 8, 66, 13, 1, -2, 10, -4, -0.01, -0.2, 7, -4, 0.8, -22, 5, 19, -23, 0.001, 87}; DeterminantFromMinor minor = new DeterminantFromMinor(5); double minorVal = minor.compute(new DenseMatrix64F(5,5, true, mat)); assertEquals(-4745296.629148000851274,minorVal,1e-8); } @Test public void compareToNaive10x10() { Random rand = new Random(0xfff); int width = 10; DenseMatrix64F A = RandomMatrices.createRandom(width,width,rand); DeterminantFromMinor minor = new DeterminantFromMinor(width); double minorVal = minor.compute(new DenseMatrix64F(width,width, true, A.data)); double recVal = NaiveDeterminant.recursive(new DenseMatrix64F(width,width, true, A.data)); assertEquals(recVal,minorVal,1e-6); } /** * Compare it against the naive algorithm and see if it gets the same results. */ @Test public void computeMediumSized() { Random rand = new Random(0xfff); for( int width = 5; width < 12; width++ ) { DenseMatrix64F A = RandomMatrices.createRandom(width,width,rand); LUDecompositionAlt_D64 lu = new LUDecompositionAlt_D64(); lu.decompose(A); double luVal = lu.computeDeterminant().real; DeterminantFromMinor minor = new DeterminantFromMinor(width); double minorVal = minor.compute(new DenseMatrix64F(width,width, true, A.data)); assertEquals(luVal,minorVal,1e-6); } } /** * Make sure it produces the same results when it is called twice */ @Test public void testMultipleCalls() { Random rand = new Random(0xfff); int width = 6; DenseMatrix64F A = RandomMatrices.createRandom(width,width,rand); DeterminantFromMinor minor = new DeterminantFromMinor(width); double first = minor.compute(A); double second = minor.compute(A); assertEquals(first,second,1e-10); // does it produce the same results for a different matrix? DenseMatrix64F B = RandomMatrices.createRandom(width,width,rand); double third = minor.compute(B); assertFalse(first==third); // make sure it has a valid result the third time double recVal = NaiveDeterminant.recursive(B); assertEquals(third,recVal,1e-6); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/TestImplCommonOps_DenseMatrix64F.java000066400000000000000000000026201256171534400311110ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestImplCommonOps_DenseMatrix64F { Random rand = new Random(234324); @Test public void extract() { DenseMatrix64F A = RandomMatrices.createRandom(5, 5, 0, 1, rand); DenseMatrix64F B = new DenseMatrix64F(3,3); ImplCommonOps_DenseMatrix64F.extract(A, 1, 2, B, 1, 0,2,3); for( int i = 1; i < 3; i++ ) { for( int j = 2; j < 5; j++ ) { assertEquals(A.get(i,j),B.get(i,j-2),1e-8); } } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/TestImplCommonOps_Matrix64F.java000066400000000000000000000026061256171534400301360ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestImplCommonOps_Matrix64F { Random rand = new Random(234324); @Test public void extract() { DenseMatrix64F A = RandomMatrices.createRandom(5, 5, 0, 1, rand); DenseMatrix64F B = new DenseMatrix64F(3,3); ImplCommonOps_Matrix64F.extract(A, 1, 2, B, 1, 0,2,3); for( int i = 1; i < 3; i++ ) { for( int j = 2; j < 5; j++ ) { assertEquals(A.get(i,j),B.get(i,j-2),1e-8); } } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/TestRrefGaussJordanRowPivot.java000066400000000000000000000016551256171534400303520ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; /** * @author Peter Abeles */ public class TestRrefGaussJordanRowPivot extends GeneralReducedRowEchelonFormChecks { public TestRrefGaussJordanRowPivot() { super(new RrefGaussJordanRowPivot()); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/TestTransposeAlgs.java000066400000000000000000000046711256171534400263670ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestTransposeAlgs { Random rand = new Random(234234); @Test public void square() { DenseMatrix64F mat = RandomMatrices.createRandom(5,5,rand); DenseMatrix64F matTran = mat.copy(); TransposeAlgs.square(matTran); assertEquals(mat.getNumCols(),matTran.getNumRows()); assertEquals(mat.getNumRows(),matTran.getNumCols()); EjmlUnitTests.assertEqualsTrans(mat,matTran,0); } @Test public void block() { // check various shapes to make sure blocking is handled correctly for( int numRows = 1; numRows < 15; numRows += 2 ) { for( int numCols = 1; numCols < 15; numCols += 2) { DenseMatrix64F mat = RandomMatrices.createRandom(numRows,numCols,rand); DenseMatrix64F matTran = new DenseMatrix64F(numCols,numRows); TransposeAlgs.block(mat,matTran,7); assertEquals(numCols,matTran.getNumRows()); assertEquals(numRows,matTran.getNumCols()); EjmlUnitTests.assertEqualsTrans(mat,matTran,0); } } } @Test public void standard() { DenseMatrix64F mat = RandomMatrices.createRandom(5,7,rand); DenseMatrix64F matTran = new DenseMatrix64F(7,5); TransposeAlgs.standard(mat,matTran); assertEquals(mat.getNumCols(),matTran.getNumRows()); assertEquals(mat.getNumRows(),matTran.getNumCols()); EjmlUnitTests.assertEqualsTrans(mat,matTran,0); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/TestUnrolledDeterminantFromMinor.java000066400000000000000000000031211256171534400313770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestUnrolledDeterminantFromMinor { Random rand = new Random(234234); @Test public void testAll() { for( int N = 2; N <= UnrolledDeterminantFromMinor.MAX; N++ ) { DenseMatrix64F A = RandomMatrices.createRandom(N,N,rand); double unrolled = UnrolledDeterminantFromMinor.det(A); LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); assertTrue( alg.decompose(A) ); double expected = alg.computeDeterminant().real; assertEquals(expected,unrolled,1e-8); } } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/misc/TestUnrolledInverseFromMinor.java000066400000000000000000000037111256171534400305450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestUnrolledInverseFromMinor { Random rand = new Random(234234); /** * Compare it against LU decomposition */ @Test public void compareToLU() { for( int N = 2; N <= UnrolledInverseFromMinor.MAX; N++ ) { DenseMatrix64F A = RandomMatrices.createRandom(N,N,rand); DenseMatrix64F expected = new DenseMatrix64F(N,N); DenseMatrix64F found = new DenseMatrix64F(N,N); // first compute inverse by LU LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); LinearSolverLu_D64 solver = new LinearSolverLu_D64(alg); assertTrue( solver.setA(A)); solver.invert(expected); // compute the result from the algorithm being tested UnrolledInverseFromMinor.inv(A,found); EjmlUnitTests.assertEquals(expected,found,1e-8); } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400221155ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/CheckMatrixMultShape.java000066400000000000000000000126641256171534400270160ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.MatrixDimensionException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * Checks to see if the input to a matrix mutiply is accepted or rejected correctly depending * on the shape in the input matrices. Java reflections is used to grab all functions * with "mult" in its name and then it determins if any of matrices are transposed. * * @author Peter Abeles */ public class CheckMatrixMultShape { Class theClass; public CheckMatrixMultShape( Class theClass ) { this.theClass = theClass; } /** * Perform all shape input checks. * * @throws Throwable */ public void checkAll() { int numChecked = 0; Method methods[] = theClass.getMethods(); for( Method method : methods ) { String name = method.getName(); // only look at function which perform matrix multiplcation if( !name.contains("mult") || name.contains("Element") || name.contains("Inner") || name.contains("Outer") ) continue; boolean transA = false; boolean transB = false; if( name.contains("TransAB")) { transA = true; transB = true; } else if( name.contains("TransA")) { transA = true; } else if( name.contains("TransB")) { transB = true; } try { checkPositive(method, transA, transB); checkNegative(method,transA,transB); } catch( Throwable e ) { System.out.println("Failed on "+name); e.printStackTrace(); fail("An exception was thrown"); } numChecked++; } // make sure some functions were checked! assertTrue(numChecked!=0); } /** * Iterate through a variety of different sizes and shapes of matrices. */ private void checkPositive( Method func, boolean transA, boolean transB ) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { for( int i = 1; i <= 4; i++ ) { for( int j = 1; j <= 4; j++ ) { for( int k = 1; k <= 4; k++ ) { checkPositive(func,transA,transB,i,j,k); } } } } /** * See if the function can be called with matrices of the correct size */ private void checkPositive(Method func, boolean transA, boolean transB , int m , int n , int o ) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { DenseMatrix64F A,B; DenseMatrix64F C = new DenseMatrix64F(m,o); if( transA ) { A = new DenseMatrix64F(n,m); } else { A = new DenseMatrix64F(m,n); } if( transB ) { B = new DenseMatrix64F(o,n); } else { B = new DenseMatrix64F(n,o); } TestMatrixMatrixMult.invoke(func, 2.0, A, B, C); } /** * See if the function throws an exception when it is given bad inputs */ private void checkNegative(Method func, boolean transA, boolean transB) throws NoSuchMethodException, IllegalAccessException { // System.out.println("func = "+func); // correct = 2,4,4,3,2,3 // i,j,j,k,i,k // mis matched i checkNegative(func,2,4,4,3,6,3,transA,transB); // missmatched j checkNegative(func,2,4,5,3,2,3,transA,transB); // miss matched k checkNegative(func,2,4,4,7,2,3,transA,transB); } /** * See if the function throws an exception when it is given bad inputs */ private void checkNegative(Method func, int m_a , int n_a , int m_b , int n_b , int m_c , int n_c , boolean transA, boolean transB) throws NoSuchMethodException, IllegalAccessException { DenseMatrix64F A,B; DenseMatrix64F C = new DenseMatrix64F(m_c,n_c); if( transA ) { A = new DenseMatrix64F(n_a,m_a); } else { A = new DenseMatrix64F(m_a,n_a); } if( transB ) { B = new DenseMatrix64F(n_b,m_b); } else { B = new DenseMatrix64F(m_b,n_b); } try { TestMatrixMatrixMult.invoke(func, 2.0, A, B, C); fail("An exception should have been thrown."); } catch( InvocationTargetException e ) { assertTrue(e.getCause().getClass() == MatrixDimensionException.class ); } } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/CheckMatrixVectorMultShape.java000066400000000000000000000105621256171534400301740ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.MatrixDimensionException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * Checks to see if the input to a matrix vector mutiply is accepted or rejected correctly depending * on the shape in the input matrices. Java reflections is used to grab all functions * with "mult" in its name and then it determins if any of matrices are transposed. * * @author Peter Abeles */ public class CheckMatrixVectorMultShape { Class theClass; public CheckMatrixVectorMultShape( Class theClass ) { this.theClass = theClass; } /** * Perform all shape input checks. * * @throws Throwable */ public void checkAll() { int numChecked = 0; Method methods[] = theClass.getMethods(); for( Method method : methods ) { String name = method.getName(); // only look at function which perform matrix multiplcation if( !name.contains("mult")) continue; boolean transA = false; if( name.contains("TransA")) { transA = true; } try { checkPositive(method, transA); checkNegative(method,transA); } catch( Throwable e ) { System.out.println("Failed on function: "+name); e.printStackTrace(); fail("An exception was thrown"); } numChecked++; } // make sure some functions were checked! assertTrue(numChecked!=0); } /** * See if the function can be called with matrices of the correct size */ private void checkPositive(Method func, boolean transA) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { DenseMatrix64F A,B; DenseMatrix64F C = new DenseMatrix64F(2,1); if( transA ) { A = new DenseMatrix64F(4,2); } else { A = new DenseMatrix64F(2,4); } // should work for B as a column or row vector B = new DenseMatrix64F(4,1); func.invoke(null,A,B,C); B = new DenseMatrix64F(1,4); func.invoke(null,A,B,C); } /** * See if the function throws an exception when it is given bad inputs */ private void checkNegative(Method func, boolean transA) throws NoSuchMethodException, IllegalAccessException { DenseMatrix64F A,B; DenseMatrix64F C = new DenseMatrix64F(2,1); if( transA ) { A = new DenseMatrix64F(2,4); } else { A = new DenseMatrix64F(4,2); } // see if it catched B not being a vector B = new DenseMatrix64F(4,2); invokeExpectFail(func, A, B, C); // B is not compatible with A B = new DenseMatrix64F(3,1); invokeExpectFail(func, A, B, C); // C is a row vector B = new DenseMatrix64F(4,1); C = new DenseMatrix64F(1,2); invokeExpectFail(func, A, B, C); // C is not a vector C = new DenseMatrix64F(2,2); invokeExpectFail(func, A, B, C); // C is not compatible with A C = new DenseMatrix64F(3,1); invokeExpectFail(func, A, B, C); } private void invokeExpectFail(Method func, DenseMatrix64F a, DenseMatrix64F b, DenseMatrix64F c) throws IllegalAccessException { try { func.invoke(null, b, a, c); } catch( InvocationTargetException e ) { assertTrue(e.getCause().getClass() == MatrixDimensionException.class ); } } }ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/TestMatrixMatrixMult.java000066400000000000000000000220171256171534400271150ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestMatrixMatrixMult { Random rand = new Random(121342); /** * Checks to see that it only accepts input matrices that have compatible shapes */ @Test public void checkShapesOfInput() { CheckMatrixMultShape check = new CheckMatrixMultShape(MatrixMatrixMult.class); check.checkAll(); } @Test public void checkZeroRowsColumns() throws InvocationTargetException, IllegalAccessException { checkZeros(5,0,0,6); checkZeros(0,5,5,0); } /** * Checks to see if the input 'c' matrix is not 'a' or 'b' */ @Test public void checkInputInstance() throws IllegalAccessException { Method methods[] = MatrixMatrixMult.class.getMethods(); for( Method method : methods ) { String name = method.getName(); if( !name.contains("mult") ) continue; // make sure it checks that the c matrix is not a or b try { DenseMatrix64F a = new DenseMatrix64F(2,2); DenseMatrix64F b = new DenseMatrix64F(2,2); invoke(method,2.0,a,b,a); fail("An exception should have been thrown"); } catch( InvocationTargetException e ) { assertTrue(e.getTargetException() instanceof IllegalArgumentException ); } try { DenseMatrix64F a = new DenseMatrix64F(2,2); DenseMatrix64F b = new DenseMatrix64F(2,2); invoke(method,2.0,a,b,b); fail("An exception should have been thrown"); } catch( InvocationTargetException e ) { assertTrue(e.getTargetException() instanceof IllegalArgumentException ); } } } /** * Use java reflections to get a list of all the functions. From the name extract what * the function is supposed to do. then compute the expected results. * * Correctness is tested against a known case. */ @Test public void checkAllAgainstKnown() throws InvocationTargetException, IllegalAccessException { double d[] = new double[]{0,1,2,3,4,5,6,7,8,9,10,11,12}; DenseMatrix64F a_orig = new DenseMatrix64F(2,3, true, d); DenseMatrix64F b_orig = new DenseMatrix64F(3,4, true, d); DenseMatrix64F c_orig = RandomMatrices.createRandom(2,4,rand); DenseMatrix64F r_orig = new DenseMatrix64F(2,4, true, 20, 23, 26, 29, 56, 68, 80, 92); checkResults(a_orig,b_orig,c_orig,r_orig); } /** * Creates a bunch of random matrices and computes the expected results using mult(). * * The known case is needed since this test case tests against other algorithms in * this library, which could in theory be wrong. * * @throws InvocationTargetException * @throws IllegalAccessException */ @Test public void checkAgainstRandomDiffShapes() throws InvocationTargetException, IllegalAccessException { for( int i = 1; i <= 4; i++ ) { for( int j = 1; j <= 4; j++ ) { for( int k = 1; k <= 4; k++ ) { DenseMatrix64F a_orig = RandomMatrices.createRandom(i,j, rand); DenseMatrix64F b_orig = RandomMatrices.createRandom(j,k, rand); DenseMatrix64F c_orig = RandomMatrices.createRandom(i,k, rand); DenseMatrix64F r_orig = RandomMatrices.createRandom(i,k,rand); MatrixMatrixMult.mult_small(a_orig,b_orig,r_orig); checkResults(a_orig,b_orig,c_orig,r_orig); } } } } /** * Sees if all the matrix multiplications produce the expected results against the provided * known solution. */ private void checkResults( DenseMatrix64F a_orig , DenseMatrix64F b_orig , DenseMatrix64F c_orig , DenseMatrix64F r_orig ) throws InvocationTargetException, IllegalAccessException { double alpha = 2.5; int numChecked = 0; Method methods[] = MatrixMatrixMult.class.getMethods(); for( Method method : methods ) { String name = method.getName(); // System.out.println(name); // only look at function which perform matrix multiplications if( !name.contains("mult") ) continue; DenseMatrix64F a = a_orig.copy(); DenseMatrix64F b = b_orig.copy(); DenseMatrix64F c = c_orig.copy(); boolean add = name.contains("multAdd"); boolean hasAlpha = method.getGenericParameterTypes()[0] == double.class; if( name.contains("TransAB")) { transpose(a); transpose(b); } else if( name.contains("TransA")) { transpose(a); } else if( name.contains("TransB")) { transpose(b); } DenseMatrix64F expected = r_orig.copy(); double []expectedData = expected.data; if( hasAlpha ) { for( int i = 0; i < expectedData.length; i++ ) { expectedData[i] *= alpha; } } if( add ) { for( int i = 0; i < expectedData.length; i++ ) { expectedData[i] += c_orig.get(i); } } invoke(method,alpha,a,b,c); EjmlUnitTests.assertEquals(expected,c,1e-12); numChecked++; } assertEquals(numChecked,32); } /** * Sees if all the matrix multiplications produce the expected results against the provided * known solution. */ private void checkZeros( int rowsA , int colsA , int rowsB , int colsB ) throws InvocationTargetException, IllegalAccessException { double alpha = 2.5; int numChecked = 0; Method methods[] = MatrixMatrixMult.class.getMethods(); for( Method method : methods ) { String name = method.getName(); // only look at function which perform matrix multiplications if( !name.contains("mult") ) continue; // System.out.println(name); DenseMatrix64F a = new DenseMatrix64F(rowsA,colsA); DenseMatrix64F b = new DenseMatrix64F(rowsB,colsB); DenseMatrix64F c = RandomMatrices.createRandom(rowsA,colsB,rand); boolean add = name.contains("multAdd"); if( name.contains("TransAB")) { transpose(a); transpose(b); } else if( name.contains("TransA")) { transpose(a); } else if( name.contains("TransB")) { transpose(b); } DenseMatrix64F original = c.copy(); invoke(method,alpha,a,b,c); if( add ) { assertTrue(MatrixFeatures.isEquals(original, c)); } else { assertTrue(MatrixFeatures.isZeros(c, 1e-8)); } numChecked++; } assertEquals(numChecked,32); } private void transpose( DenseMatrix64F a ) { DenseMatrix64F b = new DenseMatrix64F(a.numCols,a.numRows); CommonOps.transpose(a,b); a.set(b); } public static void invoke(Method func, double alpha, DenseMatrix64F a, DenseMatrix64F b, DenseMatrix64F c) throws IllegalAccessException, InvocationTargetException { if( func.getParameterTypes().length == 3 ) { func.invoke(null, a, b, c); } else { if( func.getParameterTypes()[0] == double.class ) { if( func.getParameterTypes().length == 4 ) func.invoke(null,alpha, a, b, c); else func.invoke(null,alpha, a, b, c,null); } else { func.invoke(null, a, b, c,null); } } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/TestMatrixMultProduct.java000066400000000000000000000055551256171534400273010ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestMatrixMultProduct { Random rand = new Random(2345); @Test public void outer() { DenseMatrix64F A = RandomMatrices.createRandom(20, 10, rand); DenseMatrix64F found = new DenseMatrix64F(20,20); DenseMatrix64F expected = new DenseMatrix64F(20,20); MatrixMatrixMult.multTransB(A, A, expected); MatrixMultProduct.outer(A, found); assertTrue(MatrixFeatures.isIdentical(expected, found, 1e-8)); } @Test public void inner_small() { DenseMatrix64F A = RandomMatrices.createRandom(20, 10, rand); DenseMatrix64F found = new DenseMatrix64F(10,10); DenseMatrix64F expected = new DenseMatrix64F(10,10); MatrixMatrixMult.multTransA_reorder(A,A,expected); MatrixMultProduct.inner_small(A, found); assertTrue(MatrixFeatures.isIdentical(expected, found, 1e-8)); } @Test public void inner_reorder() { DenseMatrix64F A = RandomMatrices.createRandom(20,10,rand); DenseMatrix64F found = new DenseMatrix64F(10,10); DenseMatrix64F expected = new DenseMatrix64F(10,10); MatrixMatrixMult.multTransA_reorder(A,A,expected); MatrixMultProduct.inner_reorder(A, found); assertTrue(MatrixFeatures.isIdentical(expected, found, 1e-8)); } @Test public void inner_reorder_upper() { DenseMatrix64F A = RandomMatrices.createRandom(20,10,rand); DenseMatrix64F found = new DenseMatrix64F(10,10); DenseMatrix64F expected = new DenseMatrix64F(10,10); MatrixMatrixMult.multTransA_reorder(A,A,expected); MatrixMultProduct.inner_reorder_upper(A, found); // only check the upper triangle for( int i = 0; i < found.numRows; i++ ) { for( int j = i; j < found.numCols; j++ ) { assertEquals(expected.get(i,j),found.get(i,j),1e-8); } } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/TestMatrixVectorMult.java000066400000000000000000000137751256171534400271260ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.data.UtilTestMatrix; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestMatrixVectorMult { Random rand = new Random(0x7354); @Test public void checkShapesOfInput() { CheckMatrixVectorMultShape check = new CheckMatrixVectorMultShape(MatrixVectorMult.class); check.checkAll(); } @Test public void mult() { double d[] = new double[]{0,1,2,3,4,5}; DenseMatrix64F a = new DenseMatrix64F(2,3, true, d); DenseMatrix64F b = new DenseMatrix64F(3,1, true, d); DenseMatrix64F c = RandomMatrices.createRandom(2,1,rand); MatrixVectorMult.mult(a,b,c); UtilTestMatrix.checkMat(c,5,14); } @Test public void mult_zero() { double d[] = new double[]{0,1,2,3,4,5}; DenseMatrix64F a = new DenseMatrix64F(2,3, true, d); DenseMatrix64F b = new DenseMatrix64F(3,1, true, d); DenseMatrix64F c = RandomMatrices.createRandom(2,1,rand); MatrixVectorMult.mult(a,b,c); UtilTestMatrix.checkMat(c,5,14); } @Test public void multAdd() { double d[] = new double[]{0,1,2,3,4,5}; DenseMatrix64F a = new DenseMatrix64F(2,3, true, d); DenseMatrix64F b = new DenseMatrix64F(3,1, true, d); DenseMatrix64F c = new DenseMatrix64F(2,1, true, 2, 6); MatrixVectorMult.multAdd(a,b,c); UtilTestMatrix.checkMat(c,7,20); } @Test public void multTransA_small() { double d[] = new double[]{0,1,2,3,4,5}; DenseMatrix64F a = new DenseMatrix64F(3,2, true, d); DenseMatrix64F b = new DenseMatrix64F(3,1, true, d); DenseMatrix64F c = RandomMatrices.createRandom(2,1,rand); MatrixVectorMult.multTransA_small(a,b,c); UtilTestMatrix.checkMat(c,10,13); } @Test public void multTransA_reorder() { double d[] = new double[]{0,1,2,3,4,5}; DenseMatrix64F a = new DenseMatrix64F(3,2, true, d); DenseMatrix64F b = new DenseMatrix64F(3,1, true, d); DenseMatrix64F c = RandomMatrices.createRandom(2,1,rand); MatrixVectorMult.multTransA_reorder(a,b,c); UtilTestMatrix.checkMat(c,10,13); } @Test public void multAddTransA_small() { double d[] = new double[]{0,1,2,3,4,5}; DenseMatrix64F a = new DenseMatrix64F(3,2, true, d); DenseMatrix64F b = new DenseMatrix64F(3,1, true, d); DenseMatrix64F c = new DenseMatrix64F(2,1, true, 2, 6); MatrixVectorMult.multAddTransA_small(a,b,c); UtilTestMatrix.checkMat(c,12,19); } @Test public void multAddTransA_reorder() { double d[] = new double[]{0,1,2,3,4,5}; DenseMatrix64F a = new DenseMatrix64F(3,2, true, d); DenseMatrix64F b = new DenseMatrix64F(3,1, true, d); DenseMatrix64F c = new DenseMatrix64F(2,1, true, 2, 6); MatrixVectorMult.multAddTransA_reorder(a,b,c); UtilTestMatrix.checkMat(c,12,19); } @Test public void checkZeroRowsColumns() throws InvocationTargetException, IllegalAccessException { checkZeros(5,0); checkZeros(0,5); } /** * Sees if all the matrix multiplications produce the expected results against the provided * known solution. */ private void checkZeros( int rowsA , int colsA ) throws InvocationTargetException, IllegalAccessException { int numChecked = 0; Method methods[] = MatrixVectorMult.class.getMethods(); for( Method method : methods ) { String name = method.getName(); // only look at function which perform matrix multiplications if( !name.contains("mult") ) continue; // System.out.println(name); DenseMatrix64F a = new DenseMatrix64F(rowsA,colsA); DenseMatrix64F b = new DenseMatrix64F(colsA,1); DenseMatrix64F c = RandomMatrices.createRandom(rowsA,1,rand); boolean add = name.contains("multAdd"); if( name.contains("TransAB")) { CommonOps.transpose(a); CommonOps.transpose(b); } else if( name.contains("TransA")) { CommonOps.transpose(a); } else if( name.contains("TransB")) { CommonOps.transpose(b); } DenseMatrix64F original = c.copy(); invoke(method,a,b,c); if( add ) { assertTrue(MatrixFeatures.isEquals(original, c)); } else { assertTrue(MatrixFeatures.isZeros(c, 1e-8)); } numChecked++; } assertEquals(numChecked,6); } public static void invoke(Method func, DenseMatrix64F a, DenseMatrix64F b, DenseMatrix64F c) throws IllegalAccessException, InvocationTargetException { if( func.getParameterTypes().length == 3 ) { func.invoke(null, a, b, c); } else { throw new RuntimeException("WTF?"); } } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/TestSubmatrixOps.java000066400000000000000000000027471256171534400262720ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; /** * @author Peter Abeles */ public class TestSubmatrixOps { @Test public void setSubMatrix() { DenseMatrix64F A = new DenseMatrix64F(5,5); DenseMatrix64F B = new DenseMatrix64F(6,6); for( int i = 0; i < A.data.length; i++ ) { A.data[i] = 1; } SubmatrixOps.setSubMatrix(A,B,1,1,2,3,2,3); // create a matrix that should be identical to B DenseMatrix64F C = new DenseMatrix64F(6,6); for( int i = 2; i < 4; i++ ) { for( int j = 3; j < 6; j++ ) { C.set(i,j,1); } } // see if they are the same EjmlUnitTests.assertEquals(B,C,0); } } ejml-0.28/main/dense64/test/org/ejml/alg/dense/mult/TestVectorVectorMult.java000066400000000000000000000137031256171534400271130ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestVectorVectorMult { Random rand = new Random(45837); @Test public void innerProduct() { DenseMatrix64F A = new DenseMatrix64F(4,1, true, 1, 2, 3, 4); DenseMatrix64F B = new DenseMatrix64F(4,1, true, -1, -2, -3, -4); double val = VectorVectorMult.innerProd(A,B); assertEquals(-30,val,1e-8); } @Test public void innerProdA() { DenseMatrix64F A = RandomMatrices.createRandom(3,4,rand); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F y = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F temp = new DenseMatrix64F(1,4); // compute the expected result first CommonOps.multTransA(x,A,temp); double expected = VectorVectorMult.innerProd(temp,y); double found = VectorVectorMult.innerProdA(x,A,y); assertEquals(expected,found,1e-8); } @Test public void innerProdTranA() { DenseMatrix64F A = RandomMatrices.createRandom(3,3,rand); DenseMatrix64F x = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F y = RandomMatrices.createRandom(3,1,rand); DenseMatrix64F Atran = new DenseMatrix64F(3,3); CommonOps.transpose(A,Atran); DenseMatrix64F temp = new DenseMatrix64F(1,3); // compute the expected result first CommonOps.multTransA(x,Atran,temp); double expected = VectorVectorMult.innerProd(temp,y); double found = VectorVectorMult.innerProdTranA(x,A,y); assertEquals(expected,found,1e-8); } @Test public void outerProd() { DenseMatrix64F A = new DenseMatrix64F(4,1, true, 1, 2, 3, 4); DenseMatrix64F B = new DenseMatrix64F(4,1, true, -1, -2, -3, -4); DenseMatrix64F C = RandomMatrices.createRandom(4,4,rand); VectorVectorMult.outerProd(A,B,C); // compare it against the equivalent matrix matrix multiply DenseMatrix64F D = RandomMatrices.createRandom(4,4,rand); MatrixMatrixMult.multTransB(A,B,D); EjmlUnitTests.assertEquals(D,C,0); } @Test public void addOuterProd() { DenseMatrix64F A = new DenseMatrix64F(4,1, true, 1, 2, 3, 4); DenseMatrix64F B = new DenseMatrix64F(4,1, true, -1, -2, -3, -4); DenseMatrix64F C = RandomMatrices.createRandom(4,4,rand); DenseMatrix64F D = C.copy(); VectorVectorMult.addOuterProd(1.0,A,B,C); // compare it against the equivalent matrix matrix multiply DenseMatrix64F E = RandomMatrices.createRandom(4,4,rand); MatrixMatrixMult.multTransB(A,B,E); CommonOps.add(D,E,D); assertTrue(MatrixFeatures.isEquals(D,C)); // now try it with another gamma C = RandomMatrices.createRandom(4,4,rand); D = C.copy(); VectorVectorMult.addOuterProd(2.5,A,B,C); MatrixMatrixMult.multTransB(2.5,A,B,E); CommonOps.add(D,E,D); EjmlUnitTests.assertEquals(D,C,0); } @Test public void householder() { DenseMatrix64F u = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F x = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F y = RandomMatrices.createRandom(4,1,rand); double gamma = 4.5; VectorVectorMult.householder(gamma,u,x,y); DenseMatrix64F L = CommonOps.identity(4,4); DenseMatrix64F y_exp = RandomMatrices.createRandom(4,1,rand); VectorVectorMult.addOuterProd(gamma,u,u,L); CommonOps.mult(L,x,y_exp); EjmlUnitTests.assertEquals(y,y_exp,1e-8); } @Test public void rank1Update_two_square() { DenseMatrix64F A = RandomMatrices.createRandom(6,6,rand); DenseMatrix64F u = RandomMatrices.createRandom(6,1,rand); DenseMatrix64F w = RandomMatrices.createRandom(6,1,rand); double gamma = -45; SimpleMatrix _A = SimpleMatrix.wrap(A); SimpleMatrix _u = SimpleMatrix.wrap(u); SimpleMatrix _w = SimpleMatrix.wrap(w); SimpleMatrix expected = _A.plus(_u.mult(_w.transpose()).scale(gamma)); DenseMatrix64F found = new DenseMatrix64F(6,6); VectorVectorMult.rank1Update(gamma,A,u,w,found); EjmlUnitTests.assertEquals(expected.getMatrix(),found,1e-8); } @Test public void rank1Update_one_square() { DenseMatrix64F A = RandomMatrices.createRandom(6,6,rand); DenseMatrix64F u = RandomMatrices.createRandom(6,1,rand); DenseMatrix64F w = RandomMatrices.createRandom(6,1,rand); double gamma = -45; SimpleMatrix _A = SimpleMatrix.wrap(A); SimpleMatrix _u = SimpleMatrix.wrap(u); SimpleMatrix _w = SimpleMatrix.wrap(w); SimpleMatrix expected = _A.plus(_u.mult(_w.transpose()).scale(gamma)); DenseMatrix64F found = A.copy(); VectorVectorMult.rank1Update(gamma,found,u,w); EjmlUnitTests.assertEquals(expected.getMatrix(),found,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/alg/fixed/000077500000000000000000000000001256171534400211355ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/alg/fixed/CompareFixedToCommonOps.java000066400000000000000000000204221256171534400265040ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.DenseMatrix64F; import org.ejml.data.FixedMatrix64F; import org.ejml.data.RealMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.ConvertMatrixType; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** * @author Peter Abeles */ public abstract class CompareFixedToCommonOps { Random rand = new Random(234); Class classFixed; int N; public CompareFixedToCommonOps(Class classFixed) { this.classFixed = classFixed; N = Integer.parseInt(classFixed.getSimpleName().charAt(8)+""); } /** * Compares equivalent functions in FixedOps to CommonOps. Inputs are randomly generated */ @Test public void compareToCommonOps() { Method[] methods = classFixed.getMethods(); int numNotMatched = 0; int numPassed = 0; int numFailed = 0; for( Method fixedM : methods ) { if( !isValid(fixedM)) continue; Method commonM = null; for( Method m : CommonOps.class.getMethods()) { if( isMatch(fixedM,m)) { commonM = m; break; } } if( commonM == null ) { // System.out.println("not matched: "+fixedM.getName()); numNotMatched++; continue; } if( compareToCommon(fixedM,commonM) ) { numPassed++; } else { numFailed++; System.out.println("Failed comparison to common: "+fixedM); } } int numExpected = 55; if( N > GenerateFixedOps.maxInverseSize ) { numExpected -= 2; } assertEquals(0,numFailed); assertEquals(1,numNotMatched); assertEquals(numExpected,numPassed); } /** * Checks to see if it is a valid Method which can be checked */ private boolean isValid( Method m ) { Class[] types = m.getParameterTypes(); for( Class c : types ) { if(FixedMatrix64F.class.isAssignableFrom(c)) return true; } return false; } private boolean isMatch( Method fixed , Method common ) { if( fixed.getName().compareTo(common.getName()) != 0 ) return false; Class[] typesFixed = fixed.getParameterTypes(); Class[] typesCommon = common.getParameterTypes(); if( typesFixed.length != typesCommon.length ) return false; for (int i = 0; i < typesFixed.length; i++) { if( RealMatrix64F.class.isAssignableFrom(typesFixed[i]) ) { if( !RealMatrix64F.class.isAssignableFrom(typesCommon[i]) ) { return false; } } } Class returnFixed = fixed.getReturnType(); Class returnCommon = common.getReturnType(); if( returnFixed == returnCommon ) return true; if( RealMatrix64F.class.isAssignableFrom(returnFixed) && RealMatrix64F.class.isAssignableFrom(returnCommon) ) return true; return false; } private boolean compareToCommon( Method fixed , Method common ) { Class[] typesFixed = fixed.getParameterTypes(); Object[] inputsFixed = new Object[ typesFixed.length ]; Object[] inputsCommon = new Object[ typesFixed.length ]; if( !handleSpecialCase(fixed.getName(),typesFixed,inputsFixed,inputsCommon) ) declareParamStandard(typesFixed, inputsFixed, inputsCommon); try { Object retFixed = fixed.invoke(null,inputsFixed); Object retCommon = common.invoke(null,inputsCommon); checkEquivalent(retFixed,retCommon); for( int i = 0; i < inputsFixed.length; i++ ) { if( !checkEquivalent(inputsFixed[i],inputsCommon[i]) ) return false; } } catch (IllegalAccessException e) { e.printStackTrace(); fail("IllegalAccessException"); } catch (InvocationTargetException e) { e.printStackTrace(); fail("InvocationTargetException"); } return true; } private void declareParamStandard(Class[] typesFixed, Object[] inputsFixed, Object[] inputsCommon) { for( int i = 0; i < typesFixed.length; i++ ) { if(FixedMatrix64F.class.isAssignableFrom(typesFixed[i])) { FixedMatrix64F f = null; try { f = (FixedMatrix64F)typesFixed[i].newInstance(); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } DenseMatrix64F m = RandomMatrices.createRandom(f.getNumRows(), f.getNumCols(), rand); ConvertMatrixType.convert(m, f); inputsFixed[i] = f; inputsCommon[i] = m; } else if( double.class == typesFixed[i] ) { inputsFixed[i] = 2.5; inputsCommon[i] = 2.5; } else if( int.class == typesFixed[i] ) { inputsFixed[i] = 1; // handle tailored towards extractRow and extractCol inputsCommon[i] = 1; } } } private boolean handleSpecialCase( String name , Class[] typesFixed , Object[] inputsFixed, Object[] inputsCommon ) { if( "mult".compareTo(name) == 0 ) { try { FixedMatrix64F f = (FixedMatrix64F)typesFixed[0].newInstance(); // see if it's a vector if( f.getNumCols() == 1 || f.getNumRows() == 1 ) { // swap the type of vector declareParamStandard(typesFixed,inputsFixed,inputsCommon); DenseMatrix64F a = (DenseMatrix64F)inputsCommon[0]; DenseMatrix64F b = (DenseMatrix64F)inputsCommon[2]; a.numRows=f.getNumCols(); a.numCols=f.getNumRows(); b.numRows=f.getNumCols(); b.numCols=f.getNumRows(); return true; } } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } return false; } private boolean checkEquivalent( Object a , Object b ) { if( a == null ) { return b == null; } else if( Double.class == a.getClass() ) { double valA = ((Double)a).doubleValue(); double valB = ((Double)b).doubleValue(); return Math.abs(valA-valB) < 1e-8; } else if(FixedMatrix64F.class.isAssignableFrom(a.getClass()) ) { DenseMatrix64F bb = (DenseMatrix64F)b; FixedMatrix64F f = (FixedMatrix64F)a; DenseMatrix64F m = new DenseMatrix64F(f.getNumRows(),f.getNumCols()); ConvertMatrixType.convert(f,m); m.numRows = bb.numRows; m.numCols = bb.numCols; return MatrixFeatures.isIdentical(m, bb, 1e-8); } else if( Boolean.class == a.getClass() ) { return true; } else if( Integer.class == a.getClass() ) { return true; } else { fail("Not sure what this is"); } return true; } } ejml-0.28/main/dense64/test/org/ejml/alg/fixed/TestFixedOps2.java000066400000000000000000000024361256171534400244500ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix2_64F; import org.ejml.data.FixedMatrix2x2_64F; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestFixedOps2 extends CompareFixedToCommonOps { public TestFixedOps2() { super(FixedOps2.class); } @Test public void diag() { FixedMatrix2x2_64F m = new FixedMatrix2x2_64F(1,2,3,4); FixedMatrix2_64F found = new FixedMatrix2_64F(); FixedOps2.diag(m,found); assertEquals(1,found.a1,1e-8); assertEquals(4,found.a2,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/alg/fixed/TestFixedOps3.java000066400000000000000000000026201256171534400244440ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix3_64F; import org.ejml.data.FixedMatrix3x3_64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestFixedOps3 extends CompareFixedToCommonOps { Random rand = new Random(234); public TestFixedOps3() { super(FixedOps3.class); } @Test public void diag() { FixedMatrix3x3_64F m = new FixedMatrix3x3_64F(1,2,3,4,5,6,7,8,9); FixedMatrix3_64F found = new FixedMatrix3_64F(); FixedOps3.diag(m,found); assertEquals(1,found.a1,1e-8); assertEquals(5,found.a2,1e-8); assertEquals(9,found.a3,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/alg/fixed/TestFixedOps4.java000066400000000000000000000026201256171534400244450ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix4_64F; import org.ejml.data.FixedMatrix4x4_64F; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestFixedOps4 extends CompareFixedToCommonOps { public TestFixedOps4() { super(FixedOps4.class); } @Test public void diag() { FixedMatrix4x4_64F m = new FixedMatrix4x4_64F(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); FixedMatrix4_64F found = new FixedMatrix4_64F(); FixedOps4.diag(m,found); assertEquals(1,found.a1,1e-8); assertEquals(6,found.a2,1e-8); assertEquals(11,found.a3,1e-8); assertEquals(16,found.a4,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/alg/fixed/TestFixedOps5.java000066400000000000000000000027201256171534400244470ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix5_64F; import org.ejml.data.FixedMatrix5x5_64F; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestFixedOps5 extends CompareFixedToCommonOps { public TestFixedOps5() { super(FixedOps5.class); } @Test public void diag() { FixedMatrix5x5_64F m = new FixedMatrix5x5_64F(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25); FixedMatrix5_64F found = new FixedMatrix5_64F(); FixedOps5.diag(m,found); assertEquals(1,found.a1,1e-8); assertEquals(7,found.a2,1e-8); assertEquals(13,found.a3,1e-8); assertEquals(19,found.a4,1e-8); assertEquals(25,found.a5,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/alg/fixed/TestFixedOps6.java000066400000000000000000000027751256171534400244620ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.FixedMatrix6_64F; import org.ejml.data.FixedMatrix6x6_64F; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestFixedOps6 extends CompareFixedToCommonOps { public TestFixedOps6() { super(FixedOps6.class); } @Test public void diag() { FixedMatrix6x6_64F m = new FixedMatrix6x6_64F(); for( int i = 0; i < 36; i++ ) m.set(i/6,i%6,i+1); FixedMatrix6_64F found = new FixedMatrix6_64F(); FixedOps6.diag(m,found); assertEquals(1,found.a1,1e-8); assertEquals(8,found.a2,1e-8); assertEquals(15,found.a3,1e-8); assertEquals(22,found.a4,1e-8); assertEquals(29,found.a5,1e-8); assertEquals(36,found.a6,1e-8); } } ejml-0.28/main/dense64/test/org/ejml/factory/000077500000000000000000000000001256171534400207425ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/factory/TestDecompositionFactory.java000066400000000000000000000046131256171534400266150ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.factory; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestDecompositionFactory { Random rand = new Random(234234); @Test public void quality_eig() { // I'm assuming it can process this matrix with no problems DenseMatrix64F A = RandomMatrices.createSymmetric(5,-1,1,rand); EigenDecomposition eig = DecompositionFactory.eig(A.numRows,true); assertTrue(eig.decompose(A)); double origQuality = DecompositionFactory.quality(A,eig); // Mess up the EVD so that it will be of poor quality eig.getEigenVector(2).set(2,0,5); double modQuality = DecompositionFactory.quality(A,eig); assertTrue(origQuality < modQuality); assertTrue(origQuality < 1e-14); } @Test public void quality_svd() { // I'm assuming it can process this matrix with no problems DenseMatrix64F A = RandomMatrices.createRandom(4,5,rand); SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows,A.numCols,true,true,false); assertTrue(svd.decompose(A)); double origQuality = DecompositionFactory.quality(A,svd); // Mess up the SVD so that it will be of poor quality svd.getSingularValues()[2] = 5; double modQuality = DecompositionFactory.quality(A,svd); assertTrue(origQuality < modQuality); assertTrue(origQuality < 1e-14); } } ejml-0.28/main/dense64/test/org/ejml/factory/TestLinearSolverFactory.java000066400000000000000000000076021256171534400264070ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.factory; import org.ejml.alg.dense.linsol.AdjustableLinearSolver; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestLinearSolverFactory { Random rand = new Random(234); @Test public void general() { DenseMatrix64F A = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F x = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F y = new DenseMatrix64F(5,1); LinearSolver solver = LinearSolverFactory.general(A.numRows, A.numCols); standardTest(A, x, y, solver); } @Test public void linear() { DenseMatrix64F A = RandomMatrices.createRandom(4,4,rand); DenseMatrix64F x = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F y = new DenseMatrix64F(4,1); LinearSolver solver = LinearSolverFactory.linear(A.numRows); standardTest(A, x, y, solver); } @Test public void leastSquares() { DenseMatrix64F A = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F x = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F y = new DenseMatrix64F(5,1); LinearSolver solver = LinearSolverFactory.leastSquares(A.numRows,A.numCols); standardTest(A, x, y, solver); } @Test public void symmetric() { DenseMatrix64F A = RandomMatrices.createSymmPosDef(5,rand); DenseMatrix64F x = RandomMatrices.createRandom(5,1,rand); DenseMatrix64F y = new DenseMatrix64F(5,1); LinearSolver solver = LinearSolverFactory.symmPosDef(A.numCols); standardTest(A, x, y, solver); } @Test public void adjustable() { DenseMatrix64F A = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F x = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F y = new DenseMatrix64F(5,1); AdjustableLinearSolver solver = LinearSolverFactory.adjustable(); standardTest(A, x, y, solver); // remove the last observation solver.removeRowFromA(y.numRows-1); // compute the adjusted solution y.numRows--; DenseMatrix64F x_adj = new DenseMatrix64F(4,1); solver.solve(y,x_adj); // The solution should still be the same assertTrue(MatrixFeatures.isIdentical(x,x_adj,1e-8)); } /** * Given A and x it computes the value of y. This is then compared against what the solver computes * x should be. */ private void standardTest(DenseMatrix64F a, DenseMatrix64F x, DenseMatrix64F y, LinearSolver solver) { solver = new LinearSolverSafe(solver); CommonOps.mult(a,x,y); DenseMatrix64F x_found = new DenseMatrix64F(x.numRows,1); assertTrue(solver.setA(a)); solver.solve(y,x_found); assertTrue(MatrixFeatures.isIdentical(x,x_found,1e-8)); } } ejml-0.28/main/dense64/test/org/ejml/ops/000077500000000000000000000000001256171534400200745ustar00rootroot00000000000000ejml-0.28/main/dense64/test/org/ejml/ops/TestCommonOps.java000066400000000000000000001073251256171534400235210ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_D64; import org.ejml.alg.dense.mult.CheckMatrixMultShape; import org.ejml.alg.dense.mult.MatrixMatrixMult; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RowD1Matrix64F; import org.ejml.data.UtilTestMatrix; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCommonOps { Random rand = new Random(0xFF); double tol = 1e-8; @Test public void checkInputShape() { CheckMatrixMultShape check = new CheckMatrixMultShape(CommonOps.class); check.checkAll(); } /** * Make sure the multiplication methods here have the same behavior as the ones in MatrixMatrixMult. */ @Test public void checkAllMatrixMults() { int numChecked = 0; Method methods[] = CommonOps.class.getMethods(); boolean oneFailed = false; for( Method method : methods ) { String name = method.getName(); // only look at function which perform matrix multiplication if( !name.contains("mult") || name.contains("Element") || name.contains("Inner") || name.contains("Outer")) continue; boolean hasAlpha = method.getGenericParameterTypes().length==4; Method checkMethod = findCheck(name,hasAlpha); boolean tranA = false; boolean tranB = false; if( name.contains("TransAB")) { tranA = true; tranB = true; } else if( name.contains("TransA")) { tranA = true; } else if( name.contains("TransB")) { tranB = true; } // System.out.println("Function = "+name+" alpha = "+hasAlpha); try { if( !checkMultMethod(method,checkMethod,hasAlpha,tranA,tranB) ) { System.out.println("Failed: Function = "+name+" alpha = "+hasAlpha); oneFailed = true; } } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } numChecked++; } assertEquals(16,numChecked); assertTrue(!oneFailed); } /** * See if zeros in rows and columns are handled correctly. */ @Test public void checkAllMatrixMult_Zeros() { int numChecked = 0; Method methods[] = CommonOps.class.getMethods(); boolean oneFailed = false; for( Method method : methods ) { String name = method.getName(); // only look at function which perform matrix multiplication if( !name.contains("mult") || name.contains("Element") || name.contains("Inner") || name.contains("Outer")) continue; try { boolean failed = !checkMultMethod(method,6,0,0,5); failed |= !checkMultMethod(method,0,5,5,0); failed |= !checkMultMethod(method,1,0,0,5); failed |= !checkMultMethod(method,6,0,0,1); failed |= !checkMultMethod(method,0,1,1,5); failed |= !checkMultMethod(method,5,1,1,0); failed |= !checkMultMethod(method,0,0,0,0); if( failed ) { System.out.println("Failed: Function = "+name); oneFailed = true; } } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } numChecked++; } assertEquals(16,numChecked); assertTrue(!oneFailed); } private Method findCheck( String name , boolean hasAlpha ) { Method checkMethod; try { if( hasAlpha ) checkMethod = MatrixMatrixMult.class.getMethod( name,double.class, RowD1Matrix64F.class, RowD1Matrix64F.class,RowD1Matrix64F.class); else checkMethod = MatrixMatrixMult.class.getMethod( name, RowD1Matrix64F.class, RowD1Matrix64F.class,RowD1Matrix64F.class); } catch (NoSuchMethodException e) { checkMethod = null; } if( checkMethod == null ) { try { if( hasAlpha ) checkMethod = MatrixMatrixMult.class.getMethod( name+"_reorder",double.class, RowD1Matrix64F.class, RowD1Matrix64F.class,RowD1Matrix64F.class); else checkMethod = MatrixMatrixMult.class.getMethod( name+"_reorder", RowD1Matrix64F.class, RowD1Matrix64F.class,RowD1Matrix64F.class); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } return checkMethod; } private boolean checkMultMethod(Method method, Method checkMethod, boolean hasAlpha, boolean tranA, boolean tranB ) throws InvocationTargetException, IllegalAccessException { // check various sizes for( int i = 1; i < 40; i++ ) { DenseMatrix64F a; if( tranA ) a = RandomMatrices.createRandom(i+1,i,rand); else a = RandomMatrices.createRandom(i,i+1,rand); DenseMatrix64F b; if( tranB ) b = RandomMatrices.createRandom(i,i+1,rand); else b = RandomMatrices.createRandom(i+1,i,rand); DenseMatrix64F c = RandomMatrices.createRandom(i,i,rand); DenseMatrix64F c_alt = c.copy(); if( hasAlpha ) { method.invoke(null,2.0,a,b,c); checkMethod.invoke(null,2.0,a,b,c_alt); } else { method.invoke(null,a,b,c); checkMethod.invoke(null,a,b,c_alt); } if( !MatrixFeatures.isIdentical(c_alt,c,tol)) return false; } // check various sizes column vector for( int i = 1; i < 4; i++ ) { DenseMatrix64F a; if( tranA ) a = RandomMatrices.createRandom(i,i+1,rand); else a = RandomMatrices.createRandom(i+1,i,rand); DenseMatrix64F b; if( tranB ) b = RandomMatrices.createRandom(1,i,rand); else b = RandomMatrices.createRandom(i,1,rand); DenseMatrix64F c = RandomMatrices.createRandom(i+1,1,rand); DenseMatrix64F c_alt = c.copy(); if( hasAlpha ) { method.invoke(null,2.0,a,b,c); checkMethod.invoke(null,2.0,a,b,c_alt); } else { method.invoke(null,a,b,c); checkMethod.invoke(null,a,b,c_alt); } if( !MatrixFeatures.isIdentical(c_alt,c,tol)) return false; } return true; } private boolean checkMultMethod(Method method, int rowsA , int colsA , int rowsB , int colsB ) throws InvocationTargetException, IllegalAccessException { String name = method.getName(); boolean tranA = false; boolean tranB = false; if( name.contains("TransAB")) { tranA = true; tranB = true; } else if( name.contains("TransA")) { tranA = true; } else if( name.contains("TransB")) { tranB = true; } boolean add = name.contains("Add"); boolean hasAlpha = method.getGenericParameterTypes().length==4; // check length zero rows and columns DenseMatrix64F a = tranA ? new DenseMatrix64F(colsA,rowsA) : new DenseMatrix64F(rowsA,colsA); DenseMatrix64F b = tranB ? new DenseMatrix64F(colsB,rowsB) : new DenseMatrix64F(rowsB,colsB); DenseMatrix64F c = RandomMatrices.createRandom(rowsA,colsB,rand); if( hasAlpha ) { method.invoke(null,2.0,a,b,c); } else { method.invoke(null,a,b,c); } if( add ) { DenseMatrix64F corig = c.copy(); assertTrue(MatrixFeatures.isIdentical(corig, c, 1e-8)); } else { assertTrue(MatrixFeatures.isZeros(c, 1e-8)); } return true; } @Test public void dot() { DenseMatrix64F a = RandomMatrices.createRandom(10,1,rand); DenseMatrix64F b = RandomMatrices.createRandom(1,10,rand); double found = CommonOps.dot(a,b); double expected = 0; for (int i = 0; i < 10; i++) { expected += a.data[i]*b.data[i]; } assertEquals(expected,found,1e-8); } @Test public void multInner() { DenseMatrix64F a = RandomMatrices.createRandom(10,4,rand); DenseMatrix64F found = RandomMatrices.createRandom(4,4,rand); DenseMatrix64F expected = RandomMatrices.createRandom(4,4,rand); CommonOps.multTransA(a, a, expected); CommonOps.multInner(a,found); assertTrue(MatrixFeatures.isIdentical(expected,found,tol)); } @Test public void multOuter() { DenseMatrix64F a = RandomMatrices.createRandom(10,4,rand); DenseMatrix64F found = RandomMatrices.createRandom(10,10,rand); DenseMatrix64F expected = RandomMatrices.createRandom(10,10,rand); CommonOps.multTransB(a, a, expected); CommonOps.multOuter(a, found); assertTrue(MatrixFeatures.isIdentical(expected,found,tol)); } @Test public void elementMult_two() { DenseMatrix64F a = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F b = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F a_orig = a.copy(); CommonOps.elementMult(a,b); for( int i = 0; i < 20; i++ ) { assertEquals(a.get(i),b.get(i)*a_orig.get(i),1e-6); } } @Test public void elementMult_three() { DenseMatrix64F a = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F b = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F c = RandomMatrices.createRandom(5,4,rand); CommonOps.elementMult(a,b,c); for( int i = 0; i < 20; i++ ) { assertEquals(c.get(i),b.get(i)*a.get(i),1e-6); } } @Test public void elementDiv_two() { DenseMatrix64F a = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F b = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F a_orig = a.copy(); CommonOps.elementDiv(a,b); for( int i = 0; i < 20; i++ ) { assertEquals(a.get(i),a_orig.get(i)/b.get(i),1e-6); } } @Test public void elementDiv_three() { DenseMatrix64F a = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F b = RandomMatrices.createRandom(5,4,rand); DenseMatrix64F c = RandomMatrices.createRandom(5,4,rand); CommonOps.elementDiv(a,b,c); for( int i = 0; i < 20; i++ ) { assertEquals(c.get(i),a.get(i)/b.get(i),1e-6); } } @Test public void solve() { DenseMatrix64F a = new DenseMatrix64F(2,2, true, 1, 2, 7, -3); DenseMatrix64F b = RandomMatrices.createRandom(2,5,rand); DenseMatrix64F c = RandomMatrices.createRandom(2,5,rand); DenseMatrix64F c_exp = RandomMatrices.createRandom(2,5,rand); assertTrue(CommonOps.solve(a,b,c)); LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); LinearSolverLu_D64 solver = new LinearSolverLu_D64(alg); assertTrue(solver.setA(a)); solver.solve(b,c_exp); EjmlUnitTests.assertEquals(c_exp,c,1e-8); } @Test public void transpose_inplace() { DenseMatrix64F mat = new DenseMatrix64F(3,3, true, 0, 1, 2, 3, 4, 5, 6, 7, 8); DenseMatrix64F matTran = new DenseMatrix64F(3,3); CommonOps.transpose(mat,matTran); CommonOps.transpose(mat); EjmlUnitTests.assertEquals(mat,matTran,1e-8); } @Test public void transpose() { DenseMatrix64F mat = new DenseMatrix64F(3,2, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F matTran = new DenseMatrix64F(2,3); CommonOps.transpose(mat,matTran); assertEquals(mat.getNumCols(),matTran.getNumRows()); assertEquals(mat.getNumRows(),matTran.getNumCols()); for( int y = 0; y < mat.getNumRows(); y++ ){ for( int x = 0; x < mat.getNumCols(); x++ ) { assertEquals(mat.get(y,x),matTran.get(x,y),1e-6); } } } @Test public void trace() { DenseMatrix64F mat = new DenseMatrix64F(3,3, true, 0, 1, 2, 3, 4, 5, 6, 7, 8); assertEquals(12,CommonOps.trace(mat),1e-6); // non square DenseMatrix64F B = RandomMatrices.createRandom(4,3,rand); CommonOps.insert(mat,B,0,0); assertEquals(12,CommonOps.trace(B),1e-6); B = RandomMatrices.createRandom(3,4,rand); CommonOps.insert(mat,B,0,0); assertEquals(12,CommonOps.trace(B),1e-6); } @Test public void invert() { for( int i = 1; i <= 10; i++ ) { DenseMatrix64F a = RandomMatrices.createRandom(i,i,rand); LUDecompositionAlt_D64 lu = new LUDecompositionAlt_D64(); LinearSolverLu_D64 solver = new LinearSolverLu_D64(lu); assertTrue(solver.setA(a)); DenseMatrix64F a_inv = new DenseMatrix64F(i,i); DenseMatrix64F a_lu = new DenseMatrix64F(i,i); solver.invert(a_lu); CommonOps.invert(a,a_inv); CommonOps.invert(a); EjmlUnitTests.assertEquals(a,a_inv,1e-8); EjmlUnitTests.assertEquals(a_lu,a,1e-8); } } /** * Checked against by computing a solution to the linear system then * seeing if the solution produces the expected output */ @Test public void pinv() { // check wide matrix DenseMatrix64F A = new DenseMatrix64F(2,4,true,1,2,3,4,5,6,7,8); DenseMatrix64F A_inv = new DenseMatrix64F(4,2); DenseMatrix64F b = new DenseMatrix64F(2,1,true,3,4); DenseMatrix64F x = new DenseMatrix64F(4,1); DenseMatrix64F found = new DenseMatrix64F(2,1); CommonOps.pinv(A,A_inv); CommonOps.mult(A_inv,b,x); CommonOps.mult(A,x,found); assertTrue(MatrixFeatures.isIdentical(b,found,1e-4)); // check tall matrix CommonOps.transpose(A); CommonOps.transpose(A_inv); b = new DenseMatrix64F(4,1,true,3,4,5,6); x.reshape(2,1); found.reshape(4,1); CommonOps.mult(A_inv,b,x); CommonOps.mult(A, x, found); assertTrue(MatrixFeatures.isIdentical(b,found,1e-4)); } @Test public void columnsToVectors() { DenseMatrix64F M = RandomMatrices.createRandom(4,5,rand); DenseMatrix64F v[] = CommonOps.columnsToVector(M, null); assertEquals(M.numCols,v.length); for( int i = 0; i < v.length; i++ ) { DenseMatrix64F a = v[i]; assertEquals(M.numRows,a.numRows); assertEquals(1,a.numCols); for( int j = 0; j < M.numRows; j++ ) { assertEquals(a.get(j),M.get(j,i),1e-8); } } } @Test public void identity() { DenseMatrix64F A = CommonOps.identity(4); assertEquals(4,A.numRows); assertEquals(4,A.numCols); assertEquals(4,CommonOps.elementSum(A),1e-8); } @Test public void identity_rect() { DenseMatrix64F A = CommonOps.identity(4,6); assertEquals(4,A.numRows); assertEquals(6,A.numCols); assertEquals(4,CommonOps.elementSum(A),1e-8); } @Test public void setIdentity() { DenseMatrix64F A = RandomMatrices.createRandom(4,4,rand); CommonOps.setIdentity(A); assertEquals(4,A.numRows); assertEquals(4,A.numCols); assertEquals(4,CommonOps.elementSum(A),1e-8); } @Test public void diag() { DenseMatrix64F A = CommonOps.diag(2.0,3.0,6.0,7.0); assertEquals(4,A.numRows); assertEquals(4,A.numCols); assertEquals(2,A.get(0,0),1e-8); assertEquals(3,A.get(1,1),1e-8); assertEquals(6,A.get(2,2),1e-8); assertEquals(7,A.get(3,3),1e-8); assertEquals(18,CommonOps.elementSum(A),1e-8); } @Test public void diag_rect() { DenseMatrix64F A = CommonOps.diagR(4,6,2.0,3.0,6.0,7.0); assertEquals(4,A.numRows); assertEquals(6,A.numCols); assertEquals(2,A.get(0,0),1e-8); assertEquals(3,A.get(1,1),1e-8); assertEquals(6,A.get(2,2),1e-8); assertEquals(7,A.get(3,3),1e-8); assertEquals(18,CommonOps.elementSum(A),1e-8); } @Test public void kron() { DenseMatrix64F A = new DenseMatrix64F(2,2, true, 1, 2, 3, 4); DenseMatrix64F B = new DenseMatrix64F(1,2, true, 4, 5); DenseMatrix64F C = new DenseMatrix64F(2,4); DenseMatrix64F C_expected = new DenseMatrix64F(2,4, true, 4, 5, 8, 10, 12, 15, 16, 20); CommonOps.kron(A,B,C); assertTrue(MatrixFeatures.isIdentical(C,C_expected,1e-8)); // test various shapes for problems for( int i = 1; i <= 3; i++ ) { for( int j = 1; j <= 3; j++ ) { for( int k = 1; k <= 3; k++ ) { for( int l = 1; l <= 3; l++ ) { A = RandomMatrices.createRandom(i,j,rand); B = RandomMatrices.createRandom(k,l,rand); C = new DenseMatrix64F(A.numRows*B.numRows,A.numCols*B.numCols); CommonOps.kron(A,B,C); assertEquals(i*k,C.numRows); assertEquals(j*l,C.numCols); } } } } } @Test public void extract() { DenseMatrix64F A = RandomMatrices.createRandom(5,5, 0, 1, rand); DenseMatrix64F B = new DenseMatrix64F(2,3); CommonOps.extract(A,1,3,2,5,B,0,0); for( int i = 1; i < 3; i++ ) { for( int j = 2; j < 5; j++ ) { assertEquals(A.get(i,j),B.get(i-1,j-2),1e-8); } } } @Test public void extract_ret() { DenseMatrix64F A = RandomMatrices.createRandom(5,5, 0, 1, rand); DenseMatrix64F B = CommonOps.extract(A,1,3,2,5); assertEquals(B.numRows,2); assertEquals(B.numCols,3); for( int i = 1; i < 3; i++ ) { for( int j = 2; j < 5; j++ ) { assertEquals(A.get(i,j),B.get(i-1,j-2),1e-8); } } } @Test public void extractDiag() { DenseMatrix64F a = RandomMatrices.createRandom(3,4, 0, 1, rand); for( int i = 0; i < 3; i++ ) { a.set(i,i,i+1); } DenseMatrix64F v = new DenseMatrix64F(3,1); CommonOps.extractDiag(a,v); for( int i = 0; i < 3; i++ ) { assertEquals( i+1 , v.get(i) , 1e-8 ); } } @Test public void extractRow() { DenseMatrix64F A = RandomMatrices.createRandom(5,6, 0, 1, rand); DenseMatrix64F B = CommonOps.extractRow(A, 3, null); assertEquals(B.numRows,1); assertEquals(B.numCols,6); for( int i = 0; i < 6; i++ ) { assertEquals(A.get(3,i),B.get(0,i),1e-8); } } @Test public void extractColumn() { DenseMatrix64F A = RandomMatrices.createRandom(5,6, 0, 1, rand); DenseMatrix64F B = CommonOps.extractColumn(A, 3, null); assertEquals(B.numRows,5); assertEquals(B.numCols,1); for( int i = 0; i < 5; i++ ) { assertEquals(A.get(i,3),B.get(i,0),1e-8); } } @Test public void insert() { DenseMatrix64F A = new DenseMatrix64F(5,5); for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { A.set(i,j,i*A.numRows+j); } } DenseMatrix64F B = new DenseMatrix64F(8,8); CommonOps.insert(A, B, 1,2); for( int i = 1; i < 6; i++ ) { for( int j = 2; j < 7; j++ ) { assertEquals(A.get(i-1,j-2),B.get(i,j),1e-8); } } } @Test public void addEquals() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 4, 3, 2, 1, 0); CommonOps.addEquals(a,b); UtilTestMatrix.checkMat(a,5,5,5,5,5,5); UtilTestMatrix.checkMat(b,5,4,3,2,1,0); } @Test public void addEquals_beta() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 4, 3, 2, 1, 0); CommonOps.addEquals(a,2.0,b); UtilTestMatrix.checkMat(a,10,9,8,7,6,5); UtilTestMatrix.checkMat(b,5,4,3,2,1,0); } @Test public void add() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 4, 3, 2, 1, 0); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.add(a,b,c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(b,5,4,3,2,1,0); UtilTestMatrix.checkMat(c,5,5,5,5,5,5); } @Test public void add_beta() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 4, 3, 2, 1, 0); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.add(a,2.0,b,c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(b,5,4,3,2,1,0); UtilTestMatrix.checkMat(c,10,9,8,7,6,5); } @Test public void add_alpha_beta() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 4, 3, 2, 1, 0); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.add(2.0,a,2.0,b,c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(b,5,4,3,2,1,0); UtilTestMatrix.checkMat(c,10,10,10,10,10,10); } @Test public void add_alpha() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 4, 3, 2, 1, 0); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.add(2.0,a,b,c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(b,5,4,3,2,1,0); UtilTestMatrix.checkMat(c,5,6,7,8,9,10); } @Test public void add_scalar_c() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.add(a,2.0,c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(c,2,3,4,5,6,7); } @Test public void add_scalar() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); CommonOps.add(a,2.0); UtilTestMatrix.checkMat(a,2,3,4,5,6,7); } @Test public void subEquals() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 5, 5, 5, 5, 5); CommonOps.subtractEquals(a, b); UtilTestMatrix.checkMat(a,-5,-4,-3,-2,-1,0); UtilTestMatrix.checkMat(b,5,5,5,5,5,5); } @Test public void subtract_matrix_matrix() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F b = new DenseMatrix64F(2,3, true, 5, 5, 5, 5, 5, 5); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.subtract(a, b, c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(b,5,5,5,5,5,5); UtilTestMatrix.checkMat(c,-5,-4,-3,-2,-1,0); } @Test public void subtract_matrix_double() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.subtract(a, 2, c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(c,-2,-1,0,1,2,3); } @Test public void subtract_double_matrix() { DenseMatrix64F a = new DenseMatrix64F(2,3, true, 0, 1, 2, 3, 4, 5); DenseMatrix64F c = RandomMatrices.createRandom(2,3,rand); CommonOps.subtract(2, a, c); UtilTestMatrix.checkMat(a,0,1,2,3,4,5); UtilTestMatrix.checkMat(c,2,1,0,-1,-2,-3); } @Test public void scale() { double s = 2.5; double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); CommonOps.scale(s,mat); assertEquals(d[0]*s,mat.get(0,0),1e-8); assertEquals(d[1]*s,mat.get(0,1),1e-8); assertEquals(d[2]*s,mat.get(1,0),1e-8); assertEquals(d[3]*s,mat.get(1,1),1e-8); } @Test public void scale_two_input() { double s = 2.5; double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); DenseMatrix64F r = new DenseMatrix64F(2,2, true, d); CommonOps.scale(s,mat,r); assertEquals(d[0],mat.get(0,0),1e-8); assertEquals(d[1],mat.get(0,1),1e-8); assertEquals(d[2],mat.get(1,0),1e-8); assertEquals(d[3],mat.get(1,1),1e-8); assertEquals(d[0]*s,r.get(0,0),1e-8); assertEquals(d[1]*s,r.get(0,1),1e-8); assertEquals(d[2]*s,r.get(1,0),1e-8); assertEquals(d[3]*s,r.get(1,1),1e-8); } @Test public void div_scalar_mat() { double s = 2.5; double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); CommonOps.divide(s,mat); assertEquals(s/d[0],mat.get(0,0),1e-8); assertEquals(s/d[1],mat.get(0,1),1e-8); assertEquals(s/d[2],mat.get(1,0),1e-8); assertEquals(s/d[3],mat.get(1,1),1e-8); } @Test public void div_mat_scalar() { double s = 2.5; double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); CommonOps.divide(mat,s); assertEquals(mat.get(0,0),d[0]/s,1e-8); assertEquals(mat.get(0,1),d[1]/s,1e-8); assertEquals(mat.get(1,0),d[2]/s,1e-8); assertEquals(mat.get(1,1),d[3]/s,1e-8); } @Test public void div_mat_scalar_out() { double s = 2.5; double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); DenseMatrix64F r = new DenseMatrix64F(2,2, true, d); CommonOps.divide(mat,s,r); assertEquals(d[0],mat.get(0,0),1e-8); assertEquals(d[1],mat.get(0,1),1e-8); assertEquals(d[2],mat.get(1,0),1e-8); assertEquals(d[3],mat.get(1,1),1e-8); assertEquals(d[0]/s,r.get(0,0),1e-8); assertEquals(d[1]/s,r.get(0,1),1e-8); assertEquals(d[2]/s,r.get(1,0),1e-8); assertEquals(d[3]/s,r.get(1,1),1e-8); } @Test public void div_scalar_mat_out() { double s = 2.5; double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); DenseMatrix64F r = new DenseMatrix64F(2,2, true, d); CommonOps.divide(s,mat,r); assertEquals(d[0],mat.get(0,0),1e-8); assertEquals(d[1],mat.get(0,1),1e-8); assertEquals(d[2],mat.get(1,0),1e-8); assertEquals(d[3],mat.get(1,1),1e-8); assertEquals(s/d[0],r.get(0,0),1e-8); assertEquals(s/d[1],r.get(0,1),1e-8); assertEquals(s/d[2],r.get(1,0),1e-8); assertEquals(s/d[3],r.get(1,1),1e-8); } @Test public void changeSign_one() { DenseMatrix64F A = RandomMatrices.createRandom(2,3,rand); DenseMatrix64F A_orig = A.copy(); CommonOps.changeSign(A); for (int i = 0; i < A.getNumElements(); i++) { assertEquals(-A.get(i),A_orig.get(i),1e-8); } } @Test public void changeSign_two() { DenseMatrix64F A = RandomMatrices.createRandom(2,3,rand); DenseMatrix64F B = RandomMatrices.createRandom(2,3,rand); CommonOps.changeSign(A,B); for (int i = 0; i < A.getNumElements(); i++) { assertEquals(A.get(i),-B.get(i),1e-8); } } @Test public void fill_dense() { double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); CommonOps.fill(mat, 1); for( int i = 0; i < mat.getNumElements(); i++ ) { assertEquals(1,mat.get(i),1e-8); } } @Test public void fill_block() { // pick the size such that it doesn't nicely line up along blocks BlockMatrix64F mat = new BlockMatrix64F(10,14,3); CommonOps.fill(mat, 1.5); for( int i = 0; i < mat.getNumElements(); i++ ) { assertEquals(1.5,mat.get(i),1e-8); } } @Test public void zero() { double d[] = new double[]{10,12.5,-2,5.5}; DenseMatrix64F mat = new DenseMatrix64F(2,2, true, d); mat.zero(); for( int i = 0; i < mat.getNumElements(); i++ ) { assertEquals(0,mat.get(i),1e-8); } } @Test public void elementMax() { DenseMatrix64F mat = new DenseMatrix64F(3,3, true, 0, 1, -2, 3, 4, 5, 6, 7, -8); double m = CommonOps.elementMax(mat); assertEquals(7,m,1e-8); } @Test public void elementMin() { DenseMatrix64F mat = new DenseMatrix64F(3,3, true, 0, 1, 2, -3, 4, 5, 6, 7, 8); double m = CommonOps.elementMin(mat); assertEquals(-3,m,1e-8); } @Test public void elementMinAbs() { DenseMatrix64F mat = new DenseMatrix64F(3,3, true, 0, 1, -2, 3, 4, 5, 6, 7, -8); double m = CommonOps.elementMinAbs(mat); assertEquals(0,m,1e-8); } @Test public void elementMaxAbs() { DenseMatrix64F mat = new DenseMatrix64F(3,3, true, 0, 1, 2, 3, 4, 5, -6, 7, -8); double m = CommonOps.elementMaxAbs(mat); assertEquals(8,m,1e-8); } @Test public void elementSum() { DenseMatrix64F M = RandomMatrices.createRandom(5,5,rand); // make it smaller than the original size to make sure it is bounding // the summation correctly M.reshape(4,3, false); double sum = 0; for( int i = 0; i < M.numRows; i++ ) { for( int j = 0; j < M.numCols; j++ ) { sum += M.get(i,j); } } assertEquals(sum,CommonOps.elementSum(M),1e-8); } @Test public void elementSumAbs() { DenseMatrix64F M = RandomMatrices.createRandom(5,5,rand); // make it smaller than the original size to make sure it is bounding // the summation correctly M.reshape(4,3, false); double sum = 0; for( int i = 0; i < M.numRows; i++ ) { for( int j = 0; j < M.numCols; j++ ) { sum += Math.abs(M.get(i,j)); } } assertEquals(sum,CommonOps.elementSum(M),1e-8); } @Test public void elementPower_mm() { DenseMatrix64F A = RandomMatrices.createRandom(4, 5, rand); DenseMatrix64F B = RandomMatrices.createRandom(4, 5, rand); DenseMatrix64F C = RandomMatrices.createRandom(4, 5, rand); CommonOps.elementPower(A, B, C); for (int i = 0; i < A.getNumElements(); i++) { double expected = Math.pow( A.get(i) , B.get(i)); assertEquals(expected,C.get(i),1e-8); } } @Test public void elementPower_ms() { double a = 1.3; DenseMatrix64F B = RandomMatrices.createRandom(4, 5, rand); DenseMatrix64F C = RandomMatrices.createRandom(4, 5, rand); CommonOps.elementPower(a,B,C); for (int i = 0; i < C.getNumElements(); i++) { double expected = Math.pow( a , B.get(i)); assertEquals(expected,C.get(i),1e-8); } } @Test public void elementPower_sm() { DenseMatrix64F A = RandomMatrices.createRandom(4, 5, rand); double b = 1.1; DenseMatrix64F C = RandomMatrices.createRandom(4, 5, rand); CommonOps.elementPower(A,b,C); for (int i = 0; i < A.getNumElements(); i++) { double expected = Math.pow( A.get(i) , b); assertEquals(expected,C.get(i),1e-8); } } @Test public void elementLog() { DenseMatrix64F A = RandomMatrices.createRandom(4, 5, rand); DenseMatrix64F C = RandomMatrices.createRandom(4, 5, rand); CommonOps.elementLog(A, C); for (int i = 0; i < A.getNumElements(); i++) { double expected = Math.log(A.get(i)); assertEquals(expected,C.get(i),1e-8); } } @Test public void elementExp() { DenseMatrix64F A = RandomMatrices.createRandom(4, 5, rand); DenseMatrix64F C = RandomMatrices.createRandom(4, 5, rand); CommonOps.elementExp(A, C); for (int i = 0; i < A.getNumElements(); i++) { double expected = Math.exp(A.get(i)); assertEquals(expected,C.get(i),1e-8); } } @Test public void sumRows() { DenseMatrix64F input = RandomMatrices.createRandom(4,5,rand); DenseMatrix64F output = new DenseMatrix64F(4,1); assertTrue( output == CommonOps.sumRows(input,output)); for( int i = 0; i < input.numRows; i++ ) { double total = 0; for( int j = 0; j < input.numCols; j++ ) { total += input.get(i,j); } assertEquals( total, output.get(i),1e-8); } // check with a null output DenseMatrix64F output2 = CommonOps.sumRows(input,null); EjmlUnitTests.assertEquals(output,output2,1e-8); } @Test public void sumCols() { DenseMatrix64F input = RandomMatrices.createRandom(4,5,rand); DenseMatrix64F output = new DenseMatrix64F(1,5); assertTrue( output == CommonOps.sumCols(input,output)); for( int i = 0; i < input.numCols; i++ ) { double total = 0; for( int j = 0; j < input.numRows; j++ ) { total += input.get(j,i); } assertEquals( total, output.get(i),1e-8); } // check with a null output DenseMatrix64F output2 = CommonOps.sumCols(input,null); EjmlUnitTests.assertEquals(output,output2,1e-8); } @Test public void rref() { DenseMatrix64F A = new DenseMatrix64F(4,6,true, 0,0,1,-1,-1,4, 2,4,2,4,2,4, 2,4,3,3,3,4, 3,6,6,3,6,6); DenseMatrix64F expected = new DenseMatrix64F(4,6,true, 1,2,0,3,0,2, 0,0,1,-1,0,2, 0,0,0,0,1,-2, 0,0,0,0,0,0); DenseMatrix64F found = CommonOps.rref(A,5, null); assertTrue(MatrixFeatures.isEquals(found,expected)); } } ejml-0.28/main/dense64/test/org/ejml/ops/TestCovarianceOps.java000066400000000000000000000027141256171534400243370ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestCovarianceOps { @Test public void isValid() { // nothing is wrong with it DenseMatrix64F m = CommonOps.identity(3); assertEquals(0, CovarianceOps.isValid(m)); // negative diagonal term m.set(1,1,-3); assertEquals(1, CovarianceOps.isValid(m)); // not symetric m = CommonOps.identity(3); m.set(1,0,30); assertEquals(2, CovarianceOps.isValid(m)); // not positive definite m = CommonOps.identity(3); m.set(1,2,-400); m.set(2,1,-400); assertEquals(3, CovarianceOps.isValid(m)); } } ejml-0.28/main/dense64/test/org/ejml/ops/TestCovarianceRandomDraw.java000066400000000000000000000054101256171534400256300ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class TestCovarianceRandomDraw { public static int N = 6000; /** * Do a lot of draws on the distribution and see if a similar distribution is computed * in the end. */ @Test public void testStatistics() { DenseMatrix64F orig_P = new DenseMatrix64F(new double[][]{{6,-2},{-2,10}}); CovarianceRandomDraw dist = new CovarianceRandomDraw(new Random(0xfeed),orig_P); DenseMatrix64F draws[] = new DenseMatrix64F[N]; // sample the distribution for( int i = 0; i < N; i++ ) { DenseMatrix64F x = new DenseMatrix64F(2,1); dist.next(x); draws[i] = x; } // compute the statistics double raw_comp_x[] = new double[2]; // find the mean for( int i = 0; i < N; i++ ) { raw_comp_x[0] += draws[i].get(0,0); raw_comp_x[1] += draws[i].get(1,0); } raw_comp_x[0] /= N; raw_comp_x[1] /= N; assertEquals(0,raw_comp_x[0],0.1); assertEquals(0.0,raw_comp_x[1],0.1); // now the covariance DenseMatrix64F comp_P = new DenseMatrix64F(2,2); DenseMatrix64F temp = new DenseMatrix64F(2,1); for( int i = 0; i < N; i++ ) { temp.set(0,0,draws[i].get(0,0)-raw_comp_x[0]); temp.set(1,0,draws[i].get(1,0)-raw_comp_x[1]); CommonOps.multAddTransB(temp,temp,comp_P); } CommonOps.scale(1.0/N,comp_P); MatrixFeatures.isIdentical(comp_P,orig_P,0.3); } /** * Make sure the input is not modified. */ @Test public void modifyInput() { DenseMatrix64F orig_P = new DenseMatrix64F(new double[][]{{6,-2},{-2,10}}); DenseMatrix64F input = orig_P.copy(); CovarianceRandomDraw dist = new CovarianceRandomDraw(new Random(0xfeed),input); assertTrue(MatrixFeatures.isIdentical(input,orig_P,1e-8)); } }ejml-0.28/main/dense64/test/org/ejml/ops/TestEigenOps.java000066400000000000000000000065101256171534400233120ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestEigenOps { Random rand = new Random(12344); /** * Compute an eigen value and compare against a known solution from octave. */ @Test public void computeEigenValue() { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 0.053610, 0.030405, 0.892620, 0.090954, 0.074065, 0.875797, 0.105369, 0.928981, 0.965506); DenseMatrix64F u = new DenseMatrix64F(3,1, true, -0.4502917, -0.4655377, -0.7619134); double value = EigenOps.computeEigenValue(A,u); assertEquals(1.59540,value,1e-4); } /** * Give it a matrix that describes a Markov process and see if it produces 1 */ @Test public void boundLargestEigenValue_markov() { // create the matrix DenseMatrix64F A = RandomMatrices.createRandom(3,3,rand); for( int i = 0; i < 3; i++ ) { double total = 0; for( int j = 0; j < 3; j++ ) { total += A.get(i,j); } for( int j = 0; j < 3; j++ ) { A.set(i,j,A.get(i,j)/total); } } double[] val = EigenOps.boundLargestEigenValue(A,null); assertEquals(1.0,val[0],1e-8); assertEquals(1.0,val[1],1e-8); } @Test public void createMatrixV() { DenseMatrix64F A = RandomMatrices.createSymmetric(3,-1,1,rand); EigenDecomposition decomp = DecompositionFactory.eig(A.numRows,true); assertTrue(decomp.decompose(A)); DenseMatrix64F V = EigenOps.createMatrixV(decomp); for( int i = 0; i < 3; i++ ) { DenseMatrix64F v = decomp.getEigenVector(i); for( int j = 0; j < 3; j++ ) { assertEquals(V.get(j,i),v.get(j),1e-8); } } } @Test public void createMatrixD() { DenseMatrix64F A = RandomMatrices.createSymmetric(3,-1,1,rand); EigenDecomposition decomp = DecompositionFactory.eig(A.numRows,true); assertTrue(decomp.decompose(A)); DenseMatrix64F D = EigenOps.createMatrixD(decomp); for( int i = 0; i < 3; i++ ) { Complex64F e = decomp.getEigenvalue(i); if( e.isReal() ) { assertEquals(e.real,D.get(i,i),1e-10); } } } } ejml-0.28/main/dense64/test/org/ejml/ops/TestMatrixFeatures.java000066400000000000000000000335701256171534400245520ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import java.util.Random; import static org.ejml.UtilEjml.parseMatrix; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestMatrixFeatures { Random rand = new Random(0xff24); @Test public void hasUncountable() { DenseMatrix64F a = new DenseMatrix64F(4,4); // check a negative case first assertFalse(MatrixFeatures.hasUncountable(a)); // check two positve cases with different types of uncountables a.set(2,2,Double.NaN); assertTrue(MatrixFeatures.hasUncountable(a)); a.set(2,2,Double.POSITIVE_INFINITY); assertTrue(MatrixFeatures.hasUncountable(a)); } @Test public void isZeros() { DenseMatrix64F a = new DenseMatrix64F(4,4); a.set(0,0,1); assertFalse(MatrixFeatures.isZeros(a,0.1)); assertTrue(MatrixFeatures.isZeros(a,2)); } @Test public void isVector() { DenseMatrix64F a = new DenseMatrix64F(4,4); assertFalse(MatrixFeatures.isVector(a)); a.reshape(3,1, false); assertTrue(MatrixFeatures.isVector(a)); a.reshape(1,3, false); assertTrue(MatrixFeatures.isVector(a)); } /** * Check some trial cases. */ @Test public void isPositiveDefinite() { DenseMatrix64F a = UtilEjml.parseMatrix("2 0 0 2",2); DenseMatrix64F b = UtilEjml.parseMatrix("0 1 1 0",2); DenseMatrix64F c = UtilEjml.parseMatrix("0 0 0 0",2); assertTrue(MatrixFeatures.isPositiveDefinite(a)); assertFalse(MatrixFeatures.isPositiveDefinite(b)); assertFalse(MatrixFeatures.isPositiveDefinite(c)); // make sure the input isn't modified assertEquals(2,a.get(0,0),1e-8); assertEquals(2,a.get(1,1),1e-8); } @Test public void isPositiveSemidefinite() { DenseMatrix64F a = UtilEjml.parseMatrix("2 0 0 2",2); DenseMatrix64F b = UtilEjml.parseMatrix("0 1 1 0",2); DenseMatrix64F c = UtilEjml.parseMatrix("0 0 0 0",2); assertTrue(MatrixFeatures.isPositiveSemidefinite(a)); assertFalse(MatrixFeatures.isPositiveSemidefinite(b)); assertTrue(MatrixFeatures.isPositiveSemidefinite(c)); // make sure the input isn't modified assertEquals(2,a.get(0,0),1e-8); assertEquals(2,a.get(1,1),1e-8); } @Test public void isSquare() { DenseMatrix64F a = new DenseMatrix64F(5,4); assertFalse(MatrixFeatures.isSquare(a)); a.reshape(4,4, false); assertTrue(MatrixFeatures.isSquare(a)); } @Test public void isDiagonalPositive() { DenseMatrix64F m = CommonOps.identity(3); assertTrue(MatrixFeatures.isDiagonalPositive(m)); m.set(1,1,-1); assertFalse(MatrixFeatures.isDiagonalPositive(m)); m.set(1,1,Double.NaN); assertFalse(MatrixFeatures.isDiagonalPositive(m)); } @Test public void isSymmetric() { DenseMatrix64F m = CommonOps.identity(3); m.set(1,2,5);m.set(2,1,5); assertTrue(MatrixFeatures.isSymmetric(m)); m.set(1,2,50); assertTrue(!MatrixFeatures.isSymmetric(m)); m.set(1,2,Double.NaN); assertTrue(!MatrixFeatures.isSymmetric(m)); } @Test public void isSkewSymmetric() { DenseMatrix64F m = CommonOps.identity(3); m.set(1,2,5);m.set(2,1,-5); assertTrue(MatrixFeatures.isSkewSymmetric(m,1e-8)); m.set(1,2,-5); assertTrue(!MatrixFeatures.isSkewSymmetric(m,1e-8)); m.set(1,2,Double.NaN); assertTrue(!MatrixFeatures.isSkewSymmetric(m,1e-8)); } @Test public void isEquals() { String a = "-0.779094 1.682750 0.039239\n" + " 1.304014 -1.880739 1.438741\n" + " -0.746918 1.382356 -0.520416"; DenseMatrix64F m = parseMatrix(a,3); DenseMatrix64F n = parseMatrix(a,3); assertTrue(MatrixFeatures.isEquals(m,n)); n.set(2,1,-0.5); assertFalse(MatrixFeatures.isEquals(m,n)); m.set(2,1,Double.NaN); n.set(2,1,Double.NaN); assertFalse(MatrixFeatures.isEquals(m,n)); m.set(2,1,Double.POSITIVE_INFINITY); n.set(2,1,Double.POSITIVE_INFINITY); assertTrue(MatrixFeatures.isEquals(m,n)); } @Test public void isEquals_tol() { String a = "-0.779094 1.682750 0.039239\n" + " 1.304014 -1.880739 1.438741\n" + " -0.746918 1.382356 -0.520416"; DenseMatrix64F m = parseMatrix(a,3); DenseMatrix64F n = parseMatrix(a,3); assertTrue(MatrixFeatures.isEquals(m,n,1e-6)); n.set(2,1,n.get(2,1)+1e-25); assertTrue(MatrixFeatures.isEquals(m,n,1e-6)); n.set(2,1,n.get(2,1)+1e-2); assertFalse(MatrixFeatures.isEquals(m,n,1e-6)); m.set(2,1,Double.NaN); n.set(2,1,Double.NaN); assertFalse(MatrixFeatures.isEquals(m,n,1e-6)); m.set(2,1,Double.POSITIVE_INFINITY); n.set(2,1,Double.POSITIVE_INFINITY); assertFalse(MatrixFeatures.isEquals(m,n,1e-6)); } @Test public void isEqualsTriangle() { // see if it works with different sized matrices for( int m = 2; m < 10; m+=3) { for( int n = 2; n < 10; n += 3 ) { DenseMatrix64F a = RandomMatrices.createRandom(m,n,rand); DenseMatrix64F b = a.copy(); // make the bottom triangle not the same b.set(m-1,0,0); assertTrue("m = "+m+" n = "+n,MatrixFeatures.isEqualsTriangle(a,b, true, 1e-8)); assertFalse(MatrixFeatures.isEqualsTriangle(a,b, false, 1e-8)); // make the upper triangle not the same b = a.copy(); b.set(0,n-1,0); assertFalse(MatrixFeatures.isEqualsTriangle(a,b, true, 1e-8)); assertTrue(MatrixFeatures.isEqualsTriangle(a,b, false, 1e-8)); } } } @Test public void isIdentical() { double values[] = new double[]{1.0,Double.NaN,Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY}; for( int i = 0; i < values.length; i++ ) { for( int j = 0; j < values.length; j++ ) { checkIdentical(values[i],values[j],1e-8,i==j); } } checkIdentical(1.0,1.5,1e-8,false); checkIdentical(1.5,1.0,1e-8,false); checkIdentical(1.0,1.0000000001,1e-8,true); checkIdentical(1.0,Double.NaN,1e-8,false); checkIdentical(Double.NaN,1.0,1e-8,false); } private void checkIdentical( double valA , double valB , double tol , boolean expected ) { DenseMatrix64F A = new DenseMatrix64F(2,2); CommonOps.fill(A, valA); DenseMatrix64F B = new DenseMatrix64F(2,2); CommonOps.fill(B, valB); assertEquals(expected,MatrixFeatures.isIdentical(A,B,tol)); } @Test public void isInverse() { DenseMatrix64F A = RandomMatrices.createRandom(3,3,-1,1,rand); DenseMatrix64F A_inv = A.copy(); CommonOps.invert(A_inv); assertTrue(MatrixFeatures.isInverse(A,A_inv,1e-10)); A_inv.set(1,2,3); assertFalse(MatrixFeatures.isInverse(A,A_inv,1e-10)); A_inv.set(1,2,Double.NaN); assertFalse(MatrixFeatures.isInverse(A,A_inv,1e-10)); } /** * Makes sure it isn't modifying the input */ @Test public void isInverse_nomodify() { DenseMatrix64F A = RandomMatrices.createRandom(3,3,-1,1,rand); DenseMatrix64F B = RandomMatrices.createRandom(3,3,-1,1,rand); DenseMatrix64F A_copy = A.copy(); DenseMatrix64F B_copy = B.copy(); MatrixFeatures.isInverse(A,B,1e-10); assertTrue(MatrixFeatures.isIdentical(A,A_copy,1e-8)); assertTrue(MatrixFeatures.isIdentical(B,B_copy,1e-8)); } @Test public void hasNaN() { DenseMatrix64F m = new DenseMatrix64F(3,3); assertFalse(MatrixFeatures.hasNaN(m)); m.set(1,2,-Double.NaN); assertTrue(MatrixFeatures.hasNaN(m)); } @Test public void isOrthogonal() { // rotation matrices are orthogonal double c = Math.cos(0.1); double s = Math.sin(0.1); DenseMatrix64F A = new DenseMatrix64F(new double[][]{{c,s},{-s,c}}); assertTrue(MatrixFeatures.isOrthogonal(A,1e-6f)); // try a negative case now A.set(0,1,495); assertFalse(MatrixFeatures.isOrthogonal(A,1e-6f)); A.set(0,1,Double.NaN); assertFalse(MatrixFeatures.isOrthogonal(A,1e-6f)); } @Test public void isRowsLinearIndependent() { // test a positive case DenseMatrix64F A = new DenseMatrix64F(2,3, true, 1, 2, 3, 2, 3, 4); assertTrue(MatrixFeatures.isRowsLinearIndependent(A)); // make sure the input wasn't modified DenseMatrix64F A_copy = new DenseMatrix64F(2,3, true, 1, 2, 3, 2, 3, 4); assertTrue(MatrixFeatures.isIdentical(A,A_copy,1e-8)); // test negative case A = new DenseMatrix64F(2,3, true, 1, 2, 3, 1, 2, 3); assertFalse(MatrixFeatures.isRowsLinearIndependent(A)); } @Test public void isConstantVal() { DenseMatrix64F a = new DenseMatrix64F(3,4); CommonOps.fill(a, 2.4); assertTrue(MatrixFeatures.isConstantVal(a,2.4,1e-8)); assertFalse(MatrixFeatures.isConstantVal(a,6,1e-8)); a.set(1,1,Double.NaN); assertFalse(MatrixFeatures.isConstantVal(a,2.4,1e-8)); } @Test public void isIdentity() { DenseMatrix64F I = CommonOps.identity(4); assertTrue(MatrixFeatures.isIdentity(I,1e-8)); I.set(3,2,0.1); assertFalse(MatrixFeatures.isIdentity(I,1e-8)); I.set(3,2,Double.NaN); assertFalse(MatrixFeatures.isIdentity(I,1e-8)); } @Test public void isNegative() { DenseMatrix64F a = RandomMatrices.createRandom(4,5,rand); DenseMatrix64F b = a.copy(); CommonOps.scale(-1,b); // test the positive case first assertTrue(MatrixFeatures.isNegative(a,b,1e-8)); // now the negative case b.set(2,2,10); assertFalse(MatrixFeatures.isNegative(a,b,1e-8)); b.set(2,2,Double.NaN); assertFalse(MatrixFeatures.isNegative(a,b,1e-8)); } @Test public void isUpperTriangle() { // test matrices that are upper triangular to various degree hessenberg for( int hessenberg = 0; hessenberg < 2; hessenberg++ ) { DenseMatrix64F A = new DenseMatrix64F(6,6); for( int i = 0; i < A.numRows; i++ ) { int s = i <= hessenberg ? 0 : i-hessenberg; for( int j = s; j < A.numCols; j++ ) { A.set(i,j,2); } } // test positive for( int i = hessenberg; i < A.numRows; i++ ) { assertTrue(MatrixFeatures.isUpperTriangle(A,i,1e-8)); } // test negative for( int i = 0; i < hessenberg; i++ ) { assertFalse(MatrixFeatures.isUpperTriangle(A,i,1e-8)); } // see if it handles NaN well A.set(4,0,Double.NaN); assertFalse(MatrixFeatures.isUpperTriangle(A,0,1e-8)); } } @Test public void rank() { DenseMatrix64F a = UtilEjml.parseMatrix("2 0 0 2",2); DenseMatrix64F a_copy = a.copy(); assertEquals(2,MatrixFeatures.rank(a)); // make sure the input wasn't modified assertTrue(MatrixFeatures.isIdentical(a,a_copy,1e-8)); a = UtilEjml.parseMatrix("2 0 0 0",2); assertEquals(1,MatrixFeatures.rank(a)); } @Test public void rank_threshold() { DenseMatrix64F a = UtilEjml.parseMatrix("2 0 0 2",2); DenseMatrix64F a_copy = a.copy(); assertEquals(2,MatrixFeatures.rank(a,1e-14)); // make sure the input wasn't modified assertTrue(MatrixFeatures.isIdentical(a,a_copy,1e-8)); a = UtilEjml.parseMatrix("2 0 0 1e-20",2); assertEquals(1,MatrixFeatures.rank(a,1e-14)); // make sure it's using the threshold parameter a = UtilEjml.parseMatrix("2 0 0 1e-20",2); assertEquals(2,MatrixFeatures.rank(a,1e-200)); } @Test public void nullity() { DenseMatrix64F a = UtilEjml.parseMatrix("2 0 0 2",2); DenseMatrix64F a_copy = a.copy(); assertEquals(0,MatrixFeatures.nullity(a)); // make sure the input wasn't modified assertTrue(MatrixFeatures.isIdentical(a,a_copy,1e-8)); a = UtilEjml.parseMatrix("2 0 0 0",2); assertEquals(1,MatrixFeatures.nullity(a)); } @Test public void nullity_threshold() { DenseMatrix64F a = UtilEjml.parseMatrix("2 0 0 2",2); DenseMatrix64F a_copy = a.copy(); assertEquals(0,MatrixFeatures.nullity(a, 1e-14)); // make sure the input wasn't modified assertTrue(MatrixFeatures.isIdentical(a,a_copy,1e-8)); a = UtilEjml.parseMatrix("2 0 0 1e-20",2); assertEquals(1,MatrixFeatures.nullity(a, 1e-14)); // make sure it's using the threshold parameter a = UtilEjml.parseMatrix("2 0 0 1e-20",2); assertEquals(0,MatrixFeatures.nullity(a, 1e-200)); } } ejml-0.28/main/dense64/test/org/ejml/ops/TestNormOps.java000066400000000000000000000152371256171534400232040ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.DenseMatrix64F; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; /** * @author Peter Abeles */ public class TestNormOps { Random rand = new Random(234); DenseMatrix64F zeroMatrix = new DenseMatrix64F(3,4); DenseMatrix64F unzeroMatrix = new DenseMatrix64F(3,2, true, 0.2, 1, -2, 3, 6, 5); DenseMatrix64F unzeroVector = new DenseMatrix64F(5,1, true, 0.3, 1, -2, 3, 4); DenseMatrix64F squareMatrix = new DenseMatrix64F(2,2, true, 0.2, 1, -2, 3); /** * Tests against the condition number from octave. */ @Test public void conditionP() { double val = NormOps.conditionP(squareMatrix,1); assertEquals(7.6923,val,1e-3); // check the non-square case val = NormOps.conditionP(unzeroMatrix,1); assertEquals(3.4325,val,1e-3); // see if the other pseudo-inverse works DenseMatrix64F trans = unzeroMatrix.copy(); CommonOps.transpose(trans); val = NormOps.conditionP(trans,1); assertEquals(3.4887,val,1e-3); } /** * Tests against the condition number from octave. */ @Test public void conditionP2() { double val = NormOps.conditionP2(unzeroMatrix); assertEquals(2.1655,val,1e-3); checkUncountable(NormOps.conditionP2(zeroMatrix)); } /** * Tested using the following operation in octave: * * sum(abs(a(:)).^3.5)^(1/3.5) */ @Test public void elementP() { double val = NormOps.elementP(unzeroMatrix,3.5); assertEquals(6.9108,val,1e-3); checkUncountable(NormOps.elementP(zeroMatrix,3.5)); } @Test public void fastElementP() { double val = NormOps.fastElementP(unzeroMatrix,3.5); assertEquals(6.9108,val,1e-3); checkUncountable(NormOps.fastElementP(zeroMatrix,3.5)); } @Test public void normalizeF() { DenseMatrix64F a = unzeroVector.copy(); NormOps.normalizeF(a); assertEquals(1,NormOps.normF(a),1e-6); } @Test public void fastNormF() { double val = NormOps.fastNormF(unzeroMatrix); assertEquals(8.6626,val,1e-3); checkUncountable(NormOps.fastNormF(zeroMatrix)); } @Test public void normF() { double val = NormOps.normF(unzeroMatrix); assertEquals(8.6626,val,1e-3); checkUncountable(NormOps.normF(zeroMatrix)); } @Test public void fastNormP2() { // check induced matrix norm double found = NormOps.fastNormP2(unzeroMatrix); double expected = NormOps.inducedP2(unzeroMatrix); assertEquals(expected,found,1e-3); // check vector norm found = NormOps.fastNormP2(unzeroVector); expected = NormOps.normF(unzeroVector); assertEquals(expected,found,1e-3); } @Test public void normP() { // check induced matrix norm double found = NormOps.normP(unzeroMatrix,2); double expected = NormOps.inducedP2(unzeroMatrix); assertEquals(expected,found,1e-3); // check vector norm found = NormOps.normP(unzeroVector,2); expected = NormOps.normF(unzeroVector); assertEquals(expected,found,1e-3); } @Test public void fastNormP() { // check induced matrix norm double found = NormOps.fastNormP(unzeroMatrix,2); double expected = NormOps.inducedP2(unzeroMatrix); assertEquals(expected,found,1e-3); // check vector norm found = NormOps.fastNormP(unzeroVector,2); expected = NormOps.normF(unzeroVector); assertEquals(expected,found,1e-3); } @Test public void normP1() { // check induced matrix norm double found = NormOps.normP1(unzeroMatrix); double expected = NormOps.inducedP1(unzeroMatrix); assertEquals(expected,found,1e-3); // check vector norm found = NormOps.normP1(unzeroVector); expected = CommonOps.elementSumAbs(unzeroVector); assertEquals(expected,found,1e-3); } @Test public void normP2() { // check induced matrix norm double found = NormOps.normP2(unzeroMatrix); double expected = NormOps.inducedP2(unzeroMatrix); assertEquals(expected,found,1e-3); // check vector norm found = NormOps.normP2(unzeroVector); expected = NormOps.normF(unzeroVector); assertEquals(expected,found,1e-3); } @Test public void normPInf() { // check induced matrix norm double found = NormOps.normPInf(unzeroMatrix); double expected = NormOps.inducedPInf(unzeroMatrix); assertEquals(expected,found,1e-3); // check vector norm found = NormOps.normPInf(unzeroVector); expected = CommonOps.elementMaxAbs(unzeroVector); assertEquals(expected,found,1e-3); } @Test public void inducedP1() { double val = NormOps.inducedP1(unzeroMatrix); assertEquals(9,val,1e-3); checkUncountable(NormOps.inducedP1(zeroMatrix)); } @Test public void inducedP2() { double val = NormOps.inducedP2(unzeroMatrix); assertEquals(7.8645,val,1e-3); checkUncountable(NormOps.inducedP2(zeroMatrix)); // make sure the largest singular value is being returned not just the first for( int i = 0; i < 20; i++ ) { SimpleMatrix A = SimpleMatrix.random(5,5,-10,10,rand); double largest = A.svd().getW().get(0); assertEquals(largest,NormOps.inducedP2(A.getMatrix()),1e-8); } } @Test public void inducedPInf() { double val = NormOps.inducedPInf(unzeroMatrix); assertEquals(11,val,1e-3); checkUncountable(NormOps.inducedPInf(zeroMatrix)); } private static void checkUncountable( double val ) { assertFalse(Double.isInfinite(val)); assertFalse(Double.isNaN(val)); } } ejml-0.28/main/dense64/test/org/ejml/ops/TestRandomMatrices.java000066400000000000000000000256641256171534400245240ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.UtilTestMatrix; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.junit.Test; import java.util.Arrays; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestRandomMatrices { Random rand = new Random(48757); /** * Checks to see if all the vectors are orthogonal and of unit length. */ @Test public void createSpan() { // test with combinations of vectors and numbers for( int dimension = 3; dimension <= 5; dimension++ ) { for( int numVectors = 1; numVectors <= dimension; numVectors++ ) { DenseMatrix64F span[] = RandomMatrices.createSpan(dimension,numVectors,rand); assertEquals(numVectors,span.length); for( int i = 0; i < span.length; i++ ) { DenseMatrix64F a = span[i]; assertEquals(1,NormOps.fastNormF(a),1e-8); for( int j = i+1; j < span.length; j++ ) { double dot = VectorVectorMult.innerProd(a,span[j]); assertEquals(0,dot,1e-8); } } } } } @Test public void createInSpan() { DenseMatrix64F span[] = RandomMatrices.createSpan(5,5,rand); DenseMatrix64F A = RandomMatrices.createInSpan(span,-1,1,rand); // reconstructed matrix DenseMatrix64F R = new DenseMatrix64F(A.numRows,A.numCols); DenseMatrix64F tmp = new DenseMatrix64F(A.numRows,A.numCols); // project the matrix into the span and recreate the original matrix for( int i = 0; i < 5; i++ ) { double val = VectorVectorMult.innerProd(span[i],A); assertTrue( Math.abs(val) > 1e-10 ); CommonOps.scale(val,span[i],tmp); CommonOps.add(R,tmp,R); } double error = SpecializedOps.diffNormF(A,R); assertEquals( error , 0 , 1e-8 ); } @Test public void createOrthogonal() { for( int numRows = 3; numRows <= 5; numRows++ ) { for( int numCols = 1; numCols <= numRows; numCols++ ) { DenseMatrix64F Q = RandomMatrices.createOrthogonal(numRows,numCols,rand); assertEquals(Q.numRows,numRows); assertEquals(Q.numCols,numCols); assertTrue(CommonOps.elementSum(Q) != 0); assertTrue(MatrixFeatures.isOrthogonal(Q,1e-8)); } } } @Test public void createDiagonal_square() { DenseMatrix64F A = RandomMatrices.createDiagonal(5,1,10,rand); assertTrue(CommonOps.elementSum(A) > 5 ); for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { double v = A.get(i,j); if( i == j ) { assertTrue(v >= 1 || v <= 10); } else { assertTrue(v == 0); } } } } @Test public void createDiagonal_general() { testDiagonal(5,3); testDiagonal(3,5); testDiagonal(3,3); } public void testDiagonal( int numRows , int numCols ) { DenseMatrix64F A = RandomMatrices.createDiagonal(numRows,numCols,1,10,rand); assertEquals(A.getNumRows(),numRows); assertEquals(A.getNumCols(),numCols); assertTrue(CommonOps.elementSum(A) > 5 ); for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { double v = A.get(i,j); if( i == j ) { assertTrue(v >= 1 || v <= 10); } else { assertTrue(v == 0); } } } } @Test public void createSingularValues() { // check case when sv is more than or equal to the matrix dimension double sv[] = new double[]{8.2,6.2,4.1,2}; for( int numRows = 1; numRows <= 4; numRows++ ) { for( int numCols = 1; numCols <= 4; numCols++ ) { DenseMatrix64F A = RandomMatrices.createSingularValues(numRows,numCols, rand, sv); SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows,A.numCols,true,true,false); assertTrue(svd.decompose(A)); int o = Math.min(numRows,numCols); UtilTestMatrix.checkSameElements(1e-8,o,sv,svd.getSingularValues()); } } // see if it fills in zeros when it is smaller than the dimension DenseMatrix64F A = RandomMatrices.createSingularValues(5,5, rand, sv); SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows,A.numCols,true,true,false); assertTrue(svd.decompose(A)); UtilTestMatrix.checkSameElements(1e-8,sv.length,sv,svd.getSingularValues()); assertEquals(0,svd.getSingularValues()[4],1e-8); } @Test public void createEigenvaluesSymm() { DenseMatrix64F A = RandomMatrices.createEigenvaluesSymm(5,rand,1,2,3,4,5); // this should be symmetric assertTrue(MatrixFeatures.isSymmetric(A,1e-10)); // decompose the matrix and extract its eigenvalues EigenDecomposition eig = DecompositionFactory.eig(A.numRows,true); assertTrue(eig.decompose(A)); double ev[] = new double[5]; for( int i = 0; i < 5; i++ ) { Complex64F e = eig.getEigenvalue(i); assertTrue(e.isReal()); ev[i] = e.real; } // need to sort the eigenvalues so that I know where they are in the array Arrays.sort(ev); // see if they are what I expected them to be for( int i = 0; i < ev.length; i++ ) { assertEquals(i+1.0,ev[i],1e-8); } } @Test public void addRandom() { DenseMatrix64F A = new DenseMatrix64F(3,4); CommonOps.fill(A, -2.0); RandomMatrices.addRandom(A,1,2,rand); for( int i = 0; i < A.getNumElements(); i++ ) { assertTrue(A.get(i) >= -1 && A.get(i) <= 0 ); } } @Test public void createRandom() { DenseMatrix64F A = RandomMatrices.createRandom(5,4,rand); checkRandom1(A); } @Test public void createRandom_min_max() { DenseMatrix64F A = RandomMatrices.createRandom(30,20,-1,1,rand); checkRandomRange(A); } @Test public void setRandom() { DenseMatrix64F A = new DenseMatrix64F(5,4); RandomMatrices.setRandom(A,rand); checkRandom1(A); } private void checkRandom1(DenseMatrix64F a) { assertEquals(5, a.numRows); assertEquals(4, a.numCols); double total = 0; for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < a.numCols; j++ ) { double val = a.get(i,j); assertTrue( val >= 0); assertTrue( val <= 1); total += val; } } assertTrue(total>0); } @Test public void setRandom_min_max() { DenseMatrix64F A = new DenseMatrix64F(30,20); RandomMatrices.setRandom(A,-1,1,rand); checkRandomRange(A); } private void checkRandomRange(DenseMatrix64F a) { assertEquals(30, a.numRows); assertEquals(20, a.numCols); int numNeg = 0; int numPos = 0; for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < a.numCols; j++ ) { double val = a.get(i,j); if( val < 0 ) numNeg++; else numPos++; if( Math.abs(val) > 1 ) fail("Out of range"); } } assertTrue(numNeg>0); assertTrue(numPos>0); } @Test public void createGaussian() { DenseMatrix64F A = RandomMatrices.createGaussian(30, 20, 2, 0.5, rand); checkGaussian(A); } @Test public void setGaussian() { DenseMatrix64F A = new DenseMatrix64F(30,20); RandomMatrices.setGaussian(A, 2, 0.5, rand); checkGaussian(A); } private void checkGaussian(DenseMatrix64F a) { assertEquals(30, a.numRows); assertEquals(20, a.numCols); int numNeg = 0; int numPos = 0; double mean = 0; for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < a.numCols; j++ ) { double val = a.get(i,j); if( val-2 < 0 ) numNeg++; else numPos++; mean += val; } } mean /= a.numRows*a.numCols; assertEquals(mean,2,0.01); assertTrue(numNeg>0); assertTrue(numPos>0); } @Test public void createSymmPosDef() { for( int i = 0; i < 10; i++ ) { DenseMatrix64F A = RandomMatrices.createSymmPosDef(6+i,rand); assertTrue(MatrixFeatures.isPositiveDefinite(A)); } } @Test public void createSymmetric() { DenseMatrix64F A = RandomMatrices.createSymmetric(10,-1,1,rand); assertTrue(MatrixFeatures.isSymmetric(A,1e-8)); // see if it has the expected range of elements double min = CommonOps.elementMin(A); double max = CommonOps.elementMax(A); assertTrue(min < 0 && min >= -1); assertTrue(max > 0 && max <= 1); } @Test public void createUpperTriangle() { for( int hess = 0; hess < 3; hess++ ) { DenseMatrix64F A = RandomMatrices.createUpperTriangle(10,hess,-1,1,rand); assertTrue(MatrixFeatures.isUpperTriangle(A,hess,1e-8)); // quick sanity check to make sure it could be proper assertTrue(A.get(hess,0) != 0 ); // see if it has the expected range of elements double min = CommonOps.elementMin(A); double max = CommonOps.elementMax(A); assertTrue(min < 0 && min >= -1); assertTrue(max > 0 && max <= 1); } } } ejml-0.28/main/dense64/test/org/ejml/ops/TestSingularOps.java000066400000000000000000000357571256171534400240660ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestSingularOps { Random rand = new Random(234234); @Test public void descendingOrder() { // test different shapes of input matrices testDescendingOrder(3, 4, false,false); testDescendingOrder(4, 3, false,false); testDescendingOrder(3, 4, true,false); testDescendingOrder(4, 3, true,false); testDescendingInputTransposed(4,5,true,true,false); } @Test public void descendingOrder_array() { // test different shapes of input matrices testDescendingOrder(3, 4, false, true); testDescendingOrder(4, 3, false, true); testDescendingOrder(3, 4, true, true); testDescendingOrder(4, 3, true, true); testDescendingInputTransposed(4,5,true,true,true); } /** * Creates a random SVD that is highly unlikely to be in the correct order. Adjust its order * and see if it produces the same matrix. */ private void testDescendingOrder(int numRows, int numCols, boolean compact, boolean testArray ) { SimpleMatrix U,W,V; int minLength = Math.min(numRows,numCols); double singularValues[] = new double[minLength]; if( compact ) { U = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numRows,minLength,rand)); W = SimpleMatrix.wrap(RandomMatrices.createDiagonal(minLength,minLength,0,1,rand)); V = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numCols,minLength,rand)); } else { U = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numRows,numRows,rand)); W = SimpleMatrix.wrap(RandomMatrices.createDiagonal(numRows,numCols,0,1,rand)); V = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numCols,numCols,rand)); } // Compute A SimpleMatrix A=U.mult(W).mult(V.transpose()); // extract array of singular values for( int i = 0; i < singularValues.length; i++ ) singularValues[i] = W.get(i,i); // put into descending order if( testArray ) { SingularOps.descendingOrder(U.getMatrix(),false,singularValues,minLength,V.getMatrix(),false); // put back into W for( int i = 0; i < singularValues.length; i++ ) W.set(i,i,singularValues[i]); } else { SingularOps.descendingOrder(U.getMatrix(),false,W.getMatrix(),V.getMatrix(),false); } // see if it changed the results SimpleMatrix A_found = U.mult(W).mult(V.transpose()); assertTrue(A.isIdentical(A_found,1e-8)); // make sure singular values are descending if( testArray ) { for( int i = 1; i < minLength; i++ ) { assertTrue(singularValues[i-1] >= singularValues[i]); } } else { for( int i = 1; i < minLength; i++ ) { assertTrue(W.get(i-1,i-1) >= W.get(i,i)); } } } /** * Use the transpose flags and see what happens */ private void testDescendingInputTransposed(int numRows, int numCols, boolean tranU , boolean tranV , boolean testArray ) { SimpleMatrix U,S,V; int minLength = Math.min(numRows,numCols); double singularValues[] = new double[minLength]; U = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numRows,minLength,rand)); S = SimpleMatrix.wrap(RandomMatrices.createDiagonal(minLength,minLength,0,1,rand)); V = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numCols,minLength,rand)); // Compute A SimpleMatrix A=U.mult(S).mult(V.transpose()); // extract array of singular values for( int i = 0; i < singularValues.length; i++ ) singularValues[i] = S.get(i,i); // put into ascending order if( tranU ) U = U.transpose(); if( tranV ) V = V.transpose(); // put into descending order if( testArray ) { SingularOps.descendingOrder(U.getMatrix(),tranU,singularValues,minLength,V.getMatrix(),tranV); // put back into S for( int i = 0; i < singularValues.length; i++ ) S.set(i,i,singularValues[i]); } else { SingularOps.descendingOrder(U.getMatrix(),tranU,S.getMatrix(),V.getMatrix(),tranV); } // see if it changed the results if( tranU ) U = U.transpose(); if( tranV ) V = V.transpose(); SimpleMatrix A_found = U.mult(S).mult(V.transpose()); assertTrue(A.isIdentical(A_found,1e-8)); // make sure singular values are descending if( testArray ) { for( int i = 1; i < minLength; i++ ) { assertTrue(singularValues[i-1] >= singularValues[i]); } } else { for( int i = 1; i < minLength; i++ ) { assertTrue(S.get(i-1,i-1) >= S.get(i,i)); } } } /** * See if it blows up with uncountable numbers */ @Test public void descendingOrder_NaN() { int numRows = 5; int numCols = 7; int minLength = Math.min(numRows,numCols); SimpleMatrix U,S,V; U = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numRows,minLength,rand)); S = SimpleMatrix.wrap(RandomMatrices.createDiagonal(minLength,minLength,0,1,rand)); V = SimpleMatrix.wrap(RandomMatrices.createOrthogonal(numCols,minLength,rand)); // put in a NaN S.set(2,2,Double.NaN); SingularOps.descendingOrder(U.getMatrix(),false,S.getMatrix(),V.getMatrix(),false); assertTrue( Double.isNaN(S.get(minLength-1,minLength-1))); // put in an Inf S.set(2,2,Double.POSITIVE_INFINITY); SingularOps.descendingOrder(U.getMatrix(),false,S.getMatrix(),V.getMatrix(),false); assertTrue( Double.isInfinite(S.get(0,0))); } /** * Gives it correct input matrices and makes sure no exceptions are thrown. All permutations * are tested. */ @Test public void checkSvdMatrixSize_positive() { checkSvdMatrixSize_positive(4,5); checkSvdMatrixSize_positive(5,4); } /** * Checks a few of the many possible bad inputs */ @Test public void checkSvdMatrixSize_negative() { checkSvdMatrixSize_negative(4,5); checkSvdMatrixSize_negative(5,4); } private void checkSvdMatrixSize_positive( int numRows , int numCols ) { int s = Math.min(numRows,numCols); // create a none compact SVD DenseMatrix64F U = new DenseMatrix64F(numRows,numRows); DenseMatrix64F W = new DenseMatrix64F(numRows,numCols); DenseMatrix64F V = new DenseMatrix64F(numCols,numCols); SingularOps.checkSvdMatrixSize(U,false,W,V,false); CommonOps.transpose(U);CommonOps.transpose(V); SingularOps.checkSvdMatrixSize(U,true,W,V,true); // compact SVD U = new DenseMatrix64F(numRows,s); W = new DenseMatrix64F(s,s); V = new DenseMatrix64F(numCols,s); SingularOps.checkSvdMatrixSize(U,false,W,V,false); CommonOps.transpose(U);CommonOps.transpose(V); SingularOps.checkSvdMatrixSize(U,true,W,V,true); // see what happens if you throw in some null matrices SingularOps.checkSvdMatrixSize(null,false,W,null,false); SingularOps.checkSvdMatrixSize(null,true,W,V,true); SingularOps.checkSvdMatrixSize(U,true,W,null,true); } private void checkSvdMatrixSize_negative( int numRows , int numCols ) { int s = Math.min(numRows,numCols); // create a none compact SVD DenseMatrix64F U = new DenseMatrix64F(numRows,s); DenseMatrix64F W = new DenseMatrix64F(numRows,numCols); DenseMatrix64F V = new DenseMatrix64F(numCols,s); try { SingularOps.checkSvdMatrixSize(U,false,W,V,false); fail("An exception should have been thrown"); } catch( RuntimeException e) {} // compact SVD U = new DenseMatrix64F(numRows,s); W = new DenseMatrix64F(s,s); V = new DenseMatrix64F(numCols,s); try { SingularOps.checkSvdMatrixSize(U,true,W,V,true); fail("An exception should have been thrown"); } catch( RuntimeException e) {} CommonOps.transpose(U);CommonOps.transpose(V); try { SingularOps.checkSvdMatrixSize(U,false,W,V,false); fail("An exception should have been thrown"); } catch( RuntimeException e) {} } @Test public void nullVector() { for( int numRows = 2; numRows < 10; numRows++ ) { for( int numCols = 2; numCols < 10; numCols++ ) { // construct a matrix with a null space by decomposition a random matrix // and setting one of its singular values to zero SimpleMatrix A = SimpleMatrix.wrap(RandomMatrices.createRandom(numRows,numCols,rand)); SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows(), A.numCols(),true,true,false); assertTrue(svd.decompose(A.getMatrix())); SimpleMatrix U = SimpleMatrix.wrap(svd.getU(null,false)); SimpleMatrix S = SimpleMatrix.wrap(svd.getW(null)); SimpleMatrix Vt = SimpleMatrix.wrap(svd.getV(null,true)); // pick an element inconveniently in the middle to be the null space S.set(1,1,0); svd.getSingularValues()[1] = 0; A=U.mult(S).mult(Vt); // Find the right null space SimpleMatrix v = SimpleMatrix.wrap(SingularOps.nullVector(svd, true , null)); // see if the returned vector really is the null space SimpleMatrix ns = A.mult(v); for( int i = 0; i < ns.numRows(); i++ ) { assertEquals(0,ns.get(i),1e-8); } // Find the left null space v = SimpleMatrix.wrap(SingularOps.nullVector(svd, false , null)); // see if the returned vector really is the null space ns = v.transpose().mult(A); for( int i = 0; i < ns.numRows(); i++ ) { assertEquals(0,ns.get(i),1e-8); } } } } @Test public void nullSpace() { for( int numRows = 2; numRows < 5; numRows++ ) { for( int numCols = 2; numCols < 5; numCols++ ) { // construct a matrix with a null space by decomposition a random matrix // and setting one of its singular values to zero SimpleMatrix A = SimpleMatrix.wrap(RandomMatrices.createRandom(numRows,numCols,rand)); SingularValueDecomposition svd = DecompositionFactory.svd(A.numRows(), A.numCols(),true,true,false); assertTrue(svd.decompose(A.getMatrix())); SimpleMatrix U = SimpleMatrix.wrap(svd.getU(null,false)); SimpleMatrix S = SimpleMatrix.wrap(svd.getW(null)); SimpleMatrix Vt = SimpleMatrix.wrap(svd.getV(null,true)); // pick an element inconveniently in the middle to be the null space S.set(1,1,0); svd.getSingularValues()[1] = 0; A=U.mult(S).mult(Vt); // now find the null space SimpleMatrix ns = SimpleMatrix.wrap(SingularOps.nullSpace(svd,null,1e-15)); // make sure the null space is not all zero assertTrue( Math.abs(CommonOps.elementMaxAbs(ns.getMatrix())) > 0 ); // check the null space's size assertEquals(ns.numRows(),A.numCols()); assertEquals(ns.numCols(),1+Math.max(numCols-numRows,0)); // see if the results are null SimpleMatrix found = A.mult(ns); assertTrue( Math.abs(CommonOps.elementMaxAbs(found.getMatrix())) <= 1e-15 ); } } } /** * Decompose a singular matrix and see if it produces the expected result */ @Test public void rank_and_nullity(){ DenseMatrix64F A = new DenseMatrix64F(3,3, true, -0.988228951897092, -1.086594333683141, -1.433160736952583, -3.190200029661606, 0.190459703263404, -6.475629910954768, 1.400596416735888, 7.158603907761226, -0.778109120408813); rank_and_nullity(A,2,1); //wide matrix A = new DenseMatrix64F(1,3,true,1,0,0); rank_and_nullity(A,1,2); // tall matrix A = new DenseMatrix64F(3,1,true,1,0,0); rank_and_nullity(A,1,0); } public void rank_and_nullity( DenseMatrix64F A , int rank , int nullity ) { SingularValueDecomposition alg = DecompositionFactory.svd(A.numRows,A.numCols,true,true,false); assertTrue(alg.decompose(A)); assertEquals(rank,SingularOps.rank(alg, UtilEjml.EPS)); assertEquals(nullity,SingularOps.nullity(alg, UtilEjml.EPS)); } /** * Decompose a singular matrix and see if it produces the expected result */ @Test public void rank_and_nullity_noArgument(){ DenseMatrix64F A = new DenseMatrix64F(3,3, true, -0.988228951897092, -1.086594333683141, -1.433160736952583, -3.190200029661606, 0.190459703263404, -6.475629910954768, 1.400596416735888, 7.158603907761226, -0.778109120408813); rank_and_nullity_noArgument(A, 2, 1); //wide matrix A = new DenseMatrix64F(1,3,true,1,0,0); rank_and_nullity_noArgument(A,1,2); // tall matrix A = new DenseMatrix64F(3,1,true,1,0,0); rank_and_nullity_noArgument(A,1,0); } public void rank_and_nullity_noArgument( DenseMatrix64F A , int rank , int nullity ) { SingularValueDecomposition alg = DecompositionFactory.svd(A.numRows,A.numCols,true,true,false); assertTrue(alg.decompose(A)); assertEquals(rank,SingularOps.rank(alg)); assertEquals(nullity,SingularOps.nullity(alg)); } } ejml-0.28/main/dense64/test/org/ejml/ops/TestSpecializedOps.java000066400000000000000000000202211256171534400245120ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestSpecializedOps { Random rand = new Random(7476547); @Test public void createReflector() { DenseMatrix64F u = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F Q = SpecializedOps.createReflector(u); assertTrue(MatrixFeatures.isOrthogonal(Q,1e-8)); DenseMatrix64F w = new DenseMatrix64F(4,1); CommonOps.mult(Q,u,w); assertTrue(MatrixFeatures.isNegative(u,w,1e-8)); } @Test public void createReflector_gamma() { DenseMatrix64F u = RandomMatrices.createRandom(4,1,rand); double gamma = 1.5; DenseMatrix64F Q = SpecializedOps.createReflector(u,gamma); DenseMatrix64F w = RandomMatrices.createRandom(4,1,rand); DenseMatrix64F v_found = new DenseMatrix64F(4,1); CommonOps.mult(Q,w,v_found); DenseMatrix64F v_exp = new DenseMatrix64F(4,1); VectorVectorMult.householder(-gamma,u,w,v_exp); assertTrue(MatrixFeatures.isIdentical(v_found,v_exp,1e-8)); } @Test public void copyChangeRow() { DenseMatrix64F A = RandomMatrices.createRandom(3,2,rand); DenseMatrix64F B = A.copy(); int []order = new int[]{2,0,1}; DenseMatrix64F C = SpecializedOps.copyChangeRow(order,A,null); // make sure it didn't modify A assertTrue(MatrixFeatures.isIdentical(A,B,0)); // see if the row change was correctly performed for( int i = 0; i < order.length; i++ ) { int o = order[i]; for( int j = 0; j < A.numCols; j++ ) { assertEquals(A.get(o,j),C.get(i,j),1e-16); } } } @Test public void copyTriangle() { for( int m = 2; m <= 6; m += 2 ) { for( int n = 2; n <= 6; n += 2 ) { DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); DenseMatrix64F B = SpecializedOps.copyTriangle(A,null,true); assertTrue(MatrixFeatures.isEqualsTriangle(A,B, true, 1e-8)); assertFalse(MatrixFeatures.isEquals(A,B,1e-8)); CommonOps.fill(B, 0); SpecializedOps.copyTriangle(A,B,false); assertTrue(MatrixFeatures.isEqualsTriangle(A,B, false, 1e-8)); assertFalse(MatrixFeatures.isEquals(A,B,1e-8)); } } } @Test public void diffNormF() { DenseMatrix64F a = RandomMatrices.createRandom(3,2,rand); DenseMatrix64F b = RandomMatrices.createRandom(3,2,rand); DenseMatrix64F c = RandomMatrices.createRandom(3,2,rand); CommonOps.subtract(a, b, c); double expectedNorm = NormOps.fastNormF(c); double foundNorm = SpecializedOps.diffNormF(a,b); assertEquals(expectedNorm,foundNorm,1e-8); } @Test public void diffNormP1() { DenseMatrix64F a = RandomMatrices.createRandom(3,2,rand); DenseMatrix64F b = RandomMatrices.createRandom(3,2,rand); DenseMatrix64F c = RandomMatrices.createRandom(3,2,rand); CommonOps.subtract(a, b, c); double expectedNorm = 0; for( int i = 0; i < c.getNumElements(); i++ ) { expectedNorm += Math.abs(c.get(i)); } double foundNorm = SpecializedOps.diffNormP1(a,b); assertEquals(expectedNorm,foundNorm,1e-8); } @Test public void addIdentity() { DenseMatrix64F M = RandomMatrices.createRandom(4,4,rand); DenseMatrix64F A = M.copy(); SpecializedOps.addIdentity(A,A,2.0); CommonOps.subtractEquals(A, M); double total = CommonOps.elementSum(A); assertEquals(4*2,total,1e-8); } @Test public void subvector() { DenseMatrix64F A = RandomMatrices.createRandom(4,5,rand); DenseMatrix64F v = new DenseMatrix64F(7,1); // first extract a row vector SpecializedOps.subvector(A,2,1,2,true,1,v); assertEquals(0,v.get(0),1e-8); for( int i = 0; i < 2; i++ ) { assertEquals(A.get(2,1+i),v.get(1+i),1e-8); } // now extract a column vector SpecializedOps.subvector(A,2,1,2,false,1,v); for( int i = 0; i < 2; i++ ) { assertEquals(A.get(2+i,1),v.get(1+i),1e-8); } } @Test public void splitIntoVectors() { DenseMatrix64F A = RandomMatrices.createRandom(3,5,rand); // column vectors DenseMatrix64F v[] = SpecializedOps.splitIntoVectors(A,true); assertEquals(5,v.length); for( int i = 0; i < v.length; i++ ) { DenseMatrix64F a = v[i]; assertEquals(3,a.getNumRows()); assertEquals(1,a.getNumCols()); for( int j = 0; j < A.numRows; j++ ) { assertEquals(A.get(j,i),a.get(j),1e-8); } } // row vectors v = SpecializedOps.splitIntoVectors(A,false); assertEquals(3,v.length); for( int i = 0; i < v.length; i++ ) { DenseMatrix64F a = v[i]; assertEquals(1,a.getNumRows()); assertEquals(5,a.getNumCols()); for( int j = 0; j < A.numCols; j++ ) { assertEquals(A.get(i,j),a.get(j),1e-8); } } } @Test public void pivotMatrix() { int pivots[] = new int[]{1,0,3,2}; DenseMatrix64F A = RandomMatrices.createRandom(4,4,rand); DenseMatrix64F P = SpecializedOps.pivotMatrix(null,pivots,4,false); DenseMatrix64F Pt = SpecializedOps.pivotMatrix(null,pivots,4,true); DenseMatrix64F B = new DenseMatrix64F(4,4); // see if it swapped the rows CommonOps.mult(P,A,B); for( int i = 0; i < 4; i++ ) { int index = pivots[i]; for( int j = 0; j < 4; j++ ) { double val = A.get(index,j); assertEquals(val,B.get(i,j),1e-8); } } // see if it transposed CommonOps.transpose(P,B); assertTrue(MatrixFeatures.isIdentical(B,Pt,1e-8)); } @Test public void diagProd() { DenseMatrix64F A = new DenseMatrix64F(3,3); A.set(0,0,1); A.set(1,1,2); A.set(2,2,3); double found = SpecializedOps.diagProd(A); assertEquals(6,found,1e-8); } @Test public void elementDiagonalMaxAbs() { DenseMatrix64F A = RandomMatrices.createRandom(4,5,rand); double expected = 0; for (int i = 0; i < 4; i++) { double a = A.get(i,i); if( Math.abs(a) > expected ) expected = Math.abs(a); } double found = SpecializedOps.elementDiagonalMaxAbs(A); assertEquals(expected,found,1e-8); } @Test public void qualityTriangular() { DenseMatrix64F A = RandomMatrices.createRandom(4,4,rand); double max = SpecializedOps.elementDiagonalMaxAbs(A); double expected = 1.0; for (int i = 0; i < 4; i++) { expected *= A.get(i,i)/max; } double found = SpecializedOps.qualityTriangular(A); assertEquals(expected,found,1e-8); } @Test public void elementSumSq() { DenseMatrix64F A = new DenseMatrix64F(2,3,true,1,2,3,4,5,6); double expected = 1+4+9+16+25+36; double found = SpecializedOps.elementSumSq(A); assertEquals(expected,found,1e-8); } } ejml-0.28/main/denseC64/000077500000000000000000000000001256171534400147015ustar00rootroot00000000000000ejml-0.28/main/denseC64/build.gradle000066400000000000000000000002301256171534400171530ustar00rootroot00000000000000dependencies { compile project(':main:core') testCompile project(':main:dense64') } idea { module { name = "EJML Dense C64" } }ejml-0.28/main/denseC64/generate/000077500000000000000000000000001256171534400164735ustar00rootroot00000000000000ejml-0.28/main/denseC64/generate/org/000077500000000000000000000000001256171534400172625ustar00rootroot00000000000000ejml-0.28/main/denseC64/generate/org/ejml/000077500000000000000000000000001256171534400202115ustar00rootroot00000000000000ejml-0.28/main/denseC64/generate/org/ejml/alg/000077500000000000000000000000001256171534400207545ustar00rootroot00000000000000ejml-0.28/main/denseC64/generate/org/ejml/alg/dense/000077500000000000000000000000001256171534400220525ustar00rootroot00000000000000ejml-0.28/main/denseC64/generate/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400230335ustar00rootroot00000000000000ejml-0.28/main/denseC64/generate/org/ejml/alg/dense/mult/GenerateCMatrixMatrixMult.java000066400000000000000000000253051256171534400307540ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.alg.generic.CodeGeneratorMisc; import java.io.FileNotFoundException; import java.io.PrintStream; /** * @author Peter Abeles */ public class GenerateCMatrixMatrixMult { PrintStream stream; public GenerateCMatrixMatrixMult(String fileName) throws FileNotFoundException { stream = new PrintStream(fileName); } public void createClass() { String preamble = CodeGeneratorMisc.COPYRIGHT + "package org.ejml.alg.dense.mult;\n" + "\n" + "import org.ejml.data.CDenseMatrix64F;\n" + "import org.ejml.ops.CCommonOps;\n" + "\n" + "/**\n" + " *

Matrix multiplication routines for complex dense matrices in a row-major format.

\n" + " *\n" + " *

\n" + " * DO NOT MODIFY! Auto generated by {@link org.ejml.alg.dense.mult.GenerateCMatrixMatrixMult}.\n" + " *

\n" + " *\n" + " * @author Peter Abeles\n" + " */\n" + "public class CMatrixMatrixMult {\n"; stream.print(preamble); for( int i = 0; i < 2; i++ ) { boolean alpha = i == 1; for( int j = 0; j < 2; j++ ) { boolean add = j == 1; printMult_reroder(alpha,add); stream.print("\n"); printMult_small(alpha,add); stream.print("\n"); } } stream.print("}\n"); } public void printMult_reroder( boolean alpha , boolean add ) { String header,valLine; header = makeHeader("mult","reorder",add,alpha, false, false,false); String tempVars = ""; if( alpha ) { tempVars = " double realTmp,imgTmp;"; valLine = " realTmp = a.data[indexA++];\n" + " imgTmp = a.data[indexA++];\n" + " realA = realAlpha*realTmp - imgAlpha*imgTmp;\n" + " imgA = realAlpha*imgTmp + imgAlpha*realTmp;\n"; } else { valLine = " realA = a.data[indexA++];\n" + " imgA = a.data[indexA++];\n"; } String assignment = add ? "+=" : "="; String foo = header + makeBoundsCheck(false,false, null)+handleZeros(add) + " double realA,imgA;\n" + tempVars + "\n" + " int indexCbase= 0;\n" + " int strideA = a.getRowStride();\n" + " int strideB = b.getRowStride();\n" + " int strideC = c.getRowStride();\n" + " int endOfKLoop = b.numRows*strideB;\n" + "\n" + " for( int i = 0; i < a.numRows; i++ ) {\n" + " int indexA = i*strideA;\n" + "\n" + " // need to assign c.data to a value initially\n" + " int indexB = 0;\n" + " int indexC = indexCbase;\n" + " int end = indexB + strideB;\n" + "\n" + valLine + "\n" + " while( indexB < end ) {\n" + " double realB = b.data[indexB++];\n" + " double imgB = b.data[indexB++];\n" + "\n" + " c.data[indexC++] "+assignment+" realA*realB - imgA*imgB;\n" + " c.data[indexC++] "+assignment+" realA*imgB + imgA*realB;\n" + " }\n" + "\n" + " // now add to it\n" + " while( indexB != endOfKLoop ) { // k loop\n" + " indexC = indexCbase;\n" + " end = indexB + strideB;\n" + "\n" + valLine + "\n" + " while( indexB < end ) { // j loop\n" + " double realB = b.data[indexB++];\n" + " double imgB = b.data[indexB++];\n" + "\n" + " c.data[indexC++] += realA*realB - imgA*imgB;\n" + " c.data[indexC++] += realA*imgB + imgA*realB;\n" + " }\n" + " }\n" + " indexCbase += strideC;\n" + " }\n" + " }\n\n"; stream.print(foo); } public void printMult_small( boolean alpha , boolean add ) { String header,valLine; header = makeHeader("mult","small",add,alpha, false, false,false); String assignment = add ? "+=" : "="; if( alpha ) { valLine = " c.data[cIndex++] "+assignment+" realAlpha*realTotal - imgAlpha*imgTotal;\n" + " c.data[cIndex++] "+assignment+" realAlpha*imgTotal + imgAlpha*realTotal;\n"; } else { valLine = " c.data[cIndex++] "+assignment+" realTotal;\n" + " c.data[cIndex++] "+assignment+" imgTotal;\n"; } String foo = header + makeBoundsCheck(false,false, null)+ " int aIndexStart = 0;\n" + " int cIndex = 0;\n" + "\n" + " int strideA = a.getRowStride();\n" + " int strideB = b.getRowStride();\n" + "\n" + " for( int i = 0; i < a.numRows; i++ ) {\n" + " for( int j = 0; j < b.numCols; j++ ) {\n" + " double realTotal = 0;\n" + " double imgTotal = 0;\n" + "\n" + " int indexA = aIndexStart;\n" + " int indexB = j*2;\n" + " int end = indexA + strideA;\n" + " while( indexA < end ) {\n" + " double realA = a.data[indexA++];\n" + " double imgA = a.data[indexA++];\n" + "\n" + " double realB = b.data[indexB];\n" + " double imgB = b.data[indexB+1];\n" + "\n" + " realTotal += realA*realB - imgA*imgB;\n" + " imgTotal += realA*imgB + imgA*realB;\n" + "\n" + " indexB += strideB;\n" + " }\n" + "\n" + valLine + " }\n" + " aIndexStart += strideA;\n" + " }\n" + " }\n\n"; stream.print(foo); } private String makeBoundsCheck(boolean tranA, boolean tranB, String auxLength) { String a_numCols = tranA ? "a.numRows" : "a.numCols"; String a_numRows = tranA ? "a.numCols" : "a.numRows"; String b_numCols = tranB ? "b.numRows" : "b.numCols"; String b_numRows = tranB ? "b.numCols" : "b.numRows"; String ret = " if( a == c || b == c )\n" + " throw new IllegalArgumentException(\"Neither 'a' or 'b' can be the same matrix as 'c'\");\n"+ " else if( "+a_numCols+" != "+b_numRows+" ) {\n" + " throw new MatrixDimensionException(\"The 'a' and 'b' matrices do not have compatible dimensions\");\n" + " } else if( "+a_numRows+" != c.numRows || "+b_numCols+" != c.numCols ) {\n" + " throw new MatrixDimensionException(\"The results matrix does not have the desired dimensions\");\n" + " }\n" + "\n"; if( auxLength != null ) { ret += " if( aux == null ) aux = new double[ "+auxLength+" ];\n\n"; } return ret; } private String handleZeros( boolean add ) { String fill = add ? "" : " CCommonOps.fill(c,0,0);\n"; String ret = " if( a.numCols == 0 || a.numRows == 0 ) {\n" + fill + " return;\n" + " }\n"; return ret; } private String makeHeader(String nameOp, String variant, boolean add, boolean hasAlpha, boolean hasAux, boolean tranA, boolean tranB) { if( add ) nameOp += "Add"; // make the op name if( tranA && tranB ) { nameOp += "TransAB"; } else if( tranA ) { nameOp += "TransA"; } else if( tranB ) { nameOp += "TransB"; } String ret = " public static void "+nameOp; if( variant != null ) ret += "_"+variant+"( "; else ret += "( "; if( hasAlpha ) ret += "double realAlpha , double imgAlpha , "; if( hasAux ) { ret += "CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c , double []aux )\n"; } else { ret += "CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c )\n"; } ret += " {\n"; return ret; } public static void main(String[] args) throws FileNotFoundException { GenerateCMatrixMatrixMult gen = new GenerateCMatrixMatrixMult("CMatrixMatrixMult.java"); gen.createClass(); } } ejml-0.28/main/denseC64/src/000077500000000000000000000000001256171534400154705ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/000077500000000000000000000000001256171534400162575ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/000077500000000000000000000000001256171534400172065ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/000077500000000000000000000000001256171534400177515ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/000077500000000000000000000000001256171534400210475ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/000077500000000000000000000000001256171534400230255ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/CTriangularSolver.java000066400000000000000000000133071256171534400273020ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose; /** *

* This contains algorithms for solving systems of equations where T is a * non-singular triangular complex matrix:
*
* T*x = b
*
* where x and b are vectors, and T is an n by n matrix. T can either be a lower or upper triangular matrix.
*

*

* These functions are designed for use inside of other algorithms. To use them directly * is dangerous since no sanity checks are performed. *

* * @author Peter Abeles */ public class CTriangularSolver { /** *

* This is a forward substitution solver for non-singular upper triangular matrices. *
* b = U-1b
*
* where b is a vector, U is an n by n matrix.
*

* * @param U An n by n non-singular upper triangular matrix. Not modified. * @param b A vector of length n. Modified. * @param n The size of the matrices. */ public static void solveU( double U[] , double []b , int n ) { // for( int i =n-1; i>=0; i-- ) { // double sum = b[i]; // for( int j = i+1; j =0; i-- ) { double sumReal = b[i*2]; double sumImg = b[i*2+1]; int indexU = i*stride+i*2+2; for( int j = i+1; j * Solves for non-singular lower triangular matrices with real valued diagonal elements * using forward substitution. *
* b = L-1b
*
* where b is a vector, L is an n by n matrix.
*

* * @param L An n by n non-singular lower triangular matrix. Not modified. * @param b A vector of length n. Modified. * @param n The size of the matrices. */ public static void solveL_diagReal(double L[], double[] b, int n) { // for( int i = 0; i < n; i++ ) { // double sum = b[i]; // for( int k=0; k * This is a forward substitution solver for non-singular lower triangular matrices with * real valued diagonal elements. *
* b = (LCT)-1b
*
* where b is a vector, L is an n by n matrix.
*

*

* L is a lower triangular matrix, but it comes up with a solution as if it was * an upper triangular matrix that was computed by conjugate transposing L. *

* * @param L An n by n non-singular lower triangular matrix. Not modified. * @param b A vector of length n. Modified. * @param n The size of the matrices. */ public static void solveConjTranL_diagReal(double L[], double[] b, int n) { // for( int i =n-1; i>=0; i-- ) { // double sum = b[i]; // for( int k = i+1; k =0; i-- ) { double realSum = b[i*2]; double imagSum = b[i*2+1]; int indexB = (i+1)*2; for( int k = i+1; k * This is an abstract class for a Cholesky decomposition. It provides the solvers, but the actual * decomposition is provided in other classes. *

* * @see org.ejml.interfaces.decomposition.CholeskyDecomposition * @author Peter Abeles */ public abstract class CholeskyDecompositionCommon_CD64 implements CholeskyDecomposition { // width and height of the matrix protected int n; // the decomposed matrix protected CDenseMatrix64F T; protected double[] t; // is it a lower triangular matrix or an upper triangular matrix protected boolean lower; // storage for the determinant protected Complex64F det = new Complex64F(); /** * Specifies if a lower or upper variant should be constructed. * * @param lower should a lower or upper triangular matrix be used. */ public CholeskyDecompositionCommon_CD64(boolean lower) { this.lower = lower; } /** * {@inheritDoc} */ @Override public boolean isLower() { return lower; } /** * {@inheritDoc} */ @Override public boolean decompose( CDenseMatrix64F mat ) { if( mat.numRows != mat.numCols ) { throw new IllegalArgumentException("Must be a square matrix."); } n = mat.numRows; T = mat; t = T.data; if(lower) { return decomposeLower(); } else { return decomposeUpper(); } } @Override public boolean inputModified() { return true; } /** * Performs an lower triangular decomposition. * * @return true if the matrix was decomposed. */ protected abstract boolean decomposeLower(); /** * Performs an upper triangular decomposition. * * @return true if the matrix was decomposed. */ protected abstract boolean decomposeUpper(); @Override public CDenseMatrix64F getT( CDenseMatrix64F T ) { // see if it needs to declare a new matrix or not if( T == null ) { T = new CDenseMatrix64F(n,n); } else { if( T.numRows != n || T.numCols != n ) throw new IllegalArgumentException("Unexpected matrix dimension for T."); CCommonOps.fill(T, 0,0); } // write the values to T if( lower ) { for( int i = 0; i < n; i++ ) { int index = i*n*2; for( int j = 0; j <= i; j++ ) { T.data[index] = this.T.data[index]; index++; T.data[index] = this.T.data[index]; index++; } } } else { for( int i = 0; i < n; i++ ) { int index = (i*n + i)*2; for( int j = i; j < n; j++ ) { T.data[index] = this.T.data[index]; index++; T.data[index] = this.T.data[index]; index++; } } } return T; } /** * Returns the raw decomposed matrix. * * @return A lower or upper triangular matrix. */ public CDenseMatrix64F _getT() { return T; } @Override public Complex64F computeDeterminant() { double prod = 1; // take advantage of the diagonal elements all being real int total = n*n*2; for( int i = 0; i < total; i += 2*(n + 1) ) { prod *= t[i]; } det.real = prod*prod; det.imaginary = 0; return det; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/chol/CholeskyDecompositionInner_CD64.java000066400000000000000000000134521256171534400326540ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.chol; import org.ejml.UtilEjml; /** *

* This implementation of a Cholesky decomposition using the inner-product form. *

* * @author Peter Abeles */ public class CholeskyDecompositionInner_CD64 extends CholeskyDecompositionCommon_CD64 { // tolerance for testing to see if diagonal elements are real double tolerance = UtilEjml.EPS; public CholeskyDecompositionInner_CD64() { super(true); } public CholeskyDecompositionInner_CD64(boolean lower) { super(lower); } public void setTolerance(double tolerance) { this.tolerance = tolerance; } @Override protected boolean decomposeLower() { if( n == 0 ) throw new IllegalArgumentException("Cholesky is undefined for 0 by 0 matrix"); double real_el_ii=0; int stride = n*2; for( int i = 0; i < n; i++ ) { for( int j = i; j < n; j++ ) { double realSum = t[i*stride+j*2 ]; double imagSum = t[i*stride+j*2+1]; if( i == j ) { // its easy to prove that for the cholesky decomposition to be valid the original // diagonal elements must be real if( Math.abs(imagSum) > tolerance*Math.abs(realSum) ) return false; // This takes advantage of the fact that when you multiply a complex number by // its conjigate the result is a real number int end = i*stride+i*2; for( int index = i*stride; index < end; ) { double real = t[index++]; double imag = t[index++]; realSum -= real*real + imag*imag; } if( realSum <= 0 ) { return false; } real_el_ii = Math.sqrt(realSum); t[i*stride+i*2] = real_el_ii; t[i*stride+i*2+1] = 0; } else { int iEl = i*stride; // row i is inside the lower triangle int jEl = j*stride; // row j conjugate transposed upper triangle int end = iEl+i*2; // k = 0:i-1 for( ; iEl tolerance*Math.abs(realSum) ) return false; for (int k = 0; k < i; k++) { double real = t[k*stride+i*2 ]; double imag = t[k*stride+i*2+1]; realSum -= real*real + imag*imag; } if( realSum <= 0 ) { return false; } real_el_ii = Math.sqrt(realSum); t[i*stride+i*2] = real_el_ii; t[i*stride+i*2+1] = 0; } else { for( int k = 0; k < i; k++ ) { double realI = t[k*stride+i*2 ]; double imagI = t[k*stride+i*2+1]; double realJ = t[k*stride+j*2 ]; double imagJ = t[k*stride+j*2+1]; realSum -= realI*realJ + imagI*imagJ; imagSum -= realI*imagJ - realJ*imagI; } t[i*stride+j*2] = realSum/real_el_ii; t[i*stride+j*2+1] = imagSum/real_el_ii; } } } return true; } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/lu/000077500000000000000000000000001256171534400234455ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/lu/LUDecompositionAlt_CD64.java000066400000000000000000000111161256171534400305460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.lu; import org.ejml.data.CDenseMatrix64F; /** *

* An LU decomposition algorithm that originally came from Jama. In general this is faster than * what is in NR since it creates a cache of a column, which makes a big difference in larger * matrices. *

* * @author Peter Abeles */ public class LUDecompositionAlt_CD64 extends LUDecompositionBase_CD64 { /** * This is a modified version of what was found in the JAMA package. The order that it * performs its permutations in is the primary difference from NR * * @param a The matrix that is to be decomposed. Not modified. * @return true If the matrix can be decomposed and false if it can not. */ public boolean decompose( CDenseMatrix64F a ) { decomposeCommonInit(a); double LUcolj[] = vv; for( int j = 0; j < n; j++ ) { // make a copy of the column to avoid cache jumping issues for( int i = 0; i < m; i++) { LUcolj[i*2] = dataLU[i*stride + j*2]; LUcolj[i*2+1] = dataLU[i*stride + j*2+1]; } // Apply previous transformations. for( int i = 0; i < m; i++ ) { int rowIndex = i*stride; // Most of the time is spent in the following dot product. int kmax = i < j ? i : j; double realS = 0.0; double imgS = 0.0; for (int k = 0; k < kmax; k++) { double realD = dataLU[rowIndex+k*2]; double imgD = dataLU[rowIndex+k*2+1]; double realCol = LUcolj[k*2]; double imgCol = LUcolj[k*2+1]; realS += realD*realCol - imgD*imgCol; imgS += realD*imgCol + imgD*realCol; } dataLU[rowIndex+j*2] = LUcolj[i*2] -= realS; dataLU[rowIndex+j*2+1] = LUcolj[i*2+1] -= imgS; } // Find pivot and exchange if necessary. int p = j; double max = mag(LUcolj, p * 2); for (int i = j+1; i < m; i++) { double v = mag(LUcolj, i * 2); if ( v > max) { p = i; max = v; } } if (p != j) { // swap the rows // for (int k = 0; k < n; k++) { // double t = dataLU[p*n + k]; // dataLU[p*n + k] = dataLU[j*n + k]; // dataLU[j*n + k] = t; // } int rowP = p*stride; int rowJ = j*stride; int endP = rowP+stride; for (;rowP < endP; rowP++,rowJ++) { double t = dataLU[rowP]; dataLU[rowP] = dataLU[rowJ]; dataLU[rowJ] = t; } int k = pivot[p]; pivot[p] = pivot[j]; pivot[j] = k; pivsign = -pivsign; } indx[j] = p; // Compute multipliers. if (j < m ) { double realLujj = dataLU[j*stride+j*2]; double imgLujj = dataLU[j*stride+j*2+1]; double magLujj = realLujj*realLujj + imgLujj*imgLujj; if( realLujj != 0 || imgLujj != 0) { for (int i = j+1; i < m; i++) { double realLU = dataLU[i*stride+j*2]; double imagLU = dataLU[i*stride+j*2+1]; dataLU[i*stride+j*2] = (realLU*realLujj + imagLU*imgLujj)/magLujj; dataLU[i*stride+j*2+1] = (imagLU*realLujj - realLU*imgLujj)/magLujj; } } } } return true; } private static double mag( double d[] , int index ) { double r = d[index]; double i = d[index+1]; return r*r + i*i; } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/lu/LUDecompositionBase_CD64.java000066400000000000000000000205231256171534400307020ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.lu; import org.ejml.UtilEjml; import org.ejml.alg.dense.decompose.CTriangularSolver; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CSpecializedOps; /** *

* Contains common data structures and operations for LU decomposition algorithms. *

* @author Peter Abeles */ public abstract class LUDecompositionBase_CD64 implements LUDecomposition { // the decomposed matrix protected CDenseMatrix64F LU; // it can decompose a matrix up to this size protected int maxWidth=-1; // the shape of the matrix protected int m,n,stride; // data in the matrix protected double dataLU[]; // used in set, solve, invert protected double vv[]; // used in set protected int indx[]; protected int pivot[]; // used by determinant protected double pivsign; protected Complex64F det = new Complex64F(); public void setExpectedMaxSize( int numRows , int numCols ) { LU = new CDenseMatrix64F(numRows,numCols); this.dataLU = LU.data; maxWidth = Math.max(numRows,numCols); vv = new double[ maxWidth*2 ]; indx = new int[ maxWidth ]; pivot = new int[ maxWidth ]; } public CDenseMatrix64F getLU() { return LU; } public int[] getIndx() { return indx; } public int[] getPivot() { return pivot; } @Override public boolean inputModified() { return false; } /** * Writes the lower triangular matrix into the specified matrix. * * @param lower Where the lower triangular matrix is written to. */ @Override public CDenseMatrix64F getLower( CDenseMatrix64F lower ) { int numRows = LU.numRows; int numCols = LU.numRows < LU.numCols ? LU.numRows : LU.numCols; if( lower == null ) { lower = new CDenseMatrix64F(numRows,numCols); } else { if( lower.numCols != numCols || lower.numRows != numRows ) throw new IllegalArgumentException("Unexpected matrix dimension"); CCommonOps.fill(lower,0, 0); } for( int i = 0; i < numCols; i++ ) { lower.set(i,i,1.0,0.0); for( int j = 0; j < i; j++ ) { int indexLU = LU.getIndex(i,j); int indexL = lower.getIndex(i,j); double real = LU.data[indexLU]; double imaginary = LU.data[indexLU+1]; lower.data[indexL] = real; lower.data[indexL+1] = imaginary; } } if( numRows > numCols ) { for( int i = numCols; i < numRows; i++ ) { for( int j = 0; j < numCols; j++ ) { int indexLU = LU.getIndex(i,j); int indexL = lower.getIndex(i,j); double real = LU.data[indexLU]; double imaginary = LU.data[indexLU+1]; lower.data[indexL] = real; lower.data[indexL+1] = imaginary; } } } return lower; } /** * Writes the upper triangular matrix into the specified matrix. * * @param upper Where the upper triangular matrix is writen to. */ @Override public CDenseMatrix64F getUpper( CDenseMatrix64F upper ) { int numRows = LU.numRows < LU.numCols ? LU.numRows : LU.numCols; int numCols = LU.numCols; if( upper == null ) { upper = new CDenseMatrix64F(numRows, numCols); } else { if( upper.numCols != numCols || upper.numRows != numRows ) throw new IllegalArgumentException("Unexpected matrix dimension"); CCommonOps.fill(upper, 0,0); } for( int i = 0; i < numRows; i++ ) { for( int j = i; j < numCols; j++ ) { int indexLU = LU.getIndex(i,j); int indexU = upper.getIndex(i,j); double real = LU.data[indexLU]; double imaginary = LU.data[indexLU+1]; upper.data[indexU] = real; upper.data[indexU+1] = imaginary; } } return upper; } public CDenseMatrix64F getPivot( CDenseMatrix64F pivot ) { return CSpecializedOps.pivotMatrix(pivot, this.pivot, LU.numRows, false); } protected void decomposeCommonInit(CDenseMatrix64F a) { if( a.numRows > maxWidth || a.numCols > maxWidth ) { setExpectedMaxSize(a.numRows,a.numCols); } m = a.numRows; n = a.numCols; stride = n*2; LU.set(a); for (int i = 0; i < m; i++) { pivot[i] = i; } pivsign = 1; } /** * Determines if the decomposed matrix is singular. This function can return * false and the matrix be almost singular, which is still bad. * * @return true if singular false otherwise. */ @Override public boolean isSingular() { for( int i = 0; i < m; i++ ) { double real = dataLU[i*stride+i*2]; double imaginary = dataLU[i*stride+i*2+1]; double mag2 = real*real + imaginary*imaginary; if( mag2 < UtilEjml.EPS*UtilEjml.EPS ) return true; } return false; } /** * Computes the determinant from the LU decomposition. * * @return The matrix's determinant. */ @Override public Complex64F computeDeterminant() { if( m != n ) throw new IllegalArgumentException("Must be a square matrix."); double realRet = pivsign; double realImg = 0; int total = m*stride; for( int i = 0; i < total; i += stride + 2 ) { double real = dataLU[i]; double imaginary = dataLU[i+1]; double r = realRet*real - realImg*imaginary; double t = realRet*imaginary + realImg*real; realRet = r; realImg = t; } det.set(realRet,realImg); return det; } public double quality() { return CSpecializedOps.qualityTriangular(LU); } /** * a specialized version of solve that avoid additional checks that are not needed. */ public void _solveVectorInternal( double []vv ) { // Solve L*Y = B solveL(vv); // Solve U*X = Y; CTriangularSolver.solveU(dataLU, vv, n); } /** * Solve the using the lower triangular matrix in LU. Diagonal elements are assumed * to be 1 */ protected void solveL(double[] vv) { int ii = 0; for( int i = 0; i < n; i++ ) { int ip = indx[i]; double sumReal = vv[ip*2]; double sumImg = vv[ip*2+1]; vv[ip*2] = vv[i*2]; vv[ip*2+1] = vv[i*2+1]; if( ii != 0 ) { // for( int j = ii-1; j < i; j++ ) // sum -= dataLU[i* n +j]*vv[j]; int index = i*stride + (ii-1)*2; for( int j = ii-1; j < i; j++ ){ double luReal = dataLU[index++]; double luImg = dataLU[index++]; double vvReal = vv[j*2]; double vvImg = vv[j*2+1]; sumReal -= luReal*vvReal - luImg*vvImg; sumImg -= luReal*vvImg + luImg*vvReal; } } else if( sumReal*sumReal + sumImg*sumImg != 0.0 ) { ii=i+1; } vv[i*2] = sumReal; vv[i*2+1] = sumImg; } } public double[] _getVV() { return vv; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/qr/000077500000000000000000000000001256171534400234475ustar00rootroot00000000000000QRDecompositionHouseholderColumn_CD64.java000066400000000000000000000242341256171534400334170ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; /** *

* Householder QR decomposition is rich in operations along the columns of the matrix. This can be * taken advantage of by solving for the Q matrix in a column major format to reduce the number * of CPU cache misses and the number of copies that are performed. *

* * @see org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholder_D64 * * @author Peter Abeles */ public class QRDecompositionHouseholderColumn_CD64 implements QRDecomposition { /** * Where the Q and R matrices are stored. R is stored in the * upper triangular portion and Q on the lower bit. Lower columns * are where u is stored. Q_k = (I - gamma_k*u_k*u_k^T). */ protected double dataQR[][]; // [ column][ row ] // used internally to store temporary data protected double v[]; // dimension of the decomposed matrices protected int numCols; // this is 'n' protected int numRows; // this is 'm' protected int minLength; // the computed gamma for Q_k matrix protected double gammas[]; // local variables protected double gamma; protected Complex64F tau = new Complex64F(); // did it encounter an error? protected boolean error; public void setExpectedMaxSize( int numRows , int numCols ) { this.numCols = numCols; this.numRows = numRows; minLength = Math.min(numCols,numRows); int maxLength = Math.max(numCols,numRows); if( dataQR == null || dataQR.length < numCols || dataQR[0].length < numRows*2 ) { dataQR = new double[ numCols ][ numRows*2 ]; v = new double[ maxLength*2 ]; gammas = new double[ minLength ]; } if( v.length < maxLength*2 ) { v = new double[ maxLength*2 ]; } if( gammas.length < minLength ) { gammas = new double[ minLength ]; } } /** * Returns the combined QR matrix in a 2D array format that is column major. * * @return The QR matrix in a 2D matrix column major format. [ column ][ row ] */ public double[][] getQR() { return dataQR; } /** * Computes the Q matrix from the imformation stored in the QR matrix. This * operation requires about 4(m2n-mn2+n3/3) flops. * * @param Q The orthogonal Q matrix. */ @Override public CDenseMatrix64F getQ( CDenseMatrix64F Q , boolean compact ) { if( compact ) { if( Q == null ) { Q = CCommonOps.identity(numRows, minLength); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CCommonOps.setIdentity(Q); } } } else { if( Q == null ) { Q = CCommonOps.identity(numRows); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CCommonOps.setIdentity(Q); } } } for( int j = minLength-1; j >= 0; j-- ) { double u[] = dataQR[j]; double vvReal = u[j*2]; double vvImag = u[j*2+1]; u[j*2] = 1; u[j*2+1] = 0; double gammaReal = gammas[j]; QrHelperFunctions_CD64.rank1UpdateMultR(Q, u,0, gammaReal,j, j, numRows, v); u[j*2] = vvReal; u[j*2+1] = vvImag; } return Q; } /** * Returns an upper triangular matrix which is the R in the QR decomposition. If compact then the input * expected to be size = [min(rows,cols) , numCols] otherwise size = [numRows,numCols]. * * @param R Storage for upper triangular matrix. * @param compact If true then a compact matrix is expected. */ @Override public CDenseMatrix64F getR(CDenseMatrix64F R, boolean compact) { if( R == null ) { if( compact ) { R = new CDenseMatrix64F(minLength,numCols); } else R = new CDenseMatrix64F(numRows,numCols); } else { if( compact ) { if( R.numCols != numCols || R.numRows != minLength ) throw new IllegalArgumentException( "Unexpected dimensions: found( "+R.numRows+" "+R.numCols+" ) expected( "+minLength+" "+numCols+" )"); } else { if( R.numCols != numCols || R.numRows != numRows ) throw new IllegalArgumentException("Unexpected dimensions"); } for( int i = 0; i < R.numRows; i++ ) { int min = Math.min(i,R.numCols); for( int j = 0; j < min; j++ ) { R.set(i,j,0,0); } } } for( int j = 0; j < numCols; j++ ) { double colR[] = dataQR[j]; int l = Math.min(j,numRows-1); for( int i = 0; i <= l; i++ ) { R.set(i,j,colR[i*2],colR[i*2+1]); } } return R; } /** *

* To decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m2-2m2/3 flops. *

* *

* The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. *

*/ @Override public boolean decompose( CDenseMatrix64F A ) { setExpectedMaxSize(A.numRows, A.numCols); convertToColumnMajor(A); error = false; for( int j = 0; j < minLength; j++ ) { householder(j); updateA(j); } return !error; } @Override public boolean inputModified() { return false; } /** * Converts the standard row-major matrix into a column-major vector * that is advantageous for this problem. * * @param A original matrix that is to be decomposed. */ protected void convertToColumnMajor(CDenseMatrix64F A) { for( int x = 0; x < numCols; x++ ) { double colQ[] = dataQR[x]; int indexCol = 0; for( int y = 0; y < numRows; y++ ) { int index = (y*numCols+x)*2; colQ[indexCol++] = A.data[index]; colQ[indexCol++] = A.data[index+1]; } } } /** *

* Computes the householder vector "u" for the first column of submatrix j. Note this is * a specialized householder for this problem. There is some protection against * overfloaw and underflow. *

*

* Q = I - γuuT *

*

* This function finds the values of 'u' and 'γ'. *

* * @param j Which submatrix to work off of. */ protected void householder( int j ) { final double u[] = dataQR[j]; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow final double max = QrHelperFunctions_CD64.findMax(u, j, numRows - j); if( max == 0.0 ) { gamma = 0; error = true; } else { // computes tau and gamma, and normalizes u by max gamma = QrHelperFunctions_CD64.computeTauGammaAndDivide(j, numRows, u, max, tau); // divide u by u_0 // double u_0 = u[j] + tau; double real_u_0 = u[j*2] + tau.real; double imag_u_0 = u[j*2+1] + tau.imaginary; QrHelperFunctions_CD64.divideElements(j + 1, numRows, u, 0, real_u_0,imag_u_0 ); tau.real *= max; tau.imaginary *= max; u[j*2] = -tau.real; u[j*2+1] = -tau.imaginary; } gammas[j] = gamma; } /** *

* Takes the results from the householder computation and updates the 'A' matrix.
*
* A = (I - γ*u*uH)A *

* * @param w The submatrix. */ protected void updateA( int w ) { final double u[] = dataQR[w]; for( int j = w+1; j < numCols; j++ ) { final double colQ[] = dataQR[j]; // first element in u is assumed to be 1.0 + 0*i double realSum = colQ[w*2]; double imagSum = colQ[w*2+1]; for( int k = w+1; k < numRows; k++ ) { double realU = u[k*2]; double imagU = -u[k*2+1]; double realQ = colQ[k*2]; double imagQ = colQ[k*2+1]; realSum += realU*realQ - imagU*imagQ; imagSum += imagU*realQ + realU*imagQ; } realSum *= gamma; imagSum *= gamma; colQ[w*2 ] -= realSum; colQ[w*2+1] -= imagSum; for( int i = w+1; i < numRows; i++ ) { double realU = u[i*2]; double imagU = u[i*2+1]; colQ[i*2] -= realU*realSum - imagU*imagSum; colQ[i*2+1]-= imagU*realSum + realU*imagSum; } } } public double[] getGammas() { return gammas; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/qr/QRDecompositionHouseholderTran_CD64.java000066400000000000000000000271111256171534400331420ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; /** *

* Householder QR decomposition is rich in operations along the columns of the matrix. This can be * taken advantage of by solving for the Q matrix in a column major format to reduce the number * of CPU cache misses and the number of copies that are performed. *

* * @see org.ejml.alg.dense.decomposition.qr.QRDecompositionHouseholder_D64 * * @author Peter Abeles */ // TODO figure out why this is significantly slower than col public class QRDecompositionHouseholderTran_CD64 implements QRDecomposition { /** * Where the Q and R matrices are stored. For speed reasons * this is transposed */ protected CDenseMatrix64F QR; // used internally to store temporary data protected double v[]; // dimension of the decomposed matrices protected int numCols; // this is 'n' protected int numRows; // this is 'm' protected int minLength; // the computed gamma for Q_k matrix protected double gammas[]; // local variables protected double gamma; protected Complex64F tau = new Complex64F(); // did it encounter an error? protected boolean error; public void setExpectedMaxSize( int numRows , int numCols ) { this.numCols = numCols; this.numRows = numRows; minLength = Math.min(numCols,numRows); int maxLength = Math.max(numCols,numRows); if( QR == null ) { QR = new CDenseMatrix64F(numCols,numRows); v = new double[ maxLength*2 ]; gammas = new double[ minLength ]; } else { QR.reshape(numCols,numRows); } if( v.length < maxLength*2 ) { v = new double[ maxLength*2 ]; } if( gammas.length < minLength ) { gammas = new double[ minLength ]; } } /** * Inner matrix that stores the decomposition */ public CDenseMatrix64F getQR() { return QR; } /** * Computes the Q matrix from the information stored in the QR matrix. This * operation requires about 4(mn-mn2+n3/3) flops. * * @param Q The orthogonal Q matrix. */ @Override public CDenseMatrix64F getQ( CDenseMatrix64F Q , boolean compact ) { if( compact ) { if( Q == null ) { Q = CCommonOps.identity(numRows, minLength); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CCommonOps.setIdentity(Q); } } } else { if( Q == null ) { Q = CCommonOps.identity(numRows); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CCommonOps.setIdentity(Q); } } } // Unlike applyQ() this takes advantage of zeros in the identity matrix // by not multiplying across all rows. for( int j = minLength-1; j >= 0; j-- ) { int diagIndex = (j*numRows+j)*2; double realBefore = QR.data[diagIndex]; double imagBefore = QR.data[diagIndex+1]; QR.data[diagIndex] = 1; QR.data[diagIndex+1] = 0; QrHelperFunctions_CD64.rank1UpdateMultR(Q, QR.data, j * numRows, gammas[j], j, j, numRows, v); QR.data[diagIndex] = realBefore; QR.data[diagIndex+1] = imagBefore; } return Q; } /** * A = Q*A * * @param A Matrix that is being multiplied by Q. Is modified. */ public void applyQ( CDenseMatrix64F A ) { if( A.numRows != numRows ) throw new IllegalArgumentException("A must have at least "+numRows+" rows."); for( int j = minLength-1; j >= 0; j-- ) { int diagIndex = (j*numRows+j)*2; double realBefore = QR.data[diagIndex]; double imagBefore = QR.data[diagIndex+1]; QR.data[diagIndex] = 1; QR.data[diagIndex+1] = 0; QrHelperFunctions_CD64.rank1UpdateMultR(A, QR.data, j * numRows, gammas[j], 0, j, numRows, v); QR.data[diagIndex] = realBefore; QR.data[diagIndex+1] = imagBefore; } } /** * A = QH*A * * @param A Matrix that is being multiplied by QT. Is modified. */ public void applyTranQ( CDenseMatrix64F A ) { for( int j = 0; j < minLength; j++ ) { int diagIndex = (j*numRows+j)*2; double realBefore = QR.data[diagIndex]; double imagBefore = QR.data[diagIndex+1]; QR.data[diagIndex] = 1; QR.data[diagIndex+1] = 0; QrHelperFunctions_CD64.rank1UpdateMultR(A, QR.data, j * numRows, gammas[j], 0, j, numRows, v); QR.data[diagIndex] = realBefore; QR.data[diagIndex+1] = imagBefore; } } /** * Returns an upper triangular matrix which is the R in the QR decomposition. * * @param R An upper triangular matrix. * @param compact */ @Override public CDenseMatrix64F getR(CDenseMatrix64F R, boolean compact) { if( R == null ) { if( compact ) { R = new CDenseMatrix64F(minLength,numCols); } else R = new CDenseMatrix64F(numRows,numCols); } else { if( compact ) { if( R.numCols != numCols || R.numRows != minLength ) throw new IllegalArgumentException("Unexpected dimensions"); } else { if( R.numCols != numCols || R.numRows != numRows ) throw new IllegalArgumentException("Unexpected dimensions"); } for( int i = 0; i < R.numRows; i++ ) { int min = Math.min(i,R.numCols); for( int j = 0; j < min; j++ ) { R.set(i, j, 0, 0); } } } for( int i = 0; i < R.numRows; i++ ) { for( int j = i; j < R.numCols; j++ ) { int index = QR.getIndex(j,i); R.set(i,j,QR.data[index],QR.data[index+1]); } } return R; } /** *

* To decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m2-2m2/3 flops. *

* *

* The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. *

*/ @Override public boolean decompose( CDenseMatrix64F A ) { setExpectedMaxSize(A.numRows, A.numCols); CCommonOps.transpose(A, QR); error = false; for( int j = 0; j < minLength; j++ ) { householder(j); updateA(j); } return !error; } @Override public boolean inputModified() { return false; } /** *

* Computes the householder vector "u" for the first column of submatrix j. Note this is * a specialized householder for this problem. There is some protection against * overflow and underflow. *

*

* Q = I - γuuH *

*

* This function finds the values of 'u' and 'γ'. *

* * @param j Which submatrix to work off of. */ protected void householder( final int j ) { int startQR = j*numRows; int endQR = startQR+numRows; startQR += j; final double max = QrHelperFunctions_CD64.findMax(QR.data, startQR, numRows - j); if( max == 0.0 ) { gamma = 0; error = true; } else { // computes tau and normalizes u by max gamma = QrHelperFunctions_CD64.computeTauGammaAndDivide(startQR, endQR, QR.data, max,tau); // divide u by u_0 double realU0 = QR.data[startQR*2] + tau.real; double imagU0 = QR.data[startQR*2+1] + tau.imaginary; QrHelperFunctions_CD64.divideElements(startQR + 1, endQR, QR.data,0,realU0, imagU0); tau.real *= max; tau.imaginary *= max; QR.data[startQR*2] = -tau.real; QR.data[startQR*2+1] = -tau.imaginary; } gammas[j] = gamma; } /** *

* Takes the results from the householder computation and updates the 'A' matrix.
*
* A = (I - γ*u*uH)A *

* * @param w The submatrix. */ protected void updateA( final int w ) { // int rowW = w*numRows; // int rowJ = rowW + numRows; // // for( int j = w+1; j < numCols; j++ , rowJ += numRows) { // double val = QR.data[rowJ + w]; // // // val = gamma*u^T * A // for( int k = w+1; k < numRows; k++ ) { // val += QR.data[rowW + k]*QR.data[rowJ + k]; // } // val *= gamma; // // // A - val*u // QR.data[rowJ + w] -= val; // for( int i = w+1; i < numRows; i++ ) { // QR.data[rowJ + i] -= QR.data[rowW + i]*val; // } // } final double data[] = QR.data; int rowW = w*numRows + w + 1; int rowJ = rowW + numRows; final int rowJEnd = 2*(rowJ + (numCols-w-1)*numRows); final int indexWEnd = 2*(rowW + numRows - w - 1); rowJ = 2*rowJ; rowW = 2*rowW; for( ; rowJEnd != rowJ; rowJ += numRows*2) { // assume the first element in u is 1 double realVal = data[rowJ - 2]; double imagVal = data[rowJ - 1]; int indexW = rowW; int indexJ = rowJ; while( indexW != indexWEnd ) { double realW = data[indexW++]; double imagW = -data[indexW++]; double realJ = data[indexJ++]; double imagJ = data[indexJ++]; realVal += realW*realJ - imagW*imagJ; imagVal += realW*imagJ + imagW*realJ; } realVal *= gamma; imagVal *= gamma; data[rowJ - 2] -= realVal; data[rowJ - 1] -= imagVal; indexW = rowW; indexJ = rowJ; while( indexW != indexWEnd ) { double realW = data[indexW++]; double imagW = data[indexW++]; data[indexJ++] -= realW*realVal - imagW*imagVal; data[indexJ++] -= realW*imagVal + imagW*realVal; } } } public double[] getGammas() { return gammas; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/qr/QRDecompositionHouseholder_CD64.java000066400000000000000000000332171256171534400323210ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; /** *

* This variation of complex QR decomposition uses reflections to compute the Q matrix. * Each reflection uses a householder operations, hence its name. To provide a meaningful solution * the original matrix must have full rank. This is intended for processing of small to medium matrices. *

*

* Both Q and R are stored in the same m by n matrix. Q is not stored directly, instead the u from * Qk=(I-γ*u*uH) is stored. Decomposition requires about 2n*m2-2m2/3 flops. *

* *

* See the QR reflections algorithm described in:
* David S. Watkins, "Fundamentals of Matrix Computations" 2nd Edition, 2002 *

* *

* For the most part this is a straight forward implementation. To improve performance on large matrices a column is * written to an array and the order * of some of the loops has been changed. This will degrade performance noticeably on small matrices. Since * it is unlikely that the QR decomposition would be a bottle neck when small matrices are involved only * one implementation is provided. *

* * @author Peter Abeles */ public class QRDecompositionHouseholder_CD64 implements QRDecomposition { /** * Where the Q and R matrices are stored. R is stored in the * upper triangular portion and Q on the lower bit. Lower columns * are where u is stored. Q_k = (I - gamma_k*u_k*u_k^H). */ protected CDenseMatrix64F QR; // used internally to store temporary data protected double u[],v[]; // dimension of the decomposed matrices protected int numCols; // this is 'n' protected int numRows; // this is 'm' protected int minLength; protected double dataQR[]; // the computed gamma for Q_k matrix protected double gammas[]; // local variables protected double realGamma; // gamma is always real protected double realTau,imagTau; // did it encounter an error? protected boolean error; public void setExpectedMaxSize( int numRows , int numCols ) { error = false; this.numCols = numCols; this.numRows = numRows; minLength = Math.min(numRows,numCols); int maxLength = Math.max(numRows,numCols); if( QR == null ) { QR = new CDenseMatrix64F(numRows,numCols); u = new double[ maxLength*2 ]; v = new double[ maxLength*2 ]; gammas = new double[ minLength ]; } else { QR.reshape(numRows,numCols); } dataQR = QR.data; if( u.length < maxLength*2 ) { u = new double[ maxLength*2 ]; v = new double[ maxLength*2 ]; } if( gammas.length < minLength ) { gammas = new double[ minLength ]; } } /** * Returns a single matrix which contains the combined values of Q and R. This * is possible since Q is symmetric and R is upper triangular. * * @return The combined Q R matrix. */ public CDenseMatrix64F getQR() { return QR; } /** * Computes the Q matrix from the information stored in the QR matrix. This * operation requires about 4(m2n-mn2+n3/3) flops. * * @param Q The orthogonal Q matrix. */ @Override public CDenseMatrix64F getQ( CDenseMatrix64F Q , boolean compact ) { if( compact ) { if( Q == null ) { Q = CCommonOps.identity(numRows,minLength); } else { if( Q.numRows != numRows || Q.numCols != minLength ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CCommonOps.setIdentity(Q); } } } else { if( Q == null ) { Q = CCommonOps.identity(numRows); } else { if( Q.numRows != numRows || Q.numCols != numRows ) { throw new IllegalArgumentException("Unexpected matrix dimension."); } else { CCommonOps.setIdentity(Q); } } } for( int j = minLength-1; j >= 0; j-- ) { u[2*j] = 1; u[2*j+1] = 0; for( int i = j+1; i < numRows; i++ ) { int indexQR = QR.getIndex(i,j); u[i*2] = QR.data[indexQR]; u[i*2+1] = QR.data[indexQR+1]; } QrHelperFunctions_CD64.rank1UpdateMultR(Q,u,0,gammas[j],j,j,numRows,v); } return Q; } /** * Returns an upper triangular matrix which is the R in the QR decomposition. * * @param R An upper triangular matrix. * @param compact */ @Override public CDenseMatrix64F getR(CDenseMatrix64F R, boolean compact) { if( R == null ) { if( compact ) { R = new CDenseMatrix64F(minLength,numCols); } else R = new CDenseMatrix64F(numRows,numCols); } else { if( compact ) { if( R.numCols != numCols || R.numRows != minLength ) throw new IllegalArgumentException("Unexpected dimensions"); } else { if( R.numCols != numCols || R.numRows != numRows ) throw new IllegalArgumentException("Unexpected dimensions"); } for( int i = 0; i < R.numRows; i++ ) { int min = Math.min(i,R.numCols); for( int j = 0; j < min; j++ ) { R.set(i,j,0,0); } } } for( int i = 0; i < minLength; i++ ) { for( int j = i; j < numCols; j++ ) { int indexQR = QR.getIndex(i,j); double realQR = QR.data[indexQR]; double imagQR = QR.data[indexQR+1]; R.set(i,j,realQR,imagQR); } } return R; } /** *

* In order to decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m2-2m2/3 flops. *

* *

* The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. *

*/ @Override public boolean decompose( CDenseMatrix64F A ) { commonSetup(A); for( int j = 0; j < minLength; j++ ) { householder(j); updateA(j); } return !error; } @Override public boolean inputModified() { return false; } /** *

* Computes the householder vector "u" for the first column of submatrix j. Note this is * a specialized householder for this problem. There is some protection against * overflow and underflow. *

*

* Q = I - γuuH *

*

* This function finds the values of 'u' and 'γ'. *

* * @param j Which submatrix to work off of. */ protected void householder( int j ) { // find the element with the largest absolute value in the column and make a copy int indexQR = 2*(j+j*numCols); int indexU = 2*j; double max = 0; for( int i = j; i < numRows; i++ ) { double realD = u[indexU++] = dataQR[indexQR]; double imagD = u[indexU++] = dataQR[indexQR+1]; // absolute value of d double magD = realD*realD + imagD*imagD; if( max < magD ) { max = magD; } indexQR += numCols*2; } max = Math.sqrt(max); if( max == 0.0 ) { realGamma = 0; error = true; } else { // compute the norm2 of the vector, with each element // normalized by the max value to avoid overflow problems double nx = 0; indexU = 2*j; for( int i = j; i < numRows; i++ ) { double realD = u[indexU++] /= max; double imagD = u[indexU++] /= max; nx += realD*realD + imagD*imagD; } nx = Math.sqrt(nx); double real_x0 = u[2*j]; double imag_x0 = u[2*j+1]; double mag_x0 = Math.sqrt(real_x0*real_x0 + imag_x0*imag_x0); // TODO Could stability be improved by computing theta so that this // special case doesn't need to be handled? if( mag_x0 == 0 ) { realTau = nx; imagTau = 0; } else { realTau = real_x0 / mag_x0 * nx; imagTau = imag_x0 / mag_x0 * nx; } double top,bottom; // if there is a chance they can cancel swap the sign if ( real_x0*realTau<0) { realTau = -realTau; imagTau = -imagTau; top = nx * nx - nx *mag_x0; bottom = mag_x0*mag_x0 - 2.0* nx *mag_x0 + nx * nx; } else { top = nx * nx + nx *mag_x0; bottom = mag_x0*mag_x0 + 2.0* nx *mag_x0 + nx * nx; } realGamma = bottom/top; double real_u_0 = real_x0 + realTau; double imag_u_0 = imag_x0 + imagTau; double norm_u_0 = real_u_0*real_u_0 + imag_u_0*imag_u_0; indexU = (j+1)*2; for( int i = j+1; i < numRows; i++ ) { double realU = u[indexU]; double imagU = u[indexU+1]; u[indexU++] = (realU*real_u_0 + imagU*imag_u_0)/norm_u_0; u[indexU++] = (imagU*real_u_0 - realU*imag_u_0)/norm_u_0; } u[2*j ] = 1; u[2*j+1] = 0; realTau *= max; imagTau *= max; } gammas[j] = realGamma; } /** *

* Takes the results from the householder computation and updates the 'A' matrix.
*
* A = (I - γ*u*uH)A *

* * @param w The submatrix. */ protected void updateA( int w ) { // much of the code below is equivalent to the rank1Update function // however, since τ has already been computed there is no need to // recompute it, saving a few multiplication operations // for( int i = w+1; i < numCols; i++ ) { // double val = 0; // // for( int k = w; k < numRows; k++ ) { // val += u[k]*dataQR[k*numCols +i]; // } // v[i] = gamma*val; // } // This is functionally the same as the above code but the order has been changed // to avoid jumping the cpu cache int stride = numCols*2; double realU = u[w*2]; double imagU = -u[w*2+1]; int indexQR = w*stride+(w+1)*2; for( int i = w+1; i < numCols; i++ ) { double realQR = dataQR[indexQR++]; double imagQR = dataQR[indexQR++]; v[i*2] = realU*realQR - imagU*imagQR; v[i*2+1] = realU*imagQR + imagU*realQR; } for( int k = w+1; k < numRows; k++ ) { realU = u[k*2]; imagU = -u[k*2+1]; indexQR = k*stride+(w+1)*2; for( int i = w+1; i < numCols; i++ ) { double realQR = dataQR[indexQR++]; double imagQR = dataQR[indexQR++]; // v[i] += u[k]*dataQR[k*numCols +i]; v[i*2] += realU*realQR - imagU*imagQR; v[i*2+1] += realU*imagQR + imagU*realQR; } } for( int i = w+1; i < numCols; i++ ) { v[i*2] *= realGamma; v[i*2+1] *= realGamma; } // end of reordered code for( int i = w; i < numRows; i++ ) { double realI = u[i*2]; double imagI = u[i*2+1]; indexQR = i*stride+(w+1)*2; for( int j = w+1; j < numCols; j++ ) { double realJ = v[j*2]; double imagJ = v[j*2+1]; // dataQR[i*numCols+j] -= valU*v[j]; dataQR[indexQR++] -= realI*realJ - imagI*imagJ; dataQR[indexQR++] -= realI*imagJ + imagI*realJ; } } if( w < numCols ) { dataQR[2*w+w*stride] = -realTau; dataQR[2*w+w*stride+1] = -imagTau; } // save the Q matrix in the lower portion of QR for( int i = w+1; i < numRows; i++ ) { dataQR[2*w+i*stride] = u[i*2]; dataQR[2*w+i*stride + 1] = u[i*2 + 1]; } } /** * This function performs sanity check on the input for decompose and sets up the QR matrix. * * @param A */ protected void commonSetup(CDenseMatrix64F A) { setExpectedMaxSize(A.numRows,A.numCols); QR.set(A); } public double[] getGammas() { return gammas; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/decompose/qr/QrHelperFunctions_CD64.java000066400000000000000000000237311256171534400304530ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; /** *

* Contains different functions that are useful for computing the QR decomposition of a matrix. *

* *

* Two different families of functions are provided for help in computing reflectors. Internally * both of these functions switch between normalization by division or multiplication. Multiplication * is most often significantly faster than division (2 or 3 times) but produces less accurate results * on very small numbers. It checks to see if round off error is significant and decides which * one it should do. *

* *

* Tests were done using the stability benchmark in jmatbench and there doesn't seem to be * any advantage to always dividing by the max instead of checking and deciding. The most * noticeable difference between the two methods is with very small numbers. *

* * @author Peter Abeles */ public class QrHelperFunctions_CD64 { /** * Returns the maximum magnitude of the complex numbers * @param u Array of complex numbers * @param startU first index to consider in u * @param length Number of complex numebrs to consider * @return magnitude */ public static double findMax( double[] u, int startU , int length ) { double max = -1; int index = startU*2; int stopIndex = (startU + length)*2; for( ; index < stopIndex;) { double real = u[index++]; double img = u[index++]; double val = real*real + img*img; if( val > max ) { max = val; } } return Math.sqrt(max); } /** * Performs the following operation:
* u[(startU+j):(startU+numRows)] /= A
* were u and A are a complex */ public static void divideElements(final int j, final int numRows , final double[] u, final int startU , final double realA, final double imagA ) { double mag2 = realA*realA + imagA*imagA; int index = (j+startU)*2; for( int i = j; i < numRows; i++ ) { double realU = u[index]; double imagU = u[index+1]; // u[i+startU] /= u_0; u[index++] = (realU*realA + imagU*imagA)/mag2; u[index++] = (imagU*realA - realU*imagA)/mag2; } } /** * Performs the following operations: *
     * x = x / max
     * tau = x0*|x|/|xo|   adjust sign to avoid cancelation
     * u = x; u0 = x0 + tau; u = u/u0  (x is not divided by x0)
     * gamma = 2/|u|^2
     * 
* Note that u is not explicitly computed here. * * @param start Element in 'u' that it starts at. * @param stop Element in 'u' that it stops at. * @param x Array * @param max Max value in 'u' that is used to normalize it. * @param tau Storage for tau * @return Returns gamma */ public static double computeTauGammaAndDivide(final int start, final int stop, final double[] x, final double max, Complex64F tau) { int index = start*2; double nx = 0; for (int i = start; i < stop; i++) { double realX = x[index++] /= max; double imagX = x[index++] /= max; nx += realX * realX + imagX * imagX; } nx = Math.sqrt(nx); double real_x0 = x[2*start]; double imag_x0 = x[2*start+1]; double mag_x0 = Math.sqrt(real_x0*real_x0 + imag_x0*imag_x0); // TODO Could stability be improved by computing theta so that this // special case doesn't need to be handled? if( mag_x0 == 0 ) { tau.real = nx; tau.imaginary = 0; } else { tau.real = real_x0 / mag_x0 * nx; tau.imaginary = imag_x0 / mag_x0 * nx; } double top,bottom; // if there is a chance they can cancel swap the sign if ( real_x0*tau.real<0) { tau.real = -tau.real; tau.imaginary = -tau.imaginary; top = nx * nx - nx *mag_x0; bottom = mag_x0*mag_x0 - 2.0* nx *mag_x0 + nx * nx; } else { top = nx * nx + nx *mag_x0; bottom = mag_x0*mag_x0 + 2.0* nx *mag_x0 + nx * nx; } return bottom/top; // gamma } /** *

* Performs a rank-1 update operation on the submatrix specified by w with the multiply on the right.
*
* A = (I - γ*u*uH)*A
*

* * @param A matrix * @param u vector * @param offsetU offset added to w0 when indexing u. Multiplied by 2 since complex. * @param gammaR real component of gamma * @param colA0 first column in A sub-matrix. * @param w0 first index in sub-array in u and row sub-matrix in A * @param w1 last index + 1 in sub-array in u and row sub-matrix in A * @param _temp temporary storage. Same size as u. */ public static void rank1UpdateMultR(CDenseMatrix64F A, double u[], int offsetU, double gammaR , int colA0, int w0, int w1, double _temp[]) { // for( int i = colA0; i < A.numCols; i++ ) { // double val = 0; // // for( int k = w0; k < w1; k++ ) { // val += u[k+offsetU]*A.data[k*A.numCols +i]; // } // _temp[i] = gamma*val; // } // reordered to reduce cpu cache issues int indexU = (w0+offsetU)*2; double realU = u[indexU]; double imagU = -u[indexU+1]; int indexA = w0*A.numCols*2 + colA0*2; int indexTmp = colA0*2; for( int i = colA0; i < A.numCols; i++ ) { double realA = A.data[indexA++]; double imagA = A.data[indexA++]; _temp[indexTmp++] = realU*realA - imagU*imagA; _temp[indexTmp++] = realU*imagA + imagU*realA; } for( int k = w0+1; k < w1; k++ ) { indexA = k*A.numCols*2 + colA0*2; indexU = (k+offsetU)*2; indexTmp = colA0*2; realU = u[indexU]; imagU = -u[indexU+1]; for( int i = colA0; i < A.numCols; i++ ) { double realA = A.data[indexA++]; double imagA = A.data[indexA++]; _temp[indexTmp++] += realU*realA - imagU*imagA; _temp[indexTmp++] += realU*imagA + imagU*realA; } } indexTmp = colA0*2; for( int i = colA0; i < A.numCols; i++ ) { double realTmp = _temp[indexTmp]; double imagTmp = _temp[indexTmp+1]; _temp[indexTmp++] = gammaR*realTmp; _temp[indexTmp++] = gammaR*imagTmp; } // end of reorder for( int i = w0; i < w1; i++ ) { indexA = i*A.numCols*2 + colA0*2; indexU = (i+offsetU)*2; indexTmp = colA0*2; realU = u[indexU]; imagU = u[indexU+1]; for( int j = colA0; j < A.numCols; j++ ) { double realTmp = _temp[indexTmp++]; double imagTmp = _temp[indexTmp++]; A.data[indexA++] -= realU*realTmp - imagU*imagTmp; A.data[indexA++] -= realU*imagTmp + imagU*realTmp; } } } /** *

* Performs a rank-1 update operation on the submatrix specified by w with the multiply on the left.
*
* A = A(I - γ*u*uH)
*

*

* The order that matrix multiplies are performed has been carefully selected * to minimize the number of operations. *

* *

* Before this can become a truly generic operation the submatrix specification needs * to be made more generic. *

*/ public static void rank1UpdateMultL( CDenseMatrix64F A , double u[] , double gammaR , double gammaI , int colA0, int w0 , int w1 ) { for( int i = colA0; i < A.numRows; i++ ) { int startIndex = i*A.numCols*2+w0*2; double realSum = 0,imagSum=0; int rowIndex = startIndex; int indexU = w0*2; for( int j = w0; j < w1; j++ ) { double realA = A.data[rowIndex++]; double imajA = A.data[rowIndex++]; double realU = u[indexU++]; double imajU = u[indexU++]; realSum += realA*realU - imajA*imajU; imagSum += realA*imajU + imajA*realU; } double realTmp = -(gammaR*realSum - gammaI*imagSum); double imagTmp = -(gammaR*imagSum + gammaI*realSum); rowIndex = startIndex; indexU = w0*2; for( int j = w0; j < w1; j++ ) { double realU = u[indexU++]; double imagU = -u[indexU++]; A.data[rowIndex++] += realTmp*realU - imagTmp*imagU; A.data[rowIndex++] += realTmp*imagU + imagTmp*realU; } } } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/000077500000000000000000000000001256171534400223475ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/CInvertUsingSolve.java000066400000000000000000000035601256171534400266070ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CCommonOps; /** * A matrix can be easily inverted by solving a system with an identify matrix. The only * disadvantage of this approach is that additional computations are required compared to * a specialized solution. * * @author Peter Abeles */ public class CInvertUsingSolve { public static void invert( LinearSolver solver , CDenseMatrix64F A , CDenseMatrix64F A_inv , CDenseMatrix64F storage) { if( A.numRows != A_inv.numRows || A.numCols != A_inv.numCols) { throw new IllegalArgumentException("A and A_inv must have the same dimensions"); } CCommonOps.setIdentity(storage); solver.solve(storage,A_inv); } public static void invert( LinearSolver solver , CDenseMatrix64F A , CDenseMatrix64F A_inv ) { if( A.numRows != A_inv.numRows || A.numCols != A_inv.numCols) { throw new IllegalArgumentException("A and A_inv must have the same dimensions"); } CCommonOps.setIdentity(A_inv); solver.solve(A_inv,A_inv); } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/LinearSolverAbstract_CD64.java000066400000000000000000000032761256171534400300330ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** *

* An abstract class that provides some common functionality and a default implementation * of invert that uses the solve function of the child class. *

* *

* The extending class must explicity call {@link #_setA(org.ejml.data.CDenseMatrix64F)} * inside of its {@link #setA} function. *

* * @author Peter Abeles */ public abstract class LinearSolverAbstract_CD64 implements LinearSolver { protected CDenseMatrix64F A; protected int numRows; protected int numCols; protected int stride; public CDenseMatrix64F getA() { return A; } protected void _setA(CDenseMatrix64F A) { this.A = A; this.numRows = A.numRows; this.numCols = A.numCols; this.stride = numCols*2; } @Override public void invert(CDenseMatrix64F A_inv) { CInvertUsingSolve.invert(this,A,A_inv); } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/chol/000077500000000000000000000000001256171534400232745ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/chol/LinearSolverChol_CD64.java000066400000000000000000000127401256171534400300760ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.dense.decompose.CTriangularSolver; import org.ejml.alg.dense.decompose.chol.CholeskyDecompositionCommon_CD64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.ops.CSpecializedOps; import java.util.Arrays; /** * @author Peter Abeles */ public class LinearSolverChol_CD64 extends LinearSolverAbstract_CD64 { CholeskyDecompositionCommon_CD64 decomposer; int n; double vv[] = new double[0]; double t[]; public LinearSolverChol_CD64(CholeskyDecompositionCommon_CD64 decomposer) { this.decomposer = decomposer; } @Override public boolean setA(CDenseMatrix64F A) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("Matrix must be square"); _setA(A); if( decomposer.decompose(A) ){ n = A.numCols; if( vv.length < n*2 ) vv = new double[n*2]; t = decomposer._getT().data; return true; } else { return false; } } @Override public double quality() { return CSpecializedOps.qualityTriangular(decomposer._getT()); } /** *

* Using the decomposition, finds the value of 'X' in the linear equation below:
* * A*x = b
* * where A has dimension of n by n, x and b are n by m dimension. *

*

* *Note* that 'b' and 'x' can be the same matrix instance. *

* * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is writen to. Modified. */ @Override public void solve( CDenseMatrix64F B , CDenseMatrix64F X ) { if( B.numCols != X.numCols || B.numRows != n || X.numRows != n) { throw new IllegalArgumentException("Unexpected matrix size"); } int numCols = B.numCols; double dataB[] = B.data; double dataX[] = X.data; if(decomposer.isLower()) { for( int j = 0; j < numCols; j++ ) { for( int i = 0; i < n; i++ ) { vv[i*2] = dataB[(i*numCols+j)*2]; vv[i*2+1] = dataB[(i*numCols+j)*2+1]; } solveInternalL(); for( int i = 0; i < n; i++ ) { dataX[(i*numCols+j)*2 ] = vv[i*2]; dataX[(i*numCols+j)*2+1] = vv[i*2+1]; } } } else { throw new RuntimeException("Implement"); } } /** * Used internally to find the solution to a single column vector. */ private void solveInternalL() { // This takes advantage of the diagonal elements always being real numbers // solve L*y=b storing y in x CTriangularSolver.solveL_diagReal(t, vv, n); // solve L^T*x=y CTriangularSolver.solveConjTranL_diagReal(t, vv, n); } /** * Sets the matrix 'inv' equal to the inverse of the matrix that was decomposed. * * @param inv Where the value of the inverse will be stored. Modified. */ @Override public void invert( CDenseMatrix64F inv ) { if( inv.numRows != n || inv.numCols != n ) { throw new RuntimeException("Unexpected matrix dimension"); } if( inv.data == t ) { throw new IllegalArgumentException("Passing in the same matrix that was decomposed."); } if(decomposer.isLower()) { setToInverseL(inv.data); } else { throw new RuntimeException("Implement"); } } /** * Sets the matrix to the inverse using a lower triangular matrix. */ public void setToInverseL( double a[] ) { // the more direct method which takes full advantage of the sparsity of the data structures proved to // be difficult to get right due to the conjugates and reordering. // See comparable real number code for an example. for (int col = 0; col < n; col++) { Arrays.fill(vv,0); vv[col*2] = 1; CTriangularSolver.solveL_diagReal(t, vv, n); CTriangularSolver.solveConjTranL_diagReal(t, vv, n); for( int i = 0; i < n; i++ ) { a[(i*numCols+col)*2 ] = vv[i*2]; a[(i*numCols+col)*2+1] = vv[i*2+1]; } } // NOTE: If you want to make inverse faster take advantage of the sparsity } @Override public boolean modifiesA() { return decomposer.inputModified(); } @Override public boolean modifiesB() { return false; } @Override public CholeskyDecomposition getDecomposition() { return decomposer; } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/lu/000077500000000000000000000000001256171534400227675ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/lu/LinearSolverLuBase_CD64.java000066400000000000000000000050451256171534400300570ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decompose.lu.LUDecompositionBase_CD64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_CD64; import org.ejml.data.CDenseMatrix64F; import java.util.Arrays; /** * @author Peter Abeles */ public abstract class LinearSolverLuBase_CD64 extends LinearSolverAbstract_CD64 { protected LUDecompositionBase_CD64 decomp; public LinearSolverLuBase_CD64(LUDecompositionBase_CD64 decomp) { this.decomp = decomp; } @Override public boolean setA(CDenseMatrix64F A) { _setA(A); return decomp.decompose(A); } @Override public double quality() { return decomp.quality(); } @Override public void invert(CDenseMatrix64F A_inv) { double []vv = decomp._getVV(); CDenseMatrix64F LU = decomp.getLU(); if( A_inv.numCols != LU.numCols || A_inv.numRows != LU.numRows ) throw new IllegalArgumentException("Unexpected matrix dimension"); int n = A.numCols; double dataInv[] = A_inv.data; int strideAinv = A_inv.getRowStride(); for( int j = 0; j < n; j++ ) { // don't need to change inv into an identity matrix before hand Arrays.fill(vv,0,n*2,0); vv[j*2] = 1; vv[j*2+1] = 0; decomp._solveVectorInternal(vv); // for( int i = 0; i < n; i++ ) dataInv[i* n +j] = vv[i]; int index = j*2; for( int i = 0; i < n; i++ , index += strideAinv) { dataInv[index] = vv[i*2]; dataInv[index+1] = vv[i*2+1]; } } } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public LUDecompositionBase_CD64 getDecomposition() { return decomp; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/lu/LinearSolverLu_CD64.java000066400000000000000000000045351256171534400272670ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decompose.lu.LUDecompositionBase_CD64; import org.ejml.data.CDenseMatrix64F; /** * For each column in the B matrix it makes a copy, which is then solved for and * writen into X. By making a copy of the column cpu cache issues are reduced. * * @author Peter Abeles */ public class LinearSolverLu_CD64 extends LinearSolverLuBase_CD64 { public LinearSolverLu_CD64(LUDecompositionBase_CD64 decomp) { super(decomp); } @Override public void solve(CDenseMatrix64F b, CDenseMatrix64F x) { if( b.numCols != x.numCols || b.numRows != numRows || x.numRows != numCols) { throw new IllegalArgumentException("Unexpected matrix size"); } int bnumCols = b.numCols; int bstride = b.getRowStride(); double dataB[] = b.data; double dataX[] = x.data; double []vv = decomp._getVV(); // for( int j = 0; j < numCols; j++ ) { // for( int i = 0; i < this.numCols; i++ ) vv[i] = dataB[i*numCols+j]; // decomp._solveVectorInternal(vv); // for( int i = 0; i < this.numCols; i++ ) dataX[i*numCols+j] = vv[i]; // } for( int j = 0; j < bnumCols; j++ ) { int index = j*2; for( int i = 0; i < numRows; i++ , index += bstride ) { vv[i*2] = dataB[index]; vv[i*2+1] = dataB[index+1]; } decomp._solveVectorInternal(vv); index = j*2; for( int i = 0; i < numRows; i++ , index += bstride ) { dataX[index] = vv[i*2]; dataX[index+1] = vv[i*2+1]; } } } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/qr/000077500000000000000000000000001256171534400227715ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrHouseCol_CD64.java000066400000000000000000000123641256171534400307340ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decompose.CTriangularSolver; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholderColumn_CD64; import org.ejml.alg.dense.decompose.qr.QrHelperFunctions_CD64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.ops.CSpecializedOps; /** *

* QR decomposition can be used to solve for systems. However, this is not as computationally efficient * as LU decomposition and costs about 3n2 flops. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^H b
*

* *

* A column major decomposition is used in this solver. *

* * @author Peter Abeles */ public class LinearSolverQrHouseCol_CD64 extends LinearSolverAbstract_CD64 { private QRDecompositionHouseholderColumn_CD64 decomposer; private CDenseMatrix64F a = new CDenseMatrix64F(1,1); private CDenseMatrix64F temp = new CDenseMatrix64F(1,1); protected int maxRows = -1; protected int maxCols = -1; private double[][] QR; // a column major QR matrix private CDenseMatrix64F R = new CDenseMatrix64F(1,1); private double gammas[]; /** * Creates a linear solver that uses QR decomposition. */ public LinearSolverQrHouseCol_CD64() { decomposer = new QRDecompositionHouseholderColumn_CD64(); } public void setMaxSize( int maxRows , int maxCols ) { this.maxRows = maxRows; this.maxCols = maxCols; } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(CDenseMatrix64F A) { if( A.numRows < A.numCols ) throw new IllegalArgumentException("Can't solve for wide systems. More variables than equations."); if( A.numRows > maxRows || A.numCols > maxCols ) setMaxSize(A.numRows,A.numCols); R.reshape(A.numCols,A.numCols); a.reshape(A.numRows,1); temp.reshape(A.numRows,1); _setA(A); if( !decomposer.decompose(A) ) return false; gammas = decomposer.getGammas(); QR = decomposer.getQR(); decomposer.getR(R,true); return true; } @Override public double quality() { return CSpecializedOps.qualityTriangular(R); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is written to. Modified. */ @Override public void solve(CDenseMatrix64F B, CDenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X: X rows = "+X.numRows+" expected = "+numCols); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { int indexB = (i*BnumCols + colB)*2; a.data[i*2] = B.data[indexB]; a.data[i*2+1] = B.data[indexB+1]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for( int n = 0; n < numCols; n++ ) { double []u = QR[n]; double realVV = u[n*2]; double imagVV = u[n*2+1]; u[n*2] = 1; u[n*2+1] = 0; QrHelperFunctions_CD64.rank1UpdateMultR(a, u,0, gammas[n], 0, n, numRows, temp.data); u[n*2] = realVV; u[n*2+1] = imagVV; } // solve for Rx = b using the standard upper triangular solver CTriangularSolver.solveU(R.data, a.data, numCols); // save the results for( int i = 0; i < numCols; i++ ) { int indexB = (i*BnumCols + colB)*2; X.data[indexB] = a.data[i*2]; X.data[indexB+1] = a.data[i*2+1]; } } } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public QRDecompositionHouseholderColumn_CD64 getDecomposition() { return decomposer; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrHouseTran_CD64.java000066400000000000000000000133431256171534400311210ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decompose.CTriangularSolver; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholderTran_CD64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CSpecializedOps; /** *

* QR decomposition can be used to solve for systems. However, this is not as computationally efficient * as LU decomposition and costs about 3n2 flops. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^H b
*

* *

* A column major decomposition is used in this solver. *

* * @author Peter Abeles */ public class LinearSolverQrHouseTran_CD64 extends LinearSolverAbstract_CD64 { private QRDecompositionHouseholderTran_CD64 decomposer; private double []a; protected int maxRows = -1; protected int maxCols = -1; private CDenseMatrix64F QR; // a column major QR matrix private CDenseMatrix64F U; /** * Creates a linear solver that uses QR decomposition. */ public LinearSolverQrHouseTran_CD64() { decomposer = new QRDecompositionHouseholderTran_CD64(); } public void setMaxSize( int maxRows , int maxCols ) { this.maxRows = maxRows; this.maxCols = maxCols; a = new double[ maxRows*2 ]; } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(CDenseMatrix64F A) { if( A.numRows > maxRows || A.numCols > maxCols ) setMaxSize(A.numRows,A.numCols); _setA(A); if( !decomposer.decompose(A) ) return false; QR = decomposer.getQR(); return true; } @Override public double quality() { // even those it is transposed the diagonal elements are at the same // elements return CSpecializedOps.qualityTriangular(QR); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is written to. Modified. */ @Override public void solve(CDenseMatrix64F B, CDenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X: X rows = "+X.numRows+" expected = "+numCols); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); U = decomposer.getR(U,true); final double gammas[] = decomposer.getGammas(); final double dataQR[] = QR.data; final int BnumCols = B.numCols; // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { int indexB = (i*BnumCols + colB)*2; a[i*2] = B.data[indexB]; a[i*2+1] = B.data[indexB+1]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^H)*b = b - u*(gamma*U^H*b) for( int n = 0; n < numCols; n++ ) { int indexU = (n*numRows + n + 1)*2; double realUb = a[n*2]; double imagUb = a[n*2+1]; // U^H*b for( int i = n+1; i < numRows; i++ ) { double realU = dataQR[indexU++]; double imagU = -dataQR[indexU++]; double realB = a[i*2]; double imagB = a[i*2+1]; realUb += realU*realB - imagU*imagB; imagUb += realU*imagB + imagU*realB; } // gamma*U^T*b realUb *= gammas[n]; imagUb *= gammas[n]; a[n*2] -= realUb; a[n*2+1] -= imagUb; indexU = (n*numRows + n + 1)*2; for( int i = n+1; i < numRows; i++) { double realU = dataQR[indexU++]; double imagU = dataQR[indexU++]; a[i*2] -= realU*realUb - imagU*imagUb; a[i*2+1] -= realU*imagUb + imagU*realUb; } } // solve for Rx = b using the standard upper triangular solver CTriangularSolver.solveU(U.data, a, numCols); // save the results for( int i = 0; i < numCols; i++ ) { int indexX = (i*X.numCols+colB)*2; X.data[indexX] = a[i*2]; X.data[indexX+1] = a[i*2+1]; } } } @Override public boolean modifiesA() { return decomposer.inputModified(); } @Override public boolean modifiesB() { return false; } @Override public QRDecomposition getDecomposition() { return decomposer; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQrHouse_CD64.java000066400000000000000000000123711256171534400302740ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decompose.CTriangularSolver; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholder_CD64; import org.ejml.alg.dense.linsol.LinearSolverAbstract_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CSpecializedOps; /** *

* QR decomposition can be used to solve for systems. However, this is not as computationally efficient * as LU decomposition and costs about 3n2 flops. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^H b
*

* * @author Peter Abeles */ public class LinearSolverQrHouse_CD64 extends LinearSolverAbstract_CD64 { private QRDecompositionHouseholder_CD64 decomposer; private double []a,u; private int maxRows = -1; private CDenseMatrix64F QR; private double gammas[]; /** * Creates a linear solver that uses QR decomposition. */ public LinearSolverQrHouse_CD64() { decomposer = new QRDecompositionHouseholder_CD64(); } public void setMaxSize( int maxRows ) { this.maxRows = maxRows; a = new double[ maxRows*2 ]; u = new double[ maxRows*2 ]; } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(CDenseMatrix64F A) { if( A.numRows > maxRows ) { setMaxSize(A.numRows); } _setA(A); if( !decomposer.decompose(A) ) return false; gammas = decomposer.getGammas(); QR = decomposer.getQR(); return true; } @Override public double quality() { return CSpecializedOps.qualityTriangular(QR); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is writen to. Modified. */ @Override public void solve(CDenseMatrix64F B, CDenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X"); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { int indexB = (i*BnumCols + colB)*2; a[i*2] = B.data[indexB]; a[i*2+1] = B.data[indexB+1]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^H)*b = b - u*(gamma*U^H*b) for( int n = 0; n < numCols; n++ ) { u[n*2] = 1; u[n*2+1] = 0; double realUb = a[2*n]; double imagUb = a[2*n+1]; // U^H*b for( int i = n+1; i < numRows; i++ ) { int indexQR = (i*QR.numCols+n)*2; double realU = u[i*2] = QR.data[indexQR]; double imagU = u[i*2+1] = QR.data[indexQR+1]; double realB = a[i*2]; double imagB = a[i*2+1]; realUb += realU*realB + imagU*imagB; imagUb += realU*imagB - imagU*realB; } // gamma*U^H*b realUb *= gammas[n]; imagUb *= gammas[n]; for( int i = n; i < numRows; i++ ) { double realU = u[i*2]; double imagU = u[i*2+1]; a[i*2 ] -= realU*realUb - imagU*imagUb; a[i*2+1] -= realU*imagUb + imagU*realUb; } } // solve for Rx = b using the standard upper triangular solver CTriangularSolver.solveU(QR.data, a, numCols); // save the results for( int i = 0; i < numCols; i++ ) { int indexX = (i*X.numCols+colB)*2; X.data[indexX] = a[i*2]; X.data[indexX+1] = a[i*2+1]; } } } @Override public boolean modifiesA() { return false; } @Override public boolean modifiesB() { return false; } @Override public QRDecomposition getDecomposition() { return decomposer; } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/linsol/qr/LinearSolverQr_CD64.java000066400000000000000000000117361256171534400272740ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decompose.CTriangularSolver; import org.ejml.alg.dense.linsol.LinearSolverAbstract_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CSpecializedOps; /** *

* A solver for a generic QR decomposition algorithm. This will in general be a bit slower than the * specialized once since the full Q and R matrices need to be extracted. *

*

* It solve for x by first multiplying b by the transpose of Q then solving for the result. *
* QRx=b
* Rx=Q^H b
*

* * @author Peter Abeles */ public class LinearSolverQr_CD64 extends LinearSolverAbstract_CD64 { private QRDecomposition decomposer; protected int maxRows = -1; protected int maxCols = -1; protected CDenseMatrix64F Q; protected CDenseMatrix64F Qt; protected CDenseMatrix64F R; private CDenseMatrix64F Y,Z; /** * Creates a linear solver that uses QR decomposition. * */ public LinearSolverQr_CD64(QRDecomposition decomposer) { this.decomposer = decomposer; } /** * Changes the size of the matrix it can solve for * * @param maxRows Maximum number of rows in the matrix it will decompose. * @param maxCols Maximum number of columns in the matrix it will decompose. */ public void setMaxSize( int maxRows , int maxCols ) { this.maxRows = maxRows; this.maxCols = maxCols; Q = new CDenseMatrix64F(maxRows,maxRows); Qt = new CDenseMatrix64F(maxRows,maxRows); R = new CDenseMatrix64F(maxRows,maxCols); Y = new CDenseMatrix64F(maxRows,1); Z = new CDenseMatrix64F(maxRows,1); } /** * Performs QR decomposition on A * * @param A not modified. */ @Override public boolean setA(CDenseMatrix64F A) { if( A.numRows > maxRows || A.numCols > maxCols ) { setMaxSize(A.numRows,A.numCols); } _setA(A); if( !decomposer.decompose(A) ) return false; Q.reshape(numRows,numRows); R.reshape(numRows,numCols); decomposer.getQ(Q,false); decomposer.getR(R,false); CCommonOps.transposeConjugate(Q,Qt); return true; } @Override public double quality() { return CSpecializedOps.qualityTriangular(R); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is written to. Modified. */ @Override public void solve(CDenseMatrix64F B, CDenseMatrix64F X) { if( X.numRows != numCols ) throw new IllegalArgumentException("Unexpected dimensions for X"); else if( B.numRows != numRows || B.numCols != X.numCols ) throw new IllegalArgumentException("Unexpected dimensions for B"); int BnumCols = B.numCols; Y.reshape(numRows,1); Z.reshape(numRows,1); // solve each column one by one for( int colB = 0; colB < BnumCols; colB++ ) { // make a copy of this column in the vector for( int i = 0; i < numRows; i++ ) { int indexB = B.getIndex(i,colB); Y.data[i*2] = B.data[indexB]; Y.data[i*2+1] = B.data[indexB+1]; } // Solve Qa=b // a = Q'b CCommonOps.mult(Qt, Y, Z); // solve for Rx = b using the standard upper triangular solver CTriangularSolver.solveU(R.data, Z.data, numCols); // save the results for( int i = 0; i < numCols; i++ ) { X.set(i,colB,Z.data[i*2],Z.data[i*2+1]); } } } @Override public boolean modifiesA() { return decomposer.inputModified(); } @Override public boolean modifiesB() { return false; } @Override public QRDecomposition getDecomposition() { return decomposer; } public QRDecomposition getDecomposer() { return decomposer; } public CDenseMatrix64F getQ() { return Q; } public CDenseMatrix64F getR() { return R; } }ejml-0.28/main/denseC64/src/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400220025ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/misc/CTransposeAlgs.java000066400000000000000000000101721256171534400255360ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.CDenseMatrix64F; /** * Algorithms for transposing dense complex matrices * * @author Peter Abeles */ public class CTransposeAlgs { /** * In-place transpose for a square matrix. On most architectures it is faster than the standard transpose * algorithm, but on most modern computers it's slower than block transpose. * * @param mat The matrix that is transposed in-place. Modified. */ public static void square( CDenseMatrix64F mat ) { int index = 2; int rowStride = mat.getRowStride(); int indexEnd = rowStride; for( int i = 0; i < mat.numRows; i++ , index += (i+1)*2 , indexEnd += rowStride ) { int indexOther = (i+1)*rowStride + i*2; for( ; index < indexEnd; index += 2, indexOther += rowStride) { double real = mat.data[ index ]; double img = mat.data[ index+1 ]; mat.data[ index ] = mat.data[ indexOther ]; mat.data[ index+1 ] = mat.data[ indexOther+1 ]; mat.data[indexOther] = real; mat.data[indexOther+1] = img; } } } public static void squareConjugate( CDenseMatrix64F mat ) { int index = 2; int rowStride = mat.getRowStride(); int indexEnd = rowStride; for( int i = 0; i < mat.numRows; i++ , index += (i+1)*2 , indexEnd += rowStride ) { mat.data[ index-1 ] = -mat.data[ index-1 ]; int indexOther = (i+1)*rowStride + i*2; for( ; index < indexEnd; index += 2, indexOther += rowStride) { double real = mat.data[ index ]; double img = mat.data[ index+1 ]; mat.data[ index ] = mat.data[ indexOther ]; mat.data[ index+1 ] = -mat.data[ indexOther+1 ]; mat.data[indexOther] = real; mat.data[indexOther+1] = -img; } } } /** * A straight forward transpose. Good for small non-square matrices. * * @param A Original matrix. Not modified. * @param A_tran Transposed matrix. Modified. */ public static void standard( CDenseMatrix64F A, CDenseMatrix64F A_tran) { int index = 0; int rowStrideTran = A_tran.getRowStride(); int rowStride = A.getRowStride(); for( int i = 0; i < A_tran.numRows; i++ ) { int index2 = i*2; int end = index + rowStrideTran; while( index < end ) { A_tran.data[index++] = A.data[ index2 ]; A_tran.data[index++] = A.data[ index2+1 ]; index2 += rowStride; } } } /** * A straight forward conjugate transpose. Good for small non-square matrices. * * @param A Original matrix. Not modified. * @param A_tran Transposed matrix. Modified. */ public static void standardConjugate( CDenseMatrix64F A, CDenseMatrix64F A_tran) { int index = 0; int rowStrideTran = A_tran.getRowStride(); int rowStride = A.getRowStride(); for( int i = 0; i < A_tran.numRows; i++ ) { int index2 = i*2; int end = index + rowStrideTran; while( index < end ) { A_tran.data[index++] = A.data[ index2 ]; A_tran.data[index++] = -A.data[ index2+1 ]; index2 += rowStride; } } } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400220305ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/alg/dense/mult/CMatrixMatrixMult.java000066400000000000000000000404371256171534400263010ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.CDenseMatrix64F; import org.ejml.ops.CCommonOps; import org.ejml.ops.MatrixDimensionException; /** *

Matrix multiplication routines for complex dense matrices in a row-major format.

* *

* DO NOT MODIFY! Auto generated by {@link org.ejml.alg.dense.mult.GenerateCMatrixMatrixMult}. *

* * @author Peter Abeles */ public class CMatrixMatrixMult { public static void mult_reorder( CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( a.numCols == 0 || a.numRows == 0 ) { CCommonOps.fill(c,0,0); return; } double realA,imgA; int indexCbase= 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); int strideC = c.getRowStride(); int endOfKLoop = b.numRows*strideB; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*strideA; // need to assign c.data to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + strideB; realA = a.data[indexA++]; imgA = a.data[indexA++]; while( indexB < end ) { double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] = realA*realB - imgA*imgB; c.data[indexC++] = realA*imgB + imgA*realB; } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + strideB; realA = a.data[indexA++]; imgA = a.data[indexA++]; while( indexB < end ) { // j loop double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] += realA*realB - imgA*imgB; c.data[indexC++] += realA*imgB + imgA*realB; } } indexCbase += strideC; } } public static void mult_small( CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } int aIndexStart = 0; int cIndex = 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < b.numCols; j++ ) { double realTotal = 0; double imgTotal = 0; int indexA = aIndexStart; int indexB = j*2; int end = indexA + strideA; while( indexA < end ) { double realA = a.data[indexA++]; double imgA = a.data[indexA++]; double realB = b.data[indexB]; double imgB = b.data[indexB+1]; realTotal += realA*realB - imgA*imgB; imgTotal += realA*imgB + imgA*realB; indexB += strideB; } c.data[cIndex++] = realTotal; c.data[cIndex++] = imgTotal; } aIndexStart += strideA; } } public static void multAdd_reorder( CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( a.numCols == 0 || a.numRows == 0 ) { return; } double realA,imgA; int indexCbase= 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); int strideC = c.getRowStride(); int endOfKLoop = b.numRows*strideB; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*strideA; // need to assign c.data to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + strideB; realA = a.data[indexA++]; imgA = a.data[indexA++]; while( indexB < end ) { double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] += realA*realB - imgA*imgB; c.data[indexC++] += realA*imgB + imgA*realB; } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + strideB; realA = a.data[indexA++]; imgA = a.data[indexA++]; while( indexB < end ) { // j loop double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] += realA*realB - imgA*imgB; c.data[indexC++] += realA*imgB + imgA*realB; } } indexCbase += strideC; } } public static void multAdd_small( CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } int aIndexStart = 0; int cIndex = 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < b.numCols; j++ ) { double realTotal = 0; double imgTotal = 0; int indexA = aIndexStart; int indexB = j*2; int end = indexA + strideA; while( indexA < end ) { double realA = a.data[indexA++]; double imgA = a.data[indexA++]; double realB = b.data[indexB]; double imgB = b.data[indexB+1]; realTotal += realA*realB - imgA*imgB; imgTotal += realA*imgB + imgA*realB; indexB += strideB; } c.data[cIndex++] += realTotal; c.data[cIndex++] += imgTotal; } aIndexStart += strideA; } } public static void mult_reorder( double realAlpha , double imgAlpha , CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( a.numCols == 0 || a.numRows == 0 ) { CCommonOps.fill(c,0,0); return; } double realA,imgA; double realTmp,imgTmp; int indexCbase= 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); int strideC = c.getRowStride(); int endOfKLoop = b.numRows*strideB; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*strideA; // need to assign c.data to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + strideB; realTmp = a.data[indexA++]; imgTmp = a.data[indexA++]; realA = realAlpha*realTmp - imgAlpha*imgTmp; imgA = realAlpha*imgTmp + imgAlpha*realTmp; while( indexB < end ) { double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] = realA*realB - imgA*imgB; c.data[indexC++] = realA*imgB + imgA*realB; } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + strideB; realTmp = a.data[indexA++]; imgTmp = a.data[indexA++]; realA = realAlpha*realTmp - imgAlpha*imgTmp; imgA = realAlpha*imgTmp + imgAlpha*realTmp; while( indexB < end ) { // j loop double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] += realA*realB - imgA*imgB; c.data[indexC++] += realA*imgB + imgA*realB; } } indexCbase += strideC; } } public static void mult_small( double realAlpha , double imgAlpha , CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } int aIndexStart = 0; int cIndex = 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < b.numCols; j++ ) { double realTotal = 0; double imgTotal = 0; int indexA = aIndexStart; int indexB = j*2; int end = indexA + strideA; while( indexA < end ) { double realA = a.data[indexA++]; double imgA = a.data[indexA++]; double realB = b.data[indexB]; double imgB = b.data[indexB+1]; realTotal += realA*realB - imgA*imgB; imgTotal += realA*imgB + imgA*realB; indexB += strideB; } c.data[cIndex++] = realAlpha*realTotal - imgAlpha*imgTotal; c.data[cIndex++] = realAlpha*imgTotal + imgAlpha*realTotal; } aIndexStart += strideA; } } public static void multAdd_reorder( double realAlpha , double imgAlpha , CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( a.numCols == 0 || a.numRows == 0 ) { return; } double realA,imgA; double realTmp,imgTmp; int indexCbase= 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); int strideC = c.getRowStride(); int endOfKLoop = b.numRows*strideB; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*strideA; // need to assign c.data to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + strideB; realTmp = a.data[indexA++]; imgTmp = a.data[indexA++]; realA = realAlpha*realTmp - imgAlpha*imgTmp; imgA = realAlpha*imgTmp + imgAlpha*realTmp; while( indexB < end ) { double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] += realA*realB - imgA*imgB; c.data[indexC++] += realA*imgB + imgA*realB; } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + strideB; realTmp = a.data[indexA++]; imgTmp = a.data[indexA++]; realA = realAlpha*realTmp - imgAlpha*imgTmp; imgA = realAlpha*imgTmp + imgAlpha*realTmp; while( indexB < end ) { // j loop double realB = b.data[indexB++]; double imgB = b.data[indexB++]; c.data[indexC++] += realA*realB - imgA*imgB; c.data[indexC++] += realA*imgB + imgA*realB; } } indexCbase += strideC; } } public static void multAdd_small( double realAlpha , double imgAlpha , CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( a == c || b == c ) throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'"); else if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } int aIndexStart = 0; int cIndex = 0; int strideA = a.getRowStride(); int strideB = b.getRowStride(); for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < b.numCols; j++ ) { double realTotal = 0; double imgTotal = 0; int indexA = aIndexStart; int indexB = j*2; int end = indexA + strideA; while( indexA < end ) { double realA = a.data[indexA++]; double imgA = a.data[indexA++]; double realB = b.data[indexB]; double imgB = b.data[indexB+1]; realTotal += realA*realB - imgA*imgB; imgTotal += realA*imgB + imgA*realB; indexB += strideB; } c.data[cIndex++] += realAlpha*realTotal - imgAlpha*imgTotal; c.data[cIndex++] += realAlpha*imgTotal + imgAlpha*realTotal; } aIndexStart += strideA; } } } ejml-0.28/main/denseC64/src/org/ejml/alg/dense/mult/CVectorVectorMult.java000066400000000000000000000135431256171534400262730ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; /** * Operations that involve multiplication of two vectors. * * @author Peter Abeles */ public class CVectorVectorMult { /** *

* Computes the inner product of the two vectors. In geometry this is known as the dot product.
*
* ∑k=1:n xk * yk
* where x and y are vectors with n elements. *

* *

* These functions are often used inside of highly optimized code and therefor sanity checks are * kept to a minimum. It is not recommended that any of these functions be used directly. *

* * @param x A vector with n elements. Not modified. * @param y A vector with n elements. Not modified. * @return The inner product of the two vectors. */ public static Complex64F innerProd( CDenseMatrix64F x, CDenseMatrix64F y , Complex64F output ) { if( output == null ) output = new Complex64F(); else { output.real = output.imaginary = 0; } int m = x.getDataLength(); for( int i = 0; i < m; i += 2 ) { double realX = x.data[i]; double imagX = x.data[i+1]; double realY = y.data[i]; double imagY = y.data[i+1]; output.real += realX*realY - imagX*imagY; output.imaginary += realX*imagY + imagX*realY; } return output; } /** *

* Computes the inner product between a vector and the conjugate of another one. *
*
* ∑k=1:n xk * conj(yk)
* where x and y are vectors with n elements. *

* *

* These functions are often used inside of highly optimized code and therefor sanity checks are * kept to a minimum. It is not recommended that any of these functions be used directly. *

* * @param x A vector with n elements. Not modified. * @param y A vector with n elements. Not modified. * @return The inner product of the two vectors. */ public static Complex64F innerProdH( CDenseMatrix64F x, CDenseMatrix64F y , Complex64F output ) { if( output == null ) output = new Complex64F(); else { output.real = output.imaginary = 0; } int m = x.getDataLength(); for( int i = 0; i < m; i += 2 ) { double realX = x.data[i]; double imagX = x.data[i+1]; double realY = y.data[i]; double imagY = -y.data[i+1]; output.real += realX*realY - imagX*imagY; output.imaginary += realX*imagY + imagX*realY; } return output; } /** *

* Sets A ∈ ℜ m × n equal to an outer product multiplication of the two * vectors. This is also known as a rank-1 operation.
*
* A = x * yT * where x ∈ ℜ m and y ∈ ℜ n are vectors. *

*

* Which is equivalent to: Aij = xi*yj *

* * @param x A vector with m elements. Not modified. * @param y A vector with n elements. Not modified. * @param A A Matrix with m by n elements. Modified. */ public static void outerProd( CDenseMatrix64F x, CDenseMatrix64F y, CDenseMatrix64F A ) { int m = A.numRows; int n = A.numCols; int index = 0; for( int i = 0; i < m; i++ ) { double realX = x.data[i*2]; double imagX = x.data[i*2+1]; int indexY = 0; for( int j = 0; j < n; j++ ) { double realY = y.data[indexY++]; double imagY = y.data[indexY++]; A.data[index++] = realX*realY - imagX*imagY; A.data[index++] = realX*imagY + imagX*realY; } } } /** *

* Sets A ∈ ℜ m × n equal to an outer product multiplication of the two * vectors. This is also known as a rank-1 operation.
*
* A = x * yH * where x ∈ ℜ m and y ∈ ℜ n are vectors. *

*

* Which is equivalent to: Aij = xi*yj *

* * @param x A vector with m elements. Not modified. * @param y A vector with n elements. Not modified. * @param A A Matrix with m by n elements. Modified. */ public static void outerProdH( CDenseMatrix64F x, CDenseMatrix64F y, CDenseMatrix64F A ) { int m = A.numRows; int n = A.numCols; int index = 0; for( int i = 0; i < m; i++ ) { double realX = x.data[i*2]; double imagX = x.data[i*2+1]; int indexY = 0; for( int j = 0; j < n; j++ ) { double realY = y.data[indexY++]; double imagY = -y.data[indexY++]; A.data[index++] = realX*realY - imagX*imagY; A.data[index++] = realX*imagY + imagX*realY; } } } } ejml-0.28/main/denseC64/src/org/ejml/factory/000077500000000000000000000000001256171534400206555ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/factory/CDecompositionFactory.java000066400000000000000000000070011256171534400257650ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.factory; import org.ejml.alg.dense.decompose.chol.CholeskyDecompositionInner_CD64; import org.ejml.alg.dense.decompose.lu.LUDecompositionAlt_CD64; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholderColumn_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.interfaces.decomposition.QRDecomposition; /** *

* Contains operations related to creating and evaluating the quality of common matrix decompositions. Except * in specialized situations, matrix decompositions should be instantiated from this factory instead of being * directly constructed. Low level implementations are more prone to changes and new algorithms will be * automatically placed here. *

* * @author Peter Abeles */ public class CDecompositionFactory { /** *

* Returns a {@link org.ejml.interfaces.decomposition.LUDecomposition} that has been optimized for the specified matrix size. *

* * @param numRows Number of rows the returned decomposition is optimized for. * @param numCols Number of columns that the returned decomposition is optimized for. * @return LUDecomposition */ public static LUDecomposition lu( int numRows , int numCols ) { return new LUDecompositionAlt_CD64(); } /** *

* Returns a {@link org.ejml.interfaces.decomposition.QRDecomposition} that has been optimized for the specified matrix size. *

* * @param numRows Number of rows the returned decomposition is optimized for. * @param numCols Number of columns that the returned decomposition is optimized for. * @return QRDecomposition */ public static QRDecomposition qr( int numRows , int numCols ) { return new QRDecompositionHouseholderColumn_CD64(); } /** *

* Returns a {@link org.ejml.interfaces.decomposition.CholeskyDecomposition} that has been optimized for the specified matrix size. *

* * @param size Number of rows and columns it should be optimized for * @param lower if true then it will be a lower cholesky. false for upper. Try lower. * @return QRDecomposition */ public static CholeskyDecomposition chol( int size , boolean lower ) { return new CholeskyDecompositionInner_CD64(lower); } /** * Decomposes the input matrix 'a' and makes sure it isn't modified. */ public static boolean decomposeSafe(DecompositionInterface decomposition, CDenseMatrix64F a) { if( decomposition.inputModified() ) { a = a.copy(); } return decomposition.decompose(a); } } ejml-0.28/main/denseC64/src/org/ejml/factory/CLinearSolverFactory.java000066400000000000000000000043521256171534400255640ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.factory; import org.ejml.alg.dense.decompose.chol.CholeskyDecompositionInner_CD64; import org.ejml.alg.dense.decompose.lu.LUDecompositionAlt_CD64; import org.ejml.alg.dense.linsol.chol.LinearSolverChol_CD64; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_CD64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouseCol_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * Factory for creating linear solvers of complex matrices * * @author Peter Abeles */ public class CLinearSolverFactory { /** * Creates a linear solver which uses LU decomposition internally * * @param matrixSize Approximate of rows and columns * @return Linear solver */ public static LinearSolver lu( int matrixSize ) { return new LinearSolverLu_CD64(new LUDecompositionAlt_CD64()); } /** * Creates a linear solver which uses Cholesky decomposition internally * * @param matrixSize Approximate of rows and columns * @return Linear solver */ public static LinearSolver chol( int matrixSize ) { return new LinearSolverChol_CD64(new CholeskyDecompositionInner_CD64()); } /** * Creates a linear solver which uses QR decomposition internally * * @param numRows Approximate of rows * @param numCols Approximate of columns * @return Linear solver */ public static LinearSolver qr( int numRows , int numCols ) { return new LinearSolverQrHouseCol_CD64(); } } ejml-0.28/main/denseC64/src/org/ejml/ops/000077500000000000000000000000001256171534400200075ustar00rootroot00000000000000ejml-0.28/main/denseC64/src/org/ejml/ops/CCommonOps.java000066400000000000000000000772401256171534400227010ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.EjmlParameters; import org.ejml.alg.dense.decompose.lu.LUDecompositionAlt_CD64; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.alg.dense.misc.CTransposeAlgs; import org.ejml.alg.dense.mult.CMatrixMatrixMult; import org.ejml.data.*; import org.ejml.factory.CLinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import java.util.Arrays; /** * Common operations on complex numbers * * @author Peter Abeles */ public class CCommonOps { /** *

* Creates an identity matrix of the specified size.
*
* aij = 0+0i if i ≠ j
* aij = 1+0i if i = j
*

* * @param width The width and height of the identity matrix. * @return A new instance of an identity matrix. */ public static CDenseMatrix64F identity( int width ) { CDenseMatrix64F A = new CDenseMatrix64F(width,width); for (int i = 0; i < width; i++) { A.set(i,i,1,0); } return A; } /** *

* Creates a matrix with diagonal elements set to 1 and the rest 0.
*
* aij = 0+0i if i ≠ j
* aij = 1+0i if i = j
*

* * @param width The width of the identity matrix. * @param height The height of the identity matrix. * @return A new instance of an identity matrix. */ public static CDenseMatrix64F identity( int width , int height) { CDenseMatrix64F A = new CDenseMatrix64F(width,height); int m = Math.min(width,height); for (int i = 0; i < m; i++) { A.set(i,i,1,0); } return A; } /** *

* Creates a new square matrix whose diagonal elements are specified by data and all * the other elements are zero.
*
* aij = 0 if i ≤ j
* aij = diag[i] if i = j
*

* * @param data Contains the values of the diagonal elements of the resulting matrix. * @return A new complex matrix. */ public static CDenseMatrix64F diag( double... data ) { if( data.length%2 == 1 ) throw new IllegalArgumentException("must be an even number of arguments"); int N = data.length/2; CDenseMatrix64F m = new CDenseMatrix64F(N,N); int index = 0; for (int i = 0; i < N; i++) { m.set(i,i,data[index++],data[index++]); } return m; } /** * Converts the real matrix into a complex matrix. * * @param input Real matrix. Not modified. * @param output Complex matrix. Modified. */ public static void convert( D1Matrix64F input , CD1Matrix64F output ) { if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } Arrays.fill(output.data, 0, output.getDataLength(), 0); final int length = output.getDataLength(); for( int i = 0; i < length; i += 2 ) { output.data[i] = input.data[i/2]; } } /** * Places the real component of the input matrix into the output matrix. * * @param input Complex matrix. Not modified. * @param output real matrix. Modified. */ public static DenseMatrix64F stripReal( CD1Matrix64F input , DenseMatrix64F output ) { if( output == null ) { output = new DenseMatrix64F(input.numRows,input.numCols); } else if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = input.getDataLength(); for( int i = 0; i < length; i += 2 ) { output.data[i/2] = input.data[i]; } return output; } /** * Places the imaginary component of the input matrix into the output matrix. * * @param input Complex matrix. Not modified. * @param output real matrix. Modified. */ public static DenseMatrix64F stripImaginary( CD1Matrix64F input , DenseMatrix64F output ) { if( output == null ) { output = new DenseMatrix64F(input.numRows,input.numCols); } else if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = input.getDataLength(); for( int i = 1; i < length; i += 2 ) { output.data[i/2] = input.data[i]; } return output; } /** *

* Computes the magnitude of the complex number in the input matrix and stores the results in the output * matrix. *

* * magnitude = sqrt(real^2 + imaginary^2) * * @param input Complex matrix. Not modified. * @param output real matrix. Modified. */ public static void magnitude( CD1Matrix64F input , D1Matrix64F output ) { if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = input.getDataLength(); for( int i = 0; i < length; i += 2 ) { double real = input.data[i]; double imaginary = input.data[i+1]; output.data[i/2] = Math.sqrt(real*real + imaginary*imaginary); } } /** *

* Computes the complex conjugate of the input matrix.
*
* reali,j = reali,j
* imaginaryi,j = -1*imaginaryi,j
*

* * @param input Input matrix. Not modified. * @param output The complex conjugate of the input matrix. Modified. */ public static void conjugate( CD1Matrix64F input , CD1Matrix64F output ) { if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = input.getDataLength(); for( int i = 0; i < length; i += 2 ) { output.data[i] = input.data[i]; output.data[i+1] = -input.data[i+1]; } } /** *

* Sets every element in the matrix to the specified value.
*
* aij = value *

* * @param a A matrix whose elements are about to be set. Modified. * @param real The real component * @param imaginary The imaginary component */ public static void fill(CD1Matrix64F a, double real, double imaginary) { int N = a.getDataLength(); for (int i = 0; i < N; i += 2) { a.data[i] = real; a.data[i+1] = imaginary; } } /** *

Performs the following operation:
*
* c = a + b
* cij = aij + bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add( CD1Matrix64F a , CD1Matrix64F b , CD1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numCols != c.numCols || a.numRows != c.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = a.getDataLength(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i]+b.data[i]; } } /** *

Performs the following operation:
*
* c = a - b
* cij = aij - bij
*

* *

* Matrix C can be the same instance as Matrix A and/or B. *

* * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void subtract( CD1Matrix64F a , CD1Matrix64F b , CD1Matrix64F c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numCols != c.numCols || a.numRows != c.numRows ) { throw new IllegalArgumentException("The matrices are not all the same dimension."); } final int length = a.getDataLength(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i]-b.data[i]; } } /** *

Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { * aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult(CDenseMatrix64F a, CDenseMatrix64F b, CDenseMatrix64F c) { if( b.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH) { CMatrixMatrixMult.mult_reorder(a, b, c); } else { CMatrixMatrixMult.mult_small(a, b, c); } } /** *

Performs the following operation:
*
* c = α * a * b
*
* cij = α ∑k=1:n { * aik * bkj} *

* * @param realAlpha real component of scaling factor. * @param imgAlpha imaginary component of scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void mult( double realAlpha , double imgAlpha , CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( b.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH ) { CMatrixMatrixMult.mult_reorder(realAlpha,imgAlpha,a,b,c); } else { CMatrixMatrixMult.mult_small(realAlpha,imgAlpha,a,b,c); } } /** *

* Performs the following operation:
*
* c = c + a * b
* cij = cij + ∑k=1:n { aik * bkj} *

* * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { CMatrixMatrixMult.multAdd_reorder(a, b, c); } else { CMatrixMatrixMult.multAdd_small(a,b,c); } } /** *

* Performs the following operation:
*
* c = c + α * a * b
* cij = cij + α * ∑k=1:n { aik * bkj} *

* * @param realAlpha real component of scaling factor. * @param imgAlpha imaginary component of scaling factor. * @param a The left matrix in the multiplication operation. Not modified. * @param b The right matrix in the multiplication operation. Not modified. * @param c Where the results of the operation are stored. Modified. */ public static void multAdd( double realAlpha , double imgAlpha , CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F c ) { if( b.numCols >= EjmlParameters.CMULT_COLUMN_SWITCH ) { CMatrixMatrixMult.multAdd_reorder(realAlpha,imgAlpha,a,b,c); } else { CMatrixMatrixMult.multAdd_small(realAlpha,imgAlpha,a,b,c); } } /** *

Performs an "in-place" transpose.

* *

* For square matrices the transpose is truly in-place and does not require * additional memory. For non-square matrices, internally a temporary matrix is declared and * {@link #transpose(org.ejml.data.CDenseMatrix64F, org.ejml.data.CDenseMatrix64F)} is invoked. *

* * @param mat The matrix that is to be transposed. Modified. */ public static void transpose( CDenseMatrix64F mat ) { if( mat.numCols == mat.numRows ){ CTransposeAlgs.square(mat); } else { CDenseMatrix64F b = new CDenseMatrix64F(mat.numCols,mat.numRows); transpose(mat, b); mat.reshape(b.numRows, b.numCols); mat.set(b); } } /** *

Performs an "in-place" conjugate transpose.

* * @see #transpose(org.ejml.data.CDenseMatrix64F) * * @param mat The matrix that is to be transposed. Modified. */ public static void transposeConjugate( CDenseMatrix64F mat ) { if( mat.numCols == mat.numRows ){ CTransposeAlgs.squareConjugate(mat); } else { CDenseMatrix64F b = new CDenseMatrix64F(mat.numCols,mat.numRows); transposeConjugate(mat, b); mat.reshape(b.numRows, b.numCols); mat.set(b); } } /** *

* Transposes input matrix 'a' and stores the results in output matrix 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'. *

* * @param input The original matrix. Not modified. * @param output Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static CDenseMatrix64F transpose( CDenseMatrix64F input , CDenseMatrix64F output ) { if( output == null ) { output = new CDenseMatrix64F(input.numCols,input.numRows); } else if( input.numCols != output.numRows || input.numRows != output.numCols ) { throw new IllegalArgumentException("Input and output shapes are not compatible"); } CTransposeAlgs.standard(input,output); return output; } /** *

* Conjugate transposes input matrix 'a' and stores the results in output matrix 'b':
*
* b-reali,j = a-realj,i
* b-imaginaryi,j = -1*a-imaginaryj,i
* where 'b' is the transpose of 'a'. *

* * @param input The original matrix. Not modified. * @param output Where the transpose is stored. If null a new matrix is created. Modified. * @return The transposed matrix. */ public static CDenseMatrix64F transposeConjugate( CDenseMatrix64F input , CDenseMatrix64F output ) { if( output == null ) { output = new CDenseMatrix64F(input.numCols,input.numRows); } else if( input.numCols != output.numRows || input.numRows != output.numCols ) { throw new IllegalArgumentException("Input and output shapes are not compatible"); } CTransposeAlgs.standardConjugate(input, output); return output; } /** *

* Performs a matrix inversion operation on the specified matrix and stores the results * in the same matrix.
*
* a = a-1 *

* *

* If the algorithm could not invert the matrix then false is returned. If it returns true * that just means the algorithm finished. The results could still be bad * because the matrix is singular or nearly singular. *

* * @param A The matrix that is to be inverted. Results are stored here. Modified. * @return true if it could invert the matrix false if it could not. */ public static boolean invert( CDenseMatrix64F A ) { LinearSolver solver = CLinearSolverFactory.lu(A.numRows); if( solver.setA(A) ) { solver.invert(A); } else { return false; } return true; } /** *

* Performs a matrix inversion operation that does not modify the original * and stores the results in another matrix. The two matrices must have the * same dimension.
*
* b = a-1 *

* *

* If the algorithm could not invert the matrix then false is returned. If it returns true * that just means the algorithm finished. The results could still be bad * because the matrix is singular or nearly singular. *

* *

* For medium to large matrices there might be a slight performance boost to using * {@link CLinearSolverFactory} instead. *

* * @param input The matrix that is to be inverted. Not modified. * @param output Where the inverse matrix is stored. Modified. * @return true if it could invert the matrix false if it could not. */ public static boolean invert( CDenseMatrix64F input , CDenseMatrix64F output ) { LinearSolver solver = CLinearSolverFactory.lu(input.numRows); if( solver.modifiesA() ) input = input.copy(); if( !solver.setA(input)) return false; solver.invert(output); return true; } /** *

* Solves for x in the following equation:
*
* A*x = b *

* *

* If the system could not be solved then false is returned. If it returns true * that just means the algorithm finished operating, but the results could still be bad * because 'A' is singular or nearly singular. *

* *

* If repeat calls to solve are being made then one should consider using {@link CLinearSolverFactory} * instead. *

* *

* It is ok for 'b' and 'x' to be the same matrix. *

* * @param a A matrix that is m by n. Not modified. * @param b A matrix that is n by k. Not modified. * @param x A matrix that is m by k. Modified. * * @return true if it could invert the matrix false if it could not. */ public static boolean solve( CDenseMatrix64F a , CDenseMatrix64F b , CDenseMatrix64F x ) { LinearSolver solver; if( a.numCols == a.numRows ) { solver = CLinearSolverFactory.lu(a.numRows); } else { solver = CLinearSolverFactory.qr(a.numRows, a.numCols); } // make sure the inputs 'a' and 'b' are not modified solver = new LinearSolverSafe(solver); if( !solver.setA(a) ) return false; solver.solve(b,x); return true; } /** * Returns the determinant of the matrix. If the inverse of the matrix is also * needed, then using {@link LUDecompositionAlt_CD64} directly (or any * similar algorithm) can be more efficient. * * @param mat The matrix whose determinant is to be computed. Not modified. * @return The determinant. */ public static Complex64F det( CDenseMatrix64F mat ) { LUDecompositionAlt_CD64 alg = new LUDecompositionAlt_CD64(); if( alg.inputModified() ) { mat = mat.copy(); } if( !alg.decompose(mat) ) return new Complex64F(); return alg.computeDeterminant(); } /** *

Performs element by element multiplication operation with a complex numbert
*
* outputij = inputij * (real + imaginary*i)
*

* @param input The left matrix in the multiplication operation. Not modified. * @param real Real component of the number it is multiplied by * @param imaginary Imaginary component of the number it is multiplied by * @param output Where the results of the operation are stored. Modified. */ public static void elementMultiply( CD1Matrix64F input , double real , double imaginary, CD1Matrix64F output ) { if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The 'input' and 'output' matrices do not have compatible dimensions"); } int N = input.getDataLength(); for (int i = 0; i < N; i += 2 ) { double inReal = input.data[i]; double intImag = input.data[i+1]; output.data[i] = inReal*real - intImag*imaginary; output.data[i+1] = inReal*imaginary + intImag*real; } } /** *

Performs element by element division operation with a complex number on the right
*
* outputij = inputij / (real + imaginary*i)
*

* @param input The left matrix in the multiplication operation. Not modified. * @param real Real component of the number it is multiplied by * @param imaginary Imaginary component of the number it is multiplied by * @param output Where the results of the operation are stored. Modified. */ public static void elementDivide( CD1Matrix64F input , double real , double imaginary, CD1Matrix64F output ) { if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The 'input' and 'output' matrices do not have compatible dimensions"); } double norm = real*real + imaginary*imaginary; int N = input.getDataLength(); for (int i = 0; i < N; i += 2 ) { double inReal = input.data[i]; double inImag = input.data[i+1]; output.data[i] = (inReal*real + inImag*imaginary)/norm; output.data[i+1] = (inImag*real - inReal*imaginary)/norm; } } /** *

Performs element by element division operation with a complex number on the right
*
* outputij = (real + imaginary*i) / inputij
*

* @param real Real component of the number it is multiplied by * @param imaginary Imaginary component of the number it is multiplied by * @param input The right matrix in the multiplication operation. Not modified. * @param output Where the results of the operation are stored. Modified. */ public static void elementDivide( double real , double imaginary, CD1Matrix64F input , CD1Matrix64F output ) { if( input.numCols != output.numCols || input.numRows != output.numRows ) { throw new IllegalArgumentException("The 'input' and 'output' matrices do not have compatible dimensions"); } int N = input.getDataLength(); for (int i = 0; i < N; i += 2 ) { double inReal = input.data[i]; double inImag = input.data[i+1]; double norm = inReal*inReal + inImag*inImag; output.data[i] = (real*inReal + imaginary*inImag)/norm; output.data[i+1] = (imaginary*inReal - real*inImag)/norm; } } /** *

* Returns the value of the real element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The the minimum value out of all the real values. */ public static double elementMinReal( CD1Matrix64F a ) { final int size = a.getDataLength(); double min = a.data[0]; for( int i = 2; i < size; i += 2 ) { double val = a.data[i]; if( val < min ) { min = val; } } return min; } /** *

* Returns the value of the imaginary element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The the minimum value out of all the real values. */ public static double elementMinImaginary( CD1Matrix64F a ) { final int size = a.getDataLength(); double min = a.data[1]; for( int i = 3; i < size; i += 2 ) { double val = a.data[i]; if( val < min ) { min = val; } } return min; } /** *

* Returns the value of the real element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The the minimum value out of all the real values. */ public static double elementMaxReal( CD1Matrix64F a ) { final int size = a.getDataLength(); double max = a.data[0]; for( int i = 2; i < size; i += 2 ) { double val = a.data[i]; if( val > max ) { max = val; } } return max; } /** *

* Returns the value of the imaginary element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*

* * @param a A matrix. Not modified. * @return The the minimum value out of all the real values. */ public static double elementMaxImaginary( CD1Matrix64F a ) { final int size = a.getDataLength(); double max = a.data[1]; for( int i = 3; i < size; i += 2 ) { double val = a.data[i]; if( val > max ) { max = val; } } return max; } /** *

* Returns the magnitude squared of the complex element with the largest magnitude
*
* Max{ |aij|^2 } for all i and j
*

* * @param a A matrix. Not modified. * @return The max magnitude squared */ public static double elementMaxMagnitude2( CD1Matrix64F a ) { final int size = a.getDataLength(); double max = 0; for( int i = 0; i < size; ) { double real = a.data[i++]; double imaginary = a.data[i++]; double m = real*real + imaginary*imaginary; if( m > max ) { max = m; } } return max; } /** * Sets all the diagonal elements equal to one and everything else equal to zero. * If this is a square matrix then it will be an identity matrix. * * @param mat A square matrix. */ public static void setIdentity( CDenseMatrix64F mat ) { int width = mat.numRows < mat.numCols ? mat.numRows : mat.numCols; Arrays.fill(mat.data,0,mat.getDataLength(),0); int index = 0; int stride = mat.getRowStride(); for( int i = 0; i < width; i++ , index += stride + 2) { mat.data[index] = 1; } } /** *

* Creates a new matrix which is the specified submatrix of 'src' *

*

* si-y0 , j-x0 = oij for all y0 ≤ i < y1 and x0 ≤ j < x1
*
* where 'sij' is an element in the submatrix and 'oij' is an element in the * original matrix. *

* * @param src The original matrix which is to be copied. Not modified. * @param srcX0 Start column. * @param srcX1 Stop column+1. * @param srcY0 Start row. * @param srcY1 Stop row+1. * @return Extracted submatrix. */ public static CDenseMatrix64F extract( CDenseMatrix64F src, int srcY0, int srcY1, int srcX0, int srcX1 ) { if( srcY1 <= srcY0 || srcY0 < 0 || srcY1 > src.numRows ) throw new IllegalArgumentException("srcY1 <= srcY0 || srcY0 < 0 || srcY1 > src.numRows"); if( srcX1 <= srcX0 || srcX0 < 0 || srcX1 > src.numCols ) throw new IllegalArgumentException("srcX1 <= srcX0 || srcX0 < 0 || srcX1 > src.numCols"); int w = srcX1-srcX0; int h = srcY1-srcY0; CDenseMatrix64F dst = new CDenseMatrix64F(h,w); extract(src, srcY0, srcY1, srcX0, srcX1, dst, 0, 0); return dst; } /** *

* Extracts a submatrix from 'src' and inserts it in a submatrix in 'dst'. *

*

* si-y0 , j-x0 = oij for all y0 ≤ i < y1 and x0 ≤ j < x1
*
* where 'sij' is an element in the submatrix and 'oij' is an element in the * original matrix. *

* * @param src The original matrix which is to be copied. Not modified. * @param srcX0 Start column. * @param srcX1 Stop column+1. * @param srcY0 Start row. * @param srcY1 Stop row+1. * @param dst Where the submatrix are stored. Modified. * @param dstY0 Start row in dst. * @param dstX0 start column in dst. */ public static void extract(CDenseMatrix64F src, int srcY0, int srcY1, int srcX0, int srcX1, CDenseMatrix64F dst, int dstY0, int dstX0 ) { int numRows = srcY1 - srcY0; int stride = (srcX1 - srcX0)*2; for( int y = 0; y < numRows; y++ ) { int indexSrc = src.getIndex(y+srcY0,srcX0); int indexDst = dst.getIndex(y+dstY0,dstX0); System.arraycopy(src.data,indexSrc,dst.data,indexDst, stride); } } /** * Converts the columns in a matrix into a set of vectors. * * @param A Matrix. Not modified. * @param v Optional storage for columns. * @return An array of vectors. */ public static CDenseMatrix64F[] columnsToVector(CDenseMatrix64F A, CDenseMatrix64F[] v) { CDenseMatrix64F []ret; if( v == null || v.length < A.numCols ) { ret = new CDenseMatrix64F[ A.numCols ]; } else { ret = v; } for( int i = 0; i < ret.length; i++ ) { if( ret[i] == null ) { ret[i] = new CDenseMatrix64F(A.numRows,1); } else { ret[i].reshape(A.numRows,1); } CDenseMatrix64F u = ret[i]; int indexU = 0; for( int j = 0; j < A.numRows; j++ ) { int indexA = A.getIndex(j,i); u.data[indexU++] = A.data[indexA++]; u.data[indexU++] = A.data[indexA]; } } return ret; } /** *

* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*

* * @param a A matrix. Not modified. * @return The max abs element value of the matrix. */ public static double elementMaxAbs( CDenseMatrix64F a ) { final int size = a.getDataLength(); double max = 0; for( int i = 0; i < size; i += 2 ) { double real = a.data[i]; double imag = a.data[i+1]; double val = real*real + imag*imag; if( val > max ) { max = val; } } return Math.sqrt(max); } } ejml-0.28/main/denseC64/src/org/ejml/ops/CMatrixFeatures.java000066400000000000000000000230631256171534400237240ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.decompose.chol.CholeskyDecompositionInner_CD64; import org.ejml.alg.dense.mult.CVectorVectorMult; import org.ejml.data.CD1Matrix64F; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.data.ComplexMatrix64F; /** *

* Functions for computing the features of complex matrices *

* * @author Peter Abeles */ public class CMatrixFeatures { /** * Checks to see if any element in the matrix is NaN. * * @param m A matrix. Not modified. * @return True if any element in the matrix is NaN. */ public static boolean hasNaN( CD1Matrix64F m ) { int length = m.getDataLength(); for( int i = 0; i < length; i++ ) { if( Double.isNaN(m.data[i])) return true; } return false; } /** * Checks to see if any element in the matrix is NaN of Infinite. * * @param m A matrix. Not modified. * @return True if any element in the matrix is NaN of Infinite. */ public static boolean hasUncountable( CD1Matrix64F m ) { int length = m.getDataLength(); for( int i = 0; i < length; i++ ) { double a = m.data[i]; if( Double.isNaN(a) || Double.isInfinite(a)) return true; } return false; } /** *

* Checks to see if each element in the two matrices are equal: * aij == bij *

* *

* NOTE: If any of the elements are NaN then false is returned. If two corresponding * elements are both positive or negative infinity then they are equal. *

* * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @return true if identical and false otherwise. */ public static boolean isEquals( CD1Matrix64F a, CD1Matrix64F b ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { return false; } final int length = a.getDataLength(); for( int i = 0; i < length; i++ ) { if( !(a.data[i] == b.data[i]) ) { return false; } } return true; } /** *

* Checks to see if each element in the two matrices are within tolerance of * each other: tol ≥ |aij - bij|. *

* *

* NOTE: If any of the elements are not countable then false is returned.
* NOTE: If a tolerance of zero is passed in this is equivalent to calling * {@link #isEquals(org.ejml.data.CD1Matrix64F, org.ejml.data.CD1Matrix64F)} *

* * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @param tol How close to being identical each element needs to be. * @return true if equals and false otherwise. */ public static boolean isEquals( CD1Matrix64F a , CD1Matrix64F b , double tol ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { return false; } if( tol == 0.0 ) return isEquals(a,b); final int length = a.getDataLength(); for( int i = 0; i < length; i++ ) { if( !(tol >= Math.abs(a.data[i] - b.data[i])) ) { return false; } } return true; } /** *

* Checks to see if each corresponding element in the two matrices are * within tolerance of each other or have the some symbolic meaning. This * can handle NaN and Infinite numbers. *

* *

* If both elements are countable then the following equality test is used:
* |aij - bij| ≤ tol.
* Otherwise both numbers must both be Double.NaN, Double.POSITIVE_INFINITY, or * Double.NEGATIVE_INFINITY to be identical. *

* * @param a A matrix. Not modified. * @param b A matrix. Not modified. * @param tol Tolerance for equality. * @return true if identical and false otherwise. */ public static boolean isIdentical( CD1Matrix64F a, CD1Matrix64F b , double tol ) { if( a.numRows != b.numRows || a.numCols != b.numCols ) { return false; } if( tol < 0 ) throw new IllegalArgumentException("Tolerance must be greater than or equal to zero."); final int length = a.getDataLength(); for( int i = 0; i < length; i++ ) { double valA = a.data[i]; double valB = b.data[i]; // if either is negative or positive infinity the result will be positive infinity // if either is NaN the result will be NaN double diff = Math.abs(valA-valB); // diff = NaN == false // diff = infinity == false if( tol >= diff ) continue; if( Double.isNaN(valA) ) { return Double.isNaN(valB); } else if( Double.isInfinite(valA) ) { return valA == valB; } else { return false; } } return true; } /** * Checks to see if the provided matrix is within tolerance to an identity matrix. * * @param mat Matrix being examined. Not modified. * @param tol Tolerance. * @return True if it is within tolerance to an identify matrix. */ public static boolean isIdentity( ComplexMatrix64F mat , double tol ) { // see if the result is an identity matrix Complex64F c = new Complex64F(); for (int i = 0; i < mat.getNumRows(); i++) { for (int j = 0; j < mat.getNumCols(); j++) { mat.get(i, j, c); if (i == j) { if (!(Math.abs(c.real - 1) <= tol)) return false; if (!(Math.abs(c.imaginary) <= tol)) return false; } else { if (!(Math.abs(c.real) <= tol)) return false; if (!(Math.abs(c.imaginary) <= tol)) return false; } } } return true; } /** * Hermitian matrix is a square matrix with complex entries that is equal to its own conjugate transpose. * * @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static boolean isHermitian( CDenseMatrix64F Q , double tol ) { if( Q.numCols != Q.numRows ) return false; Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); for( int i = 0; i < Q.numCols; i++ ) { for( int j = i+1; j < Q.numCols; j++ ) { Q.get(i,j,a); Q.get(j,i,b); if( Math.abs(a.real-b.real)>tol) return false; if( Math.abs(a.imaginary+b.imaginary)>tol) return false; } } return true; } /** *

* Unitary matrices have the following properties:

* Q*QH = I *

*

* This is the complex equivalent of orthogonal matrix. *

* @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static boolean isUnitary( CDenseMatrix64F Q , double tol ) { if( Q.numRows < Q.numCols ) { throw new IllegalArgumentException("The number of rows must be more than or equal to the number of columns"); } Complex64F prod = new Complex64F(); CDenseMatrix64F u[] = CCommonOps.columnsToVector(Q, null); for( int i = 0; i < u.length; i++ ) { CDenseMatrix64F a = u[i]; CVectorVectorMult.innerProdH(a, a, prod); if( Math.abs(prod.real-1) > tol) return false; if( Math.abs(prod.imaginary) > tol) return false; for( int j = i+1; j < u.length; j++ ) { CVectorVectorMult.innerProdH(a, u[j], prod); if( !(prod.getMagnitude2() <= tol*tol)) return false; } } return true; } /** *

* Checks to see if the matrix is positive definite. *

*

* xT A x > 0
* for all x where x is a non-zero vector and A is a hermitian matrix. *

* * @param A square hermitian matrix. Not modified. * * @return True if it is positive definite and false if it is not. */ public static boolean isPositiveDefinite( CDenseMatrix64F A ) { if( A.numCols != A.numRows) return false; CholeskyDecompositionInner_CD64 chol = new CholeskyDecompositionInner_CD64(true); if( chol.inputModified() ) A = A.copy(); return chol.decompose(A); } } ejml-0.28/main/denseC64/src/org/ejml/ops/CNormOps.java000066400000000000000000000033631256171534400223570ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.CDenseMatrix64F; /** * @author Peter Abeles */ public class CNormOps { /** *

* Computes the Frobenius matrix norm:
*
* normF = Sqrt{ ∑i=1:mj=1:n { aij2} } *

*

* This is equivalent to the element wise p=2 norm. See {@link #fastNormF} for another implementation * that is faster, but more prone to underflow/overflow errors. *

* * @param a The matrix whose norm is computed. Not modified. * @return The norm's value. */ public static double normF( CDenseMatrix64F a ) { double total = 0; double scale = CCommonOps.elementMaxAbs(a); if( scale == 0.0 ) return 0.0; final int size = a.getDataLength(); for( int i = 0; i < size; i += 2 ) { double real = a.data[i]/scale; double imag = a.data[i+1]/scale; total += real*real + imag*imag; } return scale*Math.sqrt(total); } } ejml-0.28/main/denseC64/src/org/ejml/ops/CRandomMatrices.java000066400000000000000000000160131256171534400236660ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.CD1Matrix64F; import org.ejml.data.CDenseMatrix64F; import java.util.Random; /** * Contains a list of functions for creating random dense complex matrices and vectors with different structures. * * @author Peter Abeles */ public class CRandomMatrices { /** *

* Returns a matrix where all the elements are selected independently from * a uniform distribution between -1 and 1 inclusive. *

* * @param numRow Number of rows in the new matrix. * @param numCol Number of columns in the new matrix. * @param rand Random number generator used to fill the matrix. * @return The randomly generated matrix. */ public static CDenseMatrix64F createRandom( int numRow , int numCol , Random rand ) { return createRandom(numRow,numCol,-1,1,rand); } /** *

* Returns a matrix where all the elements are selected independently from * a uniform distribution between 'min' and 'max' inclusive. *

* * @param numRow Number of rows in the new matrix. * @param numCol Number of columns in the new matrix. * @param min The minimum value each element can be. * @param max The maximum value each element can be. * @param rand Random number generator used to fill the matrix. * @return The randomly generated matrix. */ public static CDenseMatrix64F createRandom( int numRow , int numCol , double min , double max , Random rand ) { CDenseMatrix64F mat = new CDenseMatrix64F(numRow,numCol); setRandom(mat,min,max,rand); return mat; } /** *

* Sets each element in the matrix to a value drawn from an uniform distribution from 0 to 1 inclusive. *

* * @param mat The matrix who is to be randomized. Modified. * @param rand Random number generator used to fill the matrix. */ public static void setRandom( CDenseMatrix64F mat , Random rand ) { setRandom(mat,0,1,rand); } /** *

* Sets each element in the matrix to a value drawn from an uniform distribution from 'min' to 'max' inclusive. *

* * @param min The minimum value each element can be. * @param max The maximum value each element can be. * @param mat The matrix who is to be randomized. Modified. * @param rand Random number generator used to fill the matrix. */ public static void setRandom( CD1Matrix64F mat , double min , double max , Random rand ) { double d[] = mat.getData(); int size = mat.getDataLength(); double r = max-min; for( int i = 0; i < size; i++ ) { d[i] = r*rand.nextDouble()+min; } } /** * Creates a random symmetric positive definite matrix. * * @param width The width of the square matrix it returns. * @param rand Random number generator used to make the matrix. * @return The random symmetric positive definite matrix. */ public static CDenseMatrix64F createHermPosDef(int width, Random rand) { // This is not formally proven to work. It just seems to work. CDenseMatrix64F a = CRandomMatrices.createRandom(width,1,rand); CDenseMatrix64F b = new CDenseMatrix64F(1,width); CDenseMatrix64F c = new CDenseMatrix64F(width,width); CCommonOps.transposeConjugate(a,b); CCommonOps.mult(a, b, c); for( int i = 0; i < width; i++ ) { c.data[2*(i*width+i)] += 1; } return c; } /** * Creates a random Hermitian matrix with elements from min to max value. * * @param length Width and height of the matrix. * @param min Minimum value an element can have. * @param max Maximum value an element can have. * @param rand Random number generator. * @return A symmetric matrix. */ public static CDenseMatrix64F createHermitian(int length, double min, double max, Random rand) { CDenseMatrix64F A = new CDenseMatrix64F(length,length); setHermitian(A, min, max, rand); return A; } /** * Assigns the provided square matrix to be a random Hermitian matrix with elements from min to max value. * * @param A The matrix that is to be modified. Must be square. Modified. * @param min Minimum value an element can have. * @param max Maximum value an element can have. * @param rand Random number generator. */ public static void setHermitian(CDenseMatrix64F A, double min, double max, Random rand) { if( A.numRows != A.numCols ) throw new IllegalArgumentException("A must be a square matrix"); double range = max-min; int length = A.numRows; for( int i = 0; i < length; i++ ) { for( int j = i; j < length; j++ ) { double real = rand.nextDouble()*range + min; double imaginary = rand.nextDouble()*range + min; A.set(i,j,real,imaginary); A.set(j,i,real,-imaginary); } } } // /** // * Creates an upper triangular matrix whose values are selected from a uniform distribution. If hessenberg // * is greater than zero then a hessenberg matrix of the specified degree is created instead. // * // * @param dimen Number of rows and columns in the matrix.. // * @param hessenberg 0 for triangular matrix and > 0 for hessenberg matrix. // * @param min minimum value an element can be. // * @param max maximum value an element can be. // * @param rand random number generator used. // * @return The randomly generated matrix. // */ // public static CDenseMatrix64F createUpperTriangle( int dimen , int hessenberg , double min , double max , Random rand ) // { // if( hessenberg < 0 ) // throw new RuntimeException("hessenberg must be more than or equal to 0"); // // double range = max-min; // // CDenseMatrix64F A = new CDenseMatrix64F(dimen,dimen); // // for( int i = 0; i < dimen; i++ ) { // int start = i <= hessenberg ? 0 : i-hessenberg; // // for( int j = start; j < dimen; j++ ) { // double real = rand.nextDouble()*range + min; // double imaginary = rand.nextDouble()*range + min; // // A.set(i,j, real, imaginary); // } // // } // // return A; // } } ejml-0.28/main/denseC64/src/org/ejml/ops/CSpecializedOps.java000066400000000000000000000133701256171534400236770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.CVectorVectorMult; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; /** * @author Peter Abeles */ public class CSpecializedOps { /** *

* Creates a pivot matrix that exchanges the rows in a matrix: *
* A' = P*A
*

*

* For example, if element 0 in 'pivots' is 2 then the first row in A' will be the 3rd row in A. *

* * @param ret If null then a new matrix is declared otherwise the results are written to it. Is modified. * @param pivots Specifies the new order of rows in a matrix. * @param numPivots How many elements in pivots are being used. * @param transposed If the transpose of the matrix is returned. * @return A pivot matrix. */ public static CDenseMatrix64F pivotMatrix(CDenseMatrix64F ret, int pivots[], int numPivots, boolean transposed ) { if( ret == null ) { ret = new CDenseMatrix64F(numPivots, numPivots); } else { if( ret.numCols != numPivots || ret.numRows != numPivots ) throw new IllegalArgumentException("Unexpected matrix dimension"); CCommonOps.fill(ret, 0,0); } if( transposed ) { for( int i = 0; i < numPivots; i++ ) { ret.set(pivots[i],i,1,0); } } else { for( int i = 0; i < numPivots; i++ ) { ret.set(i,pivots[i],1,0); } } return ret; } /** *

* Returns the magnitude squared of the complex element along the diagonal with the largest magnitude
*
* Max{ |aij|^2 } for all i and j
*

* * @param a A matrix. Not modified. * @return The max magnitude squared */ public static double elementDiagMaxMagnitude2(CDenseMatrix64F a) { final int size = Math.min(a.numRows,a.numCols); int rowStride = a.getRowStride(); double max = 0; for( int i = 0; i < size; i++ ) { int index = i*rowStride + i*2; double real = a.data[index]; double imaginary = a.data[index+1]; double m = real*real + imaginary*imaginary; if( m > max ) { max = m; } } return max; } /** * Computes the quality of a triangular matrix, where the quality of a matrix * is defined in {@link org.ejml.interfaces.linsol.LinearSolver#quality()}. In * this situation the quality is the magnitude of the product of * each diagonal element divided by the magnitude of the largest diagonal element. * If all diagonal elements are zero then zero is returned. * * @return the quality of the system. */ public static double qualityTriangular(CDenseMatrix64F T) { int N = Math.min(T.numRows,T.numCols); double max = elementDiagMaxMagnitude2(T); if( max == 0.0d ) return 0.0d; max = Math.sqrt(max); int rowStride = T.getRowStride(); double qualityR = 1.0; double qualityI = 0.0; for( int i = 0; i < N; i++ ) { int index = i*rowStride + i*2; double real = T.data[index]/max; double imaginary = T.data[index]/max; double r = qualityR*real - qualityI*imaginary; double img = qualityR*imaginary + real*qualityI; qualityR = r; qualityI = img; } return Math.sqrt(qualityR*qualityR + qualityI*qualityI); } /** * Q = I - gamma*u*uH */ public static CDenseMatrix64F householder( CDenseMatrix64F u , double gamma ) { int N = u.getDataLength()/2; // u*u^H CDenseMatrix64F uut = new CDenseMatrix64F(N,N); CVectorVectorMult.outerProdH(u, u, uut); // foo = -gamma*u*u^H CCommonOps.elementMultiply(uut,-gamma,0,uut); // I + foo for (int i = 0; i < N; i++) { int index = (i*uut.numCols+i)*2; uut.data[index] = 1 + uut.data[index]; } return uut; } /** * Computes the householder vector used in QR decomposition. * * u = x / max(x) * u(0) = u(0) + |u| * u = u / u(0) * * @param x Input vector. Unmodified. * @return The found householder reflector vector */ public static CDenseMatrix64F householderVector( CDenseMatrix64F x ) { CDenseMatrix64F u = x.copy(); double max = CCommonOps.elementMaxAbs(u); CCommonOps.elementDivide(u, max, 0, u); double nx = CNormOps.normF(u); Complex64F c = new Complex64F(); u.get(0,0,c); double realTau,imagTau; if( c.getMagnitude() == 0 ) { realTau = nx; imagTau = 0; } else { realTau = c.real/c.getMagnitude()*nx; imagTau = c.imaginary/c.getMagnitude()*nx; } u.set(0,0,c.real + realTau,c.imaginary + imagTau); CCommonOps.elementDivide(u,u.getReal(0,0),u.getImaginary(0,0),u); return u; } } ejml-0.28/main/denseC64/test/000077500000000000000000000000001256171534400156605ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/000077500000000000000000000000001256171534400164475ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/000077500000000000000000000000001256171534400173765ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/000077500000000000000000000000001256171534400201415ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/000077500000000000000000000000001256171534400212375ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/000077500000000000000000000000001256171534400232155ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/CheckDecompositionInterface_CD64.java000066400000000000000000000031201256171534400321670ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.DecompositionInterface; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class CheckDecompositionInterface_CD64 { /** * Checks to see if the matrix is or is not modified as according to the modified * flag. * * @param decomp */ public static void checkModifiedInput( DecompositionInterface decomp ) { CDenseMatrix64F A = CRandomMatrices.createHermPosDef(4, new Random(0x434)); CDenseMatrix64F A_orig = A.copy(); assertTrue(decomp.decompose(A)); boolean modified = !CMatrixFeatures.isEquals(A, A_orig); assertTrue(modified+" "+decomp.inputModified(),decomp.inputModified()==modified); } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/TestCTriangularSolver.java000066400000000000000000000062531256171534400303340ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose; import org.ejml.data.CDenseMatrix64F; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCTriangularSolver { Random rand = new Random(234); @Test public void solveU() { CDenseMatrix64F U = CRandomMatrices.createRandom(3, 3, -1 ,1 ,rand); for( int i = 0; i < U.numRows; i++ ) { for( int j = 0; j < i; j++ ) { U.set(i,j,0,0); } } CDenseMatrix64F X = CRandomMatrices.createRandom(3, 1, -1 ,1 ,rand); CDenseMatrix64F B = new CDenseMatrix64F(3,1); CCommonOps.mult(U, X, B); CTriangularSolver.solveU(U.data,B.data,3); assertTrue(CMatrixFeatures.isIdentical(X, B, 1e-8)); } @Test public void solveL_diagReal() { for( int N = 1; N <= 4; N++ ) { CDenseMatrix64F L = createLowerTriangleDiagReal(N); CDenseMatrix64F X = CRandomMatrices.createRandom(N, 1, -1, 1, rand); CDenseMatrix64F B = new CDenseMatrix64F(N, 1); CCommonOps.mult(L, X, B); CTriangularSolver.solveL_diagReal(L.data, B.data, N); assertTrue(CMatrixFeatures.isIdentical(X, B, 1e-8)); } } /** * Creates a random complex lower triangular matrix with real diagonal elements */ private CDenseMatrix64F createLowerTriangleDiagReal(int n) { CDenseMatrix64F L = CRandomMatrices.createRandom(n, n, -1, 1, rand); for (int i = 0; i < L.numRows; i++) { for (int j = i + 1; j < L.numCols; j++) { L.set(i, j, 0, 0); } } for (int i = 0; i < L.numRows; i++) { L.data[(i*L.numRows+i)*2+1] = 0; } return L; } @Test public void solveConjTranL_diagReal() { for( int N = 1; N <= 4; N++ ) { CDenseMatrix64F L = createLowerTriangleDiagReal(N); CDenseMatrix64F L_ct = new CDenseMatrix64F(N, N); CCommonOps.transposeConjugate(L,L_ct); CDenseMatrix64F X = CRandomMatrices.createRandom(N, 1, -1, 1, rand); CDenseMatrix64F B = new CDenseMatrix64F(N, 1); CCommonOps.mult(L_ct, X, B); CTriangularSolver.solveConjTranL_diagReal(L.data, B.data, N); assertTrue(CMatrixFeatures.isIdentical(X, B, 1e-8)); } } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/chol/000077500000000000000000000000001256171534400241425ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/chol/GenericCholeskyTests_CD64.java000066400000000000000000000107111256171534400316260ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.chol; import org.ejml.alg.dense.decompose.CheckDecompositionInterface_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.factory.CDecompositionFactory; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ // TODO Handle special case of 1x1 matrix public abstract class GenericCholeskyTests_CD64 { Random rand = new Random(0x45478); boolean canL = true; boolean canR = true; public abstract CholeskyDecomposition create( boolean lower ); @Test public void checkModifyInput() { CheckDecompositionInterface_CD64.checkModifiedInput(create(true)); CheckDecompositionInterface_CD64.checkModifiedInput(create(false)); } /** * If it is not positive definate it should fail */ @Test public void testNotPositiveDefinite() { CDenseMatrix64F A = new CDenseMatrix64F(2, 2, true, 1, 0, -1, 0, -1, 0, -2, 0); CholeskyDecomposition alg = create(true); assertFalse(alg.decompose(A)); } /** * Test across several different matrix sizes and upper/lower decompositions using * the definition of cholesky. */ @Test public void checkWithDefinition() { for( int i = 0; i < 2; i++ ) { boolean lower = i == 0; if( lower && !canL ) continue; if( !lower && !canR ) continue; for( int size = 1; size < 10; size++ ) { checkWithDefinition(lower, size); } } } private void checkWithDefinition(boolean lower, int size) { CDenseMatrix64F A = CRandomMatrices.createHermPosDef(size, rand); CholeskyDecomposition cholesky = create(lower); assertTrue(CDecompositionFactory.decomposeSafe(cholesky, A)); CDenseMatrix64F T = cholesky.getT(null); CDenseMatrix64F T_trans = new CDenseMatrix64F(size,size); CCommonOps.transposeConjugate(T, T_trans); CDenseMatrix64F found = new CDenseMatrix64F(size,size); if( lower ) { CCommonOps.mult(T,T_trans,found); } else { CCommonOps.mult(T_trans,T,found); } assertTrue(CMatrixFeatures.isIdentical(A, found, 1e-8)); } @Test public void checkDeterminant() { for( int i = 0; i < 2; i++ ) { boolean lower = i == 0; if( lower && !canL ) continue; if( !lower && !canR ) continue; for( int size = 2; size < 20; size += 2 ) { checkDeterminant(lower, size); } } } public void checkDeterminant( boolean lower , int size ) { LUDecomposition lu = CDecompositionFactory.lu(size,size); CholeskyDecomposition cholesky = create(lower); CDenseMatrix64F A = CRandomMatrices.createHermPosDef(size, rand); assertTrue(CDecompositionFactory.decomposeSafe(lu,A)); assertTrue(CDecompositionFactory.decomposeSafe(cholesky,A)); Complex64F expected = lu.computeDeterminant(); Complex64F found = cholesky.computeDeterminant(); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } @Test public void failZeros() { CDenseMatrix64F A = new CDenseMatrix64F(3,3); assertFalse(create(true).decompose(A)); assertFalse(create(false).decompose(A)); } } TestCholeskyDecompositionCommon_CD64.java000066400000000000000000000042251256171534400340000ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/chol/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.chol; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCholeskyDecompositionCommon_CD64 { Random rand = new Random(234); int N = 6; /** * The correctness of getT(null) has been tested else where effectively. This * checks to see if it handles the case where an input is provided correctly. */ @Test public void getT() { CDenseMatrix64F A = CRandomMatrices.createHermPosDef(N, rand); CholeskyDecomposition cholesky = new Dummy(true); CDenseMatrix64F L_null = cholesky.getT(null); CDenseMatrix64F L_provided = CRandomMatrices.createRandom(N, N, rand); assertTrue( L_provided == cholesky.getT(L_provided)); assertTrue(CMatrixFeatures.isEquals(L_null, L_provided)); } private class Dummy extends CholeskyDecompositionCommon_CD64 { public Dummy(boolean lower) { super(lower); T = CRandomMatrices.createRandom(N,N,rand); n = N; } @Override protected boolean decomposeLower() { return true; } @Override protected boolean decomposeUpper() { return true; } } }TestCholeskyDecompositionInner_CD64.java000066400000000000000000000021271256171534400336220ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/chol/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.chol; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.CholeskyDecomposition; /** * @author Peter Abeles */ public class TestCholeskyDecompositionInner_CD64 extends GenericCholeskyTests_CD64 { @Override public CholeskyDecomposition create(boolean lower) { return new CholeskyDecompositionInner_CD64(lower); } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/lu/000077500000000000000000000000001256171534400236355ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/lu/GeneralLuDecompositionChecks_CD64.java000066400000000000000000000146451256171534400327660ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.lu; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public abstract class GeneralLuDecompositionChecks_CD64 { Random rand = new Random(0xff); public abstract LUDecomposition create( int numRows , int numCols ); @Test public void testModifiedInput() { CDenseMatrix64F A = CRandomMatrices.createRandom(4, 4, -1, 1, rand); CDenseMatrix64F A_orig = A.copy(); LUDecomposition alg = create(4,4); assertTrue(alg.decompose(A)); boolean modified = !CMatrixFeatures.isEquals(A,A_orig); assertEquals(modified, alg.inputModified()); } @Test public void testAllReal() { CDenseMatrix64F A = new CDenseMatrix64F(3,3, true, 5,0, 2,0, 3,0, 1.5,0, -2,0, 8,0, -3,0, 4.7,0, -0.5,0); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A.copy())); assertFalse(alg.isSingular()); CDenseMatrix64F L = alg.getLower(null); CDenseMatrix64F U = alg.getUpper(null); CDenseMatrix64F P = alg.getPivot(null); CDenseMatrix64F P_tran = new CDenseMatrix64F(P.numCols,P.numRows); CDenseMatrix64F PL = new CDenseMatrix64F(P.numRows,P.numCols); CDenseMatrix64F A_found = new CDenseMatrix64F(A.numRows,A.numCols); CCommonOps.transpose(P,P_tran); CCommonOps.mult(P_tran, L, PL); CCommonOps.mult(PL, U, A_found); assertTrue(CMatrixFeatures.isIdentical(A_found,A,1e-8)); } @Test public void testDecomposition_square_real() { for( int i = 2; i <= 20; i++ ) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,i,-1,1,rand); for (int j = 1; j < A.getDataLength(); j += 2) { A.data[j] = 0; } checkDecomposition(A); } } @Test public void testDecomposition_square_imaginary() { for( int i = 2; i <= 20; i++ ) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,i,-1,1,rand); for (int j = 0; j < A.getDataLength(); j += 2) { A.data[j] = 0; } checkDecomposition(A); } } @Test public void testDecomposition_square() { for( int i = 2; i <= 20; i++ ) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,i,-1,1,rand); checkDecomposition(A); } } @Test public void testFat() { CDenseMatrix64F A = CRandomMatrices.createRandom(2,3,-1,1,rand); checkDecomposition(A); } @Test public void testTall() { CDenseMatrix64F A = CRandomMatrices.createRandom(3,2,rand); checkDecomposition(A); } @Test public void zeroMatrix() { CDenseMatrix64F A = new CDenseMatrix64F(3,3); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A)); assertTrue(alg.isSingular()); CDenseMatrix64F L = alg.getLower(null); CDenseMatrix64F U = alg.getUpper(null); CDenseMatrix64F A_found = new CDenseMatrix64F(3,3); CCommonOps.mult(L, U, A_found); assertFalse(CMatrixFeatures.hasUncountable(A_found)); assertTrue(CMatrixFeatures.isIdentical(A_found,A,1e-8)); } @Test public void testSingular(){ CDenseMatrix64F A = new CDenseMatrix64F(3,3, true, 1,1, 2,2, 3,3, 2,2, 4,4, 6,6, 4,4, 4,4, 0,0); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A)); assertTrue(alg.isSingular()); } @Test public void testNearlySingular(){ CDenseMatrix64F A = new CDenseMatrix64F(3,3, true, 1,1, 2,2, 3,3, 2,2, 4,4, 6.1,6.1, 4,4, 4,4, 0,0); LUDecomposition alg = create(3,3); assertTrue(alg.decompose(A)); assertFalse(alg.isSingular()); } /** * Checks to see how it handles getLower getUpper functions with and without * a matrix being provided. */ @Test public void getLower_getUpper() { CDenseMatrix64F A = CRandomMatrices.createRandom(3,3,rand); LUDecomposition alg = create(3,3); alg.decompose(A); CDenseMatrix64F L_provided = CRandomMatrices.createRandom(3,3,rand); CDenseMatrix64F U_provided = CRandomMatrices.createRandom(3,3,rand); assertTrue(L_provided == alg.getLower(L_provided)); assertTrue(U_provided == alg.getUpper(U_provided)); CDenseMatrix64F L_ret = alg.getLower(null); CDenseMatrix64F U_ret = alg.getUpper(null); assertTrue(CMatrixFeatures.isEquals(L_provided,L_ret)); assertTrue(CMatrixFeatures.isEquals(U_provided,U_ret)); } private void checkDecomposition(CDenseMatrix64F a) { LUDecomposition alg = create(a.numRows, a.numCols); assertTrue(alg.decompose(a.copy())); if( a.numRows <= a.numCols) assertFalse(alg.isSingular()); CDenseMatrix64F L = alg.getLower(null); CDenseMatrix64F U = alg.getUpper(null); CDenseMatrix64F P = alg.getPivot(null); CDenseMatrix64F P_tran = new CDenseMatrix64F(P.numCols,P.numRows); CDenseMatrix64F PL = new CDenseMatrix64F(P_tran.numRows,L.numCols); CDenseMatrix64F A_found = new CDenseMatrix64F(a.numRows, a.numCols); CCommonOps.transpose(P, P_tran); CCommonOps.mult(P_tran, L, PL); CCommonOps.mult(PL, U, A_found); assertTrue(CMatrixFeatures.isIdentical(A_found, a, 1e-8)); } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/lu/TestLUDecompositionAlt_CD64.java000066400000000000000000000017351256171534400316040ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.lu; /** * @author Peter Abeles */ public class TestLUDecompositionAlt_CD64 extends GeneralLuDecompositionChecks_CD64 { @Override public LUDecompositionBase_CD64 create(int numRows, int numCols) { return new LUDecompositionAlt_CD64(); } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/lu/TestLUDecompositionBase_CD64.java000066400000000000000000000116611256171534400317350ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.lu; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.ops.CCommonOps; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.ComplexMath64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestLUDecompositionBase_CD64 { Random rand = new Random(0x3344); /** * Compare the determinant computed from LU to the value computed from the minor * matrix method. */ @Test public void testDeterminant() { Random rand = new Random(0xfff); int width = 10; CDenseMatrix64F LU = CRandomMatrices.createRandom(width,width,-1,1,rand); Complex64F expected = new Complex64F(1,0); Complex64F a = new Complex64F(); Complex64F tmp = new Complex64F(); for (int i = 0; i < width; i++) { LU.get(i, i, a); ComplexMath64F.multiply(expected,a,tmp); expected.set(tmp); } DebugDecompose alg = new DebugDecompose(width); alg.decomposeCommonInit(LU); for( int i = 0; i < width; i++ ) alg.getIndx()[i] = i; alg.setLU(LU); Complex64F found = alg.computeDeterminant(); assertEquals(expected.real,found.real,1e-6); assertEquals(expected.imaginary,found.imaginary,1e-6); } @Test public void _solveVectorInternal() { int width = 10; CDenseMatrix64F LU = CRandomMatrices.createRandom(width, width,-1,1, rand); CDenseMatrix64F L = new CDenseMatrix64F(width,width); CDenseMatrix64F U = new CDenseMatrix64F(width,width); for (int i = 0; i < width; i++) { for (int j = 0; j < width; j++) { double real = LU.getReal(i,j); double imag = LU.getImaginary(i, j); if( j <= i ) { if( j == i ) L.set(i,j,1,0); else L.set(i,j,real,imag); } if( i <= j ) { U.set(i,j,real,imag); } } } CDenseMatrix64F x = CRandomMatrices.createRandom(width, 1,-1,1, rand); CDenseMatrix64F tmp = new CDenseMatrix64F(width,1); CDenseMatrix64F b = new CDenseMatrix64F(width,1); CCommonOps.mult(U, x, tmp); CCommonOps.mult(L, tmp, b); DebugDecompose alg = new DebugDecompose(width); alg.decomposeCommonInit(LU); for( int i = 0; i < width; i++ ) alg.getIndx()[i] = i; alg.setLU(LU); alg._solveVectorInternal(b.data); for( int i = 0; i < width; i++ ) { assertEquals(x.data[i],b.data[i],1e-6); } } @Test public void solveL() { int width = 10; CDenseMatrix64F LU = CRandomMatrices.createRandom(width, width,-1,1, rand); CDenseMatrix64F L = new CDenseMatrix64F(width,width); for (int i = 0; i < width; i++) { for (int j = 0; j < width; j++) { double real = LU.getReal(i,j); double imag = LU.getImaginary(i, j); if( j <= i ) { if( j == i ) L.set(i,j,1,0); else L.set(i,j,real,imag); } } } CDenseMatrix64F x = CRandomMatrices.createRandom(width, 1,-1,1, rand); CDenseMatrix64F b = new CDenseMatrix64F(width,1); CCommonOps.mult(L, x, b); DebugDecompose alg = new DebugDecompose(width); alg.decomposeCommonInit(LU); for( int i = 0; i < width; i++ ) alg.getIndx()[i] = i; alg.setLU(LU); alg.solveL(b.data); for( int i = 0; i < width; i++ ) { assertEquals(x.data[i],b.data[i],1e-6); } } private static class DebugDecompose extends LUDecompositionBase_CD64 { public DebugDecompose(int width) { setExpectedMaxSize(width, width); m = n = width; } void setLU( CDenseMatrix64F LU ) { this.LU = LU; this.dataLU = LU.data; } @Override public boolean decompose(CDenseMatrix64F orig) { return false; } } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/qr/000077500000000000000000000000001256171534400236375ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/qr/GenericQrCheck_CD64.java000066400000000000000000000161541256171534400300460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public abstract class GenericQrCheck_CD64 { Random rand = new Random(0xff); abstract protected QRDecomposition createQRDecomposition(); @Test public void testModifiedInput() { QRDecomposition alg = createQRDecomposition(); CDenseMatrix64F A = CRandomMatrices.createRandom(6, 4, rand); CDenseMatrix64F A_orig = A.copy(); assertTrue(alg.decompose(A)); boolean modified = !CMatrixFeatures.isEquals(A,A_orig); assertTrue(modified + " " + alg.inputModified(), alg.inputModified() == modified); } /** * See if it correctly decomposes a square, tall, or wide matrix. */ @Test public void decompositionShape() { checkDecomposition(5, 5 ,false); checkDecomposition(10, 5,false); checkDecomposition(5, 10,false); checkDecomposition(5, 5 ,true); checkDecomposition(10, 5,true); checkDecomposition(5, 10,true); } private void checkDecomposition(int height, int width, boolean compact ) { QRDecomposition alg = createQRDecomposition(); CDenseMatrix64F A = CRandomMatrices.createRandom(height,width,rand); assertTrue(alg.decompose(A.copy())); int minStride = Math.min(height,width); CDenseMatrix64F Q = new CDenseMatrix64F(height,compact ? minStride : height); alg.getQ(Q, compact); CDenseMatrix64F R = new CDenseMatrix64F(compact ? minStride : height,width); alg.getR(R, compact); // see if Q has the expected properties assertTrue(CMatrixFeatures.isUnitary(Q, 1e-6)); // see if it has the expected properties CDenseMatrix64F A_found = new CDenseMatrix64F(Q.numRows,R.numCols); CCommonOps.mult(Q,R,A_found); EjmlUnitTests.assertEquals(A,A_found,1e-6); CDenseMatrix64F R_found = new CDenseMatrix64F(R.numRows,R.numCols); CCommonOps.transposeConjugate(Q); CCommonOps.mult(Q, A, R_found); } /** * Test a pathological case for computing tau */ @Test public void checkZeroInFirstElement() { int width = 4,height = 5; QRDecomposition alg = createQRDecomposition(); CDenseMatrix64F A = CRandomMatrices.createRandom(height,width,rand); // cause the pathological situation A.set(0,0,0,0); assertTrue(alg.decompose(A.copy())); CDenseMatrix64F Q = new CDenseMatrix64F(height,height); alg.getQ(Q, false); CDenseMatrix64F R = new CDenseMatrix64F(height,width); alg.getR(R, false); // see if Q has the expected properties assertTrue(CMatrixFeatures.isUnitary(Q, 1e-6)); // see if it has the expected properties CDenseMatrix64F A_found = new CDenseMatrix64F(Q.numRows,R.numCols); CCommonOps.mult(Q,R,A_found); EjmlUnitTests.assertEquals(A,A_found,1e-6); CDenseMatrix64F R_found = new CDenseMatrix64F(R.numRows,R.numCols); CCommonOps.transposeConjugate(Q); CCommonOps.mult(Q, A, R_found); } /** * See if passing in a matrix or not providing one to getQ and getR functions * has the same result */ @Test public void checkGetNullVersusNot() { int width = 5; int height = 10; QRDecomposition alg = createQRDecomposition(); CDenseMatrix64F A = CRandomMatrices.createRandom(height,width,rand); alg.decompose(A); // get the results from a provided matrix CDenseMatrix64F Q_provided = CRandomMatrices.createRandom(height,height,rand); CDenseMatrix64F R_provided = CRandomMatrices.createRandom(height,width,rand); assertTrue(R_provided == alg.getR(R_provided, false)); assertTrue(Q_provided == alg.getQ(Q_provided, false)); // get the results when no matrix is provided CDenseMatrix64F Q_null = alg.getQ(null, false); CDenseMatrix64F R_null = alg.getR(null,false); // see if they are the same assertTrue(CMatrixFeatures.isEquals(Q_provided,Q_null)); assertTrue(CMatrixFeatures.isEquals(R_provided,R_null)); } /** * Depending on if setZero being true or not the size of the R matrix changes */ @Test public void checkGetRInputSize() { int width = 5; int height = 10; QRDecomposition alg = createQRDecomposition(); CDenseMatrix64F A = CRandomMatrices.createRandom(height,width,rand); alg.decompose(A); // check the case where it creates the matrix first assertTrue(alg.getR(null,true).numRows == width); assertTrue(alg.getR(null,false).numRows == height); // check the case where a matrix is provided alg.getR(new CDenseMatrix64F(width,width),true); alg.getR(new CDenseMatrix64F(height,width),false); // check some negative cases try { alg.getR(new CDenseMatrix64F(height,width),true); fail("Should have thrown an exception"); } catch( IllegalArgumentException e ) {} try { alg.getR(new CDenseMatrix64F(width-1,width),false); fail("Should have thrown an exception"); } catch( IllegalArgumentException e ) {} } /** * See if the compact format for Q works */ @Test public void checkCompactFormat() { int height = 10; int width = 5; QRDecomposition alg = createQRDecomposition(); CDenseMatrix64F A = CRandomMatrices.createRandom(height,width,rand); alg.decompose(A); CDenseMatrix64F Q = new CDenseMatrix64F(height,width); alg.getQ(Q, true); // see if Q has the expected properties assertEquals(height,Q.numRows); assertEquals(width,Q.numCols); assertTrue(CMatrixFeatures.isUnitary(Q,1e-6)); // try to extract it with the wrong dimensions Q = new CDenseMatrix64F(height,height); try { alg.getQ(Q, true); fail("Didn't fail"); } catch( RuntimeException e ) {} } } TestQRDecompositionHouseholderColumn_CD64.java000066400000000000000000000126671256171534400344560ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.CSpecializedOps; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRDecompositionHouseholderColumn_CD64 extends GenericQrCheck_CD64 { Random rand = new Random(0xff); @Override protected QRDecomposition createQRDecomposition() { return new QRDecompositionHouseholderColumn_CD64(); } /** * Internal several householder operations are performed. This * checks to see if the householder operations and the expected result for all the * submatrices. */ @Test public void householder() { int width = 5; for( int i = 0; i < width; i++ ) { checkSubHouse(i , width); } } private void checkSubHouse(int w , int width) { DebugQR qr = new DebugQR(width,width); CDenseMatrix64F A = CRandomMatrices.createRandom(width,width,rand); qr.householder(w,A); CDenseMatrix64F U = new CDenseMatrix64F(width-w,1); System.arraycopy(qr.dataQR[w],w*2,U.data,0,(width-w)*2); // it already wrote over the first element with tau. Make it 1 + 0i again U.set(0,0,1,0); // Q = I - gamma*u*u' CDenseMatrix64F Q = CSpecializedOps.householder(U,qr.getGamma()); // check the expected properties of Q assertTrue(CMatrixFeatures.isHermitian(Q, 1e-6)); assertTrue(CMatrixFeatures.isUnitary(Q, 1e-6)); CDenseMatrix64F result = new CDenseMatrix64F(Q.numRows,Q.numCols); CDenseMatrix64F Asub = CCommonOps.extract(A, w, width, w, width); CCommonOps.mult(Q, Asub, result); Complex64F a = new Complex64F(); result.get(0,0,a); assertEquals(-qr.tau.real, a.real, 1e-8); assertEquals(-qr.tau.imaginary,a.imaginary,1e-8); for( int i = 1; i < result.numRows; i++ ) { result.get(i,0,a); assertEquals(0, a.getMagnitude2(),1e-5); } } /** * Check the results of this function against basic matrix operations * which are equivalent. */ @Test public void updateA() { int width = 5; for( int i = 0; i < width; i++ ) checkSubMatrix(width,i); } private void checkSubMatrix(int width , int w ) { DebugQR qr = new DebugQR(width,width); double gamma = 0.2; CDenseMatrix64F A = CRandomMatrices.createRandom(width,width,rand); qr.convertToColumnMajor(A); // compute the results using standard matrix operations CDenseMatrix64F u_sub = CCommonOps.extract(A, w, width, w, w+1); CDenseMatrix64F A_sub = CCommonOps.extract(A, w, width, w, width); CDenseMatrix64F expected = new CDenseMatrix64F(u_sub.numRows,u_sub.numRows); // Q = I - gamma*u*u' u_sub.set(0,0,1,0); CDenseMatrix64F Q = CSpecializedOps.householder(u_sub,gamma); CCommonOps.mult(Q,A_sub,expected); qr.updateA(w,gamma); double[][] found = qr.getQR(); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); for( int i = w; i < width; i++ ) { A.get(i,w,a); b.set(found[w][i*2],found[w][i*2+1]); assertEquals(a.real, b.real, 1e-8); assertEquals(a.imaginary,b.imaginary,1e-8); } // the right should be the same for( int i = w; i < width; i++ ) { for( int j = w+1; j < width; j++ ) { expected.get(i-w,j-w,a); b.set(found[j][i*2],found[j][i*2+1]); // found.get(i,j,b); assertEquals(a.real, b.real, 1e-6); assertEquals(a.imaginary,b.imaginary,1e-6); } } } private static class DebugQR extends QRDecompositionHouseholderColumn_CD64 { public DebugQR( int numRows , int numCols ) { setExpectedMaxSize(numRows,numCols); this.numCols = numCols; this.numRows = numRows; } public void householder( int j , CDenseMatrix64F A ) { convertToColumnMajor(A); super.householder(j); } protected void convertToColumnMajor(CDenseMatrix64F A) { super.convertToColumnMajor(A); } public void updateA( int w , double gamma ) { this.gamma = gamma; super.updateA(w); } public double getGamma() { return gamma; } } }TestQRDecompositionHouseholderTran_CD64.java000066400000000000000000000151231256171534400341130ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.CSpecializedOps; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRDecompositionHouseholderTran_CD64 extends GenericQrCheck_CD64 { Random rand = new Random(0xff); @Override protected QRDecomposition createQRDecomposition() { return new QRDecompositionHouseholderTran_CD64(); } /** * Sees if computing Q explicitly and applying Q produces the same results */ @Test public void applyQ() { CDenseMatrix64F A = CRandomMatrices.createRandom(5, 4, rand); QRDecompositionHouseholderTran_CD64 alg = new QRDecompositionHouseholderTran_CD64(); assertTrue(alg.decompose(A)); CDenseMatrix64F Q = alg.getQ(null,false); CDenseMatrix64F B = CRandomMatrices.createRandom(5,2,rand); CDenseMatrix64F expected = new CDenseMatrix64F(B.numRows,B.numCols); CCommonOps.mult(Q,B,expected); alg.applyQ(B); assertTrue(CMatrixFeatures.isIdentical(expected,B,1e-8)); } /** * Sees if computing Q^H explicitly and applying Q^H produces the same results */ @Test public void applyTranQ() { CDenseMatrix64F A = CRandomMatrices.createRandom(5,4,rand); QRDecompositionHouseholderTran_CD64 alg = new QRDecompositionHouseholderTran_CD64(); assertTrue(alg.decompose(A)); CDenseMatrix64F Q = alg.getQ(null,false); CDenseMatrix64F B = CRandomMatrices.createRandom(5,2,rand); CDenseMatrix64F expected = new CDenseMatrix64F(B.numRows,B.numCols); CCommonOps.transposeConjugate(Q); CCommonOps.mult(Q, B, expected); alg.applyTranQ(B); assertTrue(CMatrixFeatures.isIdentical(expected,B,1e-8)); } /** * A focused check to see if the internal house holder operations are performed correctly. */ @Test public void householder() { int width = 5; for( int i = 0; i < width; i++ ) { checkSubHouse(i , width); } } private void checkSubHouse(int w , int width) { DebugQR qr = new DebugQR(width,width); CDenseMatrix64F A = CRandomMatrices.createRandom(width,width,rand); qr.householder(w,A); CDenseMatrix64F U = qr.getU(w); // Q = I - gamma*u*u' CDenseMatrix64F Q = CSpecializedOps.householder(U,qr.getGamma()); // check the expected properties of Q assertTrue(CMatrixFeatures.isHermitian(Q, 1e-6)); assertTrue(CMatrixFeatures.isUnitary(Q, 1e-6)); CDenseMatrix64F result = new CDenseMatrix64F(Q.numRows,Q.numCols); CDenseMatrix64F Asub = CCommonOps.extract(A, w, width, w, width); CCommonOps.mult(Q, Asub, result); Complex64F a = new Complex64F(); result.get(0,0,a); assertEquals(-qr.tau.real, a.real, 1e-8); assertEquals(-qr.tau.imaginary,a.imaginary,1e-8); for( int i = 1; i < result.numRows; i++ ) { result.get(i,0,a); assertEquals(0, a.getMagnitude2(),1e-5); } } /** * Check the results of this function against basic matrix operations * which are equivalent. */ @Test public void updateA() { int width = 5; for( int i = 0; i < width; i++ ) checkSubMatrix(width,i); } private void checkSubMatrix(int width , int w ) { DebugQR qr = new DebugQR(width,width); double gamma = 0.2; CDenseMatrix64F A = CRandomMatrices.createRandom(width,width,rand); CCommonOps.transpose(A, qr.QR); // compute the results using standard matrix operations CDenseMatrix64F u_sub = CCommonOps.extract(A, w, width, w, w+1); CDenseMatrix64F A_sub = CCommonOps.extract(A, w, width, w, width); CDenseMatrix64F expected = new CDenseMatrix64F(u_sub.numRows,u_sub.numRows); // Q = I - gamma*u*u' u_sub.set(0,0,1,0); CDenseMatrix64F Q = CSpecializedOps.householder(u_sub,gamma); CCommonOps.mult(Q,A_sub,expected); qr.updateA(w,gamma); CDenseMatrix64F found = qr.getQR(); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); for( int i = w; i < width; i++ ) { A.get(i,w,a); found.get(w,i,b); assertEquals(a.real, b.real, 1e-8); assertEquals(a.imaginary,b.imaginary,1e-8); } // the right should be the same for( int i = w; i < width; i++ ) { for( int j = w+1; j < width; j++ ) { expected.get(i-w,j-w,a); found.get(j,i,b); assertEquals(a.real, b.real, 1e-6); assertEquals(a.imaginary,b.imaginary,1e-6); } } } private static class DebugQR extends QRDecompositionHouseholderTran_CD64 { public DebugQR(int numRows, int numCols) { setExpectedMaxSize(numRows,numCols); this.numRows = numRows; this.numCols = numCols; } public void householder( int j , CDenseMatrix64F A ) { CCommonOps.transpose(A, QR); super.householder(j); } public void updateA( int w , double gamma ) { this.gamma = gamma; super.updateA(w); } public CDenseMatrix64F getU( int w ) { CDenseMatrix64F U = new CDenseMatrix64F(numRows-w,1); System.arraycopy(QR.data,(w*numRows+w)*2,U.data,0,(numRows-w)*2); U.set(0,0,1,0); return U; } public double getGamma() { return gamma; } } } TestQRDecompositionHouseholder_CD64.java000066400000000000000000000131721256171534400332700ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.CSpecializedOps; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQRDecompositionHouseholder_CD64 extends GenericQrCheck_CD64 { Random rand = new Random(0xff); @Override protected QRDecomposition createQRDecomposition() { return new QRDecompositionHouseholder_CD64(); } /** * Internally several house holder operations are performed. This * checks to see if the householder operations and the expected result for all the * submatrices. */ @Test public void householder() { int width = 6; for( int i = 0; i < width; i++ ) { checkSubHouse(i, width); } } private void checkSubHouse(int w , int width) { DebugQR qr = new DebugQR(width,width); CDenseMatrix64F A = CRandomMatrices.createRandom(width,width,rand); qr.householder(w,A); CDenseMatrix64F U = new CDenseMatrix64F(width-w,1); System.arraycopy(qr.getU(),w*2,U.data,0,(width-w)*2); // Q = I - gamma*u*u' CDenseMatrix64F Q = CSpecializedOps.householder(U,qr.getGamma()); // check the expected properties of Q assertTrue(CMatrixFeatures.isHermitian(Q, 1e-6)); assertTrue(CMatrixFeatures.isUnitary(Q, 1e-6)); CDenseMatrix64F result = new CDenseMatrix64F(Q.numRows,Q.numCols); CDenseMatrix64F Asub = CCommonOps.extract(A,w,width,w,width); CCommonOps.mult(Q, Asub, result); Complex64F a = new Complex64F(); result.get(0,0,a); assertEquals(-qr.realTau, a.real, 1e-8); assertEquals(-qr.imagTau,a.imaginary,1e-8); for( int i = 1; i < result.numRows; i++ ) { result.get(i,0,a); assertEquals(0, a.getMagnitude2(),1e-5); } } /** * Check the results of this function against basic matrix operations * which are equivalent. */ @Test public void updateA() { int width = 5; for( int i = 0; i < width; i++ ) checkSubMatrix(width,i); } private void checkSubMatrix(int width , int w ) { DebugQR qr = new DebugQR(width,width); double gamma = 0.2; double realTau = 0.75; double imagTau = -0.6; CDenseMatrix64F U = CRandomMatrices.createRandom(width, 1,rand); CDenseMatrix64F A = CRandomMatrices.createRandom(width,width,rand); qr.getQR().set(A); // compute the results using standard matrix operations CDenseMatrix64F u_sub = CCommonOps.extract(U, w, width, 0, 1); CDenseMatrix64F A_sub = CCommonOps.extract(A, w, width, w, width); CDenseMatrix64F expected = new CDenseMatrix64F(u_sub.numRows,u_sub.numRows); // Q = I - gamma*u*u' CDenseMatrix64F Q = CSpecializedOps.householder(u_sub,gamma); CCommonOps.mult(Q,A_sub,expected); qr.updateA(w,U.getData(),gamma,realTau,imagTau); CDenseMatrix64F found = qr.getQR(); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); found.get(w,w,a); assertEquals(-realTau,a.real,1e-8); assertEquals(-imagTau,a.imaginary,1e-8); for( int i = w+1; i < width; i++ ) { U.get(i,0,a); found.get(i,w,b); assertEquals(a.real, b.real, 1e-8); assertEquals(a.imaginary,b.imaginary,1e-8); } // the right should be the same for( int i = w; i < width; i++ ) { for( int j = w+1; j < width; j++ ) { expected.get(i-w,j-w,a); found.get(i,j,b); assertEquals(a.real, b.real, 1e-6); assertEquals(a.imaginary,b.imaginary,1e-6); } } } private static class DebugQR extends QRDecompositionHouseholder_CD64 { public DebugQR(int numRows, int numCols) { setExpectedMaxSize(numRows,numCols); this.numRows = numRows; this.numCols = numCols; } public void householder( int j , CDenseMatrix64F A ) { this.QR.set(A); super.householder(j); } public void updateA( int w , double u[] , double realGamma, double realTau, double imagTau ) { System.arraycopy(u,0,this.u,0,this.u.length); this.realGamma = realGamma; this.realTau = realTau; this.imagTau = imagTau; super.updateA(w); } public double[] getU() { return u; } public double getGamma() { return realGamma; } } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/decompose/qr/TestQrHelperFunctions_CD64.java000066400000000000000000000224471256171534400315060ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.qr; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.ComplexMath64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestQrHelperFunctions_CD64 { Random rand = new Random(234); @Test public void findMax() { double u[] = new double[50]; for (int i = 0; i < u.length; i++) { u[i] = (rand.nextDouble()-0.5)*20; } int offset = 4; int length = 5; double max = 0; for (int i = 0; i < length; i++) { double real = u[i*2+offset*2]; double img = u[i*2+offset*2+1]; if( real*real + img*img > max ) { max = real*real + img*img; } } max = Math.sqrt(max); assertEquals(max,QrHelperFunctions_CD64.findMax(u,offset,length),1e-8); } @Test public void divideElements_startU() { double u[] = new double[12*2]; for (int i = 0; i < u.length; i++ ) { u[i] = (rand.nextDouble()*0.5-1.0)*2; } double found[] = u.clone(); Complex64F A = new Complex64F(rand.nextDouble(),rand.nextDouble()); Complex64F U = new Complex64F(); Complex64F expected = new Complex64F(); int j = 3; int numRows = 8; int startU = 2; QrHelperFunctions_CD64.divideElements(j,numRows,found,startU,A.real,A.imaginary); for (int i = 0; i < 12; i++) { int index = i * 2; if( i >= j+startU && i < numRows+startU ) { U.real = u[index]; U.imaginary = u[index + 1]; ComplexMath64F.divide(U, A, expected); assertEquals(expected.real, found[index], 1e-8); assertEquals(expected.imaginary, found[index + 1], 1e-8); } else { assertEquals(u[index],found[index],1e-8); assertEquals(u[index+1],found[index+1],1e-8); } } } @Test public void computeTauGammaAndDivide() { double u[] = new double[12*2]; for (int i = 0; i < u.length; i++ ) { u[i] = (rand.nextDouble()*0.5-1.0)*2; } double max = 2.0; int j = 2; int numRows = 6; Complex64F expectedTau = new Complex64F(); double expectedGamma = 0; double[] expectedU = u.clone(); for (int i = j; i < numRows; i++) { Complex64F U = new Complex64F(u[i*2],u[i*2+1]); Complex64F div = new Complex64F(); ComplexMath64F.divide(U,new Complex64F(max,0),div); expectedU[i*2] = div.real; expectedU[i*2+1] = div.imaginary; } double normX = 0; for (int i = j; i < numRows; i++) { normX += expectedU[i*2]*expectedU[i*2] + expectedU[i*2+1]*expectedU[i*2+1]; } normX = Math.sqrt(normX); double realX0 = expectedU[j*2]; double imagX0 = expectedU[j*2+1]; double magX0 = Math.sqrt(realX0*realX0 + imagX0*imagX0); expectedTau.real = realX0*normX/magX0; expectedTau.imaginary = imagX0*normX/magX0; double realU0 = realX0 + expectedTau.real; double imagU0 = imagX0 + expectedTau.imaginary; // double normU = 1; Complex64F B = new Complex64F(realU0,imagU0); for (int i = j+1; i < numRows; i++) { Complex64F A = new Complex64F( expectedU[i*2], expectedU[i*2+1]); Complex64F result = new Complex64F(); ComplexMath64F.divide(A,B,result); normU += result.getMagnitude2(); } expectedGamma = 2.0/normU; Complex64F foundTau = new Complex64F(); double[] foundU = u.clone(); double foundGamma = QrHelperFunctions_CD64.computeTauGammaAndDivide(j,numRows,foundU,max,foundTau); for (int i = 0; i < expectedU.length; i++) { assertEquals(expectedU[i],foundU[i],1e-8); } assertEquals(expectedTau.real,foundTau.real,1e-8); assertEquals(expectedTau.imaginary,foundTau.imaginary,1e-8); assertEquals(expectedGamma,foundGamma,1e-8); } @Test public void rank1UpdateMultR() { double u[] = new double[12*2]; double uoff[] = new double[12*2+2]; double subU[] = new double[12*2]; double _temp[] = new double[u.length]; double gamma = 0.6; for (int i = 0; i < u.length; i++) { u[i] = uoff[i+2] = (rand.nextDouble()*0.5-1.0)*2; } for (int i = 1; i < 12; i++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,i,rand); for (int j = 1; j <= i; j += 2) { CDenseMatrix64F subA = CCommonOps.extract(A,A.numRows-j,A.numRows,A.numRows-j,A.numRows); System.arraycopy(u,(A.numRows-j)*2,subU,0,j*2); CDenseMatrix64F expected = rank1UpdateMultR(subA, gamma,subU); CDenseMatrix64F found = A.copy(); QrHelperFunctions_CD64.rank1UpdateMultR(found, uoff, 1, gamma, A.numRows - j, A.numRows - j, A.numRows, _temp); CDenseMatrix64F subFound = CCommonOps.extract(found,A.numRows-j,A.numRows,A.numRows-j,A.numRows); outsideIdentical(A, found, j); assertTrue(CMatrixFeatures.isEquals(expected, subFound, 1e-8)); } } } private CDenseMatrix64F rank1UpdateMultR( CDenseMatrix64F A , double gamma, double u[] ) { CDenseMatrix64F U = new CDenseMatrix64F(A.numCols,1); U.data = u; CDenseMatrix64F Ut = new CDenseMatrix64F(1,A.numCols); CCommonOps.transposeConjugate(U,Ut); CDenseMatrix64F UUt = new CDenseMatrix64F(A.numCols,A.numCols); CCommonOps.mult(gamma,0,U,Ut,UUt); CDenseMatrix64F I = CCommonOps.identity(A.numCols); CDenseMatrix64F inner = new CDenseMatrix64F(A.numCols,A.numCols); CDenseMatrix64F expected = new CDenseMatrix64F(A.numCols,A.numCols); CCommonOps.subtract(I,UUt,inner); CCommonOps.mult(inner,A,expected); return expected; } @Test public void rank1UpdateMultL() { double u[] = new double[12*2]; double subU[] = new double[12*2]; Complex64F gamma = new Complex64F(0.5,-0.2); for (int i = 0; i < u.length; i++) { u[i] = (rand.nextDouble()*0.5-1.0)*2; } for (int i = 1; i < 12; i++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,i,rand); for (int j = 1; j <= i; j += 2) { CDenseMatrix64F subA = CCommonOps.extract(A,A.numRows-j,A.numRows,A.numRows-j,A.numRows); System.arraycopy(u,(A.numRows-j)*2,subU,0,j*2); CDenseMatrix64F expected = rank1UpdateMultL(subA,gamma,subU); CDenseMatrix64F found = A.copy(); QrHelperFunctions_CD64.rank1UpdateMultL(found,u,gamma.real,gamma.imaginary, A.numRows-j,A.numRows-j,A.numRows); CDenseMatrix64F subFound = CCommonOps.extract(found,A.numRows-j,A.numRows,A.numRows-j,A.numRows); outsideIdentical(A, found, j); assertTrue(CMatrixFeatures.isEquals(expected, subFound, 1e-8)); } } } private CDenseMatrix64F rank1UpdateMultL( CDenseMatrix64F A , Complex64F gamma, double u[] ) { CDenseMatrix64F U = new CDenseMatrix64F(A.numCols,1); U.data = u; CDenseMatrix64F Ut = new CDenseMatrix64F(1,A.numCols); CCommonOps.transposeConjugate(U,Ut); CDenseMatrix64F UUt = new CDenseMatrix64F(A.numCols,A.numCols); CCommonOps.mult(gamma.real,gamma.imaginary,U,Ut,UUt); CDenseMatrix64F I = CCommonOps.identity(A.numCols); CDenseMatrix64F inner = new CDenseMatrix64F(A.numCols,A.numCols); CDenseMatrix64F expected = new CDenseMatrix64F(A.numCols,A.numCols); CCommonOps.subtract(I,UUt,inner); CCommonOps.mult(A,inner,expected); return expected; } private void outsideIdentical( CDenseMatrix64F A , CDenseMatrix64F B , int width ) { int outside = A.numRows-width; for (int i = 0; i < A.numRows; i++) { for (int j = 0; j < A.numCols; j++) { if( i < outside || j < outside ) { assertEquals(A.getReal(i,j),B.getReal(i,j),1e-8); assertEquals(A.getImaginary(i, j), B.getImaginary(i,j),1e-8); } } } } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/000077500000000000000000000000001256171534400225375ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/GenericCLinearSolverChecks.java000066400000000000000000000234661256171534400305430ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * Contains a series of tests where it solves equations from a known set problems. * * @author Peter Abeles */ public abstract class GenericCLinearSolverChecks { protected Random rand = new Random(0xff); // by default have everything run protected boolean shouldFailSingular = true; protected boolean shouldWorkRectangle = true; protected double tol = 1e-8; @Test public void solve_dimensionCheck() { CDenseMatrix64F A = CRandomMatrices.createRandom(10, 4, rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); try { CDenseMatrix64F x = CRandomMatrices.createRandom(4,2,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(9,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { CDenseMatrix64F x = CRandomMatrices.createRandom(4,3,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(10,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { CDenseMatrix64F x = CRandomMatrices.createRandom(5,2,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(10,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { CDenseMatrix64F x = CRandomMatrices.createRandom(4,2,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(10,1,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } /** * Checks to see if the modifyA() flag is set correctly */ @Test public void modifiesA() { CDenseMatrix64F A_orig = CRandomMatrices.createRandom(4,4,rand); CDenseMatrix64F A = A_orig.copy(); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); boolean modified = !CMatrixFeatures.isEquals(A_orig,A); assertTrue(modified == solver.modifiesA()); } /** * Checks to see if the modifyB() flag is set correctly */ @Test public void modifiesB() { CDenseMatrix64F A = CRandomMatrices.createRandom(4,4,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); CDenseMatrix64F B = CRandomMatrices.createRandom(4,2,rand); CDenseMatrix64F B_orig = B.copy(); CDenseMatrix64F X = new CDenseMatrix64F(A.numRows,B.numCols); solver.solve(B,X); boolean modified = !CMatrixFeatures.isEquals(B_orig,B); assertTrue(modified == solver.modifiesB()); } /** * See if a matrix that is more singular has a lower quality. */ @Test public void checkQuality() { CDenseMatrix64F A_good = CCommonOps.diag(4,0,3,0,2,0,1,0); CDenseMatrix64F A_bad = CCommonOps.diag(4,0,3,0,2,0,0.1,0); LinearSolver solver = createSafeSolver(A_good); assertTrue(solver.setA(A_good)); double q_good; try { q_good = solver.quality(); } catch( IllegalArgumentException e ) { // quality is not supported return; } assertTrue(solver.setA(A_bad)); double q_bad = solver.quality(); assertTrue(q_bad < q_good); assertEquals(q_bad*10.0,q_good,1e-8); } /** * See if quality is scale invariant */ @Test public void checkQuality_scale() { CDenseMatrix64F A = CCommonOps.diag(4,0,3,0,2,0,10,0); CDenseMatrix64F Asmall = A.copy(); CCommonOps.elementMultiply(Asmall, 0.01, 0, Asmall); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); double q; try { q = solver.quality(); } catch( IllegalArgumentException e ) { // quality is not supported return; } assertTrue(solver.setA(Asmall)); double q_small = solver.quality(); assertEquals(q_small,q,1e-8); } /** * A very easy matrix to decompose */ @Test public void square_trivial() { CDenseMatrix64F A = new CDenseMatrix64F(3,3, true, 5,0, 2,0, 3,0, 1.5,0, -2,0, 8,0, -3,0, 4.7,0, -0.5,0); CDenseMatrix64F b = new CDenseMatrix64F(3,1, true, 18,0, 21.5,0, 4.9000,0); CDenseMatrix64F x = CRandomMatrices.createRandom(3,1,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.solve(b,x); CDenseMatrix64F found = new CDenseMatrix64F(3,1); CCommonOps.mult(A,x,found); CDenseMatrix64F x_expected = new CDenseMatrix64F(3,1, true, 1,0, 2,0, 3,0); EjmlUnitTests.assertEquals(x_expected,x,1e-8); } /** * This test checks to see if it can solve a system that will require some algorithms to * perform a pivot. Pivots can change the data structure and can cause solve to fail if not * handled correctly. */ @Test public void square_pivot() { CDenseMatrix64F A = new CDenseMatrix64F(3,3, true, 0,0, 1,0, 2,0, -2,0, 4,0, 9,0, 0.5,0, 0,0, 5,0); CDenseMatrix64F x_expected = new CDenseMatrix64F(3,1, true, 8,-2, 33,1.6, 15.5,-5.7); CDenseMatrix64F x = CRandomMatrices.createRandom(3,1,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(3,1,rand); CCommonOps.mult(A,x_expected,b); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.solve(b,x); EjmlUnitTests.assertEquals(x_expected,x,1e-8); } @Test public void square_singular() { CDenseMatrix64F A = new CDenseMatrix64F(3,3); LinearSolver solver = createSafeSolver(A); assertTrue(shouldFailSingular == !solver.setA(A)); } /** * Have it solve for the coefficients in a polynomial */ @Test public void rectangular() { if( !shouldWorkRectangle ) { // skip this test return; } double t[] = new double[7*2]; for (int i = 0; i < t.length; i++) { t[i] = rand.nextDouble()*2-1.0; } double vals[] = new double[t.length]; Complex64F a = new Complex64F(1,-1); Complex64F b = new Complex64F(2,-0.4); Complex64F c = new Complex64F(3,0.9); for( int i = 0; i < t.length; i+= 2 ) { Complex64F T = new Complex64F(t[i],t[i+1]); Complex64F result = a.plus( b.times(T) ).plus( c.times(T.times(T))); vals[i] = result.real; vals[i+1] = result.imaginary; } CDenseMatrix64F B = new CDenseMatrix64F(t.length/2,1, true, vals); CDenseMatrix64F A = createPolyA(t,3); CDenseMatrix64F x = CRandomMatrices.createRandom(3,1,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.solve(B,x); assertEquals(a.real, x.getReal(0, 0),tol); assertEquals(a.imaginary,x.getImaginary(0, 0),tol); assertEquals(b.real, x.getReal(1, 0),tol); assertEquals(b.imaginary,x.getImaginary(1, 0),tol); assertEquals(c.real, x.getReal(2, 0),tol); assertEquals(c.imaginary,x.getImaginary(2, 0),tol); } private CDenseMatrix64F createPolyA( double t[] , int dof ) { CDenseMatrix64F A = new CDenseMatrix64F(t.length/2,dof); Complex64F power = new Complex64F(); Complex64F T = new Complex64F(); for( int j = 0; j < A.numRows; j++ ) { T.set(t[j*2],t[j*2+1]); power.set(1,0); for( int i = 0; i < dof; i++ ) { A.set(j,i,power.real,power.imaginary); power = power.times(T); } } return A; } @Test public void inverse() { for (int i = 2; i < 10; i++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,i,rand); CDenseMatrix64F A_inv = CRandomMatrices.createRandom(i,i,rand); LinearSolver solver = createSafeSolver(A); assertTrue(solver.setA(A)); solver.invert(A_inv); CDenseMatrix64F I = CRandomMatrices.createRandom(i,i,rand); CCommonOps.mult(A, A_inv, I); assertTrue(CMatrixFeatures.isIdentity(I,1e-8)); } } protected LinearSolver createSafeSolver( CDenseMatrix64F A ) { return new LinearSolverSafe( createSolver(A)); } protected abstract LinearSolver createSolver( CDenseMatrix64F A ); } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/TestCInvertUsingSolve.java000066400000000000000000000036621256171534400276420ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.decompose.lu.LUDecompositionAlt_CD64; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCInvertUsingSolve { Random rand = new Random(0xff); double tol = 1e-8; /** * See if it can invert a matrix that is known to be invertable. */ @Test public void invert() { CDenseMatrix64F A = new CDenseMatrix64F(3,3, true, 0,0, 1,0, 2,0, -2,0, 4,0, 9,0, 0.5,0, 0,0, 5,0); CDenseMatrix64F A_inv = CRandomMatrices.createRandom(3, 3, rand); LUDecompositionAlt_CD64 decomp = new LUDecompositionAlt_CD64(); LinearSolver solver = new LinearSolverLu_CD64(decomp); solver.setA(A); CInvertUsingSolve.invert(solver,A,A_inv); CDenseMatrix64F I = CRandomMatrices.createRandom(3,3,rand); CCommonOps.mult(A, A_inv, I); assertTrue(CMatrixFeatures.isIdentity(I,tol)); } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/chol/000077500000000000000000000000001256171534400234645ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/chol/BaseCholeskySolveTests_CD64.java000066400000000000000000000130241256171534400314570ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.dense.linsol.LinearSolverSafe; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public abstract class BaseCholeskySolveTests_CD64 { Random rand = new Random(0x45); public void standardTests() { solve_dimensionCheck(); testSolve(); testInvert(); testQuality(); testQuality_scale(); } public abstract LinearSolver createSolver(); public LinearSolver createSafeSolver() { LinearSolver solver = createSolver(); return new LinearSolverSafe(solver); } @Test public void setA_dimensionCheck() { LinearSolver solver = createSafeSolver(); try { CDenseMatrix64F A = CRandomMatrices.createRandom(4, 5, rand); assertTrue(solver.setA(A)); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } @Test public void solve_dimensionCheck() { LinearSolver solver = createSafeSolver(); CDenseMatrix64F A = CRandomMatrices.createHermPosDef(4, rand); assertTrue(solver.setA(A)); try { CDenseMatrix64F x = CRandomMatrices.createRandom(4,3,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(4,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { CDenseMatrix64F x = CRandomMatrices.createRandom(5,2,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(4,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { CDenseMatrix64F x = CRandomMatrices.createRandom(5,2,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(5,2,rand); solver.solve(b,x); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } @Test public void testSolve() { LinearSolver solver = createSolver(); for (int N = 1; N <= 4; N++) { CDenseMatrix64F A = CRandomMatrices.createHermPosDef(N,rand); CDenseMatrix64F x = CRandomMatrices.createRandom(N,1,rand); CDenseMatrix64F b = new CDenseMatrix64F(N,1); CDenseMatrix64F x_expected = x.copy(); CCommonOps.mult(A,x_expected,b); CDenseMatrix64F A_orig = A.copy(); CDenseMatrix64F B_orig = b.copy(); assertTrue(solver.setA(A)); solver.solve(b,x); assertTrue(CMatrixFeatures.isIdentical(x, x_expected, 1e-8)); // see if input was modified assertEquals(!solver.modifiesA(),CMatrixFeatures.isIdentical(A,A_orig,1e-8)); assertEquals(!solver.modifiesB(),CMatrixFeatures.isIdentical(b,B_orig,1e-8)); } } @Test public void testInvert() { LinearSolver solver = createSolver(); for (int N = 1; N <= 5; N++) { CDenseMatrix64F A = CRandomMatrices.createHermPosDef(N,rand); CDenseMatrix64F A_orig = A.copy(); CDenseMatrix64F A_inv = new CDenseMatrix64F(N,N); CDenseMatrix64F found = new CDenseMatrix64F(N,N); assertTrue(solver.setA(A)); solver.invert(A_inv); CCommonOps.mult(A_inv,A_orig,found); assertTrue(CMatrixFeatures.isIdentity(found, 1e-8)); // see if input was modified assertEquals(!solver.modifiesA(),CMatrixFeatures.isIdentical(A,A_orig,1e-8)); } } @Test public void testQuality() { LinearSolver solver = createSafeSolver(); CDenseMatrix64F A = CCommonOps.diag(3,0, 2,0, 1,0 ); CDenseMatrix64F B = CCommonOps.diag(3,0, 2,0, 0.001,0); assertTrue(solver.setA(A)); double qualityA = solver.quality(); assertTrue(solver.setA(B)); double qualityB = solver.quality(); assertTrue(qualityB < qualityA); } @Test public void testQuality_scale() { LinearSolver solver = createSafeSolver(); CDenseMatrix64F A = CCommonOps.diag(3,0 ,2,0 ,1,0); CDenseMatrix64F B = A.copy(); CCommonOps.elementMultiply(B,0.001,0,B); assertTrue(solver.setA(A)); double qualityA = solver.quality(); assertTrue(solver.setA(B)); double qualityB = solver.quality(); assertEquals(qualityB,qualityA,1e-8); } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/chol/TestLinearSolverChol_CD64.java000066400000000000000000000023031256171534400311200ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.chol; import org.ejml.alg.dense.decompose.chol.CholeskyDecompositionInner_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverChol_CD64 extends BaseCholeskySolveTests_CD64 { @Override public LinearSolver createSolver() { CholeskyDecompositionInner_CD64 alg = new CholeskyDecompositionInner_CD64(true); return new LinearSolverChol_CD64(alg); } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/lu/000077500000000000000000000000001256171534400231575ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/lu/TestLinearSolverLu_CD64.java000066400000000000000000000025611256171534400303140ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.lu; import org.ejml.alg.dense.decompose.lu.LUDecompositionAlt_CD64; import org.ejml.alg.dense.linsol.GenericCLinearSolverChecks; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverLu_CD64 extends GenericCLinearSolverChecks { public TestLinearSolverLu_CD64() { shouldWorkRectangle = false; shouldFailSingular = false; } @Override protected LinearSolver createSolver( CDenseMatrix64F A ) { LUDecompositionAlt_CD64 decomp = new LUDecompositionAlt_CD64(); return new LinearSolverLu_CD64(decomp); } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/qr/000077500000000000000000000000001256171534400231615ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQrHouseCol_CD64.java000066400000000000000000000023271256171534400317620ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.GenericCLinearSolverChecks; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQrHouseCol_CD64 extends GenericCLinearSolverChecks { public TestLinearSolverQrHouseCol_CD64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( CDenseMatrix64F A ) { return new LinearSolverQrHouseCol_CD64(); } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQrHouseTran_CD64.java000066400000000000000000000023321256171534400321450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.GenericCLinearSolverChecks; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQrHouseTran_CD64 extends GenericCLinearSolverChecks { public TestLinearSolverQrHouseTran_CD64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( CDenseMatrix64F A ) { return new LinearSolverQrHouseTran_CD64(); } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQrHouse_CD64.java000066400000000000000000000023171256171534400313230ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.linsol.GenericCLinearSolverChecks; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQrHouse_CD64 extends GenericCLinearSolverChecks { public TestLinearSolverQrHouse_CD64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( CDenseMatrix64F A ) { return new LinearSolverQrHouse_CD64(); } } ejml-0.28/main/denseC64/test/org/ejml/alg/dense/linsol/qr/TestLinearSolverQr_CD64.java000066400000000000000000000024701256171534400303170ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol.qr; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholderColumn_CD64; import org.ejml.alg.dense.linsol.GenericCLinearSolverChecks; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; /** * @author Peter Abeles */ public class TestLinearSolverQr_CD64 extends GenericCLinearSolverChecks { public TestLinearSolverQr_CD64() { // shouldFailSingular = false; } @Override protected LinearSolver createSolver( CDenseMatrix64F A ) { return new LinearSolverQr_CD64(new QRDecompositionHouseholderColumn_CD64()); } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400221725ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/misc/TestCTransposeAlgs.java000066400000000000000000000067171256171534400266000ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.ops.CRandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestCTransposeAlgs { Random rand = new Random(234); @Test public void square() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,4,-1,1,rand); CDenseMatrix64F b = a.copy(); CTransposeAlgs.square(b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { a.get(j,i,expected); b.get(i,j,found); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void squareConjugate() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,4,-1,1,rand); CDenseMatrix64F b = a.copy(); CTransposeAlgs.squareConjugate(b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { a.get(j,i,expected); b.get(i,j,found); assertEquals(expected.real,found.real,1e-8); assertEquals(-expected.imaginary,found.imaginary,1e-8); } } } @Test public void standard() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,5,-1,1,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(5, 4, -1, 1, rand); CTransposeAlgs.standard(a, b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) { a.get(i,j,expected); b.get(j,i,found); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void standardConjugate() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,5,-1,1,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(5, 4, -1, 1, rand); CTransposeAlgs.standardConjugate(a, b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) { a.get(i,j,expected); b.get(j,i,found); assertEquals(expected.real,found.real,1e-8); assertEquals(-expected.imaginary,found.imaginary,1e-8); } } } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400222205ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/alg/dense/mult/TestCMatrixMatrixMult.java000066400000000000000000000116241256171534400273250ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.ops.CCommonOps; import org.ejml.ops.CMatrixFeatures; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.ComplexMath64F; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCMatrixMatrixMult { @Test public void generalChecks() { int numChecked = 0; Method methods[] = CMatrixMatrixMult.class.getMethods(); for( Method method : methods ) { String name = method.getName(); // only look at function which perform matrix multiplications if (!name.contains("mult")) continue; // System.out.println(name); Class[] params = method.getParameterTypes(); boolean add = name.contains("Add"); boolean hasAlpha = double.class == params[0]; try { check(method,add,hasAlpha); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } numChecked++; } assertEquals(8,numChecked); } public static void check( Method method , boolean isAdd , boolean hasAlpha ) throws InvocationTargetException, IllegalAccessException { Random rand = new Random(234); double realAlpha = 2.3; double imgAlpha = 1.3; for (int i = 1; i <= 4; i++) { for (int j = 1; j <= 4; j++) { for (int k = 1; k <= 4; k++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,j,-1,1,rand); CDenseMatrix64F B = CRandomMatrices.createRandom(j,k,-1,1,rand); CDenseMatrix64F C = CRandomMatrices.createRandom(i,k,-1,1,rand); CDenseMatrix64F AB = multiply(A,B); CDenseMatrix64F expected = new CDenseMatrix64F(i,k); if( hasAlpha ) { CCommonOps.elementMultiply(AB,realAlpha,imgAlpha,AB); } if( isAdd ) { CCommonOps.add(C,AB,expected); } else { expected.set(AB); } invoke(method,realAlpha,imgAlpha,A,B,C); assertTrue(i+" "+j+" "+k,CMatrixFeatures.isEquals(expected,C,1e-8)); } } } } public static void invoke(Method func, double realAlpha, double imgAlpha, CDenseMatrix64F a, CDenseMatrix64F b, CDenseMatrix64F c) throws IllegalAccessException, InvocationTargetException { if( func.getParameterTypes().length == 3 ) { func.invoke(null, a, b, c); } else { if( func.getParameterTypes()[0] == double.class ) { if( func.getParameterTypes().length == 5 ) func.invoke(null,realAlpha, imgAlpha, a, b, c); else func.invoke(null,realAlpha, imgAlpha, a, b, c,null); } else { func.invoke(null, a, b, c,null); } } } public static CDenseMatrix64F multiply( CDenseMatrix64F A , CDenseMatrix64F B ) { CDenseMatrix64F C = new CDenseMatrix64F(A.numRows,B.numCols); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); Complex64F m = new Complex64F(); for (int i = 0; i < A.numRows; i++) { for (int j = 0; j < B.numCols; j++) { Complex64F sum = new Complex64F(); for (int k = 0; k < A.numCols; k++) { A.get(i,k,a); B.get(k,j,b); ComplexMath64F.multiply(a,b,m); sum.real += m.real; sum.imaginary += m.imaginary; } C.set(i,j,sum.real,sum.imaginary); } } return C; } }ejml-0.28/main/denseC64/test/org/ejml/alg/dense/mult/TestCVectorVectorMult.java000066400000000000000000000056501256171534400273230ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.ops.CCommonOps; import org.ejml.ops.CRandomMatrices; import org.ejml.ops.EjmlUnitTests; import org.junit.Test; import java.util.Random; /** * @author Peter Abeles */ public class TestCVectorVectorMult { Random rand = new Random(234); @Test public void innerProd() { CDenseMatrix64F a = CRandomMatrices.createRandom(1,6,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(6,1,rand); CDenseMatrix64F c = new CDenseMatrix64F(1,1); CCommonOps.mult(a,b,c); Complex64F expected = new Complex64F(); c.get(0,0,expected); Complex64F found = CVectorVectorMult.innerProd(a,b,null); EjmlUnitTests.assertEquals(expected,found,1e-8); } @Test public void innerProdH() { CDenseMatrix64F a = CRandomMatrices.createRandom(1,6,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(6,1,rand); Complex64F found = CVectorVectorMult.innerProdH(a, b, null); CDenseMatrix64F c = new CDenseMatrix64F(1,1); CCommonOps.conjugate(b,b); CCommonOps.mult(a,b,c); Complex64F expected = new Complex64F(); c.get(0,0,expected); EjmlUnitTests.assertEquals(expected,found,1e-8); } @Test public void outerProd() { CDenseMatrix64F a = CRandomMatrices.createRandom(6,1,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(1,6,rand); CDenseMatrix64F expected = new CDenseMatrix64F(6,6); CDenseMatrix64F found = new CDenseMatrix64F(6,6); CCommonOps.mult(a,b,expected); CVectorVectorMult.outerProd(a,b,found); EjmlUnitTests.assertEquals(expected,found,1e-8); } @Test public void outerProdH() { CDenseMatrix64F a = CRandomMatrices.createRandom(6,1,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(1,6,rand); CDenseMatrix64F expected = new CDenseMatrix64F(6,6); CDenseMatrix64F found = new CDenseMatrix64F(6,6); CVectorVectorMult.outerProdH(a, b, found); CCommonOps.conjugate(b,b); CCommonOps.mult(a, b, expected); EjmlUnitTests.assertEquals(expected,found,1e-8); } }ejml-0.28/main/denseC64/test/org/ejml/ops/000077500000000000000000000000001256171534400201775ustar00rootroot00000000000000ejml-0.28/main/denseC64/test/org/ejml/ops/TestCCommonOps.java000066400000000000000000000520601256171534400237220ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.CMatrixMatrixMult; import org.ejml.alg.dense.mult.TestCMatrixMatrixMult; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCCommonOps { Random rand = new Random(234); @Test public void identity_one() { CDenseMatrix64F I = CCommonOps.identity(4); assertEquals(4,I.numRows); assertEquals(4,I.numCols); assertTrue(CMatrixFeatures.isIdentity(I,1e-8)); } @Test public void identity_two() { CDenseMatrix64F I = CCommonOps.identity(4,5); assertEquals(4,I.numRows); assertEquals(5,I.numCols); assertTrue(CMatrixFeatures.isIdentity(I,1e-8)); I = CCommonOps.identity(5,4); assertEquals(5,I.numRows); assertEquals(4,I.numCols); assertTrue(CMatrixFeatures.isIdentity(I,1e-8)); } @Test public void diag() { CDenseMatrix64F m = CCommonOps.diag(1,2,3,4,5,6); assertEquals(3,m.numRows); assertEquals(3,m.numCols); Complex64F a = new Complex64F(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { m.get(i,j,a); if( i == j ) { assertEquals(2*i+1,a.real,1e-8); assertEquals(2*i+2,a.imaginary,1e-8); } else { assertEquals(0,a.real,1e-8); assertEquals(0,a.imaginary,1e-8); } } } } @Test public void convert() { DenseMatrix64F input = RandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F output = new CDenseMatrix64F(5,7); Complex64F a = new Complex64F(); CCommonOps.convert(input, output); for (int i = 0; i < input.numRows; i++) { for (int j = 0; j < input.numCols; j++) { output.get(i,j,a); assertEquals(input.get(i,j),a.getReal(),1e-8); assertEquals(0,a.getImaginary(),1e-8); } } } @Test public void stripReal() { CDenseMatrix64F input = CRandomMatrices.createRandom(5,7,-1,1,rand); DenseMatrix64F output = new DenseMatrix64F(5,7); Complex64F a = new Complex64F(); CCommonOps.stripReal(input, output); for (int i = 0; i < input.numRows; i++) { for (int j = 0; j < input.numCols; j++) { input.get(i,j,a); assertEquals(a.getReal(),output.get(i,j),1e-8); } } } @Test public void stripImaginary() { CDenseMatrix64F input = CRandomMatrices.createRandom(5,7,-1,1,rand); DenseMatrix64F output = new DenseMatrix64F(5,7); Complex64F a = new Complex64F(); CCommonOps.stripImaginary(input, output); for (int i = 0; i < input.numRows; i++) { for (int j = 0; j < input.numCols; j++) { input.get(i,j,a); assertEquals(a.getImaginary(),output.get(i,j),1e-8); } } } @Test public void magnitude() { CDenseMatrix64F input = CRandomMatrices.createRandom(5,7,-1,1,rand); DenseMatrix64F output = new DenseMatrix64F(5,7); Complex64F a = new Complex64F(); CCommonOps.magnitude(input, output); for (int i = 0; i < input.numRows; i++) { for (int j = 0; j < input.numCols; j++) { input.get(i,j,a); assertEquals(a.getMagnitude(),output.get(i,j),1e-8); } } } @Test public void conjugate() { CDenseMatrix64F matrix = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F found = CRandomMatrices.createRandom(5,7,-1,1,rand); CCommonOps.conjugate(matrix,found); for (int i = 0; i < matrix.getDataLength(); i += 2) { double real = matrix.data[i]; double img = matrix.data[i+1]; assertEquals(real, found.data[i],1e-8); assertEquals(img, -found.data[i+1],1e-8); } } @Test public void fill() { CDenseMatrix64F matrix = CRandomMatrices.createRandom(5,7,-1,1,rand); CCommonOps.fill(matrix,2,-1); for (int i = 0; i < matrix.getDataLength(); i += 2) { double real = matrix.data[i]; double img = matrix.data[i+1]; assertEquals(2,real,1e-8); assertEquals(-1,img,1e-8); } } @Test public void add() { CDenseMatrix64F matrixA = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F matrixB = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F out = CRandomMatrices.createRandom(5,7,-1,1,rand); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); CCommonOps.add(matrixA, matrixB, out); for (int i = 0; i < matrixA.numRows; i++) { for (int j = 0; j < matrixA.numCols; j++) { matrixA.get(i,j,a); matrixB.get(i,j,b); out.get(i,j,found); ComplexMath64F.plus(a, b, expected); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void subtract() { CDenseMatrix64F matrixA = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F matrixB = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F out = CRandomMatrices.createRandom(5,7,-1,1,rand); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); CCommonOps.subtract(matrixA, matrixB, out); for (int i = 0; i < matrixA.numRows; i++) { for (int j = 0; j < matrixA.numCols; j++) { matrixA.get(i,j,a); matrixB.get(i,j,b); out.get(i,j,found); ComplexMath64F.minus(a, b, expected); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } /** * Make sure the multiplication methods here have the same behavior as the ones in MatrixMatrixMult. */ @Test public void checkAllMatrixMult() { int numChecked = 0; Method methods[] = CCommonOps.class.getMethods(); for (Method method : methods) { String name = method.getName(); if( !name.startsWith("mult")) continue; // System.out.println(name); Class[] params = method.getParameterTypes(); boolean add = name.contains("Add"); boolean hasAlpha = double.class == params[0]; try { TestCMatrixMatrixMult.check(method, add, hasAlpha); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } numChecked++; } assertEquals(4,numChecked); } @Test public void multiply() { for (int i = 1; i < 10; i++) { for (int j = 1; j < 10; j++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,j,-1,1,rand); for (int k = 1; k < 10; k++) { CDenseMatrix64F B = CRandomMatrices.createRandom(j, k, -1, 1, rand); CDenseMatrix64F found = CRandomMatrices.createRandom(i, k, -1, 1, rand); CDenseMatrix64F expected = TestCMatrixMatrixMult.multiply(A, B); CMatrixMatrixMult.mult_reorder(A, B, found); assertTrue(i+" "+j+" "+k,CMatrixFeatures.isEquals(expected, found, 1e-8)); } } } } @Test public void transpose_one() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,4,-1,1,rand); CDenseMatrix64F b = a.copy(); CCommonOps.transpose(b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { a.get(i,j,expected); b.get(j,i,found); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void transposeConjugate_one() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,4,-1,1,rand); CDenseMatrix64F b = a.copy(); CCommonOps.transposeConjugate(b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { a.get(i,j,expected); b.get(j,i,found); assertEquals(expected.real,found.real,1e-8); assertEquals(-expected.imaginary,found.imaginary,1e-8); } } } @Test public void transpose_two() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,5,-1,1,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(5,4,-1,1,rand); CCommonOps.transpose(a, b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) { a.get(i,j,expected); b.get(j,i,found); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void transposeConjugate_two() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,5,-1,1,rand); CDenseMatrix64F b = CRandomMatrices.createRandom(5,4,-1,1,rand); CCommonOps.transposeConjugate(a, b); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) { a.get(i,j,expected); b.get(j,i,found); assertEquals(expected.real,found.real,1e-8); assertEquals(-expected.imaginary,found.imaginary,1e-8); } } } @Test public void invert_1() { for (int i = 1; i < 10; i++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i,i,rand); CDenseMatrix64F A_orig = A.copy(); CDenseMatrix64F I = CRandomMatrices.createRandom(i,i,rand); assertTrue(CCommonOps.invert(A)); CCommonOps.mult(A_orig,A,I); assertTrue(CMatrixFeatures.isIdentity(I, 1e-8)); } } @Test public void invert_2() { for (int i = 1; i < 10; i++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i, i, rand); CDenseMatrix64F A_orig = A.copy(); CDenseMatrix64F A_inv = new CDenseMatrix64F(i, i); CDenseMatrix64F I = CRandomMatrices.createRandom(i, i, rand); assertTrue(CCommonOps.invert(A, A_inv)); CCommonOps.mult(A, A_inv, I); assertTrue(CMatrixFeatures.isIdentity(I, 1e-8)); assertTrue(CMatrixFeatures.isIdentical(A, A_orig, 0)); } } @Test public void solve() { // square for (int i = 1; i < 10; i++) { CDenseMatrix64F A = CRandomMatrices.createRandom(i, i, rand); CDenseMatrix64F B = CRandomMatrices.createRandom(i, 1, rand); CDenseMatrix64F A_orig = A.copy(); CDenseMatrix64F B_orig = B.copy(); CDenseMatrix64F X = new CDenseMatrix64F(i, 1); assertTrue(CCommonOps.solve(A, B, X)); CDenseMatrix64F found = new CDenseMatrix64F(i, 1); CCommonOps.mult(A, X, found); assertTrue(CMatrixFeatures.isIdentical(B, found, 1e-8)); assertTrue(CMatrixFeatures.isIdentical(A, A_orig, 0)); assertTrue(CMatrixFeatures.isIdentical(B, B_orig, 0)); } // rectangular for (int i = 1; i < 10; i++) { CDenseMatrix64F A = CRandomMatrices.createRandom(2*i, i, rand); CDenseMatrix64F X = CRandomMatrices.createRandom(i, 1, rand); CDenseMatrix64F B = new CDenseMatrix64F(2*i,1); CCommonOps.mult(A,X,B); CDenseMatrix64F A_orig = A.copy(); CDenseMatrix64F B_orig = B.copy(); CDenseMatrix64F X_expected = X.copy(); assertTrue(CCommonOps.solve(A, B, X)); assertTrue(CMatrixFeatures.isIdentical(X, X_expected, 1e-8)); assertTrue(CMatrixFeatures.isIdentical(B, B_orig, 0)); assertTrue(CMatrixFeatures.isIdentical(A, A_orig, 0)); } } @Test public void det() { CDenseMatrix64F A = new CDenseMatrix64F(3,3,true, 0.854634 , 0.445620, 0.082836 , 0.212460 , 0.623783 , 0.037631, 0.585408 , 0.768956 , 0.771067 , 0.897763 , 0.125793 , 0.432187, 0.303789 , 0.044497 , 0.151182 , 0.034471 , 0.526770 , 0.570333); CDenseMatrix64F A_orig = A.copy(); Complex64F found = CCommonOps.det(A); // from octave Complex64F expected = new Complex64F(-0.40548 , 0.54188); assertEquals(expected.real,found.real,1e-3); assertEquals(expected.imaginary,found.imaginary,1e-3); assertTrue(CMatrixFeatures.isIdentical(A,A_orig,0)); } @Test public void elementMultiply() { CDenseMatrix64F in = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F out = CRandomMatrices.createRandom(5,7,-1,1,rand); Complex64F a = new Complex64F(1.2,-0.3); Complex64F b = new Complex64F(); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); CCommonOps.elementMultiply(in,a.real,a.imaginary,out); for (int i = 0; i < in.numRows; i++) { for (int j = 0; j < in.numCols; j++) { in.get(i,j,b); out.get(i,j,found); ComplexMath64F.multiply(a,b,expected); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void elementDivide_right() { CDenseMatrix64F in = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F out = CRandomMatrices.createRandom(5,7,-1,1,rand); Complex64F a = new Complex64F(); Complex64F b = new Complex64F(1.2,-0.3); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); CCommonOps.elementDivide(in,b.real,b.imaginary,out); for (int i = 0; i < in.numRows; i++) { for (int j = 0; j < in.numCols; j++) { in.get(i,j,a); out.get(i,j,found); ComplexMath64F.divide(a,b,expected); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void elementDivide_left() { CDenseMatrix64F in = CRandomMatrices.createRandom(5,7,-1,1,rand); CDenseMatrix64F out = CRandomMatrices.createRandom(5,7,-1,1,rand); Complex64F a = new Complex64F(1.2,-0.3); Complex64F b = new Complex64F(); Complex64F found = new Complex64F(); Complex64F expected = new Complex64F(); CCommonOps.elementDivide(a.real,a.imaginary,in,out); for (int i = 0; i < in.numRows; i++) { for (int j = 0; j < in.numCols; j++) { in.get(i,j,b); out.get(i,j,found); ComplexMath64F.divide(a,b,expected); assertEquals(expected.real,found.real,1e-8); assertEquals(expected.imaginary,found.imaginary,1e-8); } } } @Test public void elementMinReal() { CDenseMatrix64F m = new CDenseMatrix64F(3,4); for (int i = 0; i < m.data.length; i++) { m.data[i] = -6 + i; } assertEquals(-6, CCommonOps.elementMinReal(m),1e-8); } @Test public void elementMinImaginary() { CDenseMatrix64F m = new CDenseMatrix64F(3,4); for (int i = 0; i < m.data.length; i++) { m.data[i] = -6 + i; } assertEquals(-5, CCommonOps.elementMinImaginary(m), 1e-8); } @Test public void elementMaxReal() { CDenseMatrix64F m = new CDenseMatrix64F(3,4); for (int i = 0; i < m.data.length; i++) { m.data[i] = -6 + i; } assertEquals(-6 + 11 * 2, CCommonOps.elementMaxReal(m), 1e-8); } @Test public void elementMaxImaginary() { CDenseMatrix64F m = new CDenseMatrix64F(3,4); for (int i = 0; i < m.data.length; i++) { m.data[i] = -6 + i; } assertEquals(-5 + 11 * 2, CCommonOps.elementMaxImaginary(m), 1e-8); } @Test public void elementMaxMagnitude2() { CDenseMatrix64F m = CRandomMatrices.createRandom(4,5,-2,2,rand); DenseMatrix64F a = new DenseMatrix64F(m.numRows,m.numCols); CCommonOps.magnitude(m,a); double expected = CommonOps.elementMaxAbs(a); expected *= expected; double found = CCommonOps.elementMaxMagnitude2(m); assertEquals(expected,found,1e-8); } @Test public void setIdentity() { CDenseMatrix64F a = CRandomMatrices.createRandom(4,5,-2,2,rand); CCommonOps.setIdentity(a); Complex64F c = new Complex64F(); for (int i = 0; i < a.numRows; i++) { for (int j = 0; j < a.numCols; j++) { a.get(i,j,c); if( i == j ) { assertEquals(1,c.real,1e-8); assertEquals(0,c.imaginary,1e-8); } else { assertEquals(0,c.real,1e-8); assertEquals(0,c.imaginary,1e-8); } } } } @Test public void extract_simplified() { CDenseMatrix64F a = CRandomMatrices.createRandom(10,12,-2,2,rand); CDenseMatrix64F b = CCommonOps.extract(a,2,5,3,8); Complex64F ca = new Complex64F(); Complex64F cb = new Complex64F(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { a.get(2+i,j+3,ca); b.get( i,j , cb); assertEquals(ca.real,cb.real,1e-8); assertEquals(ca.imaginary,cb.imaginary,1e-8); } } } @Test public void extract_complex() { CDenseMatrix64F a = CRandomMatrices.createRandom(10,12,-2,2,rand); CDenseMatrix64F b = new CDenseMatrix64F(6,7); Complex64F ca = new Complex64F(); Complex64F cb = new Complex64F(); CCommonOps.extract(a,2,5,3,7,b,1,2); for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { a.get(2+i,j+3,ca); b.get(1 + i, j + 2, cb); assertEquals(ca.real,cb.real,1e-8); assertEquals(ca.imaginary,cb.imaginary,1e-8); } } } @Test public void columnsToVector() { CDenseMatrix64F a = CRandomMatrices.createRandom(10,12,-2,2,rand); CDenseMatrix64F v[] = CCommonOps.columnsToVector(a,null); Complex64F ca = new Complex64F(); Complex64F cc = new Complex64F(); for (int i = 0; i < a.numCols; i++) { CDenseMatrix64F c = v[i]; assertEquals(c.numRows,a.numRows); assertEquals(1,c.numCols); for (int j = 0; j < a.numRows; j++) { a.get(j,i,ca); c.get(j,0,cc); EjmlUnitTests.assertEquals(ca,cc,1e-8); } } } @Test public void elementMaxAbs() { CDenseMatrix64F a = CRandomMatrices.createRandom(10,12,-2,2,rand); a.set(5,6,10,12); double expected = Math.sqrt(10*10 + 12*12); double found = CCommonOps.elementMaxAbs(a); assertEquals(expected,found,1e-8); } }ejml-0.28/main/denseC64/test/org/ejml/ops/TestCMatrixFeatures.java000066400000000000000000000143071256171534400247550ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.CVectorVectorMult; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestCMatrixFeatures { Random rand = new Random(234); @Test public void hasUncountable() { CDenseMatrix64F a = new CDenseMatrix64F(4,4); // check a negative case first assertFalse(CMatrixFeatures.hasUncountable(a)); // check two positve cases with different types of uncountables a.set(2,2,Double.NaN,0); assertTrue(CMatrixFeatures.hasUncountable(a)); a.set(2,2,Double.POSITIVE_INFINITY,0); assertTrue(CMatrixFeatures.hasUncountable(a)); } @Test public void hasNaN() { CDenseMatrix64F m = new CDenseMatrix64F(3,3); assertFalse(CMatrixFeatures.hasNaN(m)); m.set(1,2,-Double.NaN,0); assertTrue(CMatrixFeatures.hasNaN(m)); } @Test public void isEquals() { CDenseMatrix64F m = CRandomMatrices.createRandom(3,4,-1,1,rand); CDenseMatrix64F n = m.copy(); assertTrue(CMatrixFeatures.isEquals(m,n)); n.set(2,1,-0.5,-0.6); assertFalse(CMatrixFeatures.isEquals(m,n)); m.set(2,1,Double.NaN,1); n.set(2,1,Double.NaN,1); assertFalse(CMatrixFeatures.isEquals(m,n)); m.set(2,1,Double.POSITIVE_INFINITY,1); n.set(2,1,Double.POSITIVE_INFINITY,1); assertTrue(CMatrixFeatures.isEquals(m,n)); } @Test public void isEquals_tol() { CDenseMatrix64F m = CRandomMatrices.createRandom(3,4,-1,1,rand); CDenseMatrix64F n = m.copy(); assertTrue(CMatrixFeatures.isEquals(m,n,1e-6)); n.data[4] += 1e-25; assertTrue(CMatrixFeatures.isEquals(m,n,1e-6)); n.data[4] += 1e-2; assertFalse(CMatrixFeatures.isEquals(m,n,1e-6)); m.set(2,1,Double.NaN,1); n.set(2,1,Double.NaN,1); assertFalse(CMatrixFeatures.isEquals(m,n,1e-6)); m.set(2,1,Double.POSITIVE_INFINITY,1); n.set(2,1,Double.POSITIVE_INFINITY,1); assertFalse(CMatrixFeatures.isEquals(m,n,1e-6)); } @Test public void isIdentical() { double values[] = new double[]{1.0,Double.NaN,Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY}; for( int i = 0; i < values.length; i++ ) { for( int j = 0; j < values.length; j++ ) { checkIdentical(values[i],values[j],1e-8,i==j); } } checkIdentical(1.0,1.5,1e-8,false); checkIdentical(1.5,1.0,1e-8,false); checkIdentical(1.0,1.0000000001,1e-8,true); checkIdentical(1.0,Double.NaN,1e-8,false); checkIdentical(Double.NaN,1.0,1e-8,false); } private void checkIdentical( double valA , double valB , double tol , boolean expected ) { CDenseMatrix64F A = new CDenseMatrix64F(2,2); CDenseMatrix64F B = new CDenseMatrix64F(2,2); CCommonOps.fill(A, valA,0); CCommonOps.fill(B, valB,0); assertEquals(expected,CMatrixFeatures.isIdentical(A,B,tol)); CCommonOps.fill(A, 0,valA); CCommonOps.fill(B, 0,valB); assertEquals(expected,CMatrixFeatures.isIdentical(A,B,tol)); } @Test public void isIdentity() { CDenseMatrix64F m = CCommonOps.diag(1,0,1,0,1,0); assertTrue(CMatrixFeatures.isIdentity(m,1e-8)); m.setImaginary(0,0,1e-12); assertTrue(CMatrixFeatures.isIdentity(m, 1e-8)); m.setReal(0, 0, 1 + 1e-12); assertTrue(CMatrixFeatures.isIdentity(m,1e-8)); assertFalse(CMatrixFeatures.isIdentity(m, 1e-15)); assertFalse(CMatrixFeatures.isIdentity(m, 1e-15)); m.setImaginary(1,0,1e-12); assertTrue(CMatrixFeatures.isIdentity(m,1e-8)); m.setReal(1,0,1e-12); assertTrue(CMatrixFeatures.isIdentity(m,1e-8)); assertFalse(CMatrixFeatures.isIdentity(m,1e-15)); assertFalse(CMatrixFeatures.isIdentity(m,1e-15)); } @Test public void isHermitian() { CDenseMatrix64F A = new CDenseMatrix64F(new double[][]{{1,1.1,2,2.1},{2,-2.1,3,3.1}}); assertTrue(CMatrixFeatures.isHermitian(A, 1e-8)); A.set(0,1,5,6); assertFalse(CMatrixFeatures.isHermitian(A, 1e-8)); } @Test public void isUnitary() { // create a reflector since it's unitary CDenseMatrix64F u = CRandomMatrices.createRandom(5,1,rand); Complex64F dot = new Complex64F(); CVectorVectorMult.innerProdH(u, u,dot); double gamma = 2.0/dot.real; CDenseMatrix64F A = CSpecializedOps.householder(u,gamma); assertTrue(CMatrixFeatures.isUnitary(A, 1e-6f)); // try a negative case now A.set(0,1,495,400); assertFalse(CMatrixFeatures.isUnitary(A, 1e-6f)); A.set(0,1,Double.NaN,Double.NaN); assertFalse(CMatrixFeatures.isUnitary(A, 1e-6f)); } /** * Check some trial cases. */ @Test public void isPositiveDefinite() { CDenseMatrix64F a = new CDenseMatrix64F(2,2,true,2,0,0,0,0,0,2,0); CDenseMatrix64F b = new CDenseMatrix64F(2,2,true,0,0,1,0,1,0,0,0); CDenseMatrix64F c = new CDenseMatrix64F(2,2); assertTrue(CMatrixFeatures.isPositiveDefinite(a)); assertFalse(CMatrixFeatures.isPositiveDefinite(b)); assertFalse(CMatrixFeatures.isPositiveDefinite(c)); // make sure the input isn't modified assertEquals(2,a.getReal(0, 0),1e-8); assertEquals(2,a.getReal(1,1),1e-8); } } ejml-0.28/main/denseC64/test/org/ejml/ops/TestCNormOps.java000066400000000000000000000027411256171534400234060ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestCNormOps { Random rand = new Random(234); @Test public void normF() { CDenseMatrix64F a = CRandomMatrices.createRandom(1,7,rand); Complex64F b = new Complex64F(); double total = 0; for (int i = 0; i < a.numRows; i++) { for (int j = 0; j < a.numCols; j++) { a.get(i,j,b); total += b.real*b.real + b.imaginary*b.imaginary; } } double expected = Math.sqrt(total); double found = CNormOps.normF(a); assertEquals(expected,found,1e-8); } }ejml-0.28/main/denseC64/test/org/ejml/ops/TestCRandomMatrices.java000066400000000000000000000111571256171534400247220ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.CDenseMatrix64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestCRandomMatrices { Random rand = new Random(234); @Test public void createRandom_min_max() { CDenseMatrix64F A = CRandomMatrices.createRandom(30,20,-1,1,rand); checkRandomRange(A); } @Test public void setRandom() { CDenseMatrix64F A = new CDenseMatrix64F(5,4); CRandomMatrices.setRandom(A,rand); checkRandom1(A); } private void checkRandom1(CDenseMatrix64F a) { assertEquals(5, a.numRows); assertEquals(4, a.numCols); double totalReal = 0; double totalImg = 0; for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < a.numCols; j++ ) { double real = a.getReal(i,j); double img = a.getImaginary(i, j); assertTrue( real >= 0); assertTrue( real <= 1); totalReal += real; assertTrue( img >= 0); assertTrue( img <= 1); totalImg += img; } } assertTrue(totalReal>0); assertTrue(totalImg>0); } @Test public void setRandom_min_max() { CDenseMatrix64F A = new CDenseMatrix64F(30,20); CRandomMatrices.setRandom(A,-1,1,rand); checkRandomRange(A); } private void checkRandomRange(CDenseMatrix64F a) { assertEquals(30, a.numRows); assertEquals(20, a.numCols); int numRealNeg = 0; int numRealPos = 0; int numImgNeg = 0; int numImgPos = 0; for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < a.numCols; j++ ) { double real = a.getReal(i,j); double img = a.getImaginary(i,j); if( real < 0 ) numRealNeg++; else numRealPos++; if( Math.abs(real) > 1 ) fail("Out of range"); if( img < 0 ) numImgNeg++; else numImgPos++; if( Math.abs(img) > 1 ) fail("Out of range"); } } assertTrue(numRealNeg>0); assertTrue(numRealPos>0); assertTrue(numImgNeg>0); assertTrue(numImgPos>0); } @Test public void createHermPosDef() { for( int i = 1; i < 20; i++ ) { CDenseMatrix64F A = CRandomMatrices.createHermPosDef(i, rand); assertTrue(CMatrixFeatures.isPositiveDefinite(A)); } } @Test public void createHermitian() { CDenseMatrix64F A = CRandomMatrices.createHermitian(10, -1, 1, rand); assertTrue(CMatrixFeatures.isHermitian(A, 1e-8)); // see if it has the expected range of elements double min = CCommonOps.elementMinReal(A); double max = CCommonOps.elementMaxReal(A); assertTrue(min < 0 && min >= -1); assertTrue(max > 0 && max <= 1); min = CCommonOps.elementMinImaginary(A); max = CCommonOps.elementMaxImaginary(A); assertTrue(min < 0 && min >= -1); assertTrue(max > 0 && max <= 1); } // // @Test // public void createUpperTriangle() { // for( int hess = 0; hess < 3; hess++ ) { // CDenseMatrix64F A = CRandomMatrices.createUpperTriangle(10,hess,-1,1,rand); // // assertTrue(MatrixFeatures.isUpperTriangle(A,hess,1e-8)); // // // quick sanity check to make sure it could be proper // assertTrue(A.get(hess,0) != 0 ); // // // see if it has the expected range of elements // double min = CommonOps.elementMin(A); // double max = CommonOps.elementMax(A); // // assertTrue(min < 0 && min >= -1); // assertTrue(max > 0 && max <= 1); // } // } } ejml-0.28/main/denseC64/test/org/ejml/ops/TestCSpecializedOps.java000066400000000000000000000114461256171534400247310ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.CVectorVectorMult; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.Complex64F; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestCSpecializedOps { Random rand = new Random(234); @Test public void pivotMatrix() { int pivots[] = new int[]{1,0,3,2}; CDenseMatrix64F A = CRandomMatrices.createRandom(4,4,-1,-1,rand); CDenseMatrix64F P = CSpecializedOps.pivotMatrix(null,pivots,4,false); CDenseMatrix64F Pt = CSpecializedOps.pivotMatrix(null,pivots,4,true); CDenseMatrix64F B = new CDenseMatrix64F(4,4); // see if it swapped the rows CCommonOps.mult(P, A, B); for( int i = 0; i < 4; i++ ) { int index = pivots[i]; for( int j = 0; j < 4; j++ ) { double real = A.getReal(index,j); double img = A.getImaginary(index, j); assertEquals(real,B.getReal(i, j),1e-8); assertEquals(img,B.getImaginary(i, j),1e-8); } } // see if it transposed CCommonOps.transpose(P,B); assertTrue(CMatrixFeatures.isIdentical(B, Pt, 1e-8)); } @Test public void elementDiagMaxMagnitude2() { CDenseMatrix64F A = CRandomMatrices.createRandom(4,5,-1,1,rand); Complex64F a = new Complex64F(); double expected = 0; for (int i = 0; i < 4; i++) { A.get(i,i,a); if( a.getMagnitude2() > expected ) expected = a.getMagnitude2(); } double found = CSpecializedOps.elementDiagMaxMagnitude2(A); assertEquals(expected, found, 1e-8); } @Test public void qualityTriangular() { CDenseMatrix64F A = CRandomMatrices.createRandom(4,4,-1,-1,rand); double max = Math.sqrt(CSpecializedOps.elementDiagMaxMagnitude2(A)); Complex64F a = new Complex64F(); Complex64F tmp = new Complex64F(); Complex64F total = new Complex64F(1,0); for (int i = 0; i < 4; i++) { A.get(i,i,a); a.real /= max; a.imaginary /= max; ComplexMath64F.multiply(total,a,tmp); total.set(tmp); } double expected = total.getMagnitude(); double found = CSpecializedOps.qualityTriangular(A); assertEquals(expected,found,1e-8); } @Test public void householder() { CDenseMatrix64F U = CRandomMatrices.createRandom(6,1,rand); double gamma = 1.6; // Q = I - gamma*U*U^H CDenseMatrix64F I = CCommonOps.identity(6); CDenseMatrix64F UUt = new CDenseMatrix64F(6,6); CDenseMatrix64F expected = new CDenseMatrix64F(6,6); CVectorVectorMult.outerProdH(U, U, UUt); CCommonOps.elementMultiply(UUt,gamma,0,UUt); CCommonOps.subtract(I,UUt,expected); CDenseMatrix64F found = CSpecializedOps.householder(U,gamma); assertTrue(CMatrixFeatures.isIdentical(expected,found,1e-8)); } @Test public void householderVector() { CDenseMatrix64F x = CRandomMatrices.createRandom(6, 1, rand); // x.set(0,0,0,0); CDenseMatrix64F u = CSpecializedOps.householderVector(x); double gamma = 2.0/Math.pow(CNormOps.normF(u), 2.0); // Q = I - gamma*U*U^H CDenseMatrix64F I = CCommonOps.identity(6); CDenseMatrix64F UUt = new CDenseMatrix64F(6,6); CDenseMatrix64F Q = new CDenseMatrix64F(6,6); CVectorVectorMult.outerProdH(u, u, UUt); CCommonOps.elementMultiply(UUt,gamma,0,UUt); CCommonOps.subtract(I,UUt,Q); CDenseMatrix64F found = new CDenseMatrix64F(x.numRows,x.numCols); CCommonOps.mult(Q,x,found); Complex64F c = new Complex64F(); found.get(0,0,c); assertTrue(c.real != 0); assertTrue(c.imaginary != 0 ); for (int i = 1; i < found.numRows; i++) { found.get(i,0,c); assertEquals(0,c.real, 1e-8); assertEquals(0,c.imaginary,1e-8); } } }ejml-0.28/main/denseC64/todo.txt000066400000000000000000000001721256171534400164070ustar00rootroot00000000000000- Cholesky - SVD - Symmetric EVD - General EVD - How to handle complex eigenvectors in a real matrix? * Use reflection?ejml-0.28/main/equation/000077500000000000000000000000001256171534400151535ustar00rootroot00000000000000ejml-0.28/main/equation/build.gradle000066400000000000000000000002671256171534400174370ustar00rootroot00000000000000dependencies { compile project(':main:core') compile project(':main:dense64') compile project(':main:simple') } idea { module { name = "EJML Equation" } }ejml-0.28/main/equation/src/000077500000000000000000000000001256171534400157425ustar00rootroot00000000000000ejml-0.28/main/equation/src/org/000077500000000000000000000000001256171534400165315ustar00rootroot00000000000000ejml-0.28/main/equation/src/org/ejml/000077500000000000000000000000001256171534400174605ustar00rootroot00000000000000ejml-0.28/main/equation/src/org/ejml/equation/000077500000000000000000000000001256171534400213055ustar00rootroot00000000000000ejml-0.28/main/equation/src/org/ejml/equation/Equation.java000066400000000000000000001345011256171534400237410ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.ejml.data.DenseMatrix64F; import org.ejml.simple.SimpleMatrix; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import static org.ejml.equation.TokenList.Type; /** *

* Equation allows the user to manipulate matrices in a more compact symbolic way, similar to Matlab and Octave. * Aliases are made to Matrices and scalar values which can then be manipulated by specifying an equation in a string. * These equations can either be "pre-compiled" [1] into a sequence of operations or immediately executed. While the * former is more verbose, when dealing with small matrices it significantly faster and runs close to the speed of * normal hand written code. *

*

* Each string represents a single line and must have one and only one assignment '=' operator. Temporary variables * are handled transparently to the user. Temporary variables are declared at compile time, but resized at runtime. * If the inputs are not resized and the code is precompiled, then no new memory will be declared. When a matrix * is assigned the results of an operation it is resized so that it can store the results. *

*

* The compiler currently produces simplistic code. For example, if it encounters the following equation "a = b*c' it * will not invoke multTransB(b,c,a), but will explicitly transpose c and then call mult(). In the future it * will recognize such short cuts. *

* *

* Usage example: *

 * Equation eq = new Equation();
 * eq.alias(x,"x", P,"P", Q,"Q");
 *
 * eq.process("x = F*x");
 * eq.process("P = F*P*F' + Q");
 * 
* Which will modify the matrices 'x' amd 'P'. Sub-matrices and inline matrix construction is also * supported. *
 * eq.process("x = [2 1 0; 0 1 3;4 5 6]*x");
 * eq.process("x(1:3,5:9) = [a ; b]*2");
 * 
*

* *

* To pre-compile one of the above lines, do the following instead: *

 * Sequence predictX = eq.compile("x = F*x");
 * predictX.perform();
 * 
* Then you can invoke it as much as you want without the "expensive" compilation step. If you are dealing with * larger matrices (e.g. 100 by 100) then it is likely that the compilation step has an insignificant runtime * cost. *

* *

* Variables can also be lazily declared and their type inferred under certain conditions. For example: *

 * eq.alias(A,"A", B,"B");
 * eq.process("C = A*B");
 * DenseMatrix64F C = eq.lookupMatrix("C");
 * 
* In this case 'C' was lazily declared. To access the variable, or any others, you can use one of the lookup*() * functions. *

* *

* Sometimes you don't get the results you expect and it can be helpful to print out the tokens and which operations * the compiler selected. To do this set the second parameter to eq.compile() or eq.process() to true: *

 * Code:
 * eq.process("C=2.1*B'*A",true);
 *
 * Output:
 * Parsed tokens:
 * ------------
 * Word:C
 * ASSIGN
 * VarSCALAR
 * TIMES
 * VarMATRIX
 * TRANSPOSE
 * TIMES
 * VarMATRIX
 *
 * Operations:
 * ------------
 * transpose-m
 * multiply-ms
 * multiply-mm
 * copy-mm
 * 
*

* *

*

Built in Constants

*
 * pi = Math.PI
 * e  = Math.E
 * 
*

* *

*

Supported functions

*
 * eye(N)       Create an identity matrix which is N by N.
 * eye(A)       Create an identity matrix which is A.numRows by A.numCols
 * normF(A)     Frobenius normal of the matrix.
 * det(A)       Determinant of the matrix
 * inv(A)       Inverse of a matrix
 * pinv(A)      Pseudo-inverse of a matrix
 * rref(A)      Reduced row echelon form of A
 * trace(A)     Trace of the matrix
 * zeros(r,c)   Matrix full of zeros with r rows and c columns.
 * ones(r,c)    Matrix full of ones with r rows and c columns.
 * diag(A)      If a vector then returns a square matrix with diagonal elements filled with vector
 * diag(A)      If a matrix then it returns the diagonal elements as a column vector
 * dot(A,B)     Returns the dot product of two vectors as a double.  Does not work on general matrices.
 * solve(A,B)   Returns the solution X from A*X = B.
 * kron(A,B)    Kronecker product
 * abs(A)       Absolute value of A.
 * max(A)       Element with the largest value in A.
 * min(A)       Element with the smallest value in A.
 * pow(a,b)     Computes a to the power of b.  Can also be invoked with "a^b" scalars only.
 * sqrt(a)      Computes the square root of a.
 * sin(a)       Math.sin(a) for scalars only
 * cos(a)       Math.cos(a) for scalars only
 * atan(a)      Math.atan(a) for scalars only
 * atan2(a,b)   Math.atan2(a,b) for scalars only
 * exp(a)       Math.exp(a) for scalars and element-wise matrices
 * log(a)       Math.log(a) for scalars and element-wise matrices
 * 
*

* *

*

Supported operations

*
 * '*'        multiplication (Matrix-Matrix, Scalar-Matrix, Scalar-Scalar)
 * '+'        addition (Matrix-Matrix, Scalar-Matrix, Scalar-Scalar)
 * '-'        subtraction (Matrix-Matrix, Scalar-Matrix, Scalar-Scalar)
 * '/'        divide (Matrix-Scalar, Scalar-Scalar)
 * '/'        matrix solve "x=b/A" is equivalent to x=solve(A,b) (Matrix-Matrix)
 * '^'        Scalar power.  a^b is a to the power of b.
 * '\'        left-divide.  Same as divide but reversed.  e.g. x=A\b is x=solve(A,b)
 * '.*'       element-wise multiplication (Matrix-Matrix)
 * './'       element-wise division (Matrix-Matrix)
 * '.^'       element-wise power. (scalar-scalar) (matrix-matrix) (scalar-matrix) (matrix-scalar)
 * '''        matrix transpose
 * '='        assignment by value (Matrix-Matrix, Scalar-Scalar)
 * 
* Order of operations: [ ' ] precedes [ ^ .^ ] precedes [ * / .* ./ ] precedes [ + - ] *

* *

*

Specialized submatrix and matrix construction syntax

*
 * Extracts a sub-matrix from A with rows 1 to 10 (inclusive) and column 3.
 *               A(1:10,3)
 * Extracts a sub-matrix from A with rows 2 to numRows-1 (inclusive) and all the columns.
 *               A(2:,:)
 * Will concat A and B along their columns and then concat the result with  C along their rows.
 *                [A,B;C]
 * Defines a 3x2 matrix.
 *            [1 2; 3 4; 4 5]
 * You can also perform operations inside:
 *            [[2 3 4]';[4 5 6]']
 * Will assign B to the sub-matrix in A.
 *             A(1:3,4:8) = B
 * 
*

* *

* Footnotes: *

 * [1] It is not compiled into Java byte-code, but into a sequence of operations stored in a List.
 * 
*

* * @author Peter Abeles */ // TODO Change parsing so that operations specify a pattern. // TODO Recycle temporary variables // TODO intelligently handle identity matrices public class Equation { HashMap variables = new HashMap(); // storage for a single word in the tokenizer char storage[] = new char[1024]; ManagerFunctions functions = new ManagerFunctions(); public Equation() { alias(Math.PI,"pi"); alias(Math.E,"e"); } /** * Adds a new Matrix variable. If one already has the same name it is written over. * * While more verbose for multiple variables, this function doesn't require new memory be declared * each time it's called. * * @param variable Matrix which is to be assigned to name * @param name The name of the variable */ public void alias( DenseMatrix64F variable , String name ) { if( isReserved(name)) throw new RuntimeException("Reserved word or contains a reserved character"); VariableMatrix old = (VariableMatrix)variables.get(name); if( old == null ) { variables.put(name, new VariableMatrix(variable)); }else { old.matrix = variable; } } public void alias( SimpleMatrix variable , String name ) { alias(variable.getMatrix(),name); } /** * Adds a new floating point variable. If one already has the same name it is written over. * @param value Value of the number * @param name Name in code */ public void alias( double value , String name ) { if( isReserved(name)) throw new RuntimeException("Reserved word or contains a reserved character"); VariableDouble old = (VariableDouble)variables.get(name); if( old == null ) { variables.put(name, new VariableDouble(value)); }else { old.value = value; } } /** * Adds a new integer variable. If one already has the same name it is written over. * @param value Value of the number * @param name Name in code */ public void alias( int value , String name ) { if( isReserved(name)) throw new RuntimeException("Reserved word or contains a reserved character"); VariableInteger old = (VariableInteger)variables.get(name); if( old == null ) { variables.put(name, new VariableInteger(value)); }else { old.value = value; } } /** * Creates multiple aliases at once. */ public void alias( Object ...args ) { if( args.length % 2 == 1 ) throw new RuntimeException("Even number of arguments expected"); for (int i = 0; i < args.length; i += 2) { if( args[i].getClass() == Integer.class ) { alias(((Integer)args[i]).intValue(),(String)args[i+1]); } else if( args[i].getClass() == Double.class ) { alias(((Double)args[i]).doubleValue(),(String)args[i+1]); } else if( args[i].getClass() == DenseMatrix64F.class ) { alias((DenseMatrix64F)args[i],(String)args[i+1]); } else if( args[i].getClass() == SimpleMatrix.class ) { alias((SimpleMatrix)args[i],(String)args[i+1]); } else { throw new RuntimeException("Unknown value type "+args[i]); } } } public Sequence compile( String equation ) { return compile(equation,false); } /** * Parses the equation and compiles it into a sequence which can be executed later on * @param equation String in simple equation format. * @param debug if true it will print out debugging information * @return Sequence of operations on the variables */ public Sequence compile( String equation , boolean debug ) { ManagerTempVariables managerTemp = new ManagerTempVariables(); functions.setManagerTemp(managerTemp); Sequence sequence = new Sequence(); TokenList tokens = extractTokens(equation,managerTemp); if( tokens.size() < 3 ) throw new RuntimeException("Too few tokens"); if( debug ) { System.out.println("Parsed tokens:\n------------"); tokens.print(); System.out.println(); } TokenList.Token t0 = tokens.getFirst(); // Get the results variable if( t0.getType() != Type.VARIABLE && t0.getType() != Type.WORD ) throw new RuntimeException("Expected variable name first. Not "+t0); // see if it is assign or a range List range = parseAssignRange(sequence, tokens, t0); TokenList.Token t1 = t0.next; if( t1.getType() != Type.SYMBOL || t1.getSymbol() != Symbol.ASSIGN ) throw new RuntimeException("Expected assign next"); // Parse the right side of the equation TokenList tokensRight = tokens.extractSubList(t1.next,tokens.last); checkForUnknownVariables(tokensRight); handleParentheses( tokensRight ,sequence); // see if it needs to be parsed more if( tokensRight.size() != 1 ) throw new RuntimeException("BUG"); if( tokensRight.getLast().getType() != Type.VARIABLE ) throw new RuntimeException("BUG the last token must be a variable"); // copy the results into the output Variable variableRight = tokensRight.getFirst().getVariable(); if( range == null) { // no range, so copy results into the entire output matrix Variable output = createVariableInferred(t0, variableRight); sequence.addOperation(Operation.copy(variableRight, output)); } else { // a sub-matrix range is specified. Copy into that inner part if( t0.getType() == Type.WORD ) { throw new RuntimeException("Can't do lazy variable initialization with submatrices. "+t0.getWord()); } sequence.addOperation(Operation.copy(variableRight, t0.getVariable(),range)); } if( debug ) { System.out.println("Operations:\n------------"); for (int i = 0; i < sequence.operations.size(); i++) { System.out.println(sequence.operations.get(i).name()); } } return sequence; } /** * Examines the list of variables for any unknown variables and throws an exception if one is found */ private void checkForUnknownVariables(TokenList tokens) { TokenList.Token t = tokens.getFirst(); while( t != null ) { if( t.getType() == Type.WORD ) throw new RuntimeException("Unknown variable on right side. "+t.getWord()); t = t.next; } } /** * Infer the type of and create a new output variable using the results from the right side of the equation. * If the type is already known just return that. */ private Variable createVariableInferred(TokenList.Token t0, Variable variableRight) { Variable result; if( t0.getType() == Type.WORD ) { switch( variableRight.getType()) { case MATRIX: alias(new DenseMatrix64F(1,1),t0.getWord()); break; case SCALAR: if( variableRight instanceof VariableInteger) { alias(0,t0.getWord()); } else { alias(1.0,t0.getWord()); } break; default: throw new RuntimeException("Unknown type"); } result = variables.get(t0.getWord()); } else { result = t0.getVariable(); } return result; } /** * See if a range for assignment is specified. If so return the range, otherwise return null */ private List parseAssignRange(Sequence sequence, TokenList tokens, TokenList.Token t0) { List range; TokenList.Token t1 = t0.next; if( t1.getType() == Type.SYMBOL ) { if( t1.symbol == Symbol.ASSIGN ) { range = null; // copy into the entire matrix } else if( t1.symbol == Symbol.PAREN_LEFT ) { // copy into a specific area range = new ArrayList(); // find the right parentheses TokenList.Token t2 = t1.next; while( t2 != null && t2.symbol != Symbol.PAREN_RIGHT ) { t2 = t2.next; } if( t2 == null ) throw new RuntimeException("Could not find closing )"); TokenList.Token n = t2.next; TokenList sublist = tokens.extractSubList(t1,t2); // remove parentheses sublist.remove(sublist.first); sublist.remove(sublist.last); // parse the range parseSubmatrixRange(sublist, sequence, range); t1 = n; if( t1.symbol != Symbol.ASSIGN ) throw new RuntimeException("Expected assign after sub-matrix"); } else { throw new RuntimeException("Expected assign or submatrix"); } } else { throw new RuntimeException("Expecting symbol after first variable"); } return range; } /** * Searches for pairs of parentheses and processes blocks inside of them. Embedded parentheses are handled * with no problem. On output only a single token should be in tokens. * @param tokens List of parsed tokens * @param sequence Sequence of operators */ protected void handleParentheses( TokenList tokens, Sequence sequence ) { List left = new ArrayList(); // find all of them TokenList.Token t = tokens.first; while( t != null ) { TokenList.Token next = t.next; if( t.getType() == Type.SYMBOL ) { if( t.getSymbol() == Symbol.PAREN_LEFT ) left.add(t); else if( t.getSymbol() == Symbol.PAREN_RIGHT ) { if( left.isEmpty() ) throw new RuntimeException(") found with no matching ("); TokenList.Token a = left.remove(left.size()-1); // remember the element before so the new one can be inserted afterwards TokenList.Token before = a.previous; TokenList sublist = tokens.extractSubList(a,t); // remove parentheses sublist.remove(sublist.first); sublist.remove(sublist.last); // if its a function before () then the () indicates its an input to a function if( before != null && before.getType() == Type.FUNCTION ) { List inputs = parseParameterCommaBlock(sublist, sequence); if (inputs.isEmpty()) throw new RuntimeException("Empty function input parameters"); else { createFunction(before, inputs, tokens, sequence); } } else if( before != null && before.getType() == Type.VARIABLE ) { // if it's a variable then that says it's a sub-matrix TokenList.Token extract = parseSubmatrixToExtract(before,sublist, sequence); // put in the extract operation tokens.insert(before,extract); tokens.remove(before); } else { // if null then it was empty inside TokenList.Token output = parseBlockNoParentheses(sublist,sequence); if (output != null) tokens.insert(before, output); } } } t = next; } if( !left.isEmpty()) throw new RuntimeException("Dangling ( parentheses"); if( tokens.size() > 1 ) { parseBlockNoParentheses(tokens, sequence); } } /** * Searches for commas in the set of tokens. Used for inputs to functions * * @return List of output tokens between the commas */ protected List parseParameterCommaBlock( TokenList tokens, Sequence sequence ) { // find all the comma tokens List commas = new ArrayList(); TokenList.Token token = tokens.first; while( token != null ) { if( token.getType() == Type.SYMBOL && token.getSymbol() == Symbol.COMMA ) { commas.add(token); } token = token.next; } List output = new ArrayList(); if( commas.isEmpty() ) { output.add(parseBlockNoParentheses(tokens, sequence)); } else { TokenList.Token before = tokens.first; for (int i = 0; i < commas.size(); i++) { TokenList.Token after = commas.get(i); if( before == after ) throw new RuntimeException("No empty function inputs allowed!"); TokenList.Token tmp = after.next; TokenList sublist = tokens.extractSubList(before,after); sublist.remove(after);// remove the comma output.add(parseBlockNoParentheses(sublist, sequence)); before = tmp; } // if the last character is a comma then after.next above will be null and thus before is null if( before == null ) throw new RuntimeException("No empty function inputs allowed!"); TokenList.Token after = tokens.last; TokenList sublist = tokens.extractSubList(before, after); output.add(parseBlockNoParentheses(sublist, sequence)); } return output; } /** * Converts a submatrix into an extract matrix operation. * @param variableTarget The variable in which the submatrix is extracted from */ protected TokenList.Token parseSubmatrixToExtract(TokenList.Token variableTarget, TokenList tokens, Sequence sequence) { List variables = new ArrayList(); variables.add(variableTarget.getVariable()); parseSubmatrixRange(tokens, sequence, variables); // first parameter is the matrix it will be extracted from. rest specify range Operation.Info info; // if it is extracting only a single number explicitly then convert it into a scalar if( variables.get(1) == variables.get(2) && variables.get(3) == variables.get(4) ) { // remove some redundant variables variables.remove(4); variables.remove(2); info = functions.create("extractScalar", variables); } else { info = functions.create("extract", variables); } sequence.addOperation(info.op); return new TokenList.Token(info.output); } /** * Parses the range for a sub-matrix and puts the results into variables. List * should be everything inside the parentheses. * * e.g. 1,2 or 2:10,4 or 2:10,3:13 * * @param variables Variables which describe the selected range */ private void parseSubmatrixRange(TokenList tokens, Sequence sequence, List variables) { TokenList.Token comma = tokens.first; while( comma != null && comma.getSymbol() != Symbol.COMMA ) comma = comma.next; if( comma == null ) throw new RuntimeException("Can't find comma inside submatrix"); TokenList listLeft = tokens.extractSubList(tokens.first,comma.previous); TokenList listRight = tokens.extractSubList(comma.next,tokens.last); parseValueRange(listLeft,sequence,variables); // rows parseValueRange(listRight,sequence,variables); // columns } /** * Parse a range written like 0:10 in which two numbers are separated by a colon. */ protected void parseValueRange( TokenList tokens, Sequence sequence , List variables ) { TokenList.Token[] t = new TokenList.Token[2]; // range of values are specified with a colon TokenList.Token colon = tokens.first; while( colon != null && colon.getSymbol() != Symbol.COLON ) { colon = colon.next; } if( colon == null ) { // no range, just a single value t[0] = t[1] = parseBlockNoParentheses(tokens,sequence); } else { if( colon.previous == null && colon.next == null) { t[0] = new TokenList.Token(VariableSpecial.Special.ALL); } else if( colon.next == null ) { TokenList listRow0 = tokens.extractSubList(tokens.first,colon.previous); t[0] = parseBlockNoParentheses(listRow0,sequence); t[1] = new TokenList.Token(VariableSpecial.Special.END); } else if( colon.previous == null ) { throw new RuntimeException(": not allowed"); } else { TokenList listRow0 = tokens.extractSubList(tokens.first, colon.previous); TokenList listRow1 = tokens.extractSubList(colon.next, tokens.last); t[0] = parseBlockNoParentheses(listRow0, sequence); t[1] = parseBlockNoParentheses(listRow1, sequence); } } for (int i = 0; i < t.length; i++) { if(t[i] == null) continue; if( t[i].getType() != Type.VARIABLE ) { throw new RuntimeException("Expected variable inside of range"); } variables.add(t[i].getVariable()); } } /** * Parses a code block with no parentheses and no commas. After it is done there should be a single token left, * which is returned. */ protected TokenList.Token parseBlockNoParentheses(TokenList tokens, Sequence sequence ) { // search for matrix bracket operations parseBracketCreateMatrix(tokens, sequence); // process operators depending on their priority parseNegOp(tokens,sequence); parseOperationsL(tokens,sequence); parseOperationsLR(new Symbol[]{Symbol.POWER,Symbol.ELEMENT_POWER}, tokens, sequence); parseOperationsLR(new Symbol[]{Symbol.TIMES, Symbol.RDIVIDE, Symbol.LDIVIDE, Symbol.ELEMENT_TIMES, Symbol.ELEMENT_DIVIDE}, tokens, sequence); parseOperationsLR(new Symbol[]{Symbol.PLUS, Symbol.MINUS}, tokens, sequence); if( tokens.size() > 1 ) throw new RuntimeException("BUG in parser. There should only be a single token left"); return tokens.first; } /** * Searches for brackets which are only used to construct new matrices by concatenating * 1 or more matrices together */ protected void parseBracketCreateMatrix(TokenList tokens, Sequence sequence) { List left = new ArrayList(); TokenList.Token t = tokens.getFirst(); while( t != null ) { TokenList.Token next = t.next; if( t.getSymbol() == Symbol.BRACKET_LEFT ) { left.add(t); } else if( t.getSymbol() == Symbol.BRACKET_RIGHT ) { if( left.isEmpty() ) throw new RuntimeException("No matching left bracket for right"); TokenList.Token start = left.remove(left.size() - 1); TokenList.Token i = start.next; // define the constructor MatrixConstructor constructor = new MatrixConstructor(functions.getManagerTemp()); TokenList.Token opStart = null; while( true ) { if( i.getType() == Type.VARIABLE ) { innerMatrixConstructorOp(tokens, sequence, constructor, opStart, i.previous); opStart = i; } else if( i.getType() == Type.SYMBOL ) { boolean finished = false; boolean ignore = true; // ignore if it's part of an inner expression if( i.getSymbol() == Symbol.SEMICOLON ) { ignore = false; } else if( i.getSymbol() == Symbol.BRACKET_RIGHT ) { finished = true; ignore = false; } if( !ignore ) { innerMatrixConstructorOp(tokens, sequence, constructor, opStart, i.previous); constructor.endRow(); opStart = null; if (finished) break; } } else { throw new RuntimeException("Unexpected token "+i); } i = i.next; } Operation.Info info = Operation.matrixConstructor(constructor); sequence.addOperation(info.op); // add the new variable to the tokens list tokens.insert(t,new TokenList.Token(info.output)); // remove used tokens tokens.extractSubList(start,t); } t = next; } if( !left.isEmpty() ) throw new RuntimeException("Dangling ["); } private void innerMatrixConstructorOp(TokenList tokens, Sequence sequence, MatrixConstructor constructor, TokenList.Token opStart, TokenList.Token opEnd) { if( opStart == null ) return; if( opStart != opEnd) { TokenList opList = tokens.extractSubList(opStart,opEnd); TokenList.Token var = parseBlockNoParentheses(opList,sequence); constructor.addToRow(var.getVariable()); } else { constructor.addToRow(opStart.getVariable()); } } /** * Searches for cases where a minus sign means negative operator. That happens when there is a minus * sign with a variable to its right and no variable to its left */ protected void parseNegOp(TokenList tokens, Sequence sequence) { if( tokens.size == 0 ) return; TokenList.Token token = tokens.first; while( token != null ) { TokenList.Token next = token.next; escape: if( token.getSymbol() == Symbol.MINUS ) { if( token.previous != null && token.previous.getType() != Type.SYMBOL) break escape; if( token.next == null || token.next.getType() == Type.SYMBOL) break escape; if( token.next.getType() != Type.VARIABLE ) throw new RuntimeException("Crap bug rethink this function"); // create the operation Operation.Info info = Operation.neg(token.next.getVariable(),functions.getManagerTemp()); // add the operation to the sequence sequence.addOperation(info.op); // update the token list TokenList.Token t = new TokenList.Token(info.output); tokens.insert(token.next,t); tokens.remove(token.next); tokens.remove(token); next = t; } token = next; } } /** * Parses operations where the input comes from variables to its left only. Hard coded to only look * for transpose for now * * @param tokens List of all the tokens * @param sequence List of operation sequence */ protected void parseOperationsL(TokenList tokens, Sequence sequence) { if( tokens.size == 0 ) return; TokenList.Token token = tokens.first; if( token.getType() != Type.VARIABLE ) throw new RuntimeException("The first token in an equation needs to be a variable and not "+token); while( token != null ) { if( token.getType() == Type.FUNCTION ) { throw new RuntimeException("Function encountered with no parentheses"); } else if( token.getType() == Type.SYMBOL && token.getSymbol() == Symbol.TRANSPOSE) { if( token.previous.getType() == Type.VARIABLE ) token = insertTranspose(token.previous,tokens,sequence); else throw new RuntimeException("Expected variable before tranpose"); } token = token.next; } } /** * Parses operations where the input comes from variables to its left and right * * @param ops List of operations which should be parsed * @param tokens List of all the tokens * @param sequence List of operation sequence */ protected void parseOperationsLR(Symbol ops[], TokenList tokens, Sequence sequence) { if( tokens.size == 0 ) return; TokenList.Token token = tokens.first; if( token.getType() != Type.VARIABLE ) throw new RuntimeException("The first token in an equation needs to be a variable and not "+token); boolean hasLeft = false; while( token != null ) { if( token.getType() == Type.FUNCTION ) { throw new RuntimeException("Function encountered with no parentheses"); } else if( token.getType() == Type.VARIABLE ) { if( hasLeft ) { if( token.previous.getType() == Type.VARIABLE ) { throw new RuntimeException("Two variables next to each other"); } if( isTargetOp(token.previous,ops)) { token = createOp(token.previous.previous,token.previous,token,tokens,sequence); } } else { hasLeft = true; } } else { if( token.previous.getType() == Type.SYMBOL ) { throw new RuntimeException("Two symbols next to each other. "+token.previous+" and "+token); } } token = token.next; } } /** * Adds a new operation to the list from the operation and two variables. The inputs are removed * from the token list and replaced by their output. */ protected TokenList.Token insertTranspose( TokenList.Token variable , TokenList tokens , Sequence sequence ) { Operation.Info info = functions.create('\'',variable.getVariable()); sequence.addOperation(info.op); // replace the symbols with their output TokenList.Token t = new TokenList.Token(info.output); // remove the transpose symbol tokens.remove(variable.next); // replace the variable with its transposed version tokens.replace(variable,t); return t; } /** * Adds a new operation to the list from the operation and two variables. The inputs are removed * from the token list and replaced by their output. */ protected TokenList.Token createOp( TokenList.Token left , TokenList.Token op , TokenList.Token right , TokenList tokens , Sequence sequence ) { Operation.Info info = functions.create(op.symbol, left.getVariable(), right.getVariable()); sequence.addOperation(info.op); // replace the symbols with their output TokenList.Token t = new TokenList.Token(info.output); tokens.remove(left); tokens.remove(right); tokens.replace(op,t); return t; } /** * Adds a new operation to the list from the operation and two variables. The inputs are removed * from the token list and replaced by their output. */ protected TokenList.Token createFunction( TokenList.Token name , List inputs , TokenList tokens , Sequence sequence ) { Operation.Info info; if( inputs.size() == 1 ) info = functions.create(name.getFunction().getName(),inputs.get(0).getVariable()); else { List vars = new ArrayList(); for (int i = 0; i < inputs.size(); i++) { vars.add(inputs.get(i).getVariable()); } info = functions.create(name.getFunction().getName(), vars ); } sequence.addOperation(info.op); // replace the symbols with the function's output TokenList.Token t = new TokenList.Token(info.output); tokens.replace(name, t); return t; } /** * Looks up a variable given its name. If none is found then return null. */ public T lookupVariable(String token) { Variable result = variables.get(token); return (T)result; } public DenseMatrix64F lookupMatrix(String token) { return ((VariableMatrix)variables.get(token)).matrix; } public int lookupInteger(String token) { return ((VariableInteger)variables.get(token)).value; } public double lookupDouble(String token) { Variable v = variables.get(token); if( v instanceof VariableMatrix ) { DenseMatrix64F m = ((VariableMatrix)v).matrix; if( m.numCols == 1 && m.numRows == 1 ) { return m.get(0,0); } else { throw new RuntimeException("Can only return 1x1 real matrices as doubles"); } } return ((VariableScalar)variables.get(token)).getDouble(); } /** * Parses the text string to extract tokens. */ protected TokenList extractTokens(String equation , ManagerTempVariables managerTemp ) { TokenList tokens = new TokenList(); int length = 0; boolean again; // process the same character twice TokenType type = TokenType.UNKNOWN; for( int i = 0; i < equation.length(); i++ ) { again = false; char c = equation.charAt(i); if( type == TokenType.WORD ) { if (isLetter(c)) { storage[length++] = c; } else { // add the variable/function name to token list String name = new String(storage, 0, length); Variable v = lookupVariable(name); if (v == null) { if (functions.isFunctionName(name)) { tokens.add(new Function(name)); } else { // see if it's type can be inferred later on tokens.add(name); } } else { tokens.add(v); } type = TokenType.UNKNOWN; again = true; // process unexpected character a second time } } else if( type == TokenType.INTEGER ) { // Handle integer numbers. Until proven to be a float if( c == '.' ) { type = TokenType.FLOAT; storage[length++] = c; } else if( c == 'e' || c == 'E' ) { type = TokenType.FLOAT_EXP; storage[length++] = c; } else if( Character.isDigit(c) ) { storage[length++] = c; } else if( isSymbol(c) || Character.isWhitespace(c) ) { int value = Integer.parseInt( new String(storage, 0, length)); tokens.add(managerTemp.createInteger(value)); type = TokenType.UNKNOWN; again = true; // process unexpected character a second time } else { throw new RuntimeException("Unexpected character at the end of an integer "+c); } } else if( type == TokenType.FLOAT ) { // Handle floating point numbers if( c == '.') { throw new RuntimeException("Unexpected '.' in a float"); } else if( c == 'e' || c == 'E' ) { storage[length++] = c; type = TokenType.FLOAT_EXP; } else if( Character.isDigit(c) ) { storage[length++] = c; } else if( isSymbol(c) || Character.isWhitespace(c) ) { double value = Double.parseDouble( new String(storage, 0, length)); tokens.add(managerTemp.createDouble(value)); type = TokenType.UNKNOWN; again = true; // process unexpected character a second time } else { throw new RuntimeException("Unexpected character at the end of an float "+c); } } else if( type == TokenType.FLOAT_EXP ) { // Handle floating point numbers in exponential format boolean end = false; if( c == '-' ) { char p = storage[length-1]; if( p == 'e' || p == 'E') { storage[length++] = c; } else { end = true; } } else if( Character.isDigit(c) ) { storage[length++] = c; } else if( isSymbol(c) || Character.isWhitespace(c) ) { end = true; } else { throw new RuntimeException("Unexpected character at the end of an float "+c); } if( end ) { double value = Double.parseDouble( new String(storage, 0, length)); tokens.add(managerTemp.createDouble(value)); type = TokenType.UNKNOWN; again = true; // process the current character again since it was unexpected } } else { if( isSymbol(c) ) { boolean special = false; if( c == '-' ) { // need to handle minus symbols carefully since it can be part of a number of a minus operator // if next to a number it should be negative sign, unless there is no operator to its left // then its a minus sign. if( i+1 < equation.length() && Character.isDigit(equation.charAt(i+1)) && (tokens.last == null || isOperatorLR(tokens.last.getSymbol()))) { type = TokenType.INTEGER; storage[0] = c; length = 1; special = true; } } if( !special ) { TokenList.Token t = tokens.add(Symbol.lookup(c)); if (t.previous != null && t.previous.getType() == Type.SYMBOL) { // there should only be two symbols in a row if its an element-wise operation if (t.previous.getSymbol() == Symbol.PERIOD) { tokens.remove(t.previous); tokens.remove(t); tokens.add(Symbol.lookupElementWise(c)); } } } } else if( Character.isWhitespace(c) ) { continue;// ignore white space } else { // start adding to the word if( Character.isDigit(c) ) { type = TokenType.INTEGER; } else { type = TokenType.WORD; } storage[0] = c; length = 1; } } // see if it should process the same character again if( again ) i--; } if( type == TokenType.WORD ) { String word = new String(storage,0,length); Variable v = lookupVariable(word); if( v == null ) throw new RuntimeException("Unknown variable "+word); tokens.add( v ); } else if( type == TokenType.INTEGER ) { tokens.add(managerTemp.createInteger(Integer.parseInt( new String(storage, 0, length)))); } else if( type == TokenType.FLOAT || type == TokenType.FLOAT_EXP ) { tokens.add(managerTemp.createDouble(Double.parseDouble( new String(storage, 0, length)))); } return tokens; } protected static enum TokenType { WORD, INTEGER, FLOAT, FLOAT_EXP, UNKNOWN } /** * Checks to see if the token is in the list of allowed character operations. Used to apply order of operations * @param token Token being checked * @param ops List of allowed character operations * @return true for it being in the list and false for it not being in the list */ protected static boolean isTargetOp( TokenList.Token token , Symbol[] ops ) { Symbol c = token.symbol; for (int i = 0; i < ops.length; i++) { if( c == ops[i]) return true; } return false; } protected static boolean isSymbol(char c) { return c == '*' || c == '/' || c == '+' || c == '-' || c == '(' || c == ')' || c == '[' || c == ']' || c == '=' || c == '\'' || c == '.' || c == ',' || c == ':' || c == ';' || c == '\\' || c == '^'; } /** * Operators which affect the variables to its left and right */ protected static boolean isOperatorLR( Symbol s ) { if( s == null ) return false; switch( s ) { case ELEMENT_DIVIDE: case ELEMENT_TIMES: case ELEMENT_POWER: case RDIVIDE: case LDIVIDE: case TIMES: case POWER: case PLUS: case MINUS: case ASSIGN: return true; } return false; } /** * Returns true if the character is a valid letter for use in a variable name */ protected static boolean isLetter( char c ) { return !(isSymbol(c) || Character.isWhitespace(c)); } /** * Returns true if the specified name is NOT allowed. It isn't allowed if it matches a built in operator * or if it contains a restricted character. */ protected boolean isReserved( String name ) { if( functions.isFunctionName(name)) return true; for (int i = 0; i < name.length(); i++) { if( !isLetter(name.charAt(i)) ) return true; } return false; } /** * Compiles and performs the provided equation. * * @param equation String in simple equation format */ public void process( String equation ) { compile(equation).perform(); } /** * Compiles and performs the provided equation. * * @param equation String in simple equation format */ public void process( String equation , boolean debug ) { compile(equation,debug).perform(); } /** * Returns the functions manager */ public ManagerFunctions getFunctions() { return functions; } } ejml-0.28/main/equation/src/org/ejml/equation/Function.java000066400000000000000000000023141256171534400237350ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * A function is an operator with the following syntax "( Input )" * * @author Peter Abeles */ public class Function { /** * Name of operator and the string it looks for when parsing */ public String name; public Function(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "Function{" + "name='" + name + '\'' + '}'; } } ejml-0.28/main/equation/src/org/ejml/equation/ManagerFunctions.java000066400000000000000000000300711256171534400254140ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Centralized place to create new instances of operations and functions. Must call * {@link #setManagerTemp} before any other functions. * * @author Peter Abeles */ public class ManagerFunctions { // List of functions which take in N inputs Map input1 = new HashMap(); Map inputN = new HashMap(); // Reference to temporary variable manager protected ManagerTempVariables managerTemp; public ManagerFunctions() { addBuiltIn(); } /** * Returns true if the string matches the name of a function */ public boolean isFunctionName( String s ) { if( input1.containsKey(s)) return true; if( inputN.containsKey(s)) return true; return false; } /** * Create a new instance of single input functions * @param name function name * @param var0 Input variable * @return Resulting operation */ public Operation.Info create( String name , Variable var0 ) { Input1 func = input1.get(name); if( func == null ) return null; return func.create(var0,managerTemp); } /** * Create a new instance of single input functions * @param name function name * @param vars Input variables * @return Resulting operation */ public Operation.Info create( String name , List vars ) { InputN func = inputN.get(name); if( func == null ) return null; return func.create(vars,managerTemp); } /** * Create a new instance of a single input function from an operator character * @param op Which operation * @param input Input variable * @return Resulting operation */ public Operation.Info create( char op , Variable input ) { switch( op ) { case '\'': return Operation.transpose(input, managerTemp); default: throw new RuntimeException("Unknown operation " + op); } } /** * Create a new instance of a two input function from an operator character * @param op Which operation * @param left Input variable on left * @param right Input variable on right * @return Resulting operation */ public Operation.Info create( Symbol op , Variable left , Variable right ) { switch( op ) { case PLUS: return Operation.add(left, right, managerTemp); case MINUS: return Operation.subtract(left, right, managerTemp); case TIMES: return Operation.multiply(left, right, managerTemp); case RDIVIDE: return Operation.divide(left, right, managerTemp); case LDIVIDE: return Operation.divide(right, left, managerTemp); case POWER: return Operation.pow(left, right, managerTemp); case ELEMENT_DIVIDE: return Operation.elementDivision(left, right, managerTemp); case ELEMENT_TIMES: return Operation.elementMult(left, right, managerTemp); case ELEMENT_POWER: return Operation.elementPow(left, right, managerTemp); default: throw new RuntimeException("Unknown operation " + op); } } /** * * @param managerTemp */ public void setManagerTemp(ManagerTempVariables managerTemp) { this.managerTemp = managerTemp; } /** * Adds a function, with a single input, to the list * @param name Name of function * @param function Function factory */ public void add( String name , Input1 function ) { input1.put(name, function); } /** * Adds a function, with a two inputs, to the list * @param name Name of function * @param function Function factory */ public void add( String name , InputN function ) { inputN.put(name,function); } /** * Adds built in functions */ private void addBuiltIn( ) { input1.put("inv",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.inv(A,manager); } }); input1.put("pinv",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.pinv(A, manager); } }); input1.put("rref",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.rref(A, manager); } }); input1.put("eye",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.eye(A, manager); } }); input1.put("det",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.det(A, manager); } }); input1.put("normF",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.normF(A, manager); } }); input1.put("trace",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.trace(A, manager); } }); input1.put("diag",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.diag(A, manager); } }); input1.put("min",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.min(A, manager); } }); input1.put("max",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.max(A, manager); } }); input1.put("abs",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.abs(A, manager); } }); input1.put("sin",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.sin(A, manager); } }); input1.put("cos",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.cos(A, manager); } }); input1.put("atan",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.atan(A, manager); } }); input1.put("exp",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.exp(A, manager); } }); input1.put("log",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.log(A, manager); } }); input1.put("sqrt",new Input1() { @Override public Operation.Info create(Variable A, ManagerTempVariables manager) { return Operation.sqrt(A, manager); } }); inputN.put("zeros",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs expected"); return Operation.zeros(inputs.get(0), inputs.get(1), manager); } }); inputN.put("ones",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs expected"); return Operation.ones(inputs.get(0), inputs.get(1), manager); } }); inputN.put("kron",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs expected"); return Operation.kron(inputs.get(0), inputs.get(1), manager); } }); inputN.put("dot",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs expected"); return Operation.dot(inputs.get(0), inputs.get(1), manager); } }); inputN.put("pow",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs expected"); return Operation.pow(inputs.get(0), inputs.get(1), manager); } }); inputN.put("atan2",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs expected"); return Operation.atan2(inputs.get(0), inputs.get(1), manager); } }); inputN.put("solve",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 2 ) throw new RuntimeException("Two inputs expected"); return Operation.solve(inputs.get(0), inputs.get(1), manager); } }); inputN.put("extract",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { return Operation.extract(inputs, manager); } }); inputN.put("extractScalar",new InputN() { @Override public Operation.Info create(List inputs, ManagerTempVariables manager) { if( inputs.size() != 3 ) throw new RuntimeException("Three inputs expected"); return Operation.extractScalar(inputs, manager); } }); } public ManagerTempVariables getManagerTemp() { return managerTemp; } /** * Creates new instances of functions from a single variable */ public static interface Input1 { Operation.Info create( Variable A , ManagerTempVariables manager ); } /** * Creates a new instance of functions from two variables */ public static interface InputN { Operation.Info create( List inputs , ManagerTempVariables manager ); } } ejml-0.28/main/equation/src/org/ejml/equation/ManagerTempVariables.java000066400000000000000000000027651256171534400262130ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Manages the creation and recycling of temporary variables used to store intermediate results. The user * cannot directly access these variables * * @author Peter Abeles */ // TODO add function to purge temporary variables. basicaly resize and redeclare their array to size 1 public class ManagerTempVariables { public VariableMatrix createMatrix() { return VariableMatrix.createTemp(); } public VariableDouble createDouble() { return new VariableDouble(0); } public VariableDouble createDouble( double value ) { return new VariableDouble(value); } public VariableInteger createInteger() { return createInteger(0); } public VariableInteger createInteger( int value ) { return new VariableInteger(value); } } ejml-0.28/main/equation/src/org/ejml/equation/MatrixConstructor.java000066400000000000000000000115441256171534400256670ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import java.util.ArrayList; import java.util.List; /** * matrix used to construct a matrix from a sequence of concatenations. * * @author Peter Abeles */ public class MatrixConstructor { VariableMatrix output; List items = new ArrayList(); List tmp = new ArrayList(); public MatrixConstructor(ManagerTempVariables manager) { this.output = manager.createMatrix(); } public void addToRow(Variable variable) { items.add( new Item(variable)); } public void endRow() { items.add(new Item()); } public void construct() { // make sure the last item is and end row if( !items.get(items.size()-1).endRow ) endRow(); setToRequiredSize(output.matrix); int matrixRow = 0; List row = new ArrayList(); for (int i = 0; i < items.size(); i++) { Item item = items.get(i); if( item.endRow ) { Item v = row.get(0); int numRows = v.getRows(); int numCols = v.getColumns(); if( v.matrix ) { CommonOps.insert(v.getMatrix(),output.matrix,matrixRow,0); } else { output.matrix.set(matrixRow,0,v.getValue()); } for (int j = 1; j < row.size(); j++) { v = row.get(j); if( v.getRows() != numRows) throw new RuntimeException("Row miss-matched. "+numRows+" "+v.getRows()); if( v.matrix ) { CommonOps.insert(v.getMatrix(),output.matrix,matrixRow,numCols); } else { output.matrix.set(matrixRow, numCols, v.getValue()); } numCols += v.getColumns(); } matrixRow += numRows; row.clear(); } else { row.add(item); } } } public VariableMatrix getOutput() { return output; } protected void setToRequiredSize( DenseMatrix64F matrix ) { int matrixRow = 0; int matrixCol = 0; List row = new ArrayList(); for (int i = 0; i < items.size(); i++) { Item item = items.get(i); if( item.endRow ) { Item v = row.get(0); int numRows = v.getRows(); int numCols = v.getColumns(); for (int j = 1; j < row.size(); j++) { v = row.get(j); if( v.getRows() != numRows) throw new RuntimeException("Row miss-matched. "+numRows+" "+v.getRows()); numCols += v.getColumns(); } matrixRow += numRows; if( matrixCol == 0 ) matrixCol = numCols; else if( matrixCol != numCols ) throw new RuntimeException("Unexpected number of columns"); row.clear(); } else { row.add(item); } } matrix.reshape(matrixRow,matrixCol); } private static class Item { Variable variable; boolean endRow; boolean matrix; private Item(Variable variable) { this.variable = variable; matrix = variable instanceof VariableMatrix; } private Item() { endRow = true; } public int getRows() { if( matrix ) { return ((VariableMatrix)variable).matrix.numRows; } else { return 1; } } public int getColumns() { if( matrix ) { return ((VariableMatrix)variable).matrix.numCols; } else { return 1; } } public DenseMatrix64F getMatrix() { return ((VariableMatrix)variable).matrix; } public double getValue() { return ((VariableScalar)variable).getDouble(); } } } ejml-0.28/main/equation/src/org/ejml/equation/Operation.java000066400000000000000000001416641256171534400241240ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.NormOps; import java.util.List; /** * Performs math operations. * * @author Peter Abeles */ public abstract class Operation { String name; protected Operation(String name) { this.name = name; } public abstract void process(); public String name() { return name; } /** * If the variable is a local temporary variable it will be resized so that the operation can complete. If not * temporary then it will not be reshaped * @param mat Variable containing the matrix * @param numRows Desired number of rows * @param numCols Desired number of columns */ protected void resize( VariableMatrix mat , int numRows , int numCols ) { if( mat.isTemp() ) { mat.matrix.reshape(numRows,numCols); } } public static Info multiply(final Variable A, final Variable B, ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("multiply-mm") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; VariableMatrix mB = (VariableMatrix)B; resize(output,mA.matrix.numRows,mB.matrix.numCols); CommonOps.mult(mA.matrix,mB.matrix,output.matrix); } }; } else if( A instanceof VariableInteger && B instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(); ret.output = output; ret.op = new Operation("multiply-ii") { @Override public void process() { VariableInteger mA = (VariableInteger)A; VariableInteger mB = (VariableInteger)B; output.value = mA.value*mB.value; } }; } else if( A instanceof VariableScalar && B instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("multiply-ss") { @Override public void process() { VariableScalar mA = (VariableScalar)A; VariableScalar mB = (VariableScalar)B; output.value = mA.getDouble()*mB.getDouble(); } }; } else { final VariableMatrix output = manager.createMatrix(); ret.output = output; final VariableMatrix m; final VariableScalar s; if( A instanceof VariableMatrix ) { m = (VariableMatrix)A; s = (VariableScalar)B; } else { m = (VariableMatrix)B; s = (VariableScalar)A; } ret.op = new Operation("multiply-ms") { @Override public void process() { output.matrix.reshape(m.matrix.numRows,m.matrix.numCols); CommonOps.scale(s.getDouble(),m.matrix,output.matrix); } }; } return ret; } public static Info divide(final Variable A, final Variable B, ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { return solve(B,A,manager); } else if( A instanceof VariableMatrix && B instanceof VariableScalar ) { final VariableMatrix output = manager.createMatrix(); final VariableMatrix m = (VariableMatrix)A; final VariableScalar s = (VariableScalar)B; ret.output = output; ret.op = new Operation("divide-ma") { @Override public void process() { output.matrix.reshape(m.matrix.numRows,m.matrix.numCols); CommonOps.divide(m.matrix,s.getDouble(),output.matrix); } }; } else if( A instanceof VariableScalar && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); final VariableMatrix m = (VariableMatrix)B; final VariableScalar s = (VariableScalar)A; ret.output = output; ret.op = new Operation("divide-ma") { @Override public void process() { output.matrix.reshape(m.matrix.numRows,m.matrix.numCols); CommonOps.divide(s.getDouble(),m.matrix,output.matrix); } }; } else if( A instanceof VariableInteger && B instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(); ret.output = output; ret.op = new Operation("divide-ii") { @Override public void process() { VariableInteger mA = (VariableInteger)A; VariableInteger mB = (VariableInteger)B; output.value = mA.value/mB.value; } }; } else { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("divide-ss") { @Override public void process() { VariableScalar mA = (VariableScalar)A; VariableScalar mB = (VariableScalar)B; output.value = mA.getDouble()/mB.getDouble(); } }; } return ret; } /** * Returns the negative of the input variable */ public static Info neg(final Variable A, ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(); ret.output = output; ret.op = new Operation("neg-i") { @Override public void process() { output.value = -((VariableInteger)A).value; } }; } else if( A instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("neg-s") { @Override public void process() { output.value = -((VariableScalar)A).getDouble(); } }; } else if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("neg-m") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix)A).matrix; output.matrix.reshape(a.numRows, a.numCols); CommonOps.changeSign(a, output.matrix); } }; } else { throw new RuntimeException("Unsupported variable "+A); } return ret; } public static Info pow(final Variable A, final Variable B, ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableScalar && B instanceof VariableScalar ) { ret.op = new Operation("pow-ss") { @Override public void process() { double a = ((VariableScalar)A).getDouble(); double b = ((VariableScalar)B).getDouble(); output.value = Math.pow(a,b); } }; } else { throw new RuntimeException("Only scalar to scalar power supported"); } return ret; } public static Info atan2(final Variable A, final Variable B, ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableScalar && B instanceof VariableScalar ) { ret.op = new Operation("atan2-ss") { @Override public void process() { double a = ((VariableScalar)A).getDouble(); double b = ((VariableScalar)B).getDouble(); output.value = Math.atan2(a, b); } }; } else { throw new RuntimeException("Only scalar to scalar atan2 supported"); } return ret; } public static Info sqrt(final Variable A, ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableScalar ) { ret.op = new Operation("sqrt-s") { @Override public void process() { double a = ((VariableScalar)A).getDouble(); output.value = Math.sqrt(a); } }; } else { throw new RuntimeException("Only scalars are supported"); } return ret; } public static Info sin(final Variable A, ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableScalar ) { ret.op = new Operation("sin-s") { @Override public void process() { output.value = Math.sin(((VariableScalar) A).getDouble()); } }; } else { throw new RuntimeException("Only scalars are supported"); } return ret; } public static Info cos(final Variable A, ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableScalar ) { ret.op = new Operation("cos-s") { @Override public void process() { output.value = Math.cos(((VariableScalar) A).getDouble()); } }; } else { throw new RuntimeException("Only scalars are supported"); } return ret; } public static Info atan(final Variable A, ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableScalar ) { ret.op = new Operation("atan-s") { @Override public void process() { output.value = Math.atan(((VariableScalar) A).getDouble()); } }; } else { throw new RuntimeException("Only scalars are supported"); } return ret; } public static Info exp(final Variable A, ManagerTempVariables manager) { final Info ret = new Info(); if( A instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("exp-s") { @Override public void process() { output.value = Math.exp(((VariableScalar) A).getDouble()); } }; } else if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("exp-m") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix)A).matrix; DenseMatrix64F out = ((VariableMatrix)ret.output).matrix; out.reshape(a.numRows,a.numCols); CommonOps.elementExp(a, out); } }; } else { throw new RuntimeException("Only scalars are supported"); } return ret; } public static Info log(final Variable A, ManagerTempVariables manager) { final Info ret = new Info(); if( A instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("log-s") { @Override public void process() { output.value = Math.log(((VariableScalar) A).getDouble()); } }; } else if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("log-m") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix)A).matrix; DenseMatrix64F out = ((VariableMatrix)ret.output).matrix; out.reshape(a.numRows,a.numCols); CommonOps.elementLog(a,out); } }; } else { throw new RuntimeException("Only scalars are supported"); } return ret; } public static Info add(final Variable A, final Variable B, ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("add-mm") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; VariableMatrix mB = (VariableMatrix)B; resize(output, mA.matrix.numRows, mA.matrix.numCols); CommonOps.add(mA.matrix, mB.matrix, output.matrix); } }; } else if( A instanceof VariableInteger && B instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(0); ret.output = output; ret.op = new Operation("add-ii") { @Override public void process() { VariableInteger mA = (VariableInteger)A; VariableInteger mB = (VariableInteger)B; output.value = mA.value + mB.value; } }; } else if( A instanceof VariableScalar && B instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("add-ss") { @Override public void process() { VariableScalar mA = (VariableScalar)A; VariableScalar mB = (VariableScalar)B; output.value = mA.getDouble() + mB.getDouble(); } }; } else { final VariableMatrix output = manager.createMatrix(); ret.output = output; final VariableMatrix m; final VariableScalar s; if( A instanceof VariableMatrix ) { m = (VariableMatrix)A; s = (VariableScalar)B; } else { m = (VariableMatrix)B; s = (VariableScalar)A; } ret.op = new Operation("add-ms") { @Override public void process() { output.matrix.reshape(m.matrix.numRows,m.matrix.numCols); CommonOps.add(m.matrix, s.getDouble(), output.matrix); } }; } return ret; } public static Info subtract(final Variable A, final Variable B, ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("subtract-mm") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; VariableMatrix mB = (VariableMatrix)B; resize(output, mA.matrix.numRows, mA.matrix.numCols); CommonOps.subtract(mA.matrix, mB.matrix, output.matrix); } }; } else if( A instanceof VariableInteger && B instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(0); ret.output = output; ret.op = new Operation("subtract-ii") { @Override public void process() { VariableInteger mA = (VariableInteger)A; VariableInteger mB = (VariableInteger)B; output.value = mA.value - mB.value; } }; } else if( A instanceof VariableScalar && B instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("subtract-ss") { @Override public void process() { VariableScalar mA = (VariableScalar)A; VariableScalar mB = (VariableScalar)B; output.value = mA.getDouble() - mB.getDouble(); } }; } else { final VariableMatrix output = manager.createMatrix(); ret.output = output; if( A instanceof VariableMatrix ) { ret.op = new Operation("subtract-ms") { @Override public void process() { DenseMatrix64F m = ((VariableMatrix)A).matrix; double v = ((VariableScalar)B).getDouble(); output.matrix.reshape(m.numRows, m.numCols); CommonOps.subtract(m, v, output.matrix); } }; } else { ret.op = new Operation("subtract-sm") { @Override public void process() { DenseMatrix64F m = ((VariableMatrix)B).matrix; double v = ((VariableScalar)A).getDouble(); output.matrix.reshape(m.numRows, m.numCols); CommonOps.subtract(v, m, output.matrix); } }; } } return ret; } public static Info elementMult( final Variable A , final Variable B , ManagerTempVariables manager ) { Info ret = new Info(); if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("elementMult-mm") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; VariableMatrix mB = (VariableMatrix)B; resize(output, mA.matrix.numRows, mA.matrix.numCols); CommonOps.elementMult(mA.matrix, mB.matrix, output.matrix); } }; } else { throw new RuntimeException("Both inputs must be matrices for element wise multiplication"); } return ret; } public static Info elementDivision( final Variable A , final Variable B , ManagerTempVariables manager ) { Info ret = new Info(); if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("elementDivision-mm") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; VariableMatrix mB = (VariableMatrix)B; resize(output, mA.matrix.numRows, mA.matrix.numCols); CommonOps.elementDiv(mA.matrix, mB.matrix, output.matrix); } }; } else { throw new RuntimeException("Both inputs must be matrices for element wise multiplication"); } return ret; } public static Info elementPow(final Variable A, final Variable B, ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableScalar && B instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("elementPow-ss") { @Override public void process() { double a = ((VariableScalar) A).getDouble(); double b = ((VariableScalar) B).getDouble(); output.value = Math.pow(a, b); } }; } else if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("elementPow-mm") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix) A).matrix; DenseMatrix64F b = ((VariableMatrix) B).matrix; resize(output, a.numRows, a.numCols); CommonOps.elementPower(a, b, output.matrix); } }; } else if( A instanceof VariableMatrix && B instanceof VariableScalar ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("elementPow-ms") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix) A).matrix; double b = ((VariableScalar) B).getDouble(); resize(output, a.numRows, a.numCols); CommonOps.elementPower(a, b, output.matrix); } }; } else if( A instanceof VariableScalar && B instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("elementPow-sm") { @Override public void process() { double a = ((VariableScalar) A).getDouble(); DenseMatrix64F b = ((VariableMatrix) B).matrix; resize(output, b.numRows, b.numCols); CommonOps.elementPower(a, b, output.matrix); } }; } else { throw new RuntimeException("Unsupport element-wise power input types"); } return ret; } public static Operation copy( final Variable src , final Variable dst ) { if( src instanceof VariableMatrix ) { if( dst instanceof VariableMatrix ) { return new Operation("copy-mm") { @Override public void process() { DenseMatrix64F d = ((VariableMatrix) dst).matrix; DenseMatrix64F s = ((VariableMatrix) src).matrix; d.reshape(s.numRows, s.numCols); d.set(((VariableMatrix) src).matrix); } }; } else if( dst instanceof VariableDouble ) { return new Operation("copy-sm1") { @Override public void process() { DenseMatrix64F s = ((VariableMatrix) src).matrix; if( s.numRows != 1 || s.numCols != 1 ) { throw new RuntimeException("Attempting to assign a non 1x1 matrix to a double"); } ((VariableDouble) dst).value = s.unsafe_get(0,0); } }; } } if( src instanceof VariableInteger && dst instanceof VariableInteger ) { return new Operation("copy-ii") { @Override public void process() { ((VariableInteger)dst).value = ((VariableInteger)src).value; } }; } if( src instanceof VariableScalar && dst instanceof VariableDouble ) { return new Operation("copy-ss") { @Override public void process() { ((VariableDouble)dst).value = ((VariableScalar)src).getDouble(); } }; } throw new RuntimeException("Copy type miss-match src = "+src.getClass().getSimpleName()+" dst = "+dst.getClass().getSimpleName()); } public static Operation copy( final Variable src , final Variable dst , final List range ) { if( src instanceof VariableMatrix && dst instanceof VariableMatrix ) { return new Operation("copyR-mm") { Extents extents = new Extents(); @Override public void process() { DenseMatrix64F msrc = ((VariableMatrix) src).matrix; DenseMatrix64F mdst = ((VariableMatrix) dst).matrix; findExtents(mdst, range, 0, extents); if (extents.col1 - extents.col0 != msrc.numCols) throw new RuntimeException("Columns don't match"); if (extents.row1 - extents.row0 != msrc.numRows) throw new RuntimeException("Rows don't match"); CommonOps.insert(msrc, mdst, extents.row0, extents.col0); } }; } else if( src instanceof VariableScalar && dst instanceof VariableMatrix ) { return new Operation("copyR-sm") { Extents extents = new Extents(); @Override public void process() { double msrc = ((VariableScalar)src).getDouble(); DenseMatrix64F mdst = ((VariableMatrix)dst).matrix; findExtents(mdst,range,0,extents); if( !mdst.isInBounds(extents.row0,extents.col0)) throw new RuntimeException("Submatrix out of bounds. Lower extent"); if( !mdst.isInBounds(extents.row1-1,extents.col1-1)) throw new RuntimeException("Submatrix out of bounds. Upper extent"); for (int i = extents.row0; i < extents.row1; i++) { int index = i*mdst.numCols + extents.col0; for (int j = extents.col0; j < extents.col1; j++) { mdst.data[index++] = msrc; } } } }; } else { throw new RuntimeException("Both variables must be of type VariableMatrix"); } } public static Info transpose( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("transpose-m") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; output.matrix.reshape(mA.matrix.numCols, mA.matrix.numRows); CommonOps.transpose(mA.matrix, output.matrix); } }; } else { throw new RuntimeException("Transpose only makes sense for a matrix"); } return ret; } /** * Matrix inverse */ public static Info inv( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("inv-m") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; output.matrix.reshape(mA.matrix.numRows,mA.matrix.numCols); if( !CommonOps.invert(mA.matrix,output.matrix) ) throw new RuntimeException("Inverse failed!"); } }; } else { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("inv-s") { @Override public void process() { VariableScalar mA = (VariableScalar)A; output.value = 1.0/mA.getDouble(); } }; } return ret; } /** * Matrix pseudo-inverse */ public static Info pinv( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("pinv-m") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; output.matrix.reshape(mA.matrix.numCols, mA.matrix.numRows); CommonOps.pinv(mA.matrix, output.matrix); } }; } else { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("pinv-s") { @Override public void process() { VariableScalar mA = (VariableScalar)A; output.value = 1.0/mA.getDouble(); } }; } return ret; } public static Info rref( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("rref-m") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix)A).matrix; output.matrix.reshape(a.numRows,a.numCols); CommonOps.rref(a, -1, output.matrix); } }; } else { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("rref-s") { @Override public void process() { double a = ((VariableScalar)A).getDouble(); output.value = a == 0 ? 0 : 1; } }; } return ret; } /** * Matrix determinant */ public static Info det( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableMatrix ) { ret.op = new Operation("det-m") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; output.value = CommonOps.det(mA.matrix); } }; } else { ret.op = new Operation("det-s") { @Override public void process() { VariableScalar mA = (VariableScalar)A; output.value = mA.getDouble(); } }; } return ret; } public static Info trace( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableMatrix ) { ret.op = new Operation("trace-m") { @Override public void process() { VariableMatrix mA = (VariableMatrix)A; output.value=CommonOps.trace(mA.matrix); } }; } else { ret.op = new Operation("trace-s") { @Override public void process() { VariableScalar mA = (VariableScalar)A; output.value = mA.getDouble(); } }; } return ret; } public static Info normF( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableMatrix ) { ret.op = new Operation("normF-m") { @Override public void process() { output.value= NormOps.normF(((VariableMatrix) A).matrix); } }; } else { ret.op = new Operation("normF-s") { @Override public void process() { output.value = Math.abs(((VariableScalar) A).getDouble()); } }; } return ret; } public static Info max( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("max-m") { @Override public void process() { output.value = CommonOps.elementMax(((VariableMatrix) A).matrix); } }; } else if( A instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(); ret.output = output; ret.op = new Operation("max-i") { @Override public void process() { output.value = ((VariableInteger)A).value; } }; } else if( A instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("max-s") { @Override public void process() { output.value = ((VariableDouble)A).getDouble(); } }; } return ret; } public static Info min( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("min-m") { @Override public void process() { output.value = CommonOps.elementMin(((VariableMatrix) A).matrix); } }; } else if( A instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(); ret.output = output; ret.op = new Operation("min-i") { @Override public void process() { output.value = ((VariableInteger)A).value; } }; } else if( A instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("min-s") { @Override public void process() { output.value = ((VariableDouble)A).getDouble(); } }; } return ret; } public static Info abs( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("abs-m") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix)A).matrix; output.matrix.reshape(a.numRows,a.numCols); int N = a.getNumElements(); for (int i = 0; i < N; i++) { output.matrix.data[i] = Math.abs(a.data[i]); } } }; } else if( A instanceof VariableInteger ) { final VariableInteger output = manager.createInteger(); ret.output = output; ret.op = new Operation("abs-i") { @Override public void process() { output.value = Math.abs(((VariableInteger)A).value); } }; } else if( A instanceof VariableScalar ) { final VariableDouble output = manager.createDouble(); ret.output = output; ret.op = new Operation("abs-s") { @Override public void process() { output.value = Math.abs((((VariableDouble) A).getDouble())); } }; } return ret; } /** * Returns an identity matrix */ public static Info eye( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); final VariableMatrix output = manager.createMatrix(); ret.output = output; if( A instanceof VariableMatrix ) { ret.op = new Operation("eye-m") { @Override public void process() { DenseMatrix64F mA = ((VariableMatrix)A).matrix; output.matrix.reshape(mA.numRows,mA.numCols); CommonOps.setIdentity(output.matrix); } }; } else if( A instanceof VariableInteger ) { ret.op = new Operation("eye-i") { @Override public void process() { int N = ((VariableInteger)A).value; output.matrix.reshape(N,N); CommonOps.setIdentity(output.matrix); } }; } else { throw new RuntimeException("Unsupported variable type "+A); } return ret; } public static Info diag( final Variable A , ManagerTempVariables manager) { Info ret = new Info(); if( A instanceof VariableMatrix ) { final VariableMatrix output = manager.createMatrix(); ret.output = output; ret.op = new Operation("diag-m") { @Override public void process() { DenseMatrix64F mA = ((VariableMatrix)A).matrix; if(MatrixFeatures.isVector(mA)) { int N = mA.getNumElements(); output.matrix.reshape(N,N); CommonOps.diag(output.matrix,N,mA.data); } else { int N = Math.min(mA.numCols,mA.numRows); output.matrix.reshape(N,1); for (int i = 0; i < N; i++) { output.matrix.data[i] = mA.unsafe_get(i,i); } } } }; } else { throw new RuntimeException("diag requires a matrix as input"); } return ret; } /** * Returns a matrix full of zeros */ public static Info zeros( final Variable A , final Variable B , ManagerTempVariables manager) { Info ret = new Info(); final VariableMatrix output = manager.createMatrix(); ret.output = output; if( A instanceof VariableInteger && B instanceof VariableInteger ) { ret.op = new Operation("zeros-ii") { @Override public void process() { int numRows = ((VariableInteger)A).value; int numCols = ((VariableInteger)B).value; output.matrix.reshape(numRows,numCols); CommonOps.fill(output.matrix,0); //not sure if this is necessary. Can its value every be modified? } }; } else { throw new RuntimeException("Expected two integers got "+A+" "+B); } return ret; } /** * Returns a matrix full of ones */ public static Info ones( final Variable A , final Variable B , ManagerTempVariables manager) { Info ret = new Info(); final VariableMatrix output = manager.createMatrix(); ret.output = output; if( A instanceof VariableInteger && B instanceof VariableInteger ) { ret.op = new Operation("ones-ii") { @Override public void process() { int numRows = ((VariableInteger)A).value; int numCols = ((VariableInteger)B).value; output.matrix.reshape(numRows,numCols); CommonOps.fill(output.matrix,1); } }; } else { throw new RuntimeException("Expected two integers got "+A+" "+B); } return ret; } /** * Kronecker product */ public static Info kron( final Variable A , final Variable B, ManagerTempVariables manager) { Info ret = new Info(); final VariableMatrix output = manager.createMatrix(); ret.output = output; if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { ret.op = new Operation("kron-mm") { @Override public void process() { DenseMatrix64F mA = ((VariableMatrix)A).matrix; DenseMatrix64F mB = ((VariableMatrix)B).matrix; output.matrix.reshape(mA.numRows * mB.numRows, mA.numCols * mB.numCols); CommonOps.kron(mA, mB, output.matrix); } }; } else { throw new RuntimeException("Both inputs must be matrices "); } return ret; } /** * If input is two vectors then it returns the dot product as a double. */ public static Info dot( final Variable A , final Variable B , ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { ret.op = new Operation("dot-mm") { @Override public void process() { DenseMatrix64F a = ((VariableMatrix)A).matrix; DenseMatrix64F b = ((VariableMatrix)B).matrix; if( !MatrixFeatures.isVector(a) || !MatrixFeatures.isVector(b)) throw new RuntimeException("Both inputs to dot() must be vectors"); output.value = VectorVectorMult.innerProd(a,b); } }; } else { throw new RuntimeException("Expected two matrices got "+A+" "+B); } return ret; } /** * If input is two vectors then it returns the dot product as a double. */ public static Info solve( final Variable A , final Variable B , ManagerTempVariables manager) { Info ret = new Info(); final VariableMatrix output = manager.createMatrix(); ret.output = output; if( A instanceof VariableMatrix && B instanceof VariableMatrix ) { ret.op = new Operation("solve-mm") { LinearSolver solver; @Override public void process() { DenseMatrix64F a = ((VariableMatrix)A).matrix; DenseMatrix64F b = ((VariableMatrix)B).matrix; if( solver == null ) { solver = LinearSolverFactory.leastSquares(a.numRows,a.numCols); } if( !solver.setA(a)) throw new RuntimeException("Solver failed!"); output.matrix.reshape(a.numCols,b.numCols); solver.solve(b, output.matrix); } }; } else { throw new RuntimeException("Expected two matrices got "+A+" "+B); } return ret; } public static Info extract( final List inputs, ManagerTempVariables manager) { Info ret = new Info(); final VariableMatrix output = manager.createMatrix(); ret.output = output; if( !(inputs.get(0) instanceof VariableMatrix)) throw new RuntimeException("First parameter must be a matrix."); for (int i = 1; i < inputs.size(); i++) { if( !(inputs.get(i) instanceof VariableInteger) && !(inputs.get(i) instanceof VariableSpecial) ) throw new RuntimeException("Last parameters must be integers or special for sub"); } ret.op = new Operation("extract") { Extents extents = new Extents(); @Override public void process() { DenseMatrix64F A = ((VariableMatrix)inputs.get(0)).matrix; findExtents(A,inputs,1,extents); output.matrix.reshape(extents.row1-extents.row0,extents.col1-extents.col0); CommonOps.extract(A,extents.row0,extents.row1,extents.col0,extents.col1,output.matrix,0,0); } }; return ret; } public static Info extractScalar( final List inputs, ManagerTempVariables manager) { Info ret = new Info(); final VariableDouble output = manager.createDouble(); ret.output = output; if( !(inputs.get(0) instanceof VariableMatrix)) throw new RuntimeException("First parameter must be a matrix."); for (int i = 1; i < 3; i++) { if( !(inputs.get(i) instanceof VariableInteger) ) throw new RuntimeException("Parameters must be integers for extract scalar"); } ret.op = new Operation("extractScalar") { Extents extents = new Extents(); @Override public void process() { DenseMatrix64F A = ((VariableMatrix)inputs.get(0)).matrix; int row = ((VariableInteger)inputs.get(1)).value; int col = ((VariableInteger)inputs.get(2)).value; output.value = A.get(row,col); } }; return ret; } /** * Parses the inputs to figure out the range of a sub-matrix. Special variables are handled to set * relative values */ protected static void findExtents( DenseMatrix64F A, List inputs , int where ,Extents e ) { if( inputs.get(where).getType() == VariableType.SPECIAL ) { e.row0 = 0; e.row1 = A.numRows; where++; } else { e.row0 = ((VariableInteger)inputs.get(where++)).value; if( inputs.get(where).getType() == VariableType.SPECIAL ) { e.row1 = A.numRows; } else { e.row1 = ((VariableInteger)inputs.get(where)).value+1; } where++; } if( inputs.get(where).getType() == VariableType.SPECIAL ) { e.col0 = 0; e.col1 = A.numCols; where++; } else { e.col0 = ((VariableInteger)inputs.get(where++)).value; if( inputs.get(where).getType() == VariableType.SPECIAL ) { e.col1 = A.numCols; } else { e.col1 = ((VariableInteger)inputs.get(where)).value+1; } where++; } if( where != inputs.size()) throw new RuntimeException("Unexpected number of inputs"); } public static Info matrixConstructor( final MatrixConstructor m ) { Info ret = new Info(); ret.output = m.getOutput(); ret.op = new Operation("matrixConstructor") { @Override public void process() { m.construct(); } }; return ret; } public static class Extents { int row0,row1; int col0,col1; } public static class Info { public Operation op; public Variable output; } } ejml-0.28/main/equation/src/org/ejml/equation/Sequence.java000066400000000000000000000026521256171534400237250ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import java.util.ArrayList; import java.util.List; /** * Contains a sequence of operations. This is the final result of compiling the equation. Once created it can * be invoked an arbitrary number of times by invoking {@link #perform()}. * * @author Peter Abeles */ public class Sequence { // List of in sequence operations which the equation string described List operations = new ArrayList(); public void addOperation( Operation operation ) { operations.add(operation); } /** * Executes the sequence of operations */ public void perform() { for (int i = 0; i < operations.size(); i++) { operations.get(i).process(); } } } ejml-0.28/main/equation/src/org/ejml/equation/Symbol.java000066400000000000000000000041661256171534400234240ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Types of low level operators which can be applied in the code * * @author Peter Abeles */ public enum Symbol { PLUS, MINUS, TIMES, LDIVIDE, RDIVIDE, POWER, PERIOD, ELEMENT_TIMES, ELEMENT_DIVIDE, ELEMENT_POWER, ASSIGN, PAREN_LEFT, PAREN_RIGHT, BRACKET_LEFT, BRACKET_RIGHT, COMMA, TRANSPOSE, COLON, SEMICOLON; public static Symbol lookup( char c ) { switch( c ) { case '.': return PERIOD; case ',': return COMMA; case '\'': return TRANSPOSE; case '+': return PLUS; case '-': return MINUS; case '*': return TIMES; case '\\': return LDIVIDE; case '/': return RDIVIDE; case '^': return POWER; case '=': return ASSIGN; case '(': return PAREN_LEFT; case ')': return PAREN_RIGHT; case '[': return BRACKET_LEFT; case ']': return BRACKET_RIGHT; case ':': return COLON; case ';': return SEMICOLON; } throw new RuntimeException("Unknown type "+c); } public static Symbol lookupElementWise( char c ) { switch( c ) { case '*': return ELEMENT_TIMES; case '/': return ELEMENT_DIVIDE; case '^': return ELEMENT_POWER; } throw new RuntimeException("Unknown element-wise type "+c); } } ejml-0.28/main/equation/src/org/ejml/equation/TokenList.java000066400000000000000000000214451256171534400240720ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Linked-list of tokens parsed from the equations string. * * @author Peter Abeles */ class TokenList { Token first; Token last; int size = 0; public TokenList() { } /** * Creates a list from the two given tokens. These tokens are assumed to form a linked list starting at 'first' * and ending at 'last' * @param first First element in the new list * @param last Last element in the new list */ public TokenList(Token first, Token last) { this.first = first; this.last = last; Token t = first; while( t != null ) { size++; t = t.next; } } /** * Adds a function to the end of the token list * @param function Function which is to be added * @return The new Token created around function */ public Token add( Function function ) { Token t = new Token(function); push( t ); return t; } /** * Adds a variable to the end of the token list * @param variable Variable which is to be added * @return The new Token created around variable */ public Token add( Variable variable ) { Token t = new Token(variable); push( t ); return t; } /** * Adds a symbol to the end of the token list * @param symbol Symbol which is to be added * @return The new Token created around symbol */ public Token add( Symbol symbol ) { Token t = new Token(symbol); push( t ); return t; } /** * Adds a word to the end of the token list * @param word word which is to be added * @return The new Token created around symbol */ public Token add( String word ) { Token t = new Token(word); push( t ); return t; } /** * Adds a new Token to the end of the linked list */ public void push( Token token ) { size++; if( first == null ) { first = token; last = token; token.previous = null; token.next = null; } else { last.next = token; token.previous = last; token.next = null; last = token; } } /** * Inserts 'token' after 'where'. if where is null then it is inserted to the beginning of the list. * @param where Where 'token' should be inserted after. if null the put at it at the beginning * @param token The token that is to be inserted */ public void insert( Token where , Token token ) { if( where == null ) { // put at the front of the list if( size == 0 ) push(token); else { first.previous = token; token.previous = null; token.next = first; first = token; size++; } } else if( where == last || null == last ) { push(token); } else { token.next = where.next; token.previous = where; where.next.previous = token; where.next = token; size++; } } /** * Removes the token from the list * @param token Token which is to be removed */ public void remove( Token token ) { if( token == first ) { first = first.next; } if( token == last ) { last = last.previous; } if( token.next != null ) { token.next.previous = token.previous; } if( token.previous != null ) { token.previous.next = token.next; } token.next = token.previous = null; size--; } /** * Removes 'original' and places 'target' at the same location */ public void replace( Token original , Token target ) { if( first == original ) first = target; if( last == original ) last = target; target.next = original.next; target.previous = original.previous; if( original.next != null ) original.next.previous = target; if( original.previous != null ) original.previous.next = target; original.next = original.previous = null; } /** * Removes elements from begin to end from the list, inclusive. Returns a new list which * is composed of the removed elements */ public TokenList extractSubList( Token begin , Token end ) { if( begin == end ) { remove(begin); return new TokenList(begin,begin); } else { if( first == begin ) { first = end.next; } if( last == end ) { last = begin.previous; } if( begin.previous != null ) { begin.previous.next = end.next; } if( end.next != null ) { end.next.previous = begin.previous; } begin.previous = null; end.next = null; TokenList ret = new TokenList(begin,end); size -= ret.size(); return ret; } } /** * Prints the list of tokens */ public String toString() { String ret = ""; Token t = first; while( t != null ) { ret += t +" "; t = t.next; } return ret; } /** * First token in the list */ public Token getFirst() { return first; } /** * Last token in the list */ public Token getLast() { return last; } /** * Number of tokens in the list */ public int size() { return size; } /** * The token class contains a reference to parsed data (e.g. function, variable, or symbol) and reference * to list elements before and after it. */ public static class Token { /** * Next element in the list. If null then it's at the end of the list */ public Token next; /** * Previous element in the list. If null then it's the first element in the list */ public Token previous; public Function function; public Variable variable; public Symbol symbol; public String word; public Token(Function function) { this.function = function; } public Token(Variable variable) { this.variable = variable; } public Token(VariableSpecial.Special special) { this.variable = new VariableSpecial(special); } public Token(Symbol symbol) { this.symbol = symbol; } public Token(String word) { this.word = word; } public Type getType() { if( function != null ) return Type.FUNCTION; else if( variable != null ) return Type.VARIABLE; else if( word != null ) return Type.WORD; else return Type.SYMBOL; } public Variable getVariable() { return variable; } public Function getFunction() { return function; } public Symbol getSymbol() { return symbol; } public String getWord() { return word; } public String toString() { switch( getType() ) { case FUNCTION: return "Func:"+function.getName(); case SYMBOL: return ""+symbol; case VARIABLE: return variable.toString(); case WORD: return "Word:"+word; } throw new RuntimeException("Unknown type"); } } public void print() { Token t = first; while( t != null ) { System.out.println(t); t = t.next; } } /** * Specifies the type of data stored in a Token. */ public static enum Type { FUNCTION, VARIABLE, SYMBOL, WORD } } ejml-0.28/main/equation/src/org/ejml/equation/Variable.java000066400000000000000000000021611256171534400236750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Instance of a variable created at compile time. This base class only specifies the type of variable which it is. * * @author Peter Abeles */ public class Variable { public VariableType type; protected Variable(VariableType type) { this.type = type; } public VariableType getType() { return type; } public String toString() { return "Var" + type; } } ejml-0.28/main/equation/src/org/ejml/equation/VariableDouble.java000066400000000000000000000020131256171534400250240ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Variable which stores an instance of double. * * @author Peter Abeles */ public class VariableDouble extends VariableScalar { public double value; public VariableDouble(double value) { this.value = value; } @Override public double getDouble() { return value; } } ejml-0.28/main/equation/src/org/ejml/equation/VariableInteger.java000066400000000000000000000020041256171534400252070ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Variable which stores an instance of int. * * @author Peter Abeles */ public class VariableInteger extends VariableScalar { public int value; public VariableInteger(int value) { this.value = value; } @Override public double getDouble() { return value; } } ejml-0.28/main/equation/src/org/ejml/equation/VariableMatrix.java000066400000000000000000000032411256171534400250620ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.ejml.data.DenseMatrix64F; /** * Storage for {@link org.ejml.data.DenseMatrix64F matrix} type variables. * * @author Peter Abeles */ public class VariableMatrix extends Variable { public DenseMatrix64F matrix; /** * If true then the matrix is dynamically resized to match the output of a function */ public boolean temp; /** * Initializes the matrix variable. If null then the variable will be a reference one. If not null then * it will be assignment. * @param matrix Matrix. */ public VariableMatrix(DenseMatrix64F matrix) { super(VariableType.MATRIX); this.matrix = matrix; } public static VariableMatrix createTemp() { VariableMatrix ret = new VariableMatrix(new DenseMatrix64F(1,1)); ret.setTemp(true); return ret; } public boolean isTemp() { return temp; } public void setTemp(boolean temp) { this.temp = temp; } } ejml-0.28/main/equation/src/org/ejml/equation/VariableScalar.java000066400000000000000000000017511256171534400250270ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Variable for storing primitive scalar data types, e.g. int and double. * * @author Peter Abeles */ public abstract class VariableScalar extends Variable { public VariableScalar() { super(VariableType.SCALAR); } public abstract double getDouble(); } ejml-0.28/main/equation/src/org/ejml/equation/VariableSpecial.java000066400000000000000000000022651256171534400252030ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * Variables which have special meanings depending on other matrices * * @author Peter Abeles */ public class VariableSpecial extends Variable { Special type; protected VariableSpecial( Special special) { super(VariableType.SPECIAL); this.type = special; } public Special getValue() { return type; } public static enum Special { /** Maximum possible value */ END, /** All values */ ALL } } ejml-0.28/main/equation/src/org/ejml/equation/VariableType.java000066400000000000000000000015271256171534400245440ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; /** * List of the types of variables. * * @author Peter Abeles */ public enum VariableType { MATRIX, SCALAR, SPECIAL } ejml-0.28/main/equation/test/000077500000000000000000000000001256171534400161325ustar00rootroot00000000000000ejml-0.28/main/equation/test/org/000077500000000000000000000000001256171534400167215ustar00rootroot00000000000000ejml-0.28/main/equation/test/org/ejml/000077500000000000000000000000001256171534400176505ustar00rootroot00000000000000ejml-0.28/main/equation/test/org/ejml/equation/000077500000000000000000000000001256171534400214755ustar00rootroot00000000000000ejml-0.28/main/equation/test/org/ejml/equation/TestEquation.java000066400000000000000000000652021256171534400247720ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.MatrixFeatures; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.ejml.equation.TokenList.Type; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestEquation { Random rand = new Random(234); /** * Basic test which checks ability parse basic operators and order of operation */ @Test public void compile_basic() { Equation eq = new Equation(); SimpleMatrix A = new SimpleMatrix(5, 6); SimpleMatrix B = SimpleMatrix.random(5, 6, -1, 1, rand); SimpleMatrix C = SimpleMatrix.random(5, 4, -1, 1, rand); SimpleMatrix D = SimpleMatrix.random(4, 6, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(C, "C"); eq.alias(D, "D"); Sequence sequence = eq.compile("A=B+C*D-B"); SimpleMatrix expected = C.mult(D); sequence.perform(); assertTrue(expected.isIdentical(A,1e-15)); } /** * Output is included in input */ @Test public void compile_output() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 6, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); Sequence sequence = eq.compile("A=A*B"); SimpleMatrix expected = A.mult(B); sequence.perform(); assertTrue(expected.isIdentical(A,1e-15)); } /** * Results are assigned to a sub-matrix */ @Test public void compile_assign_submatrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(2, 5, -1, 1, rand); SimpleMatrix A_orig = A.copy(); eq.alias(A, "A"); eq.alias(B, "B"); Sequence sequence = eq.compile("A(2:3,0:4)=B"); sequence.perform(); for (int y = 0; y < 6; y++) { for (int x = 0; x < 6; x++) { if( x < 5 && y >= 2 && y <= 3 ) { assertTrue(A.get(y,x) == B.get(y-2,x)); } else { assertTrue(x+" "+y,A.get(y,x) == A_orig.get(y,x)); } } } } @Test public void compile_assign_submatrix_special() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(4, 5, -1, 1, rand); SimpleMatrix A_orig = A.copy(); eq.alias(A, "A"); eq.alias(B, "B"); eq.process("A(2:,:)=B"); for (int y = 0; y < 6; y++) { for (int x = 0; x < 5; x++) { if( y >= 2 ) { assertTrue(A.get(y,x) == B.get(y-2,x)); } else { assertTrue(x+" "+y,A.get(y,x) == A_orig.get(y,x)); } } } } @Test public void compile_assign_submatrix_scalar() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(A, "A"); // single element eq.process("A(1,2)=0.5"); assertEquals(A.get(1, 2), 0.5, 1e-8); // multiple elements eq.process("A(1:2,2:4)=0.5"); for (int i = 1; i <= 2; i++) { for (int j = 2; j <= 4; j++) { assertEquals(A.get(i, j), 0.5, 1e-8); } } } /** * Lazily declare a variable. Which means it is not explicitly aliased */ @Test public void assign_lazy() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(A, "A"); eq.process("B=A"); DenseMatrix64F B = eq.lookupMatrix("B"); assertTrue(A.getMatrix()!=B); assertTrue(MatrixFeatures.isEquals(A.getMatrix(),B)); } /** * Place an unknown variable on the right and see if it blows up */ @Test(expected = RuntimeException.class) public void assign_lazy_right() { new Equation().process("B=A"); } /** * See if matrices are automatically resized when assinged a value */ @Test public void assign_resize_lazy() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(2, 3, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.process("B=A"); assertTrue(A.isIdentical(B,1e-8)); } @Test public void compile_parentheses() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix C = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix R = new SimpleMatrix(6, 6); eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(C, "C"); eq.alias(R, "R"); eq.process("R=A*(B+C)"); SimpleMatrix expected = A.mult(B.plus(C)); assertTrue(expected.isIdentical(R, 1e-15)); // try again with pointless ones eq.process("R=(A*((B+(C))))"); assertTrue(expected.isIdentical(R,1e-15)); } @Test public void compile_parentheses_extract() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(8, 8, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); Sequence sequence = eq.compile("A=B(2:7,1:6)"); sequence.perform(); assertTrue(A.isIdentical(B.extractMatrix(2,8,1,7), 1e-15)); // get single values now A = SimpleMatrix.random(6, 1, -1, 1, rand); eq.alias(A, "A"); sequence = eq.compile("A=B(2:7,3)"); sequence.perform(); assertTrue(A.isIdentical(B.extractMatrix(2,8,3,4), 1e-15)); // multiple in a row A = SimpleMatrix.random(1, 2, -1, 1, rand); eq.alias(A, "A"); sequence = eq.compile("A=(B(2:7,3:6))(0:0,1:2)"); sequence.perform(); assertTrue(A.isIdentical(B.extractMatrix(2,3,4,6), 1e-15)); } @Test public void compile_parentheses_extractSpecial() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 8, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(8, 8, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.process("A=B(2:,:)"); assertTrue(A.isIdentical(B.extractMatrix(2,8,0,8), 1e-15)); B = SimpleMatrix.random(6, 10, -1, 1, rand); eq.alias(B, "B"); eq.process("A=B(:,2:)"); assertTrue(A.isIdentical(B.extractMatrix(0,6,2,10), 1e-15)); } @Test public void compile_parentheses_extractScalar() { Equation eq = new Equation(); SimpleMatrix B = SimpleMatrix.random(8, 8, -1, 1, rand); eq.alias(B, "B"); eq.process("A=B(1,2)"); Variable v = eq.lookupVariable("A"); assertTrue(v instanceof VariableDouble); assertEquals(eq.lookupDouble("A"),B.get(1,2),1e-8); } @Test public void compile_neg() { Equation eq = new Equation(); eq.alias(1, "A",2, "B"); eq.process("A=-B"); assertEquals(-2, eq.lookupInteger("A")); eq.process("A=B--B"); assertEquals(4, eq.lookupInteger("A")); eq.process("A=B+-B"); assertEquals(0,eq.lookupInteger("A")); eq.process("A=B---5"); assertEquals(2-5,eq.lookupInteger("A")); eq.process("A=B--5"); assertEquals(2+5,eq.lookupInteger("A")); } @Test public void compile_constructMatrix_scalars() { Equation eq = new Equation(); SimpleMatrix expected = new SimpleMatrix(new double[][]{{0,1,2,3},{4,5,6,7},{8,1,1,1}}); SimpleMatrix A = new SimpleMatrix(3,4); eq.alias(A, "A"); Sequence sequence = eq.compile("A=[0 1 2 3; 4 5 6 7;8 1 1 1]"); sequence.perform(); assertTrue(A.isIdentical(expected, 1e-8)); } @Test public void compile_constructMatrix_MatrixAndScalar() { Equation eq = new Equation(); SimpleMatrix A = new SimpleMatrix(new double[][]{{0,1,2,3}}); SimpleMatrix found = new SimpleMatrix(1,5); eq.alias(A, "A"); eq.alias(found, "found"); Sequence sequence = eq.compile("found=[A 4]"); sequence.perform(); for (int i = 0; i < 5; i++) { assertEquals(found.get(0,i),i,1e-4); } } @Test public void compile_constructMatrix_Operations() { Equation eq = new Equation(); SimpleMatrix A = new SimpleMatrix(new double[][]{{0,1,2,3}}); SimpleMatrix found = new SimpleMatrix(5,1); eq.alias(A, "A"); eq.alias(found, "found"); Sequence sequence = eq.compile("found=[A' ; 4]"); sequence.perform(); for (int i = 0; i < 5; i++) { assertEquals(found.get(i,0),i,1e-4); } } @Test public void compile_constructMatrix_Inner() { Equation eq = new Equation(); SimpleMatrix found = new SimpleMatrix(3,2); eq.alias(found, "found"); Sequence sequence = eq.compile("found=[[1 2 3]' [4 5 [6]]']"); sequence.perform(); int index = 1; for (int x = 0; x < 2; x++) { for (int y = 0; y < 3; y++) { assertEquals(x+" "+y,found.get(y,x),index++,1e-8); } } } @Test public void compile_transpose() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix C = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix R = new SimpleMatrix(6, 6); eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(C, "C"); eq.alias(R, "R"); Sequence sequence = eq.compile("R=A'*(B'+C)'+inv(B)'"); SimpleMatrix expected = A.transpose().mult(B.transpose().plus(C).transpose()).plus(B.invert().transpose()); sequence.perform(); assertTrue(expected.isIdentical(R, 1e-15)); } @Test public void compile_elementWise() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix C = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix R = new SimpleMatrix(6, 6); eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(C, "C"); eq.alias(R, "R"); Sequence sequence = eq.compile("R=A.*(B./C)"); SimpleMatrix expected = A.elementMult(B.elementDiv(C)); sequence.perform(); assertTrue(expected.isIdentical(R, 1e-15)); } @Test public void compile_double() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 6, -1, 1, rand); double C = 2.5; double D = 1.7; eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(D, "D"); eq.alias(0.0, "E"); VariableDouble E = eq.lookupVariable("E"); Sequence sequence = eq.compile("A=2.5*B"); SimpleMatrix expected = B.scale(C); sequence.perform(); assertTrue(expected.isIdentical(A, 1e-15)); sequence = eq.compile("A=B*2.5"); sequence.perform(); assertTrue(expected.isIdentical(A, 1e-15)); sequence = eq.compile("E=2.5*D"); sequence.perform(); assertEquals(C * D, E.value, 1e-8); // try exponential formats sequence = eq.compile("E=2.001e-6*1e3"); sequence.perform(); assertEquals(2.001e-6*1e3, E.value, 1e-8); } /** * Function with one input */ @Test public void compile_function_one() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix C = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix R = new SimpleMatrix(6, 6); eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(C, "C"); eq.alias(R, "R"); // easy case Sequence sequence = eq.compile("R=inv(A)"); SimpleMatrix expected = A.invert(); sequence.perform(); assertTrue(expected.isIdentical(R, 1e-15)); // harder case sequence = eq.compile("R=inv(A)+det((A+B)*C)*B"); expected = A.invert().plus( B.scale(A.plus(B).mult(C).determinant())); sequence.perform(); assertTrue(expected.isIdentical(R, 1e-15)); // this should throw an exception try { eq.compile("R=inv*B"); fail("Implement"); } catch( RuntimeException ignore ){} } /** * Function with two input */ @Test public void compile_function_N() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(3, 4, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(4, 5, -1, 1, rand); SimpleMatrix R = new SimpleMatrix(12, 20); eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(R, "R"); eq.process("R=kron(A,B)"); SimpleMatrix expected = A.kron(B); assertTrue(expected.isIdentical(R, 1e-15)); eq.process("R=kron(A+(A')',(B+B))"); expected = A.plus(A).kron(B.plus(B)); assertTrue(expected.isIdentical(R, 1e-15)); } @Test public void handleParentheses() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); eq.functions.setManagerTemp( managerTemp ); eq.alias(new DenseMatrix64F(1, 1), "A"); eq.alias(new DenseMatrix64F(1, 1), "B"); eq.alias(new DenseMatrix64F(1, 1), "C"); // handle empty case Sequence sequence = new Sequence(); TokenList tokens = eq.extractTokens("((()))()",managerTemp); eq.handleParentheses(tokens,sequence); assertEquals(0,sequence.operations.size()); assertEquals(0,tokens.size); // embedded with just one variable sequence = new Sequence(); tokens = eq.extractTokens("(((A)))",managerTemp); eq.handleParentheses(tokens,sequence); assertEquals(0,sequence.operations.size()); assertEquals(1,tokens.size); assertTrue(tokens.first.getType() == Type.VARIABLE); // pointless sequence = new Sequence(); tokens = eq.extractTokens("((A)*(B)+(C))",managerTemp); eq.handleParentheses(tokens,sequence); assertEquals(2,sequence.operations.size()); assertEquals(1,tokens.size); assertTrue(tokens.first.getType() == Type.VARIABLE); } @Test public void parseOperations() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); eq.functions.setManagerTemp( managerTemp ); eq.alias(new DenseMatrix64F(1, 1), "A"); eq.alias(new DenseMatrix64F(1, 1), "B"); eq.alias(new DenseMatrix64F(1, 1), "C"); // give it an empty list TokenList tokens = eq.extractTokens("",managerTemp); Sequence sequence = new Sequence(); eq.parseOperationsLR(new Symbol[]{Symbol.TIMES}, tokens, sequence); assertEquals(0,sequence.operations.size()); assertEquals(0,tokens.size); // other cases tokens = eq.extractTokens("B+B-A*B*A",managerTemp); sequence = new Sequence(); eq.parseOperationsLR(new Symbol[]{Symbol.TIMES}, tokens, sequence); assertEquals(2,sequence.operations.size()); assertEquals(5,tokens.size); assertTrue(tokens.last.getType() == Type.VARIABLE); assertTrue(Symbol.MINUS==tokens.last.previous.getSymbol()); tokens = eq.extractTokens("B+B*B*A-B",managerTemp); sequence = new Sequence(); eq.parseOperationsLR(new Symbol[]{Symbol.PLUS, Symbol.MINUS}, tokens, sequence); assertEquals(2,sequence.operations.size()); assertEquals(5,tokens.size); assertTrue(tokens.last.getType() == Type.VARIABLE); assertTrue(Symbol.TIMES == tokens.last.previous.getSymbol()); assertTrue(Symbol.TIMES == tokens.first.next.next.next.getSymbol()); } @Test public void createOp() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); eq.functions.setManagerTemp( managerTemp ); eq.alias(new DenseMatrix64F(1, 1), "A"); eq.alias(new DenseMatrix64F(1, 1), "B"); TokenList tokens = eq.extractTokens("A=A*B",managerTemp); TokenList.Token t0 = tokens.first.next.next; TokenList.Token t1 = t0.next; TokenList.Token t2 = t1.next; Sequence sequence = new Sequence(); TokenList.Token found = eq.createOp(t0,t1,t2,tokens,sequence); assertTrue(found.getType() == Type.VARIABLE); assertEquals(3, tokens.size); assertTrue(Symbol.ASSIGN == tokens.first.next.getSymbol()); assertTrue(found==tokens.last); assertEquals(1, sequence.operations.size()); } @Test public void lookupVariable() { Equation eq = new Equation(); eq.alias(new DenseMatrix64F(1,1),"A"); eq.alias(new DenseMatrix64F(1,1),"BSD"); eq.lookupVariable("A"); eq.lookupVariable("BSD"); assertTrue( null == eq.lookupVariable("dDD") ); } @Test public void extractTokens() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); eq.alias(new DenseMatrix64F(1,1),"A"); eq.alias(new DenseMatrix64F(1,1),"BSD"); Variable v0 = eq.lookupVariable("A"); Variable v1 = eq.lookupVariable("BSD"); TokenList list = eq.extractTokens("A = A*A + BSD*(A+BSD) -A*BSD",managerTemp); TokenList.Token t = list.getFirst(); assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.ASSIGN==t.getSymbol()); t = t.next; assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.PLUS==t.getSymbol()); t = t.next; assertTrue(v1==t.getVariable()); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertTrue(Symbol.PAREN_LEFT==t.getSymbol()); t = t.next; assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.PLUS==t.getSymbol()); t = t.next; assertTrue(v1==t.getVariable()); t = t.next; assertTrue(Symbol.PAREN_RIGHT==t.getSymbol()); t = t.next; assertTrue(Symbol.MINUS==t.getSymbol()); t = t.next; assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertTrue(v1==t.getVariable()); t = t.next; } @Test public void extractTokens_elementWise() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); eq.alias(new DenseMatrix64F(1,1),"A"); eq.alias(new DenseMatrix64F(1,1),"BSD"); Variable v0 = eq.lookupVariable("A"); Variable v1 = eq.lookupVariable("BSD"); TokenList list = eq.extractTokens("A = (A.*A)./BSD",managerTemp); TokenList.Token t = list.getFirst(); assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.ASSIGN==t.getSymbol()); t = t.next; assertTrue(Symbol.PAREN_LEFT==t.getSymbol()); t = t.next; assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.ELEMENT_TIMES==t.getSymbol()); t = t.next; assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.PAREN_RIGHT==t.getSymbol()); t = t.next; assertTrue(Symbol.ELEMENT_DIVIDE==t.getSymbol()); t = t.next; assertTrue(v1==t.getVariable()); t = t.next; } @Test public void extractTokens_integers() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); eq.alias(new DenseMatrix64F(1,1),"A"); eq.alias(new DenseMatrix64F(1,1),"BSD"); Variable v0 = eq.lookupVariable("A"); Variable v1 = eq.lookupVariable("BSD"); TokenList list = eq.extractTokens("A*2 + 345 + 56*BSD*934",managerTemp); TokenList.Token t = list.getFirst(); assertTrue(v0 == t.getVariable()); t = t.next; assertTrue(Symbol.TIMES == t.getSymbol()); t = t.next; assertEquals(2, ((VariableInteger) t.getVariable()).value); t = t.next; assertTrue(Symbol.PLUS == t.getSymbol()); t = t.next; assertEquals(345, ((VariableInteger) t.getVariable()).value); t = t.next; assertTrue(Symbol.PLUS==t.getSymbol()); t = t.next; assertEquals(56, ((VariableInteger) t.getVariable()).value); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertTrue(v1==t.getVariable()); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertEquals(934, ((VariableInteger) t.getVariable()).value); t = t.next; } @Test public void extractTokens_doubles() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); eq.alias(new DenseMatrix64F(1,1),"A"); eq.alias(new DenseMatrix64F(1,1),"BSD"); Variable v0 = eq.lookupVariable("A"); Variable v1 = eq.lookupVariable("BSD"); TokenList list = eq.extractTokens("A*2. + 345.034 + 0.123*BSD*5.1",managerTemp); TokenList.Token t = list.getFirst(); assertTrue(v0==t.getVariable()); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertTrue(2 == ((VariableDouble) t.getVariable()).value); t = t.next; assertTrue(Symbol.PLUS==t.getSymbol()); t = t.next; assertTrue(345.034 == ((VariableDouble) t.getVariable()).value); t = t.next; assertTrue(Symbol.PLUS==t.getSymbol()); t = t.next; assertTrue(0.123 == ((VariableDouble) t.getVariable()).value); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertTrue(v1==t.getVariable()); t = t.next; assertTrue(Symbol.TIMES==t.getSymbol()); t = t.next; assertTrue(5.1==((VariableDouble)t.getVariable()).value); assertTrue(t.next == null); } /** * See if the minus symbol is handled correctly. It's meaning can very depending on the situation. */ @Test public void extractTokens_minus() { Equation eq = new Equation(); ManagerTempVariables managerTemp = new ManagerTempVariables(); TokenList list = eq.extractTokens("- 1.2",managerTemp); TokenList.Token t = list.getFirst(); assertTrue(Symbol.MINUS==t.getSymbol()); t = t.next; assertTrue(1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); list = eq.extractTokens("-1.2",managerTemp); t = list.getFirst(); assertTrue(-1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); list = eq.extractTokens("2.1-1.2",managerTemp); t = list.getFirst(); assertTrue(2.1 == ((VariableDouble) t.getVariable()).value); t = t.next; assertTrue(Symbol.MINUS==t.getSymbol()); t = t.next; assertTrue(1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); list = eq.extractTokens("2.1 -1.2",managerTemp); t = list.getFirst(); assertTrue(2.1 == ((VariableDouble) t.getVariable()).value); t = t.next; assertTrue(Symbol.MINUS==t.getSymbol()); t = t.next; assertTrue(1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); list = eq.extractTokens("2.1 - -1.2",managerTemp); t = list.getFirst(); assertTrue(2.1 == ((VariableDouble) t.getVariable()).value); t = t.next; assertTrue(Symbol.MINUS==t.getSymbol()); t = t.next; assertTrue(-1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); list = eq.extractTokens("inv(2.1) -1.2",managerTemp); t = list.getFirst(); assertTrue(t.getFunction().getName().equals("inv")); t = t.next; assertTrue(Symbol.PAREN_LEFT==t.getSymbol()); t = t.next; assertTrue(2.1 == ((VariableDouble) t.getVariable()).value); t = t.next; assertTrue(Symbol.PAREN_RIGHT==t.getSymbol()); t = t.next; assertTrue(Symbol.MINUS==t.getSymbol()); t = t.next; assertTrue(1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); list = eq.extractTokens("= -1.2",managerTemp); t = list.getFirst(); assertTrue(Symbol.ASSIGN==t.getSymbol()); t = t.next; assertTrue(-1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); list = eq.extractTokens("= - 1.2",managerTemp); t = list.getFirst(); assertTrue(Symbol.ASSIGN==t.getSymbol()); t = t.next; assertTrue(Symbol.MINUS==t.getSymbol()); t = t.next; assertTrue(1.2 == ((VariableDouble) t.getVariable()).value); assertTrue(t.next==null); } @Test public void isTargetOp() { Symbol[] targets = new Symbol[]{Symbol.PERIOD,Symbol.TIMES,Symbol.TRANSPOSE}; assertTrue(Equation.isTargetOp(new TokenList.Token(Symbol.TIMES),targets)); assertFalse(Equation.isTargetOp(new TokenList.Token(Symbol.RDIVIDE), targets)); } @Test public void isLetter() { assertTrue(Equation.isLetter('a')); assertTrue(Equation.isLetter('_')); assertTrue(Equation.isLetter('5')); assertFalse(Equation.isLetter(' ')); assertFalse(Equation.isLetter('\t')); assertFalse(Equation.isLetter('*')); assertFalse(Equation.isLetter('+')); assertFalse(Equation.isLetter('-')); assertFalse(Equation.isLetter('(')); assertFalse(Equation.isLetter(')')); assertFalse(Equation.isLetter('=')); } } ejml-0.28/main/equation/test/org/ejml/equation/TestMatrixConstructor.java000066400000000000000000000053001256171534400267100ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestMatrixConstructor { Random rand = new Random(234); @Test public void basicTest() { DenseMatrix64F A = RandomMatrices.createRandom(10,8,rand); DenseMatrix64F B = CommonOps.extract(A,0,5,0,3); DenseMatrix64F C = CommonOps.extract(A,0,5,3,8); DenseMatrix64F D = CommonOps.extract(A,5,10,0,8); MatrixConstructor alg = new MatrixConstructor(new ManagerTempVariables()); alg.addToRow(new VariableMatrix(B)); alg.addToRow(new VariableMatrix(C)); alg.endRow(); alg.addToRow(new VariableMatrix(D)); alg.construct(); DenseMatrix64F found = alg.getOutput().matrix; assertTrue(MatrixFeatures.isIdentical(A, found, 1e-8)); } @Test public void setToRequiredSize_matrix() { MatrixConstructor alg = new MatrixConstructor(new ManagerTempVariables()); alg.addToRow(new VariableMatrix(new DenseMatrix64F(2, 3))); alg.addToRow(new VariableMatrix(new DenseMatrix64F(2, 4))); alg.endRow(); alg.addToRow(new VariableMatrix(new DenseMatrix64F(1, 7))); alg.endRow(); DenseMatrix64F a = new DenseMatrix64F(1,1); alg.setToRequiredSize(a); assertEquals(7,a.numCols); assertEquals(3,a.numRows); } @Test public void setToRequiredSize_scalar() { MatrixConstructor alg = new MatrixConstructor(new ManagerTempVariables()); alg.addToRow(new VariableDouble(123)); alg.addToRow(new VariableDouble(1)); alg.endRow(); DenseMatrix64F a = new DenseMatrix64F(1,1); alg.setToRequiredSize(a); assertEquals(2,a.numCols); assertEquals(1,a.numRows); } }ejml-0.28/main/equation/test/org/ejml/equation/TestOperation.java000066400000000000000000000615161256171534400251510ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestOperation { Random rand = new Random(234); @Test public void divide_matrix_scalar() { Equation eq = new Equation(); SimpleMatrix x = SimpleMatrix.random(5, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(5, 3, -1, 1, rand); eq.alias(2.5, "A"); eq.alias(b, "b"); eq.alias(x, "x"); eq.process("x=b/A"); assertTrue(b.divide(2.5).isIdentical(x, 1e-8)); } @Test public void divide_scalar_matrix() { Equation eq = new Equation(); SimpleMatrix x = SimpleMatrix.random(5, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(5, 3, -1, 1, rand); eq.alias(2.5, "A"); eq.alias(b, "b"); eq.alias(x, "x"); eq.process("x=A/b"); DenseMatrix64F tmp = new DenseMatrix64F(5,3); CommonOps.divide(2.5,b.getMatrix(),tmp); assertTrue(MatrixFeatures.isIdentical(tmp, x.getMatrix(), 1e-8)); } @Test public void divide_int_int() { Equation eq = new Equation(); eq.alias(4, "A"); eq.alias(13, "b"); eq.alias(-1, "x"); eq.process("x=b/A"); int found = eq.lookupInteger("x"); assertEquals(13 / 4, found, 1e-8); } @Test public void divide_scalar_scalar() { Equation eq = new Equation(); eq.alias(5, "A"); eq.alias(4.2, "b"); eq.alias(-1.0, "x"); eq.process("x=b/A"); double found = eq.lookupDouble("x"); assertEquals(4.2 / 5.0, found, 1e-8); } @Test public void divide_matrix_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix x = SimpleMatrix.random(5, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(6, 3, -1, 1, rand); eq.alias(A, "A"); eq.alias(b, "b"); eq.alias(x, "x"); eq.process("x=b/A"); assertTrue(A.solve(b).isIdentical(x, 1e-8)); } @Test public void ldivide_matrix_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix x = SimpleMatrix.random(5, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(6, 3, -1, 1, rand); eq.alias(A, "A"); eq.alias(b, "b"); eq.alias(x, "x"); eq.process("x=A\\b"); assertTrue(A.solve(b).isIdentical(x, 1e-8)); } @Test public void multiply_matrix_scalar() { Equation eq = new Equation(); SimpleMatrix x = SimpleMatrix.random(5, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(5, 3, -1, 1, rand); eq.alias(2.5, "A"); eq.alias(b, "b"); eq.alias(x, "x"); eq.process("x=b*A"); assertTrue(b.scale(2.5).isIdentical(x, 1e-8)); eq.process("x=A*b"); assertTrue(b.scale(2.5).isIdentical(x, 1e-8)); } @Test public void multiply_int_int() { Equation eq = new Equation(); eq.alias(4, "A"); eq.alias(13, "b"); eq.alias(-1, "x"); eq.process("x=b*A"); int found = eq.lookupInteger("x"); assertEquals(13 * 4, found, 1e-8); } @Test public void multiply_scalar_scalar() { Equation eq = new Equation(); eq.alias(5, "A"); eq.alias(4.2, "b"); eq.alias(-1.0, "x"); eq.process("x=b*A"); double found = eq.lookupDouble("x"); assertEquals(4.2 * 5.0, found, 1e-8); } @Test public void multiply_matrix_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix x = SimpleMatrix.random(5, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(6, 3, -1, 1, rand); eq.alias(A, "A"); eq.alias(b, "b"); eq.alias(x, "x"); eq.process("b=A*x"); assertTrue(A.mult(x).isIdentical(b, 1e-8)); } @Test public void elementMult_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix c = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(a,"a",b,"b",c,"c"); eq.process("c=a.*b"); assertTrue(a.elementMult(b).isIdentical(c, 1e-8)); } @Test public void elementDivide_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix c = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(a,"a",b,"b",c,"c"); eq.process("c=a./b"); assertTrue(a.elementDiv(b).isIdentical(c, 1e-8)); } @Test public void elementPower_mm() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(6, 5, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(6, 5, 0, 1, rand); SimpleMatrix c = SimpleMatrix.random(6, 5, 0, 1, rand); eq.alias(a,"a",b,"b",c,"c"); eq.process("c=a.^b"); assertTrue(a.elementPower(b).isIdentical(c, 1e-8)); } @Test public void elementPower_ms() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(6, 5, 0, 1, rand); double b = 1.1; SimpleMatrix c = SimpleMatrix.random(6, 5, 0, 1, rand); eq.alias(a,"a",b,"b",c,"c"); eq.process("c=a.^b"); assertTrue(a.elementPower(b).isIdentical(c, 1e-8)); } @Test public void elementPower_sm() { Equation eq = new Equation(); double a = 1.1; SimpleMatrix b = SimpleMatrix.random(6, 5, 0, 1, rand); SimpleMatrix c = SimpleMatrix.random(6, 5, 0, 1, rand); eq.alias(a,"a",b,"b",c,"c"); eq.process("c=a.^b"); SimpleMatrix expected = new SimpleMatrix(6,5); CommonOps.elementPower(a,b.getMatrix(),expected.getMatrix()); assertTrue(expected.isIdentical(c, 1e-8)); } @Test public void elementPower_ss() { Equation eq = new Equation(); double a = 1.1; double b = 0.7; eq.alias(a,"a",b,"b"); eq.process("c=a.^b"); double found = eq.lookupDouble("c"); assertEquals(Math.pow(a,b),found,1e-8); } @Test public void kron_matrix_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(2, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(3, 2, -1, 1, rand); SimpleMatrix c = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(a,"a",b,"b",c,"c"); eq.process("c=kron(a,b)"); assertTrue(a.kron(b).isIdentical(c, 1e-8)); } @Test public void power_double_double() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=2.3^4.2"); assertEquals(Math.pow(2.3, 4.2), eq.lookupDouble("a"), 1e-8); } @Test public void power_int_int() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=2^4"); assertEquals(Math.pow(2,4),eq.lookupDouble("a"),1e-8); } @Test public void sqrt_int() { Equation eq = new Equation(); eq.process("a=sqrt(5)"); assertEquals(Math.sqrt(5),eq.lookupDouble("a"),1e-8); } @Test public void sqrt_double() { Equation eq = new Equation(); eq.process("a=sqrt(5.7)"); assertEquals(Math.sqrt(5.7),eq.lookupDouble("a"),1e-8); } @Test public void atan2_scalar() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=atan2(1.1,0.5)"); assertEquals(Math.atan2(1.1, 0.5), eq.lookupDouble("a"), 1e-8); } @Test public void neg_int() { Equation eq = new Equation(); eq.alias(2,"a"); eq.alias(3,"b"); eq.process("a=-b"); assertEquals(-3, eq.lookupInteger("a")); } @Test public void neg_scalar() { Equation eq = new Equation(); eq.alias(2.1,"a"); eq.alias(3.1,"b"); eq.process("a=-b"); assertEquals(-3.1, eq.lookupDouble("a"), 1e-8); } @Test public void neg_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(1, 1, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(5, 3, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.process("A=-B"); for (int i = 0; i < A.getNumElements(); i++) { assertEquals(-A.get(i),B.get(i),1e-8); } } @Test public void sin() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=sin(2.1)"); assertEquals(Math.sin(2.1), eq.lookupDouble("a"), 1e-8); } @Test public void cos() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=cos(2.1)"); assertEquals(Math.cos(2.1),eq.lookupDouble("a"),1e-8); } @Test public void atan() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=atan(2.1)"); assertEquals(Math.atan(2.1), eq.lookupDouble("a"), 1e-8); } @Test public void exp_s() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=exp(2.1)"); assertEquals(Math.exp(2.1),eq.lookupDouble("a"),1e-8); } @Test public void exp_m() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,0,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,0,1,rand); eq.alias(a,"a",b,"b"); eq.process("b=exp(a)"); SimpleMatrix expected = a.elementExp(); assertTrue(expected.isIdentical(b,1e-8)); } @Test public void log_s() { Equation eq = new Equation(); eq.alias(1.1,"a"); eq.process("a=log(2.1)"); assertEquals(Math.log(2.1),eq.lookupDouble("a"),1e-8); } @Test public void log_m() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,0,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,0,1,rand); eq.alias(a,"a",b,"b"); eq.process("b=log(a)"); SimpleMatrix expected = a.elementLog(); assertTrue(expected.isIdentical(b,1e-8)); } @Test public void add_int_int() { Equation eq = new Equation(); eq.alias(1,"a"); eq.process("a=2 + 3"); assertEquals(5,eq.lookupInteger("a"),1e-8); } @Test public void add_scalar_scalar() { Equation eq = new Equation(); eq.alias(1.2,"a"); eq.process("a= 2.3 + 3"); assertEquals(5.3, eq.lookupDouble("a"), 1e-8); } @Test public void add_matrix_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix c = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a",b,"b",c,"c"); eq.process("a=b+c"); assertTrue(b.plus(c).isIdentical(a, 1e-8)); } @Test public void add_matrix_scalar() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("a=b+2.2"); assertTrue(b.plus(2.2).isIdentical(a, 1e-8)); eq.process("a=2.2+b"); assertTrue(b.plus(2.2).isIdentical(a, 1e-8)); } @Test public void subtract_int_int() { Equation eq = new Equation(); eq.alias(1,"a"); eq.process("a=2 - 3"); assertEquals(-1, eq.lookupInteger("a"), 1e-8); } @Test public void subtract_scalar_scalar() { Equation eq = new Equation(); eq.alias(1.2,"a"); eq.process("a= 2.3 - 3"); assertEquals(2.3 - 3.0, eq.lookupDouble("a"), 1e-8); } @Test public void subtract_matrix_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix c = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a, "a", b, "b", c, "c"); eq.process("a=b-c"); assertTrue(b.minus(c).isIdentical(a, 1e-8)); } @Test public void subtract_matrix_scalar() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("a=b-2.2"); assertTrue(b.plus(-2.2).isIdentical(a, 1e-8)); eq.process("a=2.2-b"); DenseMatrix64F expected = new DenseMatrix64F(3,4); CommonOps.subtract(2.2,b.getMatrix(),expected); assertTrue(SimpleMatrix.wrap(expected).isIdentical(a, 1e-8)); } @Test public void copy_matrix_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("b=a"); assertTrue(a.isIdentical(b, 1e-8)); } @Test public void copy_double_matrix() { Equation eq = new Equation(); DenseMatrix64F src = new DenseMatrix64F(1,1,true,2.5); eq.alias(1.2,"a"); eq.alias(src,"b"); eq.process("a=b"); assertEquals(2.5, eq.lookupDouble("a"), 1e-8); // pass in a none 1x1 matrix eq.alias(new DenseMatrix64F(2,1),"b"); try { eq.process("a=b"); fail("Exception should have been thrown"); } catch( RuntimeException e ){} } @Test public void copy_int_int() { Equation eq = new Equation(); eq.alias(2,"a"); eq.alias(3,"b"); eq.process("a=b"); assertEquals(3, eq.lookupInteger("a")); } @Test public void copy_double_scalar() { Equation eq = new Equation(); // int to double eq.alias(2.2,"a"); eq.alias(3,"b"); eq.process("a=b"); assertEquals(3, eq.lookupDouble("a"),1e-8); // double to double eq.alias(3.5,"c"); eq.process("a=c"); assertEquals(3.5, eq.lookupDouble("a"),1e-8); } @Test public void copy_submatrix_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(2,3,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("b(1:2,1:3)=a"); assertTrue(a.isIdentical(b.extractMatrix(1, 3, 1, 4), 1e-8)); } @Test public void copy_submatrix_scalar() { Equation eq = new Equation(); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(b,"b"); eq.process("b(2,3)=4.5"); eq.process("b(0,0)=3.5"); assertEquals(3.5, b.get(0, 0),1e-8); assertEquals(4.5, b.get(2, 3),1e-8); } @Test public void transpose_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("b=a'"); assertTrue(a.transpose().isIdentical(b, 1e-8)); } @Test public void inv_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,3,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(3,3,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("b=inv(a)"); assertTrue(a.invert().isIdentical(b, 1e-8)); } @Test public void inv_scalar() { Equation eq = new Equation(); eq.alias(2.2,"a",3.3,"b"); eq.process("b=inv(a)"); assertEquals(1.0 / 2.2, eq.lookupDouble("b"), 1e-8); } @Test public void pinv_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(4,3,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(1,1,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("b=pinv(a)"); assertTrue(a.pseudoInverse().isIdentical(b, 1e-8)); } @Test public void pinv_scalar() { Equation eq = new Equation(); eq.alias(2.2,"a",3.3,"b"); eq.process("b=pinv(a)"); assertEquals(1.0 / 2.2, eq.lookupDouble("b"), 1e-8); } @Test public void rref_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(4,3,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(1,1,-1,1,rand); eq.alias(a,"a",b,"b"); eq.process("b=rref(a)"); DenseMatrix64F expected = new DenseMatrix64F(4,3); CommonOps.rref(a.getMatrix(),-1,expected); assertTrue(MatrixFeatures.isIdentical(expected,b.getMatrix(),1e-8)); } @Test public void rref_scalar() { Equation eq = new Equation(); eq.process("a=rref(2.3)"); assertEquals(1,eq.lookupDouble("a"),1e-8); eq.process("a=rref(0)"); assertEquals(0,eq.lookupDouble("a"),1e-8); eq.process("a=rref(-1.2)"); assertEquals(1,eq.lookupDouble("a"),1e-8); } @Test public void det_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(4,4,-1,1,rand); eq.alias(a,"a"); eq.process("b=det(a)"); assertEquals(a.determinant(),eq.lookupDouble("b"),1e-8); } @Test public void det_scalar() { Equation eq = new Equation(); eq.process("b=det(5.6)"); assertEquals(5.6, eq.lookupDouble("b"), 1e-8); } @Test public void trace_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a"); eq.process("b=trace(a)"); assertEquals(a.trace(), eq.lookupDouble("b"), 1e-8); } @Test public void normF_matrix() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a"); eq.process("b=normF(a)"); assertEquals(a.normF(), eq.lookupDouble("b"), 1e-8); } @Test public void normF_scalar() { Equation eq = new Equation(); eq.process("b=normF(5.6)"); assertEquals(5.6, eq.lookupDouble("b"), 1e-8); } @Test public void eye() { Equation eq = new Equation(); SimpleMatrix a = SimpleMatrix.random(3,4,-1,1,rand); eq.alias(a,"a"); eq.process("a=eye(3)"); assertTrue(SimpleMatrix.identity(3).isIdentical(a, 1e-8)); } @Test public void abs_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.process("B=abs(A)"); for (int i = 0; i < A.numRows(); i++) { for (int j = 0; j < A.numCols(); j++) { assertTrue(B.get(i,j)==Math.abs(A.get(i,j))); } } } @Test public void abs_int() { Equation eq = new Equation(); eq.alias(-4, "A"); eq.alias(1, "B"); eq.process("B=abs(A)"); int found = eq.lookupInteger("B"); assertEquals(4,found,1e-8); } @Test public void abs_scalar() { Equation eq = new Equation(); eq.alias(-4.6, "A"); eq.alias(1.1, "B"); eq.process("B=abs(A)"); double found = eq.lookupDouble("B"); assertEquals(4.6,found,1e-8); } @Test public void max_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(A, "A"); eq.alias(1.0, "B"); eq.process("B=max(A)"); double found = eq.lookupDouble("B"); double expected = CommonOps.elementMax(A.getMatrix()); assertEquals(expected,found,1e-8); } @Test public void max_int() { Equation eq = new Equation(); eq.alias(4, "A"); eq.alias(1, "B"); eq.process("B=max(A)"); int found = eq.lookupInteger("B"); assertEquals(4,found,1e-8); } @Test public void max_scalar() { Equation eq = new Equation(); eq.alias(4.6, "A"); eq.alias(1.1, "B"); eq.process("B=max(A)"); double found = eq.lookupDouble("B"); assertEquals(4.6,found,1e-8); } @Test public void min_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); eq.alias(A, "A"); eq.alias(1.0, "B"); eq.process("B=min(A)"); double found = eq.lookupDouble("B"); double expected = CommonOps.elementMin(A.getMatrix()); assertEquals(expected,found,1e-8); } @Test public void min_int() { Equation eq = new Equation(); eq.alias(4, "A"); eq.alias(1, "B"); eq.process("B=min(A)"); int found = eq.lookupInteger("B"); assertEquals(4,found,1e-8); } @Test public void min_scalar() { Equation eq = new Equation(); eq.alias(4.6, "A"); eq.alias(1.1, "B"); eq.process("B=min(A)"); double found = eq.lookupDouble("B"); assertEquals(4.6,found,1e-8); } @Test public void zeros() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 8, -1, 1, rand); eq.alias(A, "A"); eq.process("A=zeros(6,8)"); for (int i = 0; i < 6; i++) { for (int j = 0; j < 8; j++) { assertEquals(0,A.get(i,j),1e-8); } } } @Test public void ones() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 8, -1, 1, rand); eq.alias(A, "A"); eq.process("A=ones(6,8)"); for (int i = 0; i < 6; i++) { for (int j = 0; j < 8; j++) { assertEquals(1,A.get(i,j),1e-8); } } } @Test public void diag_vector() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 6, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 1, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.process("A=diag(B)"); for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { if( i == j ) assertEquals(B.get(i,0),A.get(i,j),1e-8); else assertEquals(0,A.get(i,j),1e-8); } } } @Test public void diag_matrix() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 8, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 1, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.process("B=diag(A)"); assertEquals(6,B.numRows()); assertEquals(1,B.numCols()); for (int i = 0; i < 6; i++) { assertEquals(A.get(i,i),B.get(i,0),1e-8); } } @Test public void dot() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 1, -1, 1, rand); SimpleMatrix B = SimpleMatrix.random(6, 1, -1, 1, rand); eq.alias(A, "A"); eq.alias(B, "B"); eq.alias(1.0, "found"); eq.process("found=dot(A,B)"); double found = ((VariableDouble)eq.lookupVariable("found")).value; assertEquals(A.dot(B),found,1e-8); } @Test public void solve() { Equation eq = new Equation(); SimpleMatrix A = SimpleMatrix.random(6, 5, -1, 1, rand); SimpleMatrix x = SimpleMatrix.random(5, 3, -1, 1, rand); SimpleMatrix b = SimpleMatrix.random(6, 3, -1, 1, rand); eq.alias(A, "A"); eq.alias(b, "b"); eq.alias(x, "x"); eq.process("x=solve(A,b)"); assertTrue(A.solve(b).isIdentical(x, 1e-8)); } } ejml-0.28/main/equation/test/org/ejml/equation/TestSequence.java000066400000000000000000000027241256171534400247550ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestSequence { int total; /** * Checks the order in which operations are run */ @Test public void order() { Sequence s = new Sequence(); s.addOperation(new Foo("a",0)); s.addOperation(new Foo("b",1)); total = 0; s.perform(); assertEquals(2,total); } public class Foo extends Operation { int expected; protected Foo(String name , int expected ) { super(name); this.expected = expected; } @Override public void process() { assertEquals(expected, total); total++; } } } ejml-0.28/main/equation/test/org/ejml/equation/TestTokenList.java000066400000000000000000000153631256171534400251240ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.equation; import org.junit.Test; import static org.ejml.equation.TokenList.Token; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestTokenList { @Test public void push() { TokenList list = new TokenList(); assertTrue(null==list.getFirst()); assertTrue(null==list.getLast()); assertEquals(0,list.size()); list.add(Symbol.MINUS); Token a = list.getFirst(); assertTrue(null!=a); assertTrue(a==list.getLast()); assertEquals(1,list.size()); list.add(Symbol.PAREN_LEFT); Token b = list.getLast(); assertTrue(a!=b); assertTrue(b!=list.getFirst()); assertEquals(2,list.size()); list.add(Symbol.PAREN_RIGHT); Token c = list.getLast(); assertTrue(a!=c); assertTrue(b!=c); assertTrue(c!=list.getFirst()); assertEquals(3,list.size()); } @Test public void insert() { TokenList list = new TokenList(); list.insert(null,new Token(Symbol.MINUS)); assertEquals(1, list.size()); assertTrue(list.first == list.last && list.first != null); list.insert(null,new Token(Symbol.PLUS)); assertEquals(2, list.size()); assertEquals(Symbol.PLUS,list.first.getSymbol()); assertEquals(Symbol.MINUS, list.first.next.getSymbol()); list.insert(list.last,new Token(Symbol.TIMES)); assertEquals(3, list.size()); assertEquals(Symbol.PLUS,list.first.getSymbol()); assertEquals(Symbol.MINUS,list.first.next.getSymbol()); assertEquals(Symbol.TIMES,list.last.getSymbol()); list.insert(list.first.next,new Token(Symbol.ASSIGN)); assertEquals(4, list.size()); assertEquals(Symbol.MINUS, list.first.next.getSymbol()); assertEquals(Symbol.ASSIGN, list.first.next.next.getSymbol()); assertEquals(Symbol.TIMES, list.first.next.next.next.getSymbol()); } @Test public void remove() { TokenList list = new TokenList(); Token A,B,C; list.add(Symbol.MINUS); list.remove(list.first); assertEquals(0,list.size); assertTrue(null==list.getFirst()); assertTrue(null==list.getLast()); A = list.add(Symbol.MINUS); list.add(Symbol.PLUS); list.remove(list.last); assertEquals(1, list.size); assertTrue(A == list.getFirst()); assertTrue(A==list.getLast()); assertTrue(A.next==null); assertTrue(A.previous==null); B = list.add(Symbol.PLUS); list.remove(list.first); assertEquals(1, list.size); assertTrue(B == list.getFirst()); assertTrue(B==list.getLast()); assertTrue(B.next==null); assertTrue(B.previous==null); list.remove(list.first); A = list.add(Symbol.MINUS); B = list.add(Symbol.PLUS); C = list.add(Symbol.TIMES); list.remove(list.first.next); assertEquals(2, list.size); assertTrue(A == list.getFirst()); assertTrue(C==list.getLast()); assertTrue(A.next==C); assertTrue(A==C.previous); } @Test public void replace() { TokenList list = new TokenList(); Token A,B,C,D; A = list.add(Symbol.MINUS); B = new Token(Symbol.PLUS); list.replace(A, B); assertEquals(1,list.size); assertTrue(B==list.getFirst()); assertTrue(B == list.getLast()); list.remove(B); A = list.add(Symbol.MINUS); B = list.add(Symbol.PLUS); C = new Token(Symbol.TIMES); list.replace(A, C); assertEquals(2, list.size); assertTrue(C==list.getFirst()); assertTrue(B==list.getLast()); assertTrue(C.previous==null); assertTrue(C.next==B); assertTrue(B.previous==C); assertTrue(B.next==null); list = new TokenList(); A=list.add(Symbol.MINUS); B=list.add(Symbol.PLUS); C=list.add(Symbol.TIMES); D=new Token(Symbol.RDIVIDE); list.replace(B,D); assertEquals(3, list.size); assertTrue(A == list.getFirst()); assertTrue(C==list.getLast()); assertTrue(A.next==D); assertTrue(A==D.previous); assertTrue(C.previous==D); assertTrue(C==D.next); } @Test public void extractSubList() { // Check when the input list has a size of 1 TokenList list = new TokenList(); list.add(Symbol.MINUS); TokenList found = list.extractSubList(list.first,list.first); assertEquals(0, list.size); assertEquals(1, found.size); assertTrue(null == list.first && null == list.last); assertTrue(found.first==found.last && found.first != null); // Remove entire thing list = new TokenList(); list.add(Symbol.MINUS); list.add(Symbol.PLUS); list.add(Symbol.RDIVIDE); found = list.extractSubList(list.first,list.last); assertEquals(0,list.size); assertEquals(3,found.size); assertEquals(Symbol.MINUS,found.first.getSymbol()); assertEquals(Symbol.RDIVIDE,found.last.getSymbol()); // Remove stuff in the middle list = new TokenList(); list.add(Symbol.MINUS); list.add(Symbol.PLUS); list.add(Symbol.RDIVIDE); list.add(Symbol.TIMES); found = list.extractSubList(list.first.next,list.last.previous); assertEquals(2,list.size); assertEquals(2,found.size); assertEquals(Symbol.MINUS,list.first.getSymbol()); assertEquals(Symbol.TIMES,list.last.getSymbol()); assertEquals(Symbol.PLUS,found.first.getSymbol()); assertEquals(Symbol.RDIVIDE,found.last.getSymbol()); } @Test public void Token_getType() { assertTrue(new Token(new VariableMatrix(null)).getType() == TokenList.Type.VARIABLE); assertTrue(new Token(Symbol.PLUS).getType() == TokenList.Type.SYMBOL); assertTrue(new Token(new Function("foo")).getType() == TokenList.Type.FUNCTION); } } ejml-0.28/main/experimental/000077500000000000000000000000001256171534400160235ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/000077500000000000000000000000001256171534400201405ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/000077500000000000000000000000001256171534400207275ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/000077500000000000000000000000001256171534400215165ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/000077500000000000000000000000001256171534400224455ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/BenchmarkElement.java000066400000000000000000000032251256171534400265160ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkElement { static Random rand = new Random(234); public static void main( String args[] ) { long N = 10000000; double num = 2.5; DenseMatrix64F A = RandomMatrices.createRandom(10,10,rand); long timeBefore = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { CommonOps.divide(A,num); } long timeAfter = System.currentTimeMillis(); System.out.println("div = "+(timeAfter-timeBefore)); A = RandomMatrices.createRandom(10,10,rand); timeBefore = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { CommonOps.scale(num,A); } timeAfter = System.currentTimeMillis(); System.out.println("scale = "+(timeAfter-timeBefore)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/BenchmarkGenerics.java000066400000000000000000000053201256171534400266620ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Checks to see if using generics slows things down. * * @author Peter Abeles */ public class BenchmarkGenerics { private static class ImplDense implements ScaleDense { @Override public void scale(double s, DenseMatrix64F mat) { for( int i = 0; i < mat.data.length; i++ ) { mat.data[i] *= s; } } } private static class ImplGeneric implements ScaleGeneric { @Override public void scale(double s, DenseMatrix64F mat) { for( int i = 0; i < mat.data.length; i++ ) { mat.data[i] *= s; } } } private static interface ScaleDense { public void scale( double s , DenseMatrix64F mat ); } private static interface ScaleGeneric { public void scale( double s , T mat ); } public static long benchmarkDense( DenseMatrix64F A , double scale , int trials ) { ScaleDense s = new ImplDense(); long before = System.currentTimeMillis(); for( int i = 0; i < trials; i++ ) { s.scale(scale,A); s.scale(1.0/scale,A); } return System.currentTimeMillis() - before; } public static long benchmarkGeneric( DenseMatrix64F A , double scale , int trials ) { ImplGeneric s = new ImplGeneric(); long before = System.currentTimeMillis(); for( int i = 0; i < trials; i++ ) { s.scale(scale,A); s.scale(1.0/scale,A); } return System.currentTimeMillis() - before; } public static void main( String []args ) { DenseMatrix64F A = RandomMatrices.createRandom(10,10,new Random(234)); int N = 10000000; System.out.println("dense = "+benchmarkDense(A,2.5,N)); System.out.println("generic = "+benchmarkGeneric(A,2.5,N)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/BenchmarkInheritanceCall.java000066400000000000000000000122551256171534400301550ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Benchmark that tests to see if referring the parent of the class versus the actual class * has any performance difference. The function used internally is matrix multiplication in "ikj" order. * * @author Peter Abeles */ public class BenchmarkInheritanceCall { public static void multParent( D1Matrix64F a , D1Matrix64F b , D1Matrix64F c ) { double dataA[] = a.data; double dataB[] = b.data; double dataC[] = c.data; double valA; int indexCbase= 0; int endOfKLoop = b.numRows*b.numCols; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*a.numCols; // need to assign dataC to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + b.numCols; valA = dataA[indexA++]; while( indexB < end ) { dataC[indexC++] = valA*dataB[indexB++]; } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + b.numCols; valA = dataA[indexA++]; while( indexB < end ) { // j loop dataC[indexC++] += valA*dataB[indexB++]; } } indexCbase += c.numCols; } } public static void multParent_wrap( D1Matrix64F a , D1Matrix64F b , D1Matrix64F c ) { double valA; int indexCbase= 0; int endOfKLoop = b.numRows*b.numCols; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*a.numCols; // need to assign dataC to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + b.numCols; valA = a.get(indexA++); while( indexB < end ) { c.set( indexC++ , valA*b.get(indexB++)); } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + b.numCols; valA = a.get(indexA++); while( indexB < end ) { // j loop c.plus( indexC++ , valA*b.get(indexB++)); } } indexCbase += c.numCols; } } public static void multChild( DenseMatrix64F a , DenseMatrix64F b , DenseMatrix64F c ) { double dataA[] = a.data; double dataB[] = b.data; double dataC[] = c.data; double valA; int indexCbase= 0; int endOfKLoop = b.numRows*b.numCols; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*a.numCols; // need to assign dataC to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + b.numCols; valA = dataA[indexA++]; while( indexB < end ) { dataC[indexC++] = valA*dataB[indexB++]; } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + b.numCols; valA = dataA[indexA++]; while( indexB < end ) { // j loop dataC[indexC++] += valA*dataB[indexB++]; } } indexCbase += c.numCols; } } public static void main( String args[] ) { Random rand = new Random(23234); DenseMatrix64F A = RandomMatrices.createRandom(2,2,rand); DenseMatrix64F B = RandomMatrices.createRandom(2,2,rand); DenseMatrix64F C = new DenseMatrix64F(2,2); int N = 40000000; long before = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { multParent(A,B,C); } long after = System.currentTimeMillis(); System.out.println("Parent: "+(after-before)); before = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { multParent_wrap(A,B,C); } after = System.currentTimeMillis(); System.out.println("Parent func: "+(after-before)); before = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { multChild(A,B,C); } after = System.currentTimeMillis(); System.out.println("Child: "+(after-before)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/BenchmarkInliningGetSet.java000066400000000000000000000104661256171534400300150ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Test to see how well set and get are inlined in DenseMatrix64F. * * @author Peter Abeles */ public class BenchmarkInliningGetSet { /** * Bounds checks are performed on get(i,j) */ public static long benchGet( DenseMatrix64F A , int n ) { long before = System.currentTimeMillis(); double total = 0; for( int iter = 0; iter < n; iter++ ) { for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { total += A.get(i,j); } } } long after = System.currentTimeMillis(); // print to ensure that ensure that an overly smart compiler does not optimize out // the whole function and to show that both produce the same results. System.out.println(total); return after-before; } /** * Unsafe version of get(i,j) with no bounds checking */ public static long getUnsafeGet( DenseMatrix64F A , int n ) { long before = System.currentTimeMillis(); double total = 0; for( int iter = 0; iter < n; iter++ ) { for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { total += A.unsafe_get(i,j); } } } long after = System.currentTimeMillis(); // print to ensure that ensure that an overly smart compiler does not optimize out // the whole function and to show that both produce the same results. System.out.println(total); return after-before; } /** * Get by index is used here. */ public static long get1D( DenseMatrix64F A , int n ) { long before = System.currentTimeMillis(); double total = 0; for( int iter = 0; iter < n; iter++ ) { int index = 0; for( int i = 0; i < A.numRows; i++ ) { int end = index+A.numCols; while( index != end ) { total += A.get(index++); } } } long after = System.currentTimeMillis(); // print to ensure that ensure that an overly smart compiler does not optimize out // the whole function and to show that both produce the same results. System.out.println(total); return after-before; } /** * Hand inlined version of get(i,j) */ public static long inlined( DenseMatrix64F A , int n ) { long before = System.currentTimeMillis(); double total = 0; for( int iter = 0; iter < n; iter++ ) { for( int i = 0; i < A.numRows; i++ ) { for( int j = 0; j < A.numCols; j++ ) { total += A.data[i*A.numCols + j]; } } } long after = System.currentTimeMillis(); // print to ensure that ensure that an overly smart compiler does not optimize out // the whole function and to show that both produce the same results. System.out.println(total); return after-before; } public static void main( String args[] ) { DenseMatrix64F A = RandomMatrices.createRandom(1000,1000,new Random()); int N = 2000; long time1D = get1D(A,N); long timeInlined = inlined(A,N); long timeGet = benchGet(A,N); long timeUnsafeGet = getUnsafeGet(A,N); System.out.println("get = "+timeGet+" Inlined "+timeInlined+" unsafe_get "+timeUnsafeGet+" get1D "+time1D); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/BenchmarkInstanceOf.java000066400000000000000000000062771256171534400271700ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml; import org.ejml.data.BlockMatrix64F; import org.ejml.data.D1Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RealMatrix64F; import org.ejml.ops.CommonOps; /** * @author Peter Abeles */ public class BenchmarkInstanceOf { public static final double SCALE = 1.1; public static final StuffA stuff = new StuffA(); public interface Stuff { public void process( Stuff a, RealMatrix64F M ); } public static class StuffA implements Stuff { @Override public void process(Stuff a, RealMatrix64F M) { if( M instanceof BlockMatrix64F) { CommonOps.scale(1.0,(BlockMatrix64F)M); } else if( M instanceof DenseMatrix64F) { CommonOps.scale(SCALE,(DenseMatrix64F)M); // CommonOps.scale(0.5,(DenseMatrix64F)M); } else if(M instanceof D1Matrix64F) { CommonOps.scale(1.0,(D1Matrix64F)M); } else { throw new IllegalArgumentException("Who knows"); } } } public static void withIfStatement( DenseMatrix64F M ) { if( M.numCols > 10 ) { CommonOps.scale(2.0,M); } else if( M.numRows > 12 ) { CommonOps.scale(2.0,M); } else { CommonOps.scale(SCALE,M); // CommonOps.scale(0.5,M); } } public static long processInstanceOf( DenseMatrix64F M , int N ) { long before = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { stuff.process(null,M); } return System.currentTimeMillis() - before; } public static long processDirect( DenseMatrix64F M , int N ) { long before = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { CommonOps.scale(SCALE,M); // CommonOps.scale(0.5,M); } return System.currentTimeMillis() - before; } public static long processIf( DenseMatrix64F M , int N ) { long before = System.currentTimeMillis(); for( int i = 0; i < N; i++ ) { withIfStatement(M); } return System.currentTimeMillis() - before; } public static void main( String args[] ) { DenseMatrix64F A = new DenseMatrix64F(2,2,true,0.1,0.5,0.7,10.0); int N = 200000000; System.out.println("instanceof "+processInstanceOf(A,N)); System.out.println("direct "+processDirect(A,N)); System.out.println("if "+processIf(A,N)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/000077500000000000000000000000001256171534400232105ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/block/000077500000000000000000000000001256171534400243025ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/block/BenchmarkBlockTranspose.java000066400000000000000000000050641256171534400317160ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.block; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare block against other transpose for DenseMatrix64F * * @author Peter Abeles */ public class BenchmarkBlockTranspose { static Random rand = new Random(234); public static long transposeDenseInPlace( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.transpose(mat); } long curr = System.currentTimeMillis(); return curr-prev; } public static long transposeDense( DenseMatrix64F mat , int numTrials) { DenseMatrix64F tran = new DenseMatrix64F(mat.numCols,mat.numRows); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.transpose(mat,tran); } long curr = System.currentTimeMillis(); return curr-prev; } public static long transposeBlock( DenseMatrix64F mat , int numTrials) { BlockMatrix64F A = new BlockMatrix64F(mat.numRows,mat.numCols); BlockMatrix64F A_t = new BlockMatrix64F(mat.numCols,mat.numRows); BlockMatrixOps.convert(mat,A); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { BlockMatrixOps.transpose(A,A_t); } long curr = System.currentTimeMillis(); return curr-prev; } public static void main( String args[] ) { DenseMatrix64F A = RandomMatrices.createRandom(5000,5000,rand); int N = 5; System.out.println("In place : "+transposeDenseInPlace(A,N)); System.out.println("Standard : "+transposeDense(A,N)); System.out.println("Block : "+transposeBlock(A,N)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/complex/000077500000000000000000000000001256171534400246575ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/complex/mult/000077500000000000000000000000001256171534400256405ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/complex/mult/BenchmarkMatrixMatrixMult.java000066400000000000000000000154341256171534400336200ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.complex.mult; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.blockd3.BlockD3MatrixOps; import org.ejml.alg.dense.mult.CMatrixMatrixMult; import org.ejml.data.BlockD3Matrix64F; import org.ejml.data.BlockMatrix64F; import org.ejml.data.CDenseMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CCommonOps; import org.ejml.ops.CRandomMatrices; import java.util.Random; /** * * Some notes: * * Other libraries implement there multiplication the same as my aux implementation, but theirs run faster. * That is because they use 2D arrays, this allows them to only increment one variable in their inner * most loop. While in mine I have to increment two. Thus there is an additional N^3 addition operations. * * @author Peter Abeles */ public class BenchmarkMatrixMatrixMult { static Random rand = new Random(234234); static int TRIALS_MULT = 10000000; public static long multiply( CDenseMatrix64F matA , CDenseMatrix64F matB , CDenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CCommonOps.mult(matA, matB, matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multSmall( CDenseMatrix64F matA , CDenseMatrix64F matB , CDenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CMatrixMatrixMult.mult_small(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } // public static long multAux( DenseMatrix64F matA , DenseMatrix64F matB , // DenseMatrix64F matResult , int numTrials) { // long prev = System.currentTimeMillis(); // // for( int i = 0; i < numTrials; i++ ) { // MatrixMatrixMult.mult_aux(matA,matB,matResult,null); // } // // long curr = System.currentTimeMillis(); // return curr-prev; // } public static long multReorder( CDenseMatrix64F matA , CDenseMatrix64F matB , CDenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CMatrixMatrixMult.mult_reorder(matA, matB, matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multBlockNative( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { BlockMatrix64F blockA = BlockMatrixOps.convert(matA); BlockMatrix64F blockB = BlockMatrixOps.convert(matB); BlockMatrix64F blockC = new BlockMatrix64F(matResult.numRows,matResult.numCols); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { BlockMatrixOps.mult(blockA,blockB,blockC); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multBlockD3Native( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { BlockD3Matrix64F blockA = BlockD3MatrixOps.convert(matA); BlockD3Matrix64F blockB = BlockD3MatrixOps.convert(matB); BlockD3Matrix64F blockC = new BlockD3Matrix64F(matResult.numRows,matResult.numCols); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { BlockD3MatrixOps.mult(blockA,blockB,blockC); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numK, int numTrials ) { System.out.println("M = "+numRows+" N = "+numCols+" K = "+numK); CDenseMatrix64F matA = CRandomMatrices.createRandom(numRows,numCols,-1,1,rand); CDenseMatrix64F matB = CRandomMatrices.createRandom(numCols,numK,-1,1,rand); CDenseMatrix64F matResult = CRandomMatrices.createRandom(numRows, numK,-1,1, rand); System.out.printf("Mult: %7d Small %7d Aux %7d Reord %7d Block %7d BlockD3 %7d\n", 0,//mult(matA,matB,matResult,numTrials), multSmall(matA,matB,matResult,numTrials), 0,//multAux(matA,matB,matResult,numTrials), multReorder(matA,matB,matResult,numTrials), 0,//multBlockNative(matA,matB,matResult,numTrials), 0);//multBlockD3Native(matA,matB,matResult,numTrials)); System.gc(); } public static void main( String args[] ) { int size[] = new int[]{2,4,10,15,20,50,100,200,500,1000,2000,4000,10000}; int count[] = new int[]{40000000,10000000,1000000,300000,100000,10000,1000,100,8,2,1,1,1}; int sizeTall[] = new int[]{1,2,4,10,20,50,100,200,500,1000,2000,5000,10000}; int countTall[] = new int[]{3000,2400,1500,1000,200,200,100,50,10,5,2,1,1}; int N = size.length; System.out.println("******* Square:\n"); for( int i = 2; i < N; i++ ) { System.out.println(); performTests(size[i],size[i],size[i],count[i]); } N = sizeTall.length; System.out.println("\n******* Wide A:"); for( int i = 0; i < N; i++ ) { System.out.println(); performTests(sizeTall[i],1500,100,countTall[i]); } System.out.println("\n******* Tall A:"); for( int i = 7; i < N; i++ ) { System.out.println(); performTests(1500,sizeTall[i],100,countTall[i]); } System.out.println("\n******* Wide B:"); for( int i = 7; i < N; i++ ) { System.out.println(); performTests(100,sizeTall[i],1500,countTall[i]); } System.out.println("\n******* Tall B:"); for( int i = 7; i < N; i++ ) { System.out.println(); performTests(100,1500,sizeTall[i],countTall[i]); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/000077500000000000000000000000001256171534400243065ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/000077500000000000000000000000001256171534400271625ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/bidiagonal/000077500000000000000000000000001256171534400312535ustar00rootroot00000000000000BenchmarkBidiagonalDecomposition.java000066400000000000000000000064431256171534400404470ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/bidiagonal/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.bidiagonal; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.BidiagonalDecomposition; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkBidiagonalDecomposition { public static long evaluate( BidiagonalDecomposition alg , DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !alg.decompose(orig.copy()) ) { throw new RuntimeException("Bad matrix"); } // alg.getU(null,false,false); // alg.getV(null,false,false); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { if( numTrials <= 0 ) return; System.out.println("row = "+ evaluate(new BidiagonalDecompositionRow_D64(),mat,numTrials)); System.out.println("tall = "+ evaluate(new BidiagonalDecompositionTall_D64(),mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000,5000,10000}; int trials[] = new int[]{(int)4e6,(int)1e6,(int)1e5,200,1,1,1,1,1}; // int trials[] = new int[]{(int)1e6,(int)2e5,(int)2e4,50,1,1,1,1,1}; System.out.println("Square matrix"); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Decomposition size %3d for %12d trials\n",w,trials[i]); System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createRandom(w,w,rand); System.out.println(" Done."); runAlgorithms(mat,trials[i]); } System.out.println("Tall matrix"); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; int h = w*3; int t = trials[i]; if( t == 0 ) continue; System.out.printf("Decomposition size w=%3d h=%3d for %12d trials\n",w,h,t); System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createRandom(h,w,rand); System.out.println(" Done."); runAlgorithms(mat,t); } } }StabilityBidiagonalDecomposition.java000066400000000000000000000064111256171534400405140ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/bidiagonal/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.bidiagonal; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.BidiagonalDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class StabilityBidiagonalDecomposition { public static double evaluate( BidiagonalDecomposition alg , DenseMatrix64F orig ) { if( !alg.decompose(orig.copy())) { return Double.NaN; } SimpleMatrix U = SimpleMatrix.wrap(alg.getU(null,false,true)); SimpleMatrix B = SimpleMatrix.wrap(alg.getB(null,true)); SimpleMatrix Vt = SimpleMatrix.wrap(alg.getV(null,true,true)); SimpleMatrix A_found = U.mult(B).mult(Vt); SimpleMatrix A = SimpleMatrix.wrap(orig); double top = A_found.minus(A).normF(); double bottom = A.normF(); return top/bottom; } private static void runAlgorithms( DenseMatrix64F mat ) { System.out.println("row = "+ evaluate(new BidiagonalDecompositionRow_D64(),mat)); System.out.println("tall = "+ evaluate(new BidiagonalDecompositionTall_D64(),mat)); } public static void main( String args [] ) { Random rand = new Random(23423); int size = 10; double scales[] = new double[]{1,0.1,1e-20,1e-100,1e-200,1e-300,1e-304,1e-308,1e-319,1e-320,1e-321,Double.MIN_VALUE}; System.out.println("Square matrix: Scale"); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < scales.length; i++ ) { System.out.printf("Decomposition size %3d for %e scale\n",size,scales[i]); DenseMatrix64F mat = RandomMatrices.createRandom(size,size,-1,1,rand); CommonOps.scale(scales[i],mat); runAlgorithms(mat); } System.out.println("Square Matrix: Singular"); double sv[] = new double[size]; for( int i = 0; i < size; i++ ) sv[i] = 2*i+5; for( int i = 0; i < 10; i++ ) { sv[0] = (9.0-i)/10.0; System.out.printf("Decomposition size %3d for %e singular\n",size,sv[0]); // System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createSingularValues(size,size,rand,sv); CommonOps.scale(scales[i],mat); // System.out.println(" Done."); runAlgorithms(mat); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/chol/000077500000000000000000000000001256171534400301075ustar00rootroot00000000000000BenchmarkCholeskyDecomposition.java000066400000000000000000000121661256171534400370320ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.EjmlParameters; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkCholeskyDecomposition { public static long choleskyL( DenseMatrix64F orig , int numTrials ) { CholeskyDecompositionInner_D64 alg = new CholeskyDecompositionInner_D64(true); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long choleskyU( DenseMatrix64F orig , int numTrials ) { CholeskyDecompositionInner_D64 alg = new CholeskyDecompositionInner_D64(false); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long choleskyL_block( DenseMatrix64F orig , int numTrials ) { CholeskyDecompositionBlock_D64 alg = new CholeskyDecompositionBlock_D64( EjmlParameters.BLOCK_WIDTH_CHOL); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long choleskyBlockU( DenseMatrix64F orig , int numTrials ) { CholeskyDecomposition_B64_to_D64 alg = new CholeskyDecomposition_B64_to_D64(false); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long choleskyBlockL( DenseMatrix64F orig , int numTrials ) { CholeskyDecomposition_B64_to_D64 alg = new CholeskyDecomposition_B64_to_D64(true); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig)) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long choleskyLDL( DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); CholeskyDecompositionLDL_D64 alg = new CholeskyDecompositionLDL_D64(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { System.out.println("Lower = "+ choleskyL(mat,numTrials)); // System.out.println("Upper = "+ choleskyU(mat,numTrials)); System.out.println("Lower Block = "+ choleskyL_block(mat,numTrials)); // System.out.println("LDL = "+ choleskyLDL(mat,numTrials)); // System.out.println("Real Block U = "+ choleskyBlockU(mat,numTrials)); System.out.println("Real Block L = "+ choleskyBlockL(mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000,4000,10000}; int trials[] = new int[]{(int)2e7,(int)5e6,(int)1e6,1000,40,3,1,1,1}; // results vary significantly depending if it starts from a small or large matrix for( int i = 4; i < size.length; i++ ) { int w = size[i]; System.out.printf("Decomposition size %3d for %12d trials\n",w,trials[i]); System.out.print("* Creating matrix "); DenseMatrix64F symMat = RandomMatrices.createSymmPosDef(w,rand); System.out.println(" Done."); runAlgorithms(symMat,trials[i]); } } }StabilityCholeksyDecomposition.java000066400000000000000000000055351256171534400371060ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/chol/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.chol; import org.ejml.EjmlParameters; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.CholeskyDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class StabilityCholeksyDecomposition { public static double evaluate( CholeskyDecomposition alg , DenseMatrix64F orig ) { if( !DecompositionFactory.decomposeSafe(alg,orig)) { return Double.NaN; } SimpleMatrix T = SimpleMatrix.wrap(alg.getT(null)); SimpleMatrix A_found = T.mult(T.transpose()); SimpleMatrix A = SimpleMatrix.wrap(orig); double top = A_found.minus(A).normF(); double bottom = A.normF(); return top/bottom; } private static void runAlgorithms( DenseMatrix64F mat ) { System.out.println("basic = "+ evaluate(new CholeskyDecompositionInner_D64(),mat)); System.out.println("block = "+ evaluate(new CholeskyDecompositionBlock_D64(EjmlParameters.BLOCK_WIDTH_CHOL),mat)); System.out.println("block64 = "+ evaluate(new CholeskyDecomposition_B64_to_D64(true),mat)); } public static void main( String args [] ) { Random rand = new Random(23423); EjmlParameters.BLOCK_SIZE = 5; for( int size = 5; size <= 15; size += 5 ) { double scales[] = new double[]{1,0.1,1e-20,1e-100,1e-200,1e-300,1e-304,1e-308,1e-319,1e-320,1e-321,Double.MIN_VALUE}; // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < scales.length; i++ ) { System.out.printf("Decomposition size %3d for %e scale\n",size,scales[i]); DenseMatrix64F mat = RandomMatrices.createSymmPosDef(size,rand); CommonOps.scale(scales[i],mat); runAlgorithms(mat); } } System.out.println(" Done."); } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/000077500000000000000000000000001256171534400277265ustar00rootroot00000000000000BenchmarkEigenDecomposition.java000066400000000000000000000041141256171534400361110ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkEigenDecomposition { public static long watched( DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); WatchedDoubleStepQRDecomposition_D64 alg = new WatchedDoubleStepQRDecomposition_D64(true); for( long i = 0; i < numTrials; i++ ) { if( !alg.decompose(orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { System.out.println("Watched = "+ watched(mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,200}; int trials[] = new int[]{200000,40000,8000,50,10}; // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Decomposing size %3d for %12d trials\n",w,trials[i]); DenseMatrix64F symMat = RandomMatrices.createRandom(w,w,rand); runAlgorithms(symMat,trials[i]); } } } RealEigenDecompositionStressTest.java000066400000000000000000000014661256171534400371550ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig; /** * @author Peter Abeles */ public class RealEigenDecompositionStressTest { } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/symm/000077500000000000000000000000001256171534400307135ustar00rootroot00000000000000BenchmarkSymmetricEigenDecomposition.java000066400000000000000000000124441256171534400410000ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/symm/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.symm; import org.ejml.alg.dense.decomposition.eig.SymmetricQRAlgorithmDecomposition_D64; import org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecompositionHouseholder_D64; import org.ejml.alg.dense.decomposition.hessenberg.TridiagonalDecomposition_B64_to_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkSymmetricEigenDecomposition { public static long symmTogether( DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); TridiagonalSimilarDecomposition decomp = DecompositionFactory.tridiagonal(orig.numRows); SymmetricQRAlgorithmDecomposition_D64 alg = new SymmetricQRAlgorithmDecomposition_D64(decomp,true); alg.setComputeVectorsWithValues(true); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long symmSeparate( DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); TridiagonalSimilarDecomposition decomp = DecompositionFactory.tridiagonal(orig.numRows); SymmetricQRAlgorithmDecomposition_D64 alg = new SymmetricQRAlgorithmDecomposition_D64(decomp,true); alg.setComputeVectorsWithValues(false); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long standardTridiag( DenseMatrix64F orig , int numTrials ) { TridiagonalSimilarDecomposition decomp = new TridiagonalDecompositionHouseholder_D64(); SymmetricQRAlgorithmDecomposition_D64 alg = new SymmetricQRAlgorithmDecomposition_D64(decomp,true); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long blockTridiag( DenseMatrix64F orig , int numTrials ) { TridiagonalSimilarDecomposition decomp = new TridiagonalDecomposition_B64_to_D64(); SymmetricQRAlgorithmDecomposition_D64 alg = new SymmetricQRAlgorithmDecomposition_D64(decomp,true); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long defaultSymm( DenseMatrix64F orig , int numTrials ) { EigenDecomposition alg = DecompositionFactory.eig(orig.numCols, true, true); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !DecompositionFactory.decomposeSafe(alg,orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { // System.out.println("Together = "+ symmTogether(mat,numTrials)); // System.out.println("Separate = "+ symmSeparate(mat,numTrials)); System.out.println("Standard = "+ standardTridiag(mat,numTrials)); System.out.println("Block = "+ blockTridiag(mat,numTrials)); System.out.println("Default = "+ defaultSymm(mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(232423); int size[] = new int[]{2,4,10,100,200,500,1000,2000,5000}; int trials[] = new int[]{2000000,400000,80000,300,40,4,1,1,1}; for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Decomposing size %3d for %12d trials\n",w,trials[i]); DenseMatrix64F symMat = RandomMatrices.createSymmetric(w,-1,1,rand); runAlgorithms(symMat,trials[i]); } } }StabilitySymmEigen.java000066400000000000000000000050621256171534400352640ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/symm/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.symm; import org.ejml.alg.dense.decomposition.eig.SymmetricQRAlgorithmDecomposition_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class StabilitySymmEigen { public static double evaluate( EigenDecomposition alg , DenseMatrix64F orig ) { if( !alg.decompose(orig)) { return Double.NaN; } return DecompositionFactory.quality(orig,alg); } private static void runAlgorithms( DenseMatrix64F mat ) { TridiagonalSimilarDecomposition decomp = DecompositionFactory.tridiagonal(0); System.out.println("qr ult = "+ evaluate(new SymmetricQRAlgorithmDecomposition_D64(decomp,true),mat)); } public static void main( String args [] ) { Random rand = new Random(239454923); int size = 10; double scales[] = new double[]{1,0.1,1e-20,1e-100,1e-200,1e-300,1e-304,1e-308,1e-310,1e-312,1e-319,1e-320,1e-321,Double.MIN_VALUE}; System.out.println("Square matrix"); DenseMatrix64F orig = RandomMatrices.createSymmetric(size,-1,1,rand); DenseMatrix64F mat = orig.copy(); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < scales.length; i++ ) { System.out.printf("Decomposition size %3d for %e scale\n",size,scales[i]); CommonOps.scale(scales[i],orig,mat); runAlgorithms(mat); } System.out.println(" Done."); } }SymmetricEigenStressTest.java000066400000000000000000000071271256171534400364760ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/symm/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.symm; import org.ejml.UtilEjml; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.ops.SpecializedOps; import java.util.Date; import java.util.Random; /** * Provides a more rigorous and time consuming series of tests to check the correctness of a * symmetric matrix eigenvalue decomposition. * * @author Peter Abeles */ public class SymmetricEigenStressTest { Random rand = new Random(234234); public void checkMatrix( int N , long seed ) { DenseMatrix64F A = new DenseMatrix64F(N,N); Random localRand = new Random(seed); RandomMatrices.createSymmetric(A,-1,1,localRand); EigenDecomposition decomp = DecompositionFactory.eig(A.numRows,true); System.out.println("Decomposing..."); if( !decomp.decompose(A) ) { throw new RuntimeException("Decomposition failed"); } DenseMatrix64F L = new DenseMatrix64F(N,1); DenseMatrix64F R = new DenseMatrix64F(N,1); for( int i = 0; i < N; i++ ) { Complex64F value = decomp.getEigenvalue(i); DenseMatrix64F vector = decomp.getEigenVector(i); if( !value.isReal()) throw new RuntimeException("Complex eigenvalue"); CommonOps.mult(A,vector,L); CommonOps.scale(value.real,vector,R); double diff = SpecializedOps.diffNormF(L,R)/N; if( diff > UtilEjml.EPS*1000 ) System.out.println("["+i+"] value = "+value.real+" error = "+diff); } System.out.println("done"); } public void checkRandomMatrices( int N ) { System.out.println("N = "+N); EigenDecomposition decomp = DecompositionFactory.eig(N,true); DenseMatrix64F A = new DenseMatrix64F(N,N); for( int i = 0; i < 1000; i++ ) { long seed = rand.nextLong(); System.out.print("Date = "+new Date()+" Seed = "+seed); Random localRand = new Random(seed); RandomMatrices.createSymmetric(A,-1,1,localRand); if( !decomp.decompose(A) ) { System.out.println("Decomposition failed"); return; } double error = DecompositionFactory.quality(A,decomp); System.out.println(" error = "+error); if( error > 0.05 || Double.isNaN(error) || Double.isInfinite(error)) { System.out.println(" Large Error"); return; } } } public static void main( String args[] ) { SymmetricEigenStressTest stress = new SymmetricEigenStressTest(); stress.checkRandomMatrices(1000); // stress.checkMatrix(1000,5878413318033397987L); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/watched/000077500000000000000000000000001256171534400313455ustar00rootroot00000000000000WatchDoubleStepQR.java000066400000000000000000000102141256171534400354270ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/eig/watched/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.eig.watched; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Created by IntelliJ IDEA. * User: pja * Date: Dec 26, 2009 * Time: 6:20:51 PM * To change this template use File | Settings | File Templates. */ public class WatchDoubleStepQR { public static void watchFindEigen( DenseMatrix64F A ) { WatchedDoubleStepQREigenvalue alg = new WatchedDoubleStepQREigenvalue(); // alg.implicitQR.printFound = true; // alg.implicitQR.normalize = true; alg.implicitQR.checkHessenberg = true; // CommonOps.scale(1e305,A); alg.process(A); System.out.println("Eigenvalues."); for( int i = 0; i < A.numRows; i++ ) { Complex64F c = alg.implicitQR.eigenvalues[i]; System.out.printf("(%8.5e img = %8.5e ) in steps %3d \n",c.real,c.imaginary,alg.implicitQR.numStepsFind[i]); } System.out.println("Number of exceptional steps = "+alg.implicitQR.numExceptional); // finding eigen vectors now WatchedDoubleStepQREigenvector algVector = new WatchedDoubleStepQREigenvector(); algVector.process(alg.implicitQR,A,null); System.out.println("Eigenvectors."); for( int i = 0; i < A.numRows; i++ ) { DenseMatrix64F v = algVector.eigenvectors[i]; if( v != null ) v.print("%8.3e"); else System.out.println("i = "+i+" is null"); } } public static void watchImplicitDouble( DenseMatrix64F A ) { WatchedDoubleStepQREigen alg = new WatchedDoubleStepQREigen(); // alg.printHumps = true; alg.setup(A); alg.implicitDoubleStep(0,4); for( int i = 0; i < 20; i++ ) { System.out.println("-----------------------------------"); alg.A.print(); System.out.println(); alg.implicitDoubleStep(0,4); System.out.println(); } } public static void watchImplicitSingle( DenseMatrix64F A ) { WatchedDoubleStepQREigen alg = new WatchedDoubleStepQREigen(); // alg.printHumps = true; alg.setup(A); double ev = -7.801; // alg.implicitSingleStep(0,4); alg.performImplicitSingleStep(0,4,ev); for( int i = 0; i < 20; i++ ) { System.out.println("-----------------------------------"); alg.A.print(); System.out.println(); // alg.implicitSingleStep(0,4); alg.performImplicitSingleStep(0,4,ev); // System.out.println(); } } public static void main( String args[]) { Random rand = new Random(23475); // Random rand = new Random(235); DenseMatrix64F A = RandomMatrices.createUpperTriangle(5,1,2,3,rand); // DenseMatrix64F A = RandomMatrices.createUpperTriangle(50,1,-2,2,rand); // DenseMatrix64F A = new DenseMatrix64F(5,5,new double[]{0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0},true); // DenseMatrix64F A = UtilEjml.parseMatrix("-0.951 0.845 -0.171 \n" + // " 0.573 -0.720 0.264 \n" + // " 0.000 0.552 -0.100",3); System.out.println("--------- Original Matrix -----------"); A.print(); System.out.println("-------------------------------------"); watchFindEigen(A); // watchImplicitDouble(A); // watchImplicitSingle(A); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/hessenberg/000077500000000000000000000000001256171534400313075ustar00rootroot00000000000000BenchmarkHessenberg.java000066400000000000000000000054271256171534400360030ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkHessenberg { public static long basic( DenseMatrix64F orig , int numTrials ) { HessenbergSimilarDecomposition_D64 alg = new HessenbergSimilarDecomposition_D64(); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !alg.decompose(orig) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } // public static long alt( DenseMatrix64F orig , int numTrials ) { // // HessenbergSimilarDecompositionAlt alg = new HessenbergSimilarDecompositionAlt(); // // long prev = System.currentTimeMillis(); // // for( long i = 0; i < numTrials; i++ ) { // if( !alg.decompose(orig) ) { // throw new RuntimeException("Bad matrix"); // } // } // // return System.currentTimeMillis() - prev; // } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { System.out.println("basic = "+ basic(mat,numTrials)); // System.out.println("alt = "+ alt(mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000}; int trials[] = new int[]{(int)2e6,(int)5e5,(int)1e5,400,15,3,1,1}; // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Decompositing size %3d for %12d trials\n",w,trials[i]); System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createRandom(w,w,rand); System.out.println(" Done."); runAlgorithms(mat,trials[i]); } } }BenchmarkTridiagonal.java000066400000000000000000000065051256171534400361510ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkTridiagonal { public static long basic( DenseMatrix64F orig , int numTrials ) { TridiagonalDecompositionHouseholder_D64 alg = new TridiagonalDecompositionHouseholder_D64(); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( alg.inputModified()) alg.decompose(orig.copy()); else alg.decompose(orig); alg.getQ(null,false); } return System.currentTimeMillis() - prev; } public static long alt( DenseMatrix64F orig , int numTrials ) { TridiagonalDecompositionHouseholderOrig_D64 alg = new TridiagonalDecompositionHouseholderOrig_D64(); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { alg.decompose(orig); } return System.currentTimeMillis() - prev; } public static long block( DenseMatrix64F orig , int numTrials ) { TridiagonalDecomposition_B64_to_D64 alg = new TridiagonalDecomposition_B64_to_D64(); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( alg.inputModified()) alg.decompose(orig.copy()); else alg.decompose(orig); alg.getQ(null,false); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { System.out.println("basic = "+ basic(mat,numTrials)); // System.out.println("alt = "+ alt(mat,numTrials)); System.out.println("block = "+ block(mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000,5000}; int trials[] = new int[]{(int)8e6,(int)2e6,(int)2e5,600,12,3,1,1,1}; // results vary significantly depending if it starts from a small or large matrix for( int i = 3; i < size.length; i++ ) { int w = size[i]; System.out.printf("Processing size %3d for %12d trials\n",w,trials[i]); System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createRandom(w,w,rand); System.out.println(" Done."); runAlgorithms(mat,trials[i]); } } }StabilityTridiagonal.java000066400000000000000000000057151256171534400362250ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/hessenberg/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.hessenberg; import org.ejml.EjmlParameters; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.TridiagonalSimilarDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class StabilityTridiagonal { public static double evaluate( TridiagonalSimilarDecomposition alg , DenseMatrix64F orig ) { if( !DecompositionFactory.decomposeSafe(alg,orig)) { throw new RuntimeException("Decomposition failed"); } SimpleMatrix O = SimpleMatrix.wrap(alg.getQ(null,false)); SimpleMatrix T = SimpleMatrix.wrap(alg.getT(null)); SimpleMatrix A_found = O.mult(T).mult(O.transpose()); SimpleMatrix A = SimpleMatrix.wrap(orig); double top = A_found.minus(A).normF(); double bottom = A.normF(); return top/bottom; } private static void runAlgorithms( DenseMatrix64F mat ) { System.out.println("tri = "+ evaluate(new TridiagonalDecompositionHouseholder_D64(),mat)); System.out.println("block = "+ evaluate(new TridiagonalDecomposition_B64_to_D64(),mat)); } public static void main( String args [] ) { EjmlParameters.BLOCK_SIZE = 10; Random rand = new Random(239454923); for( int size = 5; size <= 15; size += 5 ) { double scales[] = new double[]{1,0.1,1e-20,1e-100,1e-200,1e-300,1e-304,1e-308,1e-310,1e-312,1e-319,1e-320,1e-321,Double.MIN_VALUE}; System.out.println("Square matrix"); DenseMatrix64F orig = RandomMatrices.createSymmetric(size,-1,1,rand); DenseMatrix64F mat = orig.copy(); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < scales.length; i++ ) { System.out.printf("Decomposition size %3d for %e scale\n",size,scales[i]); CommonOps.scale(scales[i],orig,mat); runAlgorithms(mat); } } System.out.println(" Done."); } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/lu/000077500000000000000000000000001256171534400276025ustar00rootroot00000000000000BenchmarkLuDecomposition.java000066400000000000000000000046421256171534400353240ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/lu/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.lu; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.LUDecomposition; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at decomposing square matrices * * @author Peter Abeles */ public class BenchmarkLuDecomposition { public static void benchmark( LUDecomposition lu , DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !lu.decompose(orig) ) { throw new RuntimeException("Bad matrix"); } } long time = System.currentTimeMillis() - prev; System.out.printf(" %20s time = %7d\n",lu.getClass().getSimpleName(),time); } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { benchmark(new LUDecompositionAlt_D64(),mat,numTrials); benchmark(new LUDecompositionNR_D64(),mat,numTrials); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000,4000}; int trials[] = new int[]{(int)1e7,(int)5e6,(int)1e6,2000,40,3,1,1}; // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Decomposing size %3d for %12d trials\n",w,trials[i]); // System.out.print("* Creating matrix "); DenseMatrix64F symMat = RandomMatrices.createRandom(w,w,-1,1,rand); // System.out.println(" Done."); runAlgorithms(symMat,trials[i]); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/qr/000077500000000000000000000000001256171534400276045ustar00rootroot00000000000000BenchmarkQrDecomposition_CD64.java000066400000000000000000000062351256171534400360500ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholderColumn_CD64; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholderTran_CD64; import org.ejml.alg.dense.decompose.qr.QRDecompositionHouseholder_CD64; import org.ejml.data.CDenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.CRandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkQrDecomposition_CD64 { public static long generic(QRDecomposition alg, CDenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); CDenseMatrix64F B; for( long i = 0; i < numTrials; i++ ) { if( alg.inputModified()) B = orig.copy(); else B = orig; if( !alg.decompose(B) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } private static void runAlgorithms( CDenseMatrix64F mat , int numTrials ) { System.out.println("basic = "+ generic( new QRDecompositionHouseholder_CD64(), mat,numTrials)); System.out.println("column = "+ generic( new QRDecompositionHouseholderColumn_CD64() ,mat,numTrials)); System.out.println("tran = "+ generic( new QRDecompositionHouseholderTran_CD64() , mat,numTrials)); // System.out.println("pivot column = "+ generic( new QRColPivDecompositionHouseholderColumn_CD64() , mat,numTrials)); // System.out.println("block native = "+ block(mat,numTrials)); // System.out.println("block wrapper = "+ generic( new QRDecomposition_B64_to_D64() , mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000,4000}; int trials[] = new int[]{(int)2e6,(int)5e5,(int)1e4,200,2,1,1,1,1}; // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; CDenseMatrix64F mat = CRandomMatrices.createRandom(w * 4, w / 1, rand); System.out.printf("Decomposing size [ %5d , %5d ] for %12d trials\n",mat.numRows,mat.numCols,trials[i]); runAlgorithms(mat,trials[i]); } } }BenchmarkQrDecomposition_D64.java000066400000000000000000000072511256171534400357440ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.block.decomposition.qr.QRDecompositionHouseholder_B64; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkQrDecomposition_D64 { public static long generic(QRDecomposition alg, DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); DenseMatrix64F B; for( long i = 0; i < numTrials; i++ ) { if( alg.inputModified()) B = orig.copy(); else B = orig; if( !alg.decompose(B) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } public static long block( DenseMatrix64F orig , int numTrials ) { BlockMatrix64F A = BlockMatrixOps.convert(orig); QRDecompositionHouseholder_B64 alg = new QRDecompositionHouseholder_B64(); BlockMatrix64F B; long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( alg.inputModified()) B = A.copy(); else B = A; if( !alg.decompose(B) ) { throw new RuntimeException("Bad matrix"); } } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { // System.out.println("basic = "+ generic( new QRDecompositionHouseholder(), mat,numTrials)); System.out.println("column = "+ generic( new QRDecompositionHouseholderColumn_D64() ,mat,numTrials)); System.out.println("tran = "+ generic( new QRDecompositionHouseholderTran_D64() , mat,numTrials)); System.out.println("pivot column = "+ generic( new QRColPivDecompositionHouseholderColumn_D64() , mat,numTrials)); // System.out.println("block native = "+ block(mat,numTrials)); System.out.println("block wrapper = "+ generic( new QRDecomposition_B64_to_D64() , mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000,4000}; int trials[] = new int[]{(int)2e6,(int)5e5,(int)1e5,400,5,1,1,1,1}; // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; DenseMatrix64F mat = RandomMatrices.createRandom(w*4,w/1,rand); System.out.printf("Decomposing size [ %5d , %5d ] for %12d trials\n",mat.numRows,mat.numCols,trials[i]); runAlgorithms(mat,trials[i]); } } }StabilityQRDecomposition.java000066400000000000000000000074441256171534400353450ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/qr/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.qr; import org.ejml.EjmlParameters; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.QRDecomposition; import org.ejml.interfaces.decomposition.QRPDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import java.util.Random; import static org.ejml.factory.DecompositionFactory.decomposeSafe; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class StabilityQRDecomposition { public static double evaluate( QRDecomposition alg , DenseMatrix64F orig ) { if( !decomposeSafe(alg,orig)) { return Double.NaN; } SimpleMatrix Q = SimpleMatrix.wrap(alg.getQ(null,true)); SimpleMatrix R = SimpleMatrix.wrap(alg.getR(null,true)); SimpleMatrix A_found = Q.mult(R); SimpleMatrix A = SimpleMatrix.wrap(orig); return A.minus(A_found).normF()/A.normF(); } public static double evaluate( QRPDecomposition alg , DenseMatrix64F orig ) { if( !decomposeSafe(alg,orig)) { return Double.NaN; } SimpleMatrix Q = SimpleMatrix.wrap(alg.getQ(null,true)); SimpleMatrix R = SimpleMatrix.wrap(alg.getR(null,true)); SimpleMatrix P = SimpleMatrix.wrap(alg.getPivotMatrix(null)); SimpleMatrix A_found = Q.mult(R); SimpleMatrix A = SimpleMatrix.wrap(orig); return A.mult(P).minus(A_found).normF()/A.normF(); } private static void runAlgorithms( DenseMatrix64F mat ) { System.out.println("qr = "+ evaluate(new QRDecompositionHouseholder_D64(),mat)); System.out.println("qr col = "+ evaluate(new QRDecompositionHouseholderColumn_D64(),mat)); System.out.println("qr pivot col = "+ evaluate(new QRColPivDecompositionHouseholderColumn_D64(),mat)); System.out.println("qr tran = "+ evaluate(new QRDecompositionHouseholderTran_D64(),mat)); System.out.println("qr block = "+ evaluate(new QRDecomposition_B64_to_D64(),mat)); } public static void main( String args [] ) { // set the block size so that it will get triggered at a smaller size EjmlParameters.BLOCK_SIZE = 10; Random rand = new Random(239454923); for( int size = 5; size <= 15; size += 5 ) { double scales[] = new double[]{1,0.1,1e-20,1e-100,1e-200,1e-300,1e-304,1e-308,1e-310,1e-312,1e-319,1e-320,1e-321,Double.MIN_VALUE}; System.out.println("Square matrix"); DenseMatrix64F orig = RandomMatrices.createRandom(2*size,size,-1,1,rand); DenseMatrix64F mat = orig.copy(); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < scales.length; i++ ) { System.out.printf("Decomposition size %3d for %e scale\n",size,scales[i]); CommonOps.scale(scales[i],orig,mat); runAlgorithms(mat); } } System.out.println(" Done."); } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/svd/000077500000000000000000000000001256171534400277565ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/svd/BenchmarkSvd.java000066400000000000000000000105471256171534400331770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkSvd { public static String evaluate( SingularValueDecomposition alg , DenseMatrix64F orig , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !alg.decompose(orig) ) { throw new RuntimeException("Bad matrix"); } } long diff = System.currentTimeMillis() - prev; return diff+" (ms) "+(numTrials/(diff/1000.0))+" (ops/sec)"; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { // mat.print("%f"); if( numTrials <= 0 ) return; System.out.println("qr = "+ evaluate(new SvdImplicitQrDecompose_D64(true,true,true,true),mat,numTrials)); // System.out.println("qr smart = "+ evaluate(new SvdImplicitQrDecompose_UltimateS(true,true,true),mat,numTrials)); System.out.println("qr separate = "+ evaluate(new SvdImplicitQrDecompose_Ultimate(true,true,true),mat,numTrials)); // System.out.println("qr = "+ evaluate(new SvdImplicitQrDecompose(true,true,true),mat,numTrials)); // System.out.println("qr no U = "+ evaluate(new SvdImplicitQrDecompose(true,false,true),mat,numTrials)); // System.out.println("qr no U and V = "+ evaluate(new SvdImplicitQrDecompose(true,false,false),mat,numTrials)); // System.out.println("alt = "+ evaluate(new SvdNumericalRecipes(),mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,500,1000,2000,3000}; int trials[] = new int[]{(int)7e5,(int)1e5,(int)5e4,100,2,1,1,1}; System.out.println("Square matrix"); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Decomposition size %3d for %12d trials\n",w,trials[i]); System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createRandom(w,w,rand); System.out.println(" Done."); runAlgorithms(mat,trials[i]); } System.out.println("Tall matrix"); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; int t = trials[i]*3/5; if( t == 0 ) continue; System.out.printf("Decomposition size %3d for %12d trials\n",w,t); System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createRandom(2*w,w,rand); System.out.println(" Done."); runAlgorithms(mat,t); } System.out.println("Wide matrix"); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < size.length; i++ ) { int w = size[i]; int t = trials[i]*3/5; if( t == 0 ) continue; System.out.printf("Decomposition size %3d for %12d trials\n",w,t); System.out.print("* Creating matrix "); DenseMatrix64F mat = RandomMatrices.createRandom(w,2*w,rand); System.out.println(" Done."); runAlgorithms(mat,trials[i]); } } }StabilitySvdlDecomposition.java000066400000000000000000000060071256171534400360770ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/decomposition/svd/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class StabilitySvdlDecomposition { private static boolean compact = false; // These two options need to be true to compute the quality private static boolean computeU = true; private static boolean computeV = true; public static double evaluate( SingularValueDecomposition alg , DenseMatrix64F orig ) { DenseMatrix64F U=null; DenseMatrix64F W; DenseMatrix64F Vt=null; if( !alg.decompose(orig.copy())) { return Double.NaN; } W = alg.getW(null); if( computeU ) U = alg.getU(null,false).copy(); if( computeV ) Vt = alg.getV(null,true).copy(); // I'm not sure how to test quality of U or V is not computed. return DecompositionFactory.quality(orig, U,W,Vt); } private static void runAlgorithms( DenseMatrix64F mat ) { System.out.println("qr = "+ evaluate(new SvdImplicitQrDecompose_D64(compact,computeU,computeV,false),mat)); System.out.println("qr ult = "+ evaluate(new SvdImplicitQrDecompose_Ultimate(compact,computeU,computeV),mat)); } public static void main( String args [] ) { Random rand = new Random(239454923); int numCols = 10; int numRows = 30; double scales[] = new double[]{1,0.1,1e-20,1e-100,1e-200,1e-300,1e-304,1e-308,1e-310,1e-312,1e-319,1e-320,1e-321,Double.MIN_VALUE}; DenseMatrix64F orig = RandomMatrices.createRandom(numRows,numCols,-1,1,rand); DenseMatrix64F mat = orig.copy(); // results vary significantly depending if it starts from a small or large matrix for( int i = 0; i < scales.length; i++ ) { System.out.printf(" Decomposition size %3d %d for %e scale\n",numRows,numCols,scales[i]); CommonOps.scale(scales[i],orig,mat); runAlgorithms(mat); } System.out.println(); System.out.println("Done."); } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/000077500000000000000000000000001256171534400256065ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/BenchmarkInverseStability.java000066400000000000000000000151311256171534400335650ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouseCol_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * Feeds the algorithms matrices that are closer and closer to being singular * and sees at which point they break. * * @author Peter Abeles */ public class BenchmarkInverseStability { private DenseMatrix64F b = new DenseMatrix64F(3,3); private double evaluateInverse( DenseMatrix64F A , DenseMatrix64F A_inv ) { CommonOps.mult(A,A_inv,b); double total = 0; for( int y = 0; y < 3; y++ ) { for( int x = 0; x < 3; x++ ) { if( x == y ) { total += Math.abs(b.get(x,y)-1.0); } else { total += Math.abs(b.get(x,y)); } } } return total; } public void evaluateAll() { List> solvers = new ArrayList>(); List names = new ArrayList(); // solvers.add(new GaussJordanNoPivot()); // names.add("GJ NP"); // solvers.add(new GaussJordan(3)); // names.add("GJ"); // solvers.add(new LinearSolverLu(new LUDecompositionAlt())); // names.add("LU ALT"); // solvers.add(new LinearSolverLu(new LUDecompositionNR())); // names.add("LU NR"); // solvers.add(new LinearSolverLuKJI(new LUDecompositionAlt())); // names.add("LU B"); // solvers.add(new LinearSolverLu(new LUDecompositionAlt(),true)); // names.add("LU A Imp"); solvers.add(new LinearSolverQrHouseCol_D64()); names.add("QR"); // solvers.add(new LinearSolverSvdNR(new SvdNumericalRecipes())); // names.add("SVD NR"); // solvers.add(new LinearSolverUnrolled()); // names.add("Unrolled"); solvers.add(LinearSolverFactory.leastSquaresQrPivot(true, true)); names.add("P'QR compute Q"); solvers.add(LinearSolverFactory.leastSquaresQrPivot(true,false)); names.add("P'QR householder"); solvers.add(LinearSolverFactory.pseudoInverse(true)); names.add("PINV SVD"); allTheBreaks(solvers,names); } private void allTheBreaks( List> solvers , List names ) { System.out.println("Testing singular:"); for( int i = 0; i < solvers.size(); i++ ) { breakNearlySingluar(names.get(i),solvers.get(i)); } System.out.println("Testing overflow:"); for( int i = 0; i < solvers.size(); i++ ) { breakOverUnderFlow(names.get(i),solvers.get(i),true); } System.out.println("Testing underflow:"); for( int i = 0; i < solvers.size(); i++ ) { breakOverUnderFlow(names.get(i),solvers.get(i),false); } } private void breakNearlySingluar( String name , LinearSolver alg ) { double breakDelta = -1; int breakW = -1; alg = new LinearSolverSafe(alg); escape: for( int i = 0; i < 40; i++ ) { // System.out.println("i = "+i); double delta = Math.pow(0.1,i); for( int w = 0; w < 6; w++ ) { DenseMatrix64F A = new DenseMatrix64F(3,3, true, 1, 2, 3, 2, 4, 6, 4, 6, -2); DenseMatrix64F A_inv = new DenseMatrix64F(3,3); A.plus(w, delta); try { if( !alg.setA(A) ) { breakDelta = delta; breakW = w; break escape; } alg.invert(A_inv); if(evaluateInverse(A,A_inv) > 1.0 ) { breakDelta = delta; breakW = w; break escape; } } catch( RuntimeException e ) { breakDelta = delta; breakW = w; break escape; } } } System.out.printf("%20s broke at %E w = %d\n",name, breakDelta,breakW); // System.out.println(alg.getClass().getSimpleName()+" broke at "+breakDelta+" w = "+breakW); } private void breakOverUnderFlow( String name , LinearSolver alg , boolean overflow ) { boolean madeBad= false; DenseMatrix64F A_orig = RandomMatrices.createRandom(3,3,new Random(0x14)); int i; for( i = 0; i < 3000; i++ ) { // System.out.println("i = "+i); DenseMatrix64F A = new DenseMatrix64F(A_orig); if( overflow ) CommonOps.scale(Math.pow(2,i),A); else CommonOps.scale(Math.pow(1.0/2,i),A); DenseMatrix64F A_inv = new DenseMatrix64F(A.numRows,A.numCols); if(MatrixFeatures.hasUncountable(A)) { madeBad = true; break; } try { if( !alg.setA(A) ) { break; } alg.invert(A_inv); if(MatrixFeatures.hasUncountable(A_inv)) { break; } } catch( RuntimeException e ) { break; } if(evaluateInverse(A,A_inv) > 1.0 ) { break; } } if( madeBad ) { System.out.printf("%20s never broke. (%d)\n",name,i); } else { System.out.printf("%20s broke at %d.\n",name,i); } } public static void main( String arg[] ) { BenchmarkInverseStability eval = new BenchmarkInverseStability(); eval.evaluateAll(); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/BenchmarkInvertSquare.java000066400000000000000000000072071256171534400327220ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.misc.UnrolledInverseFromMinor; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ // TODO generate random stuff per trial public class BenchmarkInvertSquare { public static long invertBenchmark( LinearSolver solver , DenseMatrix64F orig , int numTrials ) { DenseMatrix64F A = new DenseMatrix64F(orig.numRows,orig.numCols); long prev = System.currentTimeMillis(); solver.setA(orig); for( long i = 0; i < numTrials; i++ ) { solver.invert(A); } return System.currentTimeMillis() - prev; } public static long invertUnrolledBenchmark( DenseMatrix64F orig , int numTrials ) { DenseMatrix64F A = new DenseMatrix64F(orig.numRows,orig.numCols); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { UnrolledInverseFromMinor.inv(orig,A); } return System.currentTimeMillis() - prev; } public static long invertOpsBenchmark( DenseMatrix64F orig , int numTrials ) { DenseMatrix64F A = new DenseMatrix64F(orig.numRows,orig.numCols); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { CommonOps.invert(orig,A); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { // System.out.println("invert GJ No Pivot = "+ invertBenchmark( // new GaussJordanNoPivot(),mat,numTrials)); // System.out.println("invert GJ = "+ invertBenchmark( // new GaussJordan(mat.numRows),mat,numTrials)); // System.out.println("invert LU = "+ invertBenchmark( // new LinearSolverLu(new LUDecompositionAlt_D64()),mat,numTrials)); // System.out.println("invert LU NR = "+ invertBenchmark( // new LinearSolverLu(new LUDecompositionNR()),mat,numTrials)); // System.out.println("invert Ops = "+ // invertOpsBenchmark(mat,numTrials)); System.out.println("unrolled = "+ invertUnrolledBenchmark(mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{5,4,6,10,100,1000,2000,5000,10000}; int trials[] = new int[]{(int)8e6,(int)5e6,(int)2e6,(int)1e6,1000,3,1,1,1}; for( int i = 0; i < 1; i++ ) { int w = size[i]; System.out.printf("Inverting size %3d for %12d trials\n",w,trials[i]); DenseMatrix64F mat = RandomMatrices.createRandom(w,w,rand); runAlgorithms(mat,trials[i]); } } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/BenchmarkInvertSymPosDef.java000066400000000000000000000104331256171534400333260ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.EjmlParameters; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionBlock_D64; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionInner_D64; import org.ejml.alg.dense.linsol.chol.LinearSolverChol_B64; import org.ejml.alg.dense.linsol.chol.LinearSolverChol_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CovarianceOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkInvertSymPosDef { public static long invertCovar( DenseMatrix64F orig , int numTrials ) { DenseMatrix64F A = new DenseMatrix64F(orig.numRows,orig.numCols); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { CovarianceOps.invert(orig,A); } return System.currentTimeMillis() - prev; } public static long invertCholesky( LinearSolver alg , DenseMatrix64F orig , int numTrials ) { alg = new LinearSolverSafe(alg); DenseMatrix64F A = new DenseMatrix64F(orig.numRows,orig.numCols); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( !alg.setA(orig) ) { throw new RuntimeException("Bad matrix"); } alg.invert(A); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F mat , int numTrials ) { System.out.println("invert covariance = "+ invertCovar(mat,numTrials)); // System.out.println("invert GJ No Pivot = "+ invertGJ_NoPivot(mat,numTrials)); // System.out.println("invert GJ = "+ invertGJ(mat,numTrials)); // System.out.println("invert LU-NR = "+ invertLU_nr(mat,numTrials)); // System.out.println("invert LU-Alt = "+ invertLU_alt(mat,numTrials)); System.out.println("invert Cholesky Inner = "+ invertCholesky( new LinearSolverChol_D64(new CholeskyDecompositionInner_D64( true)), mat,numTrials)); System.out.println("invert Cholesky Block Dense = "+ invertCholesky( new LinearSolverChol_D64(new CholeskyDecompositionBlock_D64( EjmlParameters.BLOCK_WIDTH_CHOL)), mat,numTrials)); // System.out.println("invert default = "+ invertCholesky( // LinearSolverFactory.symmetric(mat.numRows), // mat,numTrials)); // System.out.println("invert CholeskyLDL = "+ invertCholesky( // new LinearSolverCholLDL(new CholeskyDecompositionLDL()), // mat,numTrials)); System.out.println("invert CholeskyBlock64 = "+ invertCholesky( new LinearSolverChol_B64(), mat,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,6,10,100,1000,2000,4000,8000}; int trials[] = new int[]{(int)1e7,(int)3e6,(int)1e6,(int)4e5,1000,3,1,1,1}; for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Inverting size %3d for %12d trials\n",w,trials[i]); System.out.print("* Creating matrix "); DenseMatrix64F symMat = RandomMatrices.createSymmPosDef(w,rand); System.out.println(" Done."); runAlgorithms(symMat,trials[i]); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/BenchmarkRectSolve.java000066400000000000000000000064541256171534400322030ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouseCol_D64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouse_D64; import org.ejml.alg.dense.linsol.svd.SolvePseudoInverseSvd; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkRectSolve { private static final long SEED = 6; private static final Random rand = new Random(); private static DenseMatrix64F A; private static DenseMatrix64F B; private static final boolean includeSet = true; public static long solveBenchmark( LinearSolver solver , int numTrials ) { rand.setSeed(SEED); DenseMatrix64F X = new DenseMatrix64F(A.numCols,B.numCols); RandomMatrices.setRandom(A,rand); RandomMatrices.setRandom(B,rand); if( !includeSet ) solver.setA(A); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if(includeSet) solver.setA(A); solver.solve(B,X); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( int numTrials ) { System.out.println("Pseudo Inverse = "+ solveBenchmark( new SolvePseudoInverseSvd(A.numRows,A.numCols),numTrials)); System.out.println("QR house = "+ solveBenchmark( new LinearSolverQrHouse_D64(),numTrials)); System.out.println("QR house Col = "+ solveBenchmark( new LinearSolverQrHouseCol_D64(),numTrials)); } public static void main( String args [] ) { int size[] = new int[]{2,4,10,100,1000,2000}; int trials[] = new int[]{(int)2e6,(int)8e5,(int)3e5,800,3,1}; int trialsX[] = new int[]{(int)1e5,(int)6e4,(int)1e4,(int)5e3,1000,500}; System.out.println("Increasing matrix A size"); for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Solving A size %3d for %12d trials\n",w,trials[i]); A = RandomMatrices.createRandom(w*2,w,rand); B = new DenseMatrix64F(w*2,2); runAlgorithms(trials[i]); } System.out.println("Increasing matrix B size"); for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Solving B size %3d for %12d trials\n",w,trialsX[i]); A = RandomMatrices.createRandom(200,100,rand); B = new DenseMatrix64F(200,w); runAlgorithms(trialsX[i]/80); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/BenchmarkSolveEq.java000066400000000000000000000076711256171534400316550ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.alg.dense.linsol.lu.LinearSolverLuKJI_D64; import org.ejml.alg.dense.linsol.lu.LinearSolverLu_D64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouseCol_D64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouse_D64; import org.ejml.alg.dense.linsol.svd.SolvePseudoInverseSvd; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkSolveEq { private static final long SEED = 6; private static final Random rand = new Random(); private static DenseMatrix64F A; private static DenseMatrix64F B; private static boolean includeSet = false; public static long solveBenchmark( LinearSolver solver , int numTrials ) { rand.setSeed(SEED); DenseMatrix64F X = new DenseMatrix64F(B.numRows,B.numCols); RandomMatrices.setRandom(A,rand); RandomMatrices.setRandom(B,rand); if( !includeSet ) solver.setA(A); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if(includeSet) solver.setA(A); solver.solve(B,X); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( int numTrials ) { System.out.println("solve LU A = "+ solveBenchmark( new LinearSolverLu_D64(new LUDecompositionAlt_D64()),numTrials)); System.out.println("solve LU B = "+ solveBenchmark( new LinearSolverLuKJI_D64(new LUDecompositionAlt_D64()),numTrials)); System.out.println("solve QR house = "+ solveBenchmark( new LinearSolverQrHouse_D64(),numTrials)); System.out.println("solve QR house Col = "+ solveBenchmark( new LinearSolverQrHouseCol_D64(),numTrials)); System.out.println("solve PInv = "+ solveBenchmark( new SolvePseudoInverseSvd(),numTrials)); // System.out.println("solve SVD = "+ solveBenchmark( // new LinearSolverSvd(new SvdNumericalRecipes(A.numRows,A.numCols)),numTrials/8)); } public static void main( String args [] ) { int size[] = new int[]{2,4,10,100,1000,2000}; int trials[] = new int[]{(int)1e7,(int)5e6,(int)1e6,2000,8,3}; int trialsX[] = new int[]{(int)5e5,(int)4e5,(int)2e5,(int)7e4,4000,2000}; System.out.println("Increasing matrix A size"); for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Solving A size %3d for %12d trials\n",w,trials[i]); A = RandomMatrices.createRandom(w,w,rand); B = new DenseMatrix64F(w,2); runAlgorithms(trials[i]); } System.out.println("Increasing matrix B size"); for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Solving B size %3d for %12d trials\n",w,trialsX[i]); A = RandomMatrices.createRandom(100,100,rand); B = new DenseMatrix64F(100,w); runAlgorithms(trialsX[i]/80); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/BenchmarkSolveOver.java000066400000000000000000000104531256171534400322130ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.linsol.qr.LinearSolverQrBlock64_D64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouseCol_D64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouseTran_D64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrHouse_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkSolveOver { private static final long SEED = 6; private static Random rand = new Random(); private static DenseMatrix64F A; private static DenseMatrix64F B; private static boolean includeSet = false; public static long solveBenchmark( LinearSolver solver , int numTrials ) { rand.setSeed(SEED); DenseMatrix64F X = new DenseMatrix64F(A.numCols,B.numCols); RandomMatrices.setRandom(A,rand); RandomMatrices.setRandom(B,rand); DenseMatrix64F B_tmp = new DenseMatrix64F(B.numRows,B.numCols); if( !includeSet ) solver.setA(A); DenseMatrix64F A_copy = solver.modifiesA() ? A.copy() : A; long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if( solver.modifiesA() ) { A_copy.set(A); } if(includeSet) solver.setA(A_copy); if( solver.modifiesB() ) { B_tmp.set(B); solver.solve(B_tmp,X); } else { solver.solve(B,X); } } return System.currentTimeMillis() - prev; } private static void runAlgorithms( int numTrials ) { System.out.println(" solve QR house = "+ solveBenchmark( new LinearSolverQrHouse_D64(),numTrials)); System.out.println(" solve QR house Col = "+ solveBenchmark( new LinearSolverQrHouseCol_D64(),numTrials)); System.out.println(" solve QR tran = "+ solveBenchmark( new LinearSolverQrHouseTran_D64(),numTrials)); System.out.println(" solve QR Block64 = "+ solveBenchmark( new LinearSolverQrBlock64_D64(),numTrials)); System.out.println(" Selected = "+ solveBenchmark( LinearSolverFactory.leastSquares(A.numRows, A.numCols),numTrials)); // System.out.println(" solve PInv = "+ solveBenchmark( // new SolvePseudoInverse(),numTrials)); } public static void main( String args [] ) { int trialsWith[] = new int[]{3000000,1000000,200000,400,3,1,1,1,1,1}; int width[] = new int[]{2,4,10,100,500,1000,2000,5000,10000}; includeSet = true; System.out.println("Solving for least squares fitting type problems with set"); for( int i = 0; i < width.length; i++ ) { int N = width[i]*3; System.out.printf("height %d Width = %d trials = %d\n",N,width[i],trialsWith[i]); A = new DenseMatrix64F(N,width[i]); B = new DenseMatrix64F(N,1); runAlgorithms(trialsWith[i]); } System.out.println(); includeSet = false; System.out.println("Solving for least squares fitting type problems without set"); for( int i = 0; i < width.length; i++ ) { int N = width[i]*3; System.out.printf("height %d Width = %d trials = %d\n",N,width[i],trialsWith[i]); A = new DenseMatrix64F(N,width[i]); B = new DenseMatrix64F(N,1); runAlgorithms(trialsWith[i]); } } }BenchmarkSolvePseudoInverse.java000066400000000000000000000102521256171534400340110ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.decomposition.qr.QRColPivDecompositionHouseholderColumn_D64; import org.ejml.alg.dense.linsol.qr.LinearSolverQrpHouseCol_D64; import org.ejml.alg.dense.linsol.qr.SolvePseudoInverseQrp_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.LinearSolverFactory; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkSolvePseudoInverse { private static final long SEED = 6; private static final Random rand = new Random(); private static DenseMatrix64F A; private static DenseMatrix64F B; private static boolean includeSet = true; public static long solveBenchmark( LinearSolver solver , int numTrials ) { rand.setSeed(SEED); DenseMatrix64F X = new DenseMatrix64F(B.numRows,B.numCols); solver = new LinearSolverSafe(solver); if( !includeSet ) solver.setA(A); long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { if(includeSet) solver.setA(A); solver.solve(B,X); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( int numTrials ) { // System.out.println("solve SVD = "+ solveBenchmark( // new SolvePseudoInverseSvd(),numTrials)); System.out.println("solve Gen QRP Basic = "+ solveBenchmark( new SolvePseudoInverseQrp_D64(new QRColPivDecompositionHouseholderColumn_D64(),false),numTrials)); System.out.println("solve Gen QRP = "+ solveBenchmark( new SolvePseudoInverseQrp_D64(new QRColPivDecompositionHouseholderColumn_D64(),true),numTrials)); System.out.println("solve QRP Col Basic = "+ solveBenchmark( new LinearSolverQrpHouseCol_D64(new QRColPivDecompositionHouseholderColumn_D64(),false),numTrials)); System.out.println("solve QRP Col = "+ solveBenchmark( new LinearSolverQrpHouseCol_D64(new QRColPivDecompositionHouseholderColumn_D64(),true),numTrials)); System.out.println("solve QRP Col = "+ solveBenchmark( LinearSolverFactory.leastSquaresQrPivot(true,false),numTrials)); } public static void main( String args [] ) { int size[] = new int[]{2,4,10,100,1000,2000}; int trials[] = new int[]{(int)1e6,(int)5e5,(int)1e5,500,2,1}; int trialsX[] = new int[]{(int)5e5,(int)4e5,(int)2e5,(int)7e4,4000,2000}; System.out.println("Increasing matrix A size"); for( int i = 3; i < size.length; i++ ) { int w = size[i]; // create a singular matrix double singularValues[] = new double[w]; for( int j = 0; j < w-1; j++ ) singularValues[j] = 10+w-j; System.out.printf("Solving A size %3d for %12d trials\n",w,trials[i]); A = RandomMatrices.createSingularValues(w, w, rand, singularValues); B = new DenseMatrix64F(w,2); runAlgorithms(trials[i]); } System.out.println("Increasing matrix B size"); for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Solving B size %3d for %12d trials\n",w,trialsX[i]); A = RandomMatrices.createRandom(100,100,rand); B = new DenseMatrix64F(100,w); runAlgorithms(trialsX[i]/80); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/linsol/BenchmarkSolveSymPosDef.java000066400000000000000000000060501256171534400331470ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.linsol; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionInner_D64; import org.ejml.alg.dense.decomposition.chol.CholeskyDecompositionLDL_D64; import org.ejml.alg.dense.linsol.chol.LinearSolverCholLDL_D64; import org.ejml.alg.dense.linsol.chol.LinearSolverChol_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.linsol.LinearSolver; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compare the speed of various algorithms at inverting square matrices * * @author Peter Abeles */ public class BenchmarkSolveSymPosDef { public static long solve( LinearSolver solver , DenseMatrix64F A, DenseMatrix64F b , int numTrials ) { DenseMatrix64F x = new DenseMatrix64F(A.numCols,b.numCols); if( !solver.setA(A) ) { throw new RuntimeException("Bad matrix"); } long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { solver.solve(b,x); } return System.currentTimeMillis() - prev; } private static void runAlgorithms( DenseMatrix64F A , DenseMatrix64F b ,int numTrials ) { System.out.println("Solve Cholesky = "+solve( new LinearSolverChol_D64(new CholeskyDecompositionInner_D64(true)), A,b,numTrials)); System.out.println("Solve Cholesky LDL = "+solve( new LinearSolverCholLDL_D64(new CholeskyDecompositionLDL_D64()), A,b,numTrials)); } public static void main( String args [] ) { Random rand = new Random(23423); int size[] = new int[]{2,4,10,100,1000}; int trials[] = new int[]{(int)6e6,(int)1e6,(int)2e5,500,1}; for( int i = 0; i < size.length; i++ ) { int w = size[i]; System.out.printf("Matrix A size %3d for %12d trials\n",w,trials[i]); while( true ) { DenseMatrix64F mat = RandomMatrices.createRandom(w,w,rand); DenseMatrix64F symMat = new DenseMatrix64F(w,w); CommonOps.multTransA(mat,mat,symMat); DenseMatrix64F b = RandomMatrices.createRandom(w,w*2,rand); if(CommonOps.det(symMat) > 0 ) { runAlgorithms(symMat,b,trials[i]); break; } } } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400252415ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/misc/BenchmarkDeterminant.java000066400000000000000000000121421256171534400321710ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.alg.dense.decomposition.lu.LUDecompositionAlt_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkDeterminant { static int TOTAL_TRIALS = 50000000; public static long computeAuto( DenseMatrix64F mat ,int numTrials ) { long before = System.currentTimeMillis(); double total = 0; for( int i = 0; i < numTrials; i++ ) { total += UnrolledDeterminantFromMinor.det(mat); } long after = System.currentTimeMillis(); if( total == 100 ) System.out.println(total); return after-before; } public static long computeFixed4x4( DenseMatrix64F mat ) { long before = System.currentTimeMillis(); double total = 0; for( int i = 0; i < TOTAL_TRIALS; i++ ) { total += UnrolledDeterminantFromMinor.det4(mat); } long after = System.currentTimeMillis(); if( total == 100 ) System.out.println(total); return after-before; } public static long computeMinor4x4( DenseMatrix64F mat ) { long before = System.currentTimeMillis(); DeterminantFromMinor minor = new DeterminantFromMinor(4,5); double total = 0; for( int i = 0; i < TOTAL_TRIALS; i++ ) { total += minor.compute(mat); } long after = System.currentTimeMillis(); if( total == 100 ) System.out.println(total); return after-before; } public static long computeLU( DenseMatrix64F mat , int numTrials ) { long before = System.currentTimeMillis(); LUDecompositionAlt_D64 alg = new LUDecompositionAlt_D64(); double total = 0; for( int i = 0; i < numTrials; i++ ) { alg.decompose(mat); total += alg.computeDeterminant().real; } // System.out.println(" total = "+total); long after = System.currentTimeMillis(); if( total == 100 ) System.out.println(total); return after-before; } public static long computeMinor( DenseMatrix64F mat , int numTrials ) { long before = System.currentTimeMillis(); DeterminantFromMinor minor = new DeterminantFromMinor(mat.numRows,5); double total = 0; for( int i = 0; i < numTrials; i++ ) { total += minor.compute(mat); } // System.out.println(" total = "+total); long after = System.currentTimeMillis(); if( total == 100 ) System.out.println(total); return after-before; } public static long computeLeibniz( DenseMatrix64F mat , int numTrials ) { long before = System.currentTimeMillis(); double total = 0; for( int i = 0; i < numTrials; i++ ) { total += NaiveDeterminant.leibniz(mat); } // System.out.println(" total = "+total); long after = System.currentTimeMillis(); if( total == 100 ) System.out.println(total); return after-before; } public static void main( String args[] ) { double[] d = new double[]{5 ,-2 ,-4 ,0.5, 0.1, 91, 8, 66, 1, -2, 10, -4, -0.2, 7, -4, 0.8}; DenseMatrix64F mat = new DenseMatrix64F(4,4, true, d); // System.out.println("Fixed 4x4 = "+computeFixed4x4(mat)); // System.out.println("Auto 4x4 = "+computeAuto(mat,TOTAL_TRIALS)); //// System.out.println("Minor 4x4 = "+computeMinor4x4(mat)); // System.out.println("LU alg NR 4x4 = "+computeLU(mat,TOTAL_TRIALS)); //// System.out.println("Leibniz 4x4 = "+computeLeibniz(mat,TOTAL_TRIALS)); Random rand = new Random(4344535); for( int i = 2; i <= 25; i+= 1) { int numTrials = TOTAL_TRIALS/(i*i); System.out.println("Dimension = "+i+" trials = "+numTrials); mat = RandomMatrices.createRandom(i,i,rand); System.out.println(" Auto = "+computeAuto(mat,numTrials)); // System.out.println(" Minor = "+computeMinor(mat,numTrials)); // System.out.println(" Leibniz = "+computeLeibniz(mat,numTrials)); System.out.println(" LU alg NR = "+ computeLU(mat,numTrials)); } // System.out.println("Recursive 4x4 = "+computeRecursive4x4(mat)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/misc/BenchmarkImplCommonOps.java000066400000000000000000000055421256171534400324610ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RealMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkImplCommonOps { public static long extract_DenseMatrix64F( DenseMatrix64F src , DenseMatrix64F dst , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { ImplCommonOps_DenseMatrix64F.extract(src, 0, 0, dst, 0, 0, src.numRows, src.numCols); } long curr = System.currentTimeMillis(); return curr-prev; } public static long extract_Matrix64F( RealMatrix64F src , RealMatrix64F dst , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { ImplCommonOps_Matrix64F.extract(src,0,0,dst,0,0, src.getNumRows(), src.getNumCols()); } long curr = System.currentTimeMillis(); return curr-prev; } public static long extract_Common( DenseMatrix64F src , DenseMatrix64F dst , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.extract(src, 0, src.numRows, 0 , src.numCols, dst, 0, 0 ); } long curr = System.currentTimeMillis(); return curr-prev; } public static void benchmark( int N , int trials ) { Random rand = new Random(234); DenseMatrix64F src = new DenseMatrix64F(N,N); DenseMatrix64F dst = new DenseMatrix64F(N,N); RandomMatrices.addRandom(src,0,100,rand); System.out.println("N = "+N); System.out.println("extract DenseMatrix64F = "+extract_DenseMatrix64F(src,dst,trials)); System.out.println("extract Matrix64F = "+extract_Matrix64F(src,dst,trials)); System.out.println("extract Common = "+extract_Common(src, dst, trials)); } public static void main( String args[] ) { benchmark(5,10000000); benchmark(100,100000); benchmark(1000,500); benchmark(2000,75); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/misc/BenchmarkTranspose.java000066400000000000000000000107311256171534400316770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.EjmlParameters; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkTranspose { static Random rand = new Random(234); public static long square( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { TransposeAlgs.square(mat); } long curr = System.currentTimeMillis(); return curr-prev; } public static long block( DenseMatrix64F mat , int numTrials , int blockLength ) { DenseMatrix64F tran = new DenseMatrix64F(mat.numCols,mat.numRows); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { TransposeAlgs.block(mat,tran,blockLength); } long curr = System.currentTimeMillis(); return curr-prev; } public static long standard( DenseMatrix64F mat , int numTrials) { DenseMatrix64F tran = new DenseMatrix64F(mat.numCols,mat.numRows); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { TransposeAlgs.standard(mat,tran); } long curr = System.currentTimeMillis(); return curr-prev; } public static long common( DenseMatrix64F mat , int numTrials) { DenseMatrix64F tran = new DenseMatrix64F(mat.numCols,mat.numRows); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.transpose(mat,tran); } long curr = System.currentTimeMillis(); return curr-prev; } public static void main( String args[] ) { // evaluateMatrix(3, 50000000); // evaluateMatrix(20, 1000000); // evaluateMatrix(120, 50000); // evaluateMatrix(EjmlParameters.TRANSPOSE_SWITCH+1, 4000); evaluateMatrix(2000, 80); // evaluateMatrix(10000, 1); } private static void evaluateMatrix( int length , int n) { System.out.println("*** Size "+length); DenseMatrix64F A = RandomMatrices.createRandom(length,length,rand); System.out.println("---------- Square ----------------"); System.out.println("In place : "+square(A, n)); System.out.println("Block : "+block(A, n, EjmlParameters.BLOCK_WIDTH)); System.out.println("Block 15 : "+block(A, n, 15)); System.out.println("Block 20 : "+block(A, n, 20)); System.out.println("Block 30 : "+block(A, n, 30)); System.out.println("Block 50 : "+block(A, n, 50)); System.out.println("Standard : "+standard(A, n)); System.out.println("Common : "+common(A, n)); System.out.println(); System.out.println("---------- Tall ----------------"); A = RandomMatrices.createRandom(2*length,length,rand); System.out.println("Block : "+block(A, n,EjmlParameters.BLOCK_WIDTH)); System.out.println("Block 20 : "+block(A, n, 20)); System.out.println("Block 30 : "+block(A, n, 30)); System.out.println("Block 50 : "+block(A, n, 50)); System.out.println("Standard : "+standard(A, n)); System.out.println("Common : "+common(A, n)); System.out.println("---------- Wide ----------------"); A = RandomMatrices.createRandom(length,2*length,rand); System.out.println("Block : "+block(A, n, EjmlParameters.BLOCK_WIDTH)); System.out.println("Block 20 : "+block(A, n, 20)); System.out.println("Block 30 : "+block(A, n, 30)); System.out.println("Block 50 : "+block(A, n, 50)); System.out.println("Standard : "+standard(A, n)); System.out.println("Common : "+common(A, n)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400252675ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/BenchmarkMatrixMatrixMult.java000066400000000000000000000151631256171534400332460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.alg.block.BlockMatrixOps; import org.ejml.alg.blockd3.BlockD3MatrixOps; import org.ejml.data.BlockD3Matrix64F; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * * Some notes: * * Other libraries implement there multiplication the same as my aux implementation, but theirs run faster. * That is because they use 2D arrays, this allows them to only increment one variable in their inner * most loop. While in mine I have to increment two. Thus there is an additional N^3 addition operations. * * @author Peter Abeles */ public class BenchmarkMatrixMatrixMult { static Random rand = new Random(234234); static int TRIALS_MULT = 10000000; public static long mult( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.mult(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multSmall( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.mult_small(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multAux( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.mult_aux(matA,matB,matResult,null); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multReorder( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.mult_reorder(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multBlockNative( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { BlockMatrix64F blockA = BlockMatrixOps.convert(matA); BlockMatrix64F blockB = BlockMatrixOps.convert(matB); BlockMatrix64F blockC = new BlockMatrix64F(matResult.numRows,matResult.numCols); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { BlockMatrixOps.mult(blockA,blockB,blockC); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multBlockD3Native( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { BlockD3Matrix64F blockA = BlockD3MatrixOps.convert(matA); BlockD3Matrix64F blockB = BlockD3MatrixOps.convert(matB); BlockD3Matrix64F blockC = new BlockD3Matrix64F(matResult.numRows,matResult.numCols); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { BlockD3MatrixOps.mult(blockA,blockB,blockC); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numK, int numTrials ) { System.out.println("M = "+numRows+" N = "+numCols+" K = "+numK); DenseMatrix64F matA = RandomMatrices.createRandom(numRows,numCols,rand); DenseMatrix64F matB = RandomMatrices.createRandom(numCols,numK,rand); DenseMatrix64F matResult = RandomMatrices.createRandom(numRows,numK,rand); System.out.printf("Mult: %7d Small %7d Aux %7d Reord %7d Block %7d BlockD3 %7d\n", 0,//mult(matA,matB,matResult,numTrials), multSmall(matA,matB,matResult,numTrials), 0,//multAux(matA,matB,matResult,numTrials), multReorder(matA,matB,matResult,numTrials), 0,//multBlockNative(matA,matB,matResult,numTrials), 0);//multBlockD3Native(matA,matB,matResult,numTrials)); System.gc(); } public static void main( String args[] ) { int size[] = new int[]{2,4,10,15,20,50,100,200,500,1000,2000,4000,10000}; int count[] = new int[]{40000000,10000000,1000000,300000,100000,10000,1000,100,8,2,1,1,1}; int sizeTall[] = new int[]{1,2,4,10,20,50,100,200,500,1000,2000,5000,10000}; int countTall[] = new int[]{3000,2400,1500,1000,200,200,100,50,10,5,2,1,1}; int N = size.length; System.out.println("******* Square:\n"); for( int i = 5; i < N; i++ ) { System.out.println(); performTests(size[i],size[i],size[i],count[i]); } N = sizeTall.length; System.out.println("\n******* Wide A:"); for( int i = 0; i < N; i++ ) { System.out.println(); performTests(sizeTall[i],1500,100,countTall[i]); } System.out.println("\n******* Tall A:"); for( int i = 7; i < N; i++ ) { System.out.println(); performTests(1500,sizeTall[i],100,countTall[i]); } System.out.println("\n******* Wide B:"); for( int i = 7; i < N; i++ ) { System.out.println(); performTests(100,sizeTall[i],1500,countTall[i]); } System.out.println("\n******* Tall B:"); for( int i = 7; i < N; i++ ) { System.out.println(); performTests(100,1500,sizeTall[i],countTall[i]); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/BenchmarkMatrixMatrixMultAdd.java000066400000000000000000000121301256171534400336460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * * Some notes: * * Other libraries implement there multiplication the same as my aux implementation, but theirs run faster. * That is because they use 2D arrays, this allows them to only increment one variable in their inner * most loop. While in mine I have to increment two. Thus there is an additional N^3 addition operations. * * @author Peter Abeles */ public class BenchmarkMatrixMatrixMultAdd { static Random rand = new Random(234234); static int TRIALS_MULT = 10000000; public static long mult( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.multAdd(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multSmall( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multAdd_small(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multAux( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multAdd_aux(matA,matB,matResult,null); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multReorder( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multAdd_reorder(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numK, int numTrials ) { DenseMatrix64F matA = RandomMatrices.createRandom(numRows,numCols,rand); DenseMatrix64F matB = RandomMatrices.createRandom(numCols,numK,rand); DenseMatrix64F matResult = RandomMatrices.createRandom(numRows,numK,rand); System.out.printf("Mult: %7d Small %7d Aux %7d Reord %7d\n", mult(matA,matB,matResult,numTrials), multSmall(matA,matB,matResult,numTrials), multAux(matA,matB,matResult,numTrials), multReorder(matA,matB,matResult,numTrials)); System.gc(); } public static void main( String args[] ) { int size[] = new int[]{2,4,10,};//20,50,100,200,500,1000};//,2000,4000}; int count[] = new int[]{40000000,10000000,1000000,100000,10000,1000,100,8,2,1,1}; int sizeTall[] = new int[]{1,2,4,10,};//20,50,100,200,500,1000}; int countTall[] = new int[]{3000,2400,1500,1000,200,200,100,50,10,5}; System.out.println("******* Square:\n"); for( int i = 0; i < size.length; i++ ) { System.out.println("\nWidth = "+size[i]); performTests(size[i],size[i],size[i],count[i]); } System.out.println("\n******* Wide A:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nHeight = "+sizeTall[i]); performTests(sizeTall[i],1500,100,countTall[i]); } System.out.println("\n******* Tall A:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nWidth = "+sizeTall[i]); performTests(1500,sizeTall[i],100,countTall[i]); } System.out.println("\n******* Wide B:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nHeight = "+sizeTall[i]); performTests(100,sizeTall[i],1500,countTall[i]); } System.out.println("\n******* Tall B:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nWidth = "+sizeTall[i]); performTests(100,1500,sizeTall[i],countTall[i]); } } }BenchmarkMatrixMatrixMultQuad.java000066400000000000000000000054221256171534400337770ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * * @author Peter Abeles */ public class BenchmarkMatrixMatrixMultQuad { static Random rand = new Random(234234); static int TRIALS_MULT = 10000000; public static long mult1( DenseMatrix64F A , DenseMatrix64F B , DenseMatrix64F tmp, DenseMatrix64F expected , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.mult_small(A,B,tmp); MatrixMatrixMult.multTransB(tmp, A, expected); } long curr = System.currentTimeMillis(); return curr-prev; } public static long quad1( DenseMatrix64F A , DenseMatrix64F B , DenseMatrix64F expected , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMultQuad.multQuad1(A, B, expected); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numTrials ) { DenseMatrix64F A = RandomMatrices.createRandom(numRows,numCols,rand); DenseMatrix64F B = RandomMatrices.createRandom(numCols,numCols,rand); DenseMatrix64F out = RandomMatrices.createRandom(numRows, numRows, rand); DenseMatrix64F tmp = new DenseMatrix64F(numRows,numCols); System.out.printf(numRows+" "+numCols+" Mult1: %7d Quad1 %7d\n", mult1(A,B,tmp,out,numTrials), quad1(A,B,out,numTrials)); } public static void main( String args[] ) { int size[] = new int[]{2,4,10,15,20,50,100,200,500,1000,2000,4000,10000}; int count[] = new int[]{12000000,2000000,200000,60000,30000,1000,300,25,1,1,1,1,1}; int N = size.length; for( int i = 0; i < N; i++ ) { System.out.println(); performTests(size[i],size[i]*2,count[i]); } } }BenchmarkMatrixMatrixMultTransA.java000066400000000000000000000112051256171534400342710ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * * Some notes: * * Other libraries implement there multiplication the same as my aux implementation, but theirs run faster. * That is because they use 2D arrays, this allows them to only increment one variable in their inner * most loop. While in mine I have to increment two. Thus there is an additional N^3 addition operations. * * @author Peter Abeles */ public class BenchmarkMatrixMatrixMultTransA { static Random rand = new Random(234234); static int TRIALS_MULT = 10000000; public static long mult( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.multTransA(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multSmall( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multTransA_small(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multReorder( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multTransA_reorder(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numK, int numTrials ) { DenseMatrix64F matA = RandomMatrices.createRandom(numRows,numCols,rand); DenseMatrix64F matB = RandomMatrices.createRandom(numCols,numK,rand); DenseMatrix64F matResult = RandomMatrices.createRandom(numRows,numK,rand); System.out.printf("Mult: %7d Small %7d Reord %7d\n", mult(matA,matB,matResult,numTrials), multSmall(matA,matB,matResult,numTrials), multReorder(matA,matB,matResult,numTrials)); System.gc(); } public static void main( String args[] ) { int size[] = new int[]{2,4,10,20,50,100,200,500,1000};//,2000,4000}; int count[] = new int[]{40000000,10000000,1000000,100000,10000,1000,100,8,2,1,1}; int sizeTall[] = new int[]{1,2,4,10,20,50,100,200,500,1000}; int countTall[] = new int[]{3000,2400,1500,1000,200,200,100,50,10,5}; System.out.println("******* Square:\n"); for( int i = 0; i < size.length; i++ ) { System.out.println("\nWidth = "+size[i]); performTests(size[i],size[i],size[i],count[i]); } System.out.println("\n******* Wide A:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nHeight = "+sizeTall[i]); performTests(sizeTall[i],1500,100,countTall[i]); } System.out.println("\n******* Tall A:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nWidth = "+sizeTall[i]); performTests(1500,sizeTall[i],100,countTall[i]); } System.out.println("\n******* Wide B:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nHeight = "+sizeTall[i]); performTests(100,sizeTall[i],1500,countTall[i]); } System.out.println("\n******* Tall B:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nWidth = "+sizeTall[i]); performTests(100,1500,sizeTall[i],countTall[i]); } } }BenchmarkMatrixMatrixMultTransAB.java000066400000000000000000000111721256171534400343760ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * * Some notes: * * Other libraries implement there multiplication the same as my aux implementation, but theirs run faster. * That is because they use 2D arrays, this allows them to only increment one variable in their inner * most loop. While in mine I have to increment two. Thus there is an additional N^3 addition operations. * * @author Peter Abeles */ public class BenchmarkMatrixMatrixMultTransAB { static Random rand = new Random(234234); static int TRIALS_MULT = 10000000; public static long mult( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.multTransAB(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multSmall( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multTransAB(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multAux( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multTransAB_aux(matA,matB,matResult,null); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numK, int numTrials ) { DenseMatrix64F matA = RandomMatrices.createRandom(numRows,numCols,rand); DenseMatrix64F matB = RandomMatrices.createRandom(numCols,numK,rand); DenseMatrix64F matResult = RandomMatrices.createRandom(numRows,numK,rand); System.out.printf("Mult: %7d Small %7d Aux %7d\n", mult(matA,matB,matResult,numTrials), multSmall(matA,matB,matResult,numTrials), multAux(matA,matB,matResult,numTrials)); System.gc(); } public static void main( String args[] ) { int size[] = new int[]{2,4,10,20,50,100,200,500,1000};//,2000,4000}; int count[] = new int[]{40000000,10000000,1000000,100000,10000,1000,100,8,2,1,1}; int sizeTall[] = new int[]{1,2,4,10,20,50,100,200,500,1000}; int countTall[] = new int[]{3000,2400,1500,1000,200,200,100,50,10,5}; System.out.println("******* Square:\n"); for( int i = 0; i < size.length; i++ ) { System.out.println("\nWidth = "+size[i]); performTests(size[i],size[i],size[i],count[i]); } System.out.println("\n******* Wide A:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nHeight = "+sizeTall[i]); performTests(sizeTall[i],1500,100,countTall[i]); } System.out.println("\n******* Tall A:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nWidth = "+sizeTall[i]); performTests(1500,sizeTall[i],100,countTall[i]); } System.out.println("\n******* Wide B:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nHeight = "+sizeTall[i]); performTests(100,sizeTall[i],1500,countTall[i]); } System.out.println("\n******* Tall B:"); for( int i = 0; i < sizeTall.length; i++ ) { System.out.println("\nWidth = "+sizeTall[i]); performTests(100,1500,sizeTall[i],countTall[i]); } } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/BenchmarkMatrixMultAccessors.java000066400000000000000000000112601256171534400337210ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Compares different implementations of a reordered matrix multiplication that use different accessor functions. * but identical algorithms. * * @author Peter Abeles */ public class BenchmarkMatrixMultAccessors { /** * All reads/writes have been inline by hand */ public static long inlined( DenseMatrix64F a , DenseMatrix64F b , DenseMatrix64F c ) { long timeBefore = System.currentTimeMillis(); double dataA[] = a.data; double dataB[] = b.data; double dataC[] = c.data; double valA; int indexCbase= 0; int endOfKLoop = b.numRows*b.numCols; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*a.numCols; // need to assign dataC to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + b.numCols; valA = dataA[indexA++]; while( indexB < end ) { dataC[indexC++] = valA*dataB[indexB++]; } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + b.numCols; valA = dataA[indexA++]; while( indexB < end ) { // j loop dataC[indexC++] += valA*dataB[indexB++]; } } indexCbase += c.numCols; } return System.currentTimeMillis() - timeBefore; } /** * Wrapper functions with no bounds checking are used to access matrix internals */ public static long wrapped( DenseMatrix64F a , DenseMatrix64F b , DenseMatrix64F c ) { long timeBefore = System.currentTimeMillis(); double valA; int indexCbase= 0; int endOfKLoop = b.numRows*b.numCols; for( int i = 0; i < a.numRows; i++ ) { int indexA = i*a.numCols; // need to assign dataC to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + b.numCols; valA = a.get(indexA++); while( indexB < end ) { c.set( indexC++ , valA*b.get(indexB++)); } // now add to it while( indexB != endOfKLoop ) { // k loop indexC = indexCbase; end = indexB + b.numCols; valA = a.get(indexA++); while( indexB < end ) { // j loop c.plus( indexC++ , valA*b.get(indexB++)); } } indexCbase += c.numCols; } return System.currentTimeMillis() - timeBefore; } /** * Only sets and gets that are by row and column are used. */ public static long access2d( DenseMatrix64F a , DenseMatrix64F b , DenseMatrix64F c ) { long timeBefore = System.currentTimeMillis(); for( int i = 0; i < a.numRows; i++ ) { for( int j = 0; j < b.numCols; j++ ) { c.set(i,j,a.get(i,0)*b.get(0,j)); } for( int k = 1; k < b.numRows; k++ ) { for( int j = 0; j < b.numCols; j++ ) { // c.set(i,j, c.get(i,j) + a.get(i,k)*b.get(k,j)); c.data[i*b.numCols+j] +=a.get(i,k)*b.get(k,j); } } } return System.currentTimeMillis() - timeBefore; } public static void main( String args[] ) { Random rand = new Random(9234243); int N = 1000; DenseMatrix64F A = RandomMatrices.createRandom(N,N,rand); DenseMatrix64F B = RandomMatrices.createRandom(N,N,rand); DenseMatrix64F C = new DenseMatrix64F(N,N); long timeInlined = inlined(A,B,C); long timeWrapped = wrapped(A,B,C); long time2D = access2d(A,B,C); System.out.println("inlined "+timeInlined+" wrapped "+timeWrapped+" access2d "+time2D); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/BenchmarkMatrixMultProduct.java000066400000000000000000000062361256171534400334230ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkMatrixMultProduct { static Random rand = new Random(234234); static int TRIALS_MULT = 10000000; public static long multTransA( DenseMatrix64F matA , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.multTransA(matA, matA, matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long innerProd_small( DenseMatrix64F matA , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMultProduct.inner_small(matA, matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long innerProd_reorder( DenseMatrix64F matA , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMultProduct.inner_reorder(matA, matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numTrials ) { System.out.println("M = "+numRows+" N = "+numCols+" trials "+numTrials); DenseMatrix64F matA = RandomMatrices.createRandom(numRows, numCols, rand); DenseMatrix64F matResult = RandomMatrices.createRandom(numCols,numCols,rand); System.out.printf("Mult: %7d Small %7d Reord %7d\n", 0,//multTransA(matA,matResult,numTrials), innerProd_small(matA,matResult,numTrials), innerProd_reorder(matA,matResult,numTrials)); System.gc(); } public static void main( String args[] ) { int size[] = new int[]{2,4,10,15,20,50,100,200,500,1000,2000,4000,10000}; int count[] = new int[]{20000000,5000000,500000,150000,100000,5000,500,50,4,1,1,1,1}; int N = size.length; for( int i = 0; i < N; i++ ) { System.out.println(); performTests(2*size[i],size[i],count[i]); } } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/dense/mult/BenchmarkMatrixVectorOps.java000066400000000000000000000121201256171534400330520ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkMatrixVectorOps { static Random rand = new Random(234234); static int TRIALS_MULT = 40000000;//40000000; public static long mm_mult_small( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.mult_small(matA,matB,matResult); // MatrixMatrixMult.mult_aux(matA,matB,matResult,null); } long curr = System.currentTimeMillis(); return curr-prev; } public static long mm_multTranA_small( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multTransA_small(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long mm_multTranA_large( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.multTransA_reorder(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long mv_mult( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixVectorMult.mult(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long mv_multTranA_small( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixVectorMult.multTransA_small(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static long mv_multTranA_large( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matResult , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { MatrixVectorMult.multTransA_reorder(matA,matB,matResult); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performTests( int numRows , int numCols , int numTrials ) { DenseMatrix64F matA = RandomMatrices.createRandom(numRows,numCols,rand); DenseMatrix64F matA_tran = RandomMatrices.createRandom(numCols,numRows,rand); DenseMatrix64F matB = RandomMatrices.createRandom(numCols,1,rand); DenseMatrix64F matResult = RandomMatrices.createRandom(numRows,1,rand); System.out.printf("Mult Vec: %10d\n", mv_mult(matA,matB,matResult,numTrials)); System.out.printf("Mult Tran A Small Vec: %10d\n", mv_multTranA_small(matA_tran,matB,matResult,numTrials)); System.out.printf("Mult Tran A Large Vec: %10d\n", mv_multTranA_large(matA_tran,matB,matResult,numTrials)); System.out.printf("Mult small: %10d\n", mm_mult_small(matA,matB,matResult,numTrials)); System.out.printf("Mult Tran A small: %10d\n", mm_multTranA_small(matA_tran,matB,matResult,numTrials)); System.out.printf("Mult Tran A large: %10d\n", mm_multTranA_large(matA_tran,matB,matResult,numTrials)); System.gc(); } public static void main( String args[] ) { System.out.println("Small Matrix Results:") ; performTests(4,4,TRIALS_MULT); System.out.println(); System.out.println("Large Matrix Results:") ; performTests(1000,1000,2000); System.out.println(); System.out.println("Large Not Square Matrix Results:") ; performTests(20,1000,10000); } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/fixed/000077500000000000000000000000001256171534400243075ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/fixed/BenchmarkInverseFixed.java000066400000000000000000000077451256171534400313750ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.DenseMatrix64F; import org.ejml.data.FixedMatrix3x3_64F; import org.ejml.data.FixedMatrix4x4_64F; import org.ejml.data.FixedMatrix6x6_64F; import org.ejml.ops.CommonOps; import org.ejml.ops.ConvertMatrixType; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Feeds the algorithms matrices that are closer and closer to being singular * and sees at which point they break. * * @author Peter Abeles */ public class BenchmarkInverseFixed { private static Random rand = new Random(234); private static DenseMatrix64F dm3x3_a = new DenseMatrix64F(3,3); private static DenseMatrix64F dm3x3_b = new DenseMatrix64F(3,3); private static DenseMatrix64F dm4x4_a = new DenseMatrix64F(4,4); private static DenseMatrix64F dm4x4_b = new DenseMatrix64F(4,4); private static DenseMatrix64F dm6x6_a = new DenseMatrix64F(6,6); private static DenseMatrix64F dm6x6_b = new DenseMatrix64F(6,6); private static FixedMatrix3x3_64F fixed3x3_a = new FixedMatrix3x3_64F(); private static FixedMatrix3x3_64F fixed3x3_b = new FixedMatrix3x3_64F(); private static FixedMatrix4x4_64F fixed4x4_a = new FixedMatrix4x4_64F(); private static FixedMatrix4x4_64F fixed4x4_b = new FixedMatrix4x4_64F(); private static FixedMatrix6x6_64F fixed6x6_a = new FixedMatrix6x6_64F(); private static FixedMatrix6x6_64F fixed6x6_b = new FixedMatrix6x6_64F(); public static long benchmark(DenseMatrix64F a, DenseMatrix64F b , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { CommonOps.invert(a,b); } return System.currentTimeMillis() - prev; } public static long benchmark(FixedMatrix3x3_64F a, FixedMatrix3x3_64F b , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { FixedOps3.invert(a,b); } return System.currentTimeMillis() - prev; } public static long benchmark(FixedMatrix4x4_64F a, FixedMatrix4x4_64F b , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { FixedOps4.invert(a,b); } return System.currentTimeMillis() - prev; } public static void main( String arg[] ) { RandomMatrices.setRandom(dm3x3_a,rand); RandomMatrices.setRandom(dm3x3_b,rand); RandomMatrices.setRandom(dm4x4_a,rand); RandomMatrices.setRandom(dm4x4_b,rand); RandomMatrices.setRandom(dm6x6_a,rand); RandomMatrices.setRandom(dm6x6_b,rand); ConvertMatrixType.convert(dm3x3_a,fixed3x3_a); ConvertMatrixType.convert(dm3x3_b,fixed3x3_b); ConvertMatrixType.convert(dm4x4_a,fixed4x4_a); ConvertMatrixType.convert(dm4x4_b,fixed4x4_b); ConvertMatrixType.convert(dm6x6_a,fixed6x6_a); ConvertMatrixType.convert(dm6x6_b,fixed6x6_b); int numTrials = 100000; System.out.println("Dense 3x3 = "+benchmark(dm3x3_a,dm3x3_b,numTrials)); System.out.println("Fixed 3x3 = "+benchmark(fixed3x3_a,fixed3x3_b,numTrials)); System.out.println("Dense 4x4 = "+benchmark(dm4x4_a,dm4x4_b,numTrials)); System.out.println("Fixed 4x4 = "+benchmark(fixed4x4_a,fixed4x4_b,numTrials)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/alg/fixed/BenchmarkMultiplicationFixed.java000066400000000000000000000125331256171534400327460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.fixed; import org.ejml.data.DenseMatrix64F; import org.ejml.data.FixedMatrix3x3_64F; import org.ejml.data.FixedMatrix4x4_64F; import org.ejml.data.FixedMatrix6x6_64F; import org.ejml.ops.CommonOps; import org.ejml.ops.ConvertMatrixType; import org.ejml.ops.RandomMatrices; import java.util.Random; /** * Feeds the algorithms matrices that are closer and closer to being singular * and sees at which point they break. * * @author Peter Abeles */ public class BenchmarkMultiplicationFixed { private static Random rand = new Random(234); private static DenseMatrix64F dm3x3_a = new DenseMatrix64F(3,3); private static DenseMatrix64F dm3x3_b = new DenseMatrix64F(3,3); private static DenseMatrix64F dm3x3_c = new DenseMatrix64F(3,3); private static DenseMatrix64F dm4x4_a = new DenseMatrix64F(4,4); private static DenseMatrix64F dm4x4_b = new DenseMatrix64F(4,4); private static DenseMatrix64F dm4x4_c = new DenseMatrix64F(4,4); private static DenseMatrix64F dm6x6_a = new DenseMatrix64F(6,6); private static DenseMatrix64F dm6x6_b = new DenseMatrix64F(6,6); private static DenseMatrix64F dm6x6_c = new DenseMatrix64F(6,6); private static FixedMatrix3x3_64F fixed3x3_a = new FixedMatrix3x3_64F(); private static FixedMatrix3x3_64F fixed3x3_b = new FixedMatrix3x3_64F(); private static FixedMatrix3x3_64F fixed3x3_c = new FixedMatrix3x3_64F(); private static FixedMatrix4x4_64F fixed4x4_a = new FixedMatrix4x4_64F(); private static FixedMatrix4x4_64F fixed4x4_b = new FixedMatrix4x4_64F(); private static FixedMatrix4x4_64F fixed4x4_c = new FixedMatrix4x4_64F(); private static FixedMatrix6x6_64F fixed6x6_a = new FixedMatrix6x6_64F(); private static FixedMatrix6x6_64F fixed6x6_b = new FixedMatrix6x6_64F(); private static FixedMatrix6x6_64F fixed6x6_c = new FixedMatrix6x6_64F(); public static long benchmark(DenseMatrix64F a, DenseMatrix64F b , DenseMatrix64F c , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { CommonOps.mult(a,b,c); } return System.currentTimeMillis() - prev; } public static long benchmark(FixedMatrix3x3_64F a, FixedMatrix3x3_64F b , FixedMatrix3x3_64F c , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { FixedOps3.mult(a,b,c); } return System.currentTimeMillis() - prev; } public static long benchmark(FixedMatrix4x4_64F a, FixedMatrix4x4_64F b , FixedMatrix4x4_64F c , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { FixedOps4.mult(a,b,c); } return System.currentTimeMillis() - prev; } public static long benchmark(FixedMatrix6x6_64F a, FixedMatrix6x6_64F b , FixedMatrix6x6_64F c , int numTrials ) { long prev = System.currentTimeMillis(); for( long i = 0; i < numTrials; i++ ) { FixedOps6.mult(a,b,c); } return System.currentTimeMillis() - prev; } public static void main( String arg[] ) { RandomMatrices.setRandom(dm3x3_a,rand); RandomMatrices.setRandom(dm3x3_b,rand); RandomMatrices.setRandom(dm3x3_c,rand); RandomMatrices.setRandom(dm4x4_a,rand); RandomMatrices.setRandom(dm4x4_b,rand); RandomMatrices.setRandom(dm4x4_c,rand); RandomMatrices.setRandom(dm6x6_a,rand); RandomMatrices.setRandom(dm6x6_b,rand); RandomMatrices.setRandom(dm6x6_c,rand); ConvertMatrixType.convert(dm3x3_a,fixed3x3_a); ConvertMatrixType.convert(dm3x3_b,fixed3x3_b); ConvertMatrixType.convert(dm3x3_c,fixed3x3_c); ConvertMatrixType.convert(dm4x4_a,fixed4x4_a); ConvertMatrixType.convert(dm4x4_b,fixed4x4_b); ConvertMatrixType.convert(dm4x4_c,fixed4x4_c); ConvertMatrixType.convert(dm6x6_a,fixed6x6_a); ConvertMatrixType.convert(dm6x6_b,fixed6x6_b); ConvertMatrixType.convert(dm6x6_c,fixed6x6_c); int numTrials = 30000000; System.out.println("Dense 3x3 = "+benchmark(dm3x3_a,dm3x3_b,dm3x3_c,numTrials)); System.out.println("Fixed 3x3 = "+benchmark(fixed3x3_a,fixed3x3_b,fixed3x3_c,numTrials)); System.out.println("Dense 4x4 = "+benchmark(dm4x4_a,dm4x4_b,dm4x4_c,numTrials)); System.out.println("Fixed 4x4 = "+benchmark(fixed4x4_a,fixed4x4_b,fixed4x4_c,numTrials)); numTrials = 10000000; System.out.println("Dense 6x6 = "+benchmark(dm6x6_a,dm6x6_b,dm6x6_c,numTrials)); System.out.println("Fixed 6x6 = "+benchmark(fixed6x6_a,fixed6x6_b,fixed6x6_c,numTrials)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/data/000077500000000000000000000000001256171534400233565ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/data/BenchmarkFunctionReturn.java000066400000000000000000000045001256171534400310200ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; /** * Checks to see if having a return statement that isn't used makes any different or not * * @author Peter Abeles */ public class BenchmarkFunctionReturn { double data[] = new double[ 1000 ]; private void resetData() { for( int i = 0; i < data.length; i++ ) { data[i] = i + 1; } } public double funcA( int i , double b) { return data[i] *= b; } public void funcB( int i , double b) { data[i] *= b; } public long benchmarkA( int numTrials ) { resetData(); long timeBefore = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { for( int j = 0; j < 50; j++ ) { for( int k = j; k < data.length; k++ ) { funcA(k,1.1); } } } long timeAfter = System.currentTimeMillis(); return timeAfter-timeBefore; } public long benchmarkB( int numTrials ) { resetData(); long timeBefore = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { for( int j = 0; j < 50; j++ ) { for( int k = j; k < data.length; k++ ) { funcB(k,1.1); } } } long timeAfter = System.currentTimeMillis(); return timeAfter-timeBefore; } public static void main( String args[] ) { BenchmarkFunctionReturn app = new BenchmarkFunctionReturn(); int N = 100000; System.out.println("With return = "+app.benchmarkA(N)); System.out.println("No return = "+app.benchmarkB(N)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/ops/000077500000000000000000000000001256171534400232465ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/src/org/ejml/ops/BenchmarkEquality.java000066400000000000000000000043061256171534400275240ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.DenseMatrix64F; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkEquality { public static long equals( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { boolean args = false; long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { args = MatrixFeatures.isEquals(matA,matB,1e-8); } long curr = System.currentTimeMillis(); if( !args ) throw new RuntimeException("don't optimize me away!"); return curr-prev; } public static long identical( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { boolean args = false; long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { args = MatrixFeatures.isIdentical(matA,matB,1e-8); } long curr = System.currentTimeMillis(); if( !args ) throw new RuntimeException("don't optimize me away!"); return curr-prev; } public static void main( String args[] ) { Random rand = new Random(234234); DenseMatrix64F A = RandomMatrices.createRandom(1000,2000,rand); DenseMatrix64F B = A.copy(); int N = 1000; System.out.println("Equals: "+equals(A,B,N)); System.out.println("Identical: "+identical(A,B,N)); } } ejml-0.28/main/experimental/benchmarks/src/org/ejml/ops/BenchmarkMultAndAddOps.java000066400000000000000000000263461256171534400303760ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.alg.dense.mult.MatrixMatrixMult; import org.ejml.data.DenseMatrix64F; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkMultAndAddOps { static Random rand = new Random(234234); static int TRIALS_MULT = 4000000; static int TRIALS_ADD = 100000000; public static long mult( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matB.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.mult(matA,matB,results); // MatrixMatrixMult.mult_small(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long mult_alpha( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matB.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.mult(2.0,matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long mult_alt( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matB.numCols); for( int i = 0; i < numTrials; i++ ) { MatrixMatrixMult.mult_reorder(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multTranA( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numCols,matB.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.multTransA(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multTranA_alpha( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numCols,matB.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.multTransA(2.0,matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multTranB( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matB.numRows); for( int i = 0; i < numTrials; i++ ) { CommonOps.multTransB(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multTranAB( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numCols,matB.numRows); for( int i = 0; i < numTrials; i++ ) { CommonOps.multTransAB(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multAdd( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matB.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.multAdd(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multAddTranA( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numCols,matB.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.multAddTransA(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multAddTranB( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matB.numRows); for( int i = 0; i < numTrials; i++ ) { CommonOps.multAddTransB(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long multAddTranAB( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numCols,matB.numRows); for( int i = 0; i < numTrials; i++ ) { CommonOps.multAddTransAB(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long addEquals( DenseMatrix64F matA , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matA.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.addEquals(results,matA); } long curr = System.currentTimeMillis(); return curr-prev; } public static long add( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matA.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.add(matA,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long add_a_b( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matA.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.add(1.5,matA,3.4,matB,results); } long curr = System.currentTimeMillis(); return curr-prev; } public static long addEqualBeta( DenseMatrix64F matA , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matA.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.addEquals(results,2.5,matA); } long curr = System.currentTimeMillis(); return curr-prev; } public static long minusEquals( DenseMatrix64F matA , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matA.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.subtractEquals(results, matA); } long curr = System.currentTimeMillis(); return curr-prev; } public static long minus( DenseMatrix64F matA , DenseMatrix64F matB , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F results = new DenseMatrix64F(matA.numRows,matA.numCols); for( int i = 0; i < numTrials; i++ ) { CommonOps.subtract(matA, matB, results); } long curr = System.currentTimeMillis(); return curr-prev; } public static void performMultTests( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matC , DenseMatrix64F matD , int numTrials ) { System.out.printf("Mult: = %10d\n", mult(matA,matB,numTrials)); System.out.printf("Mult Alpha: = %10d\n", mult_alpha(matA,matB,numTrials)); System.out.printf("Tran A Mult: = %10d\n", multTranA(matD,matB,numTrials)); System.out.printf("Tran A Mult Alpha: = %10d\n", multTranA_alpha(matD,matB,numTrials)); System.out.printf("Tran B Mult: = %10d\n", multTranB(matA,matC,numTrials)); System.out.printf("Tran AB Mult: = %10d\n", multTranAB(matD,matC,numTrials)); System.out.printf("Mult Add: = %10d\n", multAdd(matA,matB,numTrials)); System.out.printf("Tran A Mult Add: = %10d\n", multAddTranA(matD,matB,numTrials)); System.out.printf("Tran B Mult Add: = %10d\n", multAddTranB(matA,matC,numTrials)); System.out.printf("Tran AB Mult Add: = %10d\n", multAddTranAB(matD,matC,numTrials)); } public static void performAddTests( DenseMatrix64F matA , DenseMatrix64F matB , DenseMatrix64F matC , DenseMatrix64F matD , int numTrials ) { System.out.printf("Add Equal: = %10d\n", addEquals(matA,numTrials)); System.out.printf("Add Equals b: = %10d\n", addEqualBeta(matA,numTrials)); System.out.printf("Add: = %10d\n", add(matA,matC,numTrials)); System.out.printf("Add a b: = %10d\n", add(matA,matC,numTrials)); System.out.printf("Minus Equal: = %10d\n", minusEquals(matA,numTrials)); System.out.printf("Minus: = %10d\n", minus(matA,matC,numTrials)); } public static void main( String args[] ) { System.out.println("Small Matrix Results:") ; int N = 2; DenseMatrix64F matA = RandomMatrices.createRandom(N,N,rand); DenseMatrix64F matB = RandomMatrices.createRandom(N,N,rand); DenseMatrix64F matC,matD; performMultTests(matA,matB,matB,matA,TRIALS_MULT*10); performAddTests(matA,matB,matB,matA,TRIALS_ADD); System.out.println(); System.out.println("Large Matrix Results:") ; matA = RandomMatrices.createRandom(1000,1000,rand); matB = RandomMatrices.createRandom(1000,1000,rand); performMultTests(matA,matB,matB,matA,1); performAddTests(matA,matB,matB,matA,500); System.out.println(); System.out.println("Large Not Square Matrix Results:") ; matA = RandomMatrices.createRandom(600,1000,rand); matB = RandomMatrices.createRandom(1000,600,rand); matC = RandomMatrices.createRandom(600,1000,rand); matD = RandomMatrices.createRandom(1000,600,rand); performMultTests(matA,matB,matC,matD,1); performAddTests(matA,matB,matC,matD,1000); } }ejml-0.28/main/experimental/benchmarks/src/org/ejml/ops/BenchmarkVariousOps.java000066400000000000000000000145341256171534400300450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.ops; import org.ejml.data.DenseMatrix64F; import java.util.Arrays; import java.util.Random; /** * @author Peter Abeles */ public class BenchmarkVariousOps { static Random rand = new Random(0xffff); static int TRIALS_TRANSPOSE = 20000000; static int TRIALS_SCALE = 30000000; static int TRIALS_NORM = 10000000; static int TRIALS_DETERMINANT = 20000000; public static long transposeEml( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); DenseMatrix64F tran = new DenseMatrix64F(mat.numCols,mat.numRows); for( int i = 0; i < numTrials; i++ ) { CommonOps.transpose(mat,tran); } long curr = System.currentTimeMillis(); return curr-prev; } // public static long transposeMtj( DenseMatrix64F orig , int numTrials) { // DenseMatrix mat = UtilMatrixToolkitsJava.convertToMtj(orig); // // long prev = System.currentTimeMillis(); // // DenseMatrix tran = new DenseMatrix(mat.numColumns(),mat.numRows()); // // for( int i = 0; i < numTrials; i++ ) { // mat.transpose(tran); // } // // long curr = System.currentTimeMillis(); // return curr-prev; // } public static long scale( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.scale(10,mat); CommonOps.scale(0.1,mat); } long curr = System.currentTimeMillis(); return curr-prev; } public static long scale2( DenseMatrix64F mat , int numTrials) { DenseMatrix64F result = mat.copy(); long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.scale(10,mat,result); CommonOps.scale(0.1,mat,result); } long curr = System.currentTimeMillis(); return curr-prev; } // public static long scaleMtj( DenseMatrix64F orig , int numTrials) { // DenseMatrix mat = UtilMatrixToolkitsJava.convertToMtj(orig); // // long prev = System.currentTimeMillis(); // // for( int i = 0; i < numTrials; i++ ) { // mat.scale(10); // mat.scale(0.1); // } // // long curr = System.currentTimeMillis(); // return curr-prev; // } public static long normEml( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { NormOps.normF(mat); } long curr = System.currentTimeMillis(); return curr-prev; } public static long determinant( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { CommonOps.det(mat); } long curr = System.currentTimeMillis(); return curr-prev; } public static long fillManual( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { final int size = mat.getNumElements(); for( int j = 0; j < size; j++ ) { mat.set( j , 2 ); } } long curr = System.currentTimeMillis(); return curr-prev; } public static long fillArrays( DenseMatrix64F mat , int numTrials) { long prev = System.currentTimeMillis(); for( int i = 0; i < numTrials; i++ ) { Arrays.fill(mat.data,0,mat.getNumElements(),2); } long curr = System.currentTimeMillis(); return curr-prev; } // public static long normMtj( DenseMatrix64F orig , int numTrials) { // DenseMatrix mat = UtilMatrixToolkitsJava.convertToMtj(orig); // // long prev = System.currentTimeMillis(); // // for( int i = 0; i < numTrials; i++ ) { // mat.norm(Matrix.Norm.Frobenius); // } // // long curr = System.currentTimeMillis(); // return curr-prev; // } public static void main( String args[] ) { System.out.println("Small Matrix Results:") ; DenseMatrix64F mat = RandomMatrices.createRandom(4,4,rand); // System.out.printf("Transpose: eml = %10d\n", // transposeEml(mat,TRIALS_TRANSPOSE)); // System.out.printf("Scale: eml = %10d\n", // scale(mat,TRIALS_SCALE)); // System.out.printf("Scale2: eml = %10d\n", // scale2(mat,TRIALS_SCALE)); // System.out.printf("Norm: eml = %10d\n", // normEml(mat,TRIALS_NORM)); // System.out.printf("Determinant: eml = %10d\n", // determinant(mat,TRIALS_DETERMINANT)); System.out.printf("FillManual: eml = %10d\n", fillManual(mat,TRIALS_SCALE)); System.out.printf("FillArrays: eml = %10d\n", fillArrays(mat,TRIALS_SCALE)); System.out.println(); System.out.println("Large Matrix Results:") ; mat = RandomMatrices.createRandom(2000,2000,rand); // System.out.printf("Transpose: eml = %10d\n", // transposeEml(mat,100)); // System.out.printf("Scale: eml = %10d\n", // scaleEml(mat,100)); // System.out.printf("Norm: eml = %10d\n", // normEml(mat,100)); // System.out.printf("Determinant: eml = %10d\n", // determinant(mat,1)); System.out.printf("FillManual: eml = %10d\n", fillManual(mat,1000)); System.out.printf("FillArrays: eml = %10d\n", fillArrays(mat,1000)); } } ejml-0.28/main/experimental/benchmarks/test/000077500000000000000000000000001256171534400211175ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/test/org/000077500000000000000000000000001256171534400217065ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/test/org/ejml/000077500000000000000000000000001256171534400226355ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/test/org/ejml/alg/000077500000000000000000000000001256171534400234005ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/test/org/ejml/alg/dense/000077500000000000000000000000001256171534400244765ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/test/org/ejml/alg/dense/decompose/000077500000000000000000000000001256171534400264545ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/test/org/ejml/alg/dense/decompose/eig/000077500000000000000000000000001256171534400272205ustar00rootroot00000000000000RealEigenvalueHessenbergStressTest.java000066400000000000000000000250511256171534400367510ustar00rootroot00000000000000ejml-0.28/main/experimental/benchmarks/test/org/ejml/alg/dense/decompose/eig/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.eig; import org.ejml.alg.dense.decomposition.eig.EigenvalueExtractor; import org.ejml.alg.dense.decomposition.eig.watched.WatchedDoubleStepQREigenvalue; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.*; import java.util.Random; import static org.junit.Assert.assertEquals; /** * A stress test that sees how well eigenvalues of Hessenberg matrices can be computed. * * @author Peter Abeles */ public class RealEigenvalueHessenbergStressTest { double tol = 1e-10; Random rand = new Random(0x3434); EigenvalueExtractor extractor; // public RealEigenvalueStressTest(EigenvalueExtractor extractor) { // this.extractor = extractor; // } int numCantFindEigenvector; public RealEigenvalueHessenbergStressTest() { extractor = new WatchedDoubleStepQREigenvalue(); } public void evaluateRandom() { int sizes[] = new int[]{3,5,10,20,50,100,200}; int totalFailed = 0; numCantFindEigenvector = 0; for( int sizeIndex = 0; sizeIndex < sizes.length; sizeIndex++ ) { int n = sizes[sizeIndex]; System.out.println("Matrix size = "+n); long startTime = System.currentTimeMillis(); for( int i = 0; i < 100; i++ ) { DenseMatrix64F A = RandomMatrices.createUpperTriangle(n,1,-1,1,rand); extractor.process(A); if( isAllComplex() ) continue; totalFailed += checkEigenvalues(A); if( System.currentTimeMillis() - startTime > 10000 ) { System.out.println("i = "+i); startTime = System.currentTimeMillis(); } } } System.out.println("Num failed = "+totalFailed); System.out.println("Num couldn't find eigenvector = "+numCantFindEigenvector); } private int checkEigenvalues(DenseMatrix64F a ) { Complex64F[]ev = extractor.getEigenvalues(); // a.print("%14.5e"); int numFailed = 0; double totalError = 0; for( int j = 0; j < extractor.getNumberOfEigenvalues(); j++ ) { if( ev[j].imaginary != 0 ) continue; DenseMatrix64F v = EigenOps.computeEigenVector(a,ev[j].real).vector; Complex64F c = ev[j]; if( v == null || MatrixFeatures.hasUncountable(v)) { a.print("%f"); System.out.println("Can't find eigen vector?!?!"); numCantFindEigenvector++; EigenOps.computeEigenVector(a,ev[j].real); continue; } double error = computeError(a,v,c.getReal()); if( error > tol ) { // System.out.println("Failed on this matrix:"); // a.print("%f"); numFailed++; EigenOps.computeEigenVector(a,ev[j].real); } totalError += error; } totalError /= extractor.getNumberOfEigenvalues(); System.out.println("Mean error = "+(totalError)); return numFailed; } private double computeError( DenseMatrix64F A, DenseMatrix64F v , double eigenvalue ) { if( v == null ) { throw new RuntimeException("WTF crappy tool"); } // A.print(); // System.out.println("Eigen value = "+eigenvalue); // NormOps.normalizeF(v); // v.print(); DenseMatrix64F l = new DenseMatrix64F(A.numRows,1); CommonOps.mult(A,v,l); CommonOps.scale(eigenvalue,v); double top = SpecializedOps.diffNormF(l,v); double bottom = NormOps.normF(v); if( Double.isNaN(top) || Double.isInfinite(top) || Double.isNaN(bottom) || Double.isInfinite(bottom) ) System.out.println("bad stuff"); double result = top/bottom; // if( result >= tol || Double.isNaN(result) || Double.isInfinite(result)) // System.out.println("Crap"); return result; } public void evaluateScalingUp() { double []scales = new double[]{1.0,10.0,1e100,1e200,1e306}; evaluateScaling(scales); } public void evaluateScalingDown() { double []scales = new double[]{1.0,1e-1,1e-100,1e-200,1e-290}; evaluateScaling(scales); } private void evaluateScaling(double[] scales) { int totalFailures[] = new int[scales.length]; for( int n = 3; n < 100; n++ ) { System.out.println("Matrix size = "+n); DenseMatrix64F A = RandomMatrices.createUpperTriangle(n,1,-1,1,rand); if( !extractor.process(A) ){ throw new RuntimeException("Failed!"); } while( isAllComplex()) { System.out.println("Trying to find a matrix that isn't all complex number"); A = RandomMatrices.createUpperTriangle(n,1,-1,1,rand); extractor.process(A); } for( int indexScale = 0; indexScale < scales.length; indexScale++ ) { double s = scales[indexScale]; System.out.println("Scale = "+s); DenseMatrix64F B = A.copy(); CommonOps.scale(s,B); if( !extractor.process(B) ) { System.out.println(" Failed to converge."); continue; } // B.print("%15.6e"); totalFailures[indexScale] += checkEigenvalues(B); } } System.out.println("------------ results --------------"); for( int i = 0; i < totalFailures.length; i++ ) { System.out.printf(" %7.2e fail = %d\n",scales[i],totalFailures[i]); } } /** * See if a totally zero matrix messes it up */ public void testMatrix0() { DenseMatrix64F A = new DenseMatrix64F(5,5); if( !extractor.process(A) ){ throw new RuntimeException("Failed!"); } assertEquals(5,extractor.getNumberOfEigenvalues()); for( int i = 0 ; i < 5; i++ ) { Complex64F c = extractor.getEigenvalues()[i]; assertEquals(0,c.imaginary,1e-12); assertEquals(0,c.getReal(),1e-12); } } public void testMatrixNegHessenberg() { DenseMatrix64F A = new DenseMatrix64F(5,5, true, 0, 1, 2, 3, 5, 0, 0, 4, 9, 3, 0, 0, 0, -1, 3, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0); if( !extractor.process(A) ){ throw new RuntimeException("Failed!"); } assertEquals(5,extractor.getNumberOfEigenvalues()); for( int i = 0 ; i < 5; i++ ) { Complex64F c = extractor.getEigenvalues()[i]; assertEquals(0,c.imaginary,1e-12); assertEquals(0,c.getReal(),1e-12); } } /** * Special case that requires exceptional shifts to work */ public void testMatrixExceptional() { DenseMatrix64F A = new DenseMatrix64F(5,5, true, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0); if( !extractor.process(A) ){ throw new RuntimeException("Failed!"); } assertEquals(5,extractor.getNumberOfEigenvalues()); // TODO compare to expected eigenvalues } public void testMatrixZeroButUpperDiag() { DenseMatrix64F A = new DenseMatrix64F(5,5, true, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0); if( !extractor.process(A) ){ throw new RuntimeException("Failed!"); } assertEquals(5,extractor.getNumberOfEigenvalues()); for( int i = 0 ; i < 5; i++ ) { Complex64F c = extractor.getEigenvalues()[i]; assertEquals(0,c.imaginary,1e-12); assertEquals(0,c.getReal(),1e-12); } } public void testMatrixVerySmallButUpperDiag() { DenseMatrix64F A = new DenseMatrix64F(5,5); for( int i = 0; i < 5; i++ ) { int start = i < 2 ? 0 : i-1; for( int j = start; j < 5; j++ ) { A.set(i,j,1e-32); } } for( int i = 0; i < 4; i++) { A.set(i+1,i,i+1); } if( !extractor.process(A) ){ throw new RuntimeException("Failed!"); } assertEquals(5,extractor.getNumberOfEigenvalues()); for( int i = 0 ; i < 5; i++ ) { Complex64F c = extractor.getEigenvalues()[i]; assertEquals(0,c.imaginary,1e-12); assertEquals(0,c.getReal(),1e-12); } } public void testMatrixAlmostAllOnes() { DenseMatrix64F A = new DenseMatrix64F(5,5); for( int i = 0; i < 5; i++ ) { int start = i < 2 ? 0 : i-1; for( int j = start; j < 5; j++ ) { A.set(i,j,1); } } A.set(2,2,1e-32); A.set(3,2,1e-32); if( !extractor.process(A) ){ throw new RuntimeException("Failed!"); } // A.print("%15.5e"); assertEquals(5,extractor.getNumberOfEigenvalues()); // TODO add expected list of eigenvalues } private boolean hasComplex() { Complex64F[]ev = extractor.getEigenvalues(); for( int j = 0; j < extractor.getNumberOfEigenvalues(); j++ ) { if( ev[j].getImaginary() != 0 ) return true; } return false; } private boolean isAllComplex() { Complex64F[]ev = extractor.getEigenvalues(); for( int j = 0; j < extractor.getNumberOfEigenvalues(); j++ ) { if( ev[j].getImaginary() == 0 ) return false; } return true; } // public static void main( String []args ) { // EigenvalueExtractor extractor = new PrintDoubleStepQREigenvalue(); // // RealEigenvalueStressTest test = new RealEigenvalueStressTest(extractor); // //// test.evaluateRandom(); //// test.evaluateScalingUp(); // test.evaluateScalingDown(); // } } ejml-0.28/main/experimental/build.gradle000066400000000000000000000007061256171534400203050ustar00rootroot00000000000000dependencies { compile project(':main:core') compile project(':main:dense64') compile project(':main:denseC64') compile project(':main:simple') compile project(':main:equation') testCompile project(':main:core').sourceSets.test.output testCompile project(':main:dense64').sourceSets.test.output testCompile project(':main:denseC64').sourceSets.test.output } idea { module { name = "EJML Experimental" } }ejml-0.28/main/experimental/src/000077500000000000000000000000001256171534400166125ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/000077500000000000000000000000001256171534400174015ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/000077500000000000000000000000001256171534400203305ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/000077500000000000000000000000001256171534400210735ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/blockd3/000077500000000000000000000000001256171534400224145ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/blockd3/BlockD3MatrixOps.java000066400000000000000000000210601256171534400263460ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.blockd3; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockD3Matrix64F; import org.ejml.data.DenseMatrix64F; import java.util.Random; /** * @author Peter Abeles */ public class BlockD3MatrixOps { public static BlockD3Matrix64F convert( DenseMatrix64F src , int blockLength ) { BlockD3Matrix64F ret = new BlockD3Matrix64F(src.numRows,src.numCols,blockLength); convert(src,ret); return ret; } public static BlockD3Matrix64F convert( DenseMatrix64F src ) { BlockD3Matrix64F ret = new BlockD3Matrix64F(src.numRows,src.numCols); convert(src,ret); return ret; } public static void convert( DenseMatrix64F src , BlockD3Matrix64F dst ) { if( src.numRows != dst.numRows || src.numCols != dst.numCols ) throw new IllegalArgumentException("Must be the same size."); for( int i = 0; i < dst.numRows; i += dst.blockLength ) { int blockHeight = Math.min( dst.blockLength , dst.numRows - i); for( int j = 0; j < dst.numCols; j += dst.blockLength ) { int blockWidth = Math.min( dst.blockLength , dst.numCols - j); int indexSrcRow = i*dst.numCols + j; double block[] = dst.blocks[ i / dst.blockLength][ j/dst.blockLength]; int indexDstRow = 0; for( int k = 0; k < blockHeight; k++ ) { int indexSrc = indexSrcRow; int end = indexSrc + blockWidth; int indexDst = indexDstRow; for( ;indexSrc != end; ) { block[indexDst++] = src.data[indexSrc++]; } indexSrcRow += dst.numCols; indexDstRow += dst.blockLength; } } } } public static void convert( BlockD3Matrix64F src , DenseMatrix64F dst ) { if( dst.numRows != src.numRows || dst.numCols != src.numCols ) throw new IllegalArgumentException("Must be the same size."); for( int i = 0; i < src.numRows; i += src.blockLength ) { int blockHeight = Math.min( src.blockLength , src.numRows - i); for( int j = 0; j < src.numCols; j += src.blockLength ) { int blockWidth = Math.min( src.blockLength , src.numCols - j); int indexSrcRow = 0; int indexDstRow = i*dst.numCols + j; double block[] = src.blocks[ i / src.blockLength][ j/src.blockLength]; for( int k = 0; k < blockHeight; k++ ) { int indexDst = indexDstRow; int indexSrc = indexSrcRow; int end = indexSrc + blockWidth; for( ;indexSrc != end; ) { dst.data[indexDst++] = block[indexSrc++]; } indexDstRow += dst.numCols; indexSrcRow += src.blockLength; } } } } public static BlockD3Matrix64F random( int numRows , int numCols , double min , double max , Random rand , int blockLength ) { BlockD3Matrix64F ret = new BlockD3Matrix64F(numRows,numCols,blockLength); GenericMatrixOps.setRandom(ret,min,max,rand); return ret; } public static void mult( BlockD3Matrix64F A , BlockD3Matrix64F B , BlockD3Matrix64F C ) { if( A.numCols != B.numRows ) throw new IllegalArgumentException("Rows in A are incompatible with columns in B"); if( A.numRows != C.numRows ) throw new IllegalArgumentException("Rows in A are incompatible with rows in C"); if( B.numCols != C.numCols ) throw new IllegalArgumentException("Columns in B are incompatible with columns in C"); if( A.blockLength != B.blockLength || A.blockLength != C.blockLength ) throw new IllegalArgumentException("Block lengths are not all the same."); final int blockLength = A.blockLength; for( int i = 0; i < A.numRows; i += blockLength ) { int heightA = Math.min( blockLength , A.numRows - i); int blockI = i/blockLength; for( int j = 0; j < B.numCols; j += blockLength ) { int widthB = Math.min( blockLength , B.numCols-j); int blockJ = j/blockLength; double blockC[] = C.blocks[ blockI ][ blockJ ]; for( int k = 0; k < A.numCols; k += blockLength ) { int widthA = Math.min( blockLength , A.numCols - k); int blockK = k/blockLength; double blockA[] = A.blocks[ blockI ][ blockK ]; double blockB[] = B.blocks[ blockK ][ blockJ ]; // by inlining these functions it can be made to be comparable (but slightly // slow than) mult_reorder(). Now its about 1.5x slower if( k == 0 ) multBlockSet(blockA,blockB,blockC,heightA,widthA,widthB,blockLength); else multBlockAdd(blockA,blockB,blockC,heightA,widthA,widthB,blockLength); } } } } /** * Performs a matrix multiplication between inner block matrices. * * (m , o) += (m , n) * (n , o) */ private static void multBlockAdd( double []blockA, double []blockB, double []blockC, final int m, final int n, final int o, final int blockLength ) { // for( int i = 0; i < m; i++ ) { // for( int j = 0; j < o; j++ ) { // double val = 0; // for( int k = 0; k < n; k++ ) { // val += blockA[ i*blockLength + k]*blockB[ k*blockLength + j]; // } // // blockC[ i*blockLength + j] += val; // } // } // int rowA = 0; // for( int i = 0; i < m; i++ , rowA += blockLength) { // for( int j = 0; j < o; j++ ) { // double val = 0; // int indexB = j; // int indexA = rowA; // int end = indexA + n; // for( ; indexA != end; indexA++ , indexB += blockLength ) { // val += blockA[ indexA ]*blockB[ indexB ]; // } // // blockC[ rowA + j] += val; // } // } // for( int k = 0; k < n; k++ ) { // for( int i = 0; i < m; i++ ) { // for( int j = 0; j < o; j++ ) { // blockC[ i*blockLength + j] += blockA[ i*blockLength + k]*blockB[ k*blockLength + j]; // } // } // } for( int k = 0; k < n; k++ ) { int rowB = k*blockLength; int endB = rowB+o; for( int i = 0; i < m; i++ ) { int indexC = i*blockLength; double valA = blockA[ indexC + k]; int indexB = rowB; while( indexB != endB ) { blockC[ indexC++ ] += valA*blockB[ indexB++]; } } } } private static void multBlockSet( double []blockA, double []blockB, double []blockC, final int m, final int n, final int o, final int blockLength ) { int rowA = 0; for( int i = 0; i < m; i++ , rowA += blockLength) { for( int j = 0; j < o; j++ ) { double val = 0; int indexB = j; int indexA = rowA; int end = indexA + n; for( ; indexA != end; indexA++ , indexB += blockLength ) { val += blockA[ indexA ]*blockB[ indexB ]; } blockC[ rowA + j] = val; } } } } ejml-0.28/main/experimental/src/org/ejml/alg/dense/000077500000000000000000000000001256171534400221715ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/dense/decomposition/000077500000000000000000000000001256171534400250455ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/dense/decomposition/bidiagonal/000077500000000000000000000000001256171534400271365ustar00rootroot00000000000000BidiagonalDecompositionNaive_D64.java000066400000000000000000000126741256171534400361220ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/dense/decomposition/bidiagonal/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.bidiagonal; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.SpecializedOps; import org.ejml.simple.SimpleMatrix; /** * A slower but much simpler version of {@link BidiagonalDecompositionRow_D64} that internally uses * SimpleMatrix and explicitly computes the householder matrices. This was easier to code up and is * used to validate other implementations. * * @author Peter Abeles */ public class BidiagonalDecompositionNaive_D64 { private SimpleMatrix U; private SimpleMatrix B; private SimpleMatrix V; // number of rows private int m; // number of columns private int n; // smallest of m and n private int min; DenseMatrix64F u; public SimpleMatrix getU() { return U; } public SimpleMatrix getB() { return B; } public SimpleMatrix getV() { return V; } /** * Computes the decomposition of the provided matrix. If no errors are detected then true is returned, * false otherwise. * @param A The matrix that is being decomposed. Not modified. * @return If it detects any errors or not. */ public boolean decompose( DenseMatrix64F A ) { init(A); return _decompose(); } protected void init(DenseMatrix64F A) { m = A.numRows; n = A.numCols; min = Math.min(m,n); U = SimpleMatrix.identity(m); B = new SimpleMatrix(A); V = SimpleMatrix.identity(n); int max = Math.max(m,n); u = new DenseMatrix64F(max,1); } /** * Internal function for computing the decomposition. */ private boolean _decompose() { for( int k = 0; k < min; k++ ) { computeU(k); computeV(k); } return true; } protected void computeU( int k) { u.reshape(m,1, false); double u[] = this.u.data; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = 0; for( int i = k; i < m; i++ ) { // copy the householder vector to vector outside of the matrix to reduce caching issues // big improvement on larger matrices and a relatively small performance hit on small matrices. double val = u[i] = B.get(i,k); val = Math.abs(val); if( val > max ) max = val; } if( max > 0 ) { // -------- set up the reflector Q_k double tau = 0; // normalize to reduce overflow/underflow // and compute tau for the reflector for( int i = k; i < m; i++ ) { double val = u[i] /= max; tau += val*val; } tau = Math.sqrt(tau); if( u[k] < 0 ) tau = -tau; // write the reflector into the lower left column of the matrix double nu = u[k] + tau; u[k] = 1.0; for( int i = k+1; i < m; i++ ) { u[i] /= nu; } SimpleMatrix Q_k = SimpleMatrix.wrap(SpecializedOps.createReflector(this.u,nu/tau)); U = U.mult(Q_k); B = Q_k.mult(B); } } protected void computeV(int k) { u.reshape(n,1, false); u.zero(); double u[] = this.u.data; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow double max = 0; for( int i = k+1; i < n; i++ ) { // copy the householder vector to vector outside of the matrix to reduce caching issues // big improvement on larger matrices and a relatively small performance hit on small matrices. double val = u[i] = B.get(k,i); val = Math.abs(val); if( val > max ) max = val; } if( max > 0 ) { // -------- set up the reflector Q_k double tau = 0; // normalize to reduce overflow/underflow // and compute tau for the reflector for( int i = k+1; i < n; i++ ) { double val = u[i] /= max; tau += val*val; } tau = Math.sqrt(tau); if( u[k+1] < 0 ) tau = -tau; // write the reflector into the lower left column of the matrix double nu = u[k+1] + tau; u[k+1] = 1.0; for( int i = k+2; i < n; i++ ) { u[i] /= nu; } // ---------- multiply on the left by Q_k SimpleMatrix Q_k = SimpleMatrix.wrap(SpecializedOps.createReflector(this.u,nu/tau)); V = V.mult(Q_k); B = B.mult(Q_k); } } }ejml-0.28/main/experimental/src/org/ejml/alg/dense/decomposition/lu/000077500000000000000000000000001256171534400254655ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/dense/decomposition/lu/LUDecompositionNR_CD64.java000066400000000000000000000143501256171534400323700ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.lu; import org.ejml.alg.dense.decompose.lu.LUDecompositionBase_CD64; import org.ejml.data.CDenseMatrix64F; /** * This code is inspired from what's in numerical recipes. * * @author Peter Abeles */ public class LUDecompositionNR_CD64 extends LUDecompositionBase_CD64 { private static final double TINY = 1.0e-40; /** *

* This implementation of LU Decomposition uses the algorithm specified below: * * "Numerical Recipes The Art of Scientific Computing", Third Edition, Pages 48-55
*

* * @param orig The matrix that is to be decomposed. Not modified. * @return true If the matrix can be decomposed and false if it can not. It can * return true and still be singular. */ @Override public boolean decompose( CDenseMatrix64F orig ) { // if( orig.numCols != orig.numRows ) // throw new RuntimeException("Must be square"); decomposeCommonInit(orig); // loop over the rows to get implicit scaling information for( int i = 0; i < m; i++ ) { double big = 0; double bigReal = 0.0; double bigImg = 0.0; for( int j = 0; j < n; j++ ) { double real = dataLU[i*stride +j*2]; double img = dataLU[i*stride +j*2+1]; double temp = real*real + img*img; if( big < temp ) { big = temp; bigReal = real; bigImg = img; } } // see if it is singular if( big == 0.0 ) { bigReal = 1.0; bigImg = 0.0; } // vv = 1.0/big vv[i*2] = bigReal/(big*big); vv[i*2+1] = -bigImg/(big*big); } // outermost kij loop for( int k = 0; k < n; k++ ) { int imax=-1; // start search by row for largest pivot element double big = 0.0; for( int i=k; i< m; i++ ) { double luReal = dataLU[i*stride + k*2]; double luImg = dataLU[i*stride + k*2 + 1]; double vvReal = vv[i*2]; double vvImg = vv[i*2+1]; // double temp = vv[i*2]* dataLU[i* n +k ]; double tmpReal = luReal*vvReal - luImg*vvImg; double tmpImg = luImg*vvReal + luReal*vvReal; double tmpMag = tmpReal*tmpReal + tmpImg*tmpImg; if( tmpMag > big ) { big = tmpMag; imax=i; } } // see if it is singular if( imax < 0 ) { indx[k] = -1; return true; } else { // check to see if rows need to be interchanged if( k != imax ) { int imax_n = imax*stride; int k_n = k*stride; int end = k_n+n*2; // j=0:n-1 for( ; k_n < end; imax_n+=2,k_n+=2) { double tempReal = dataLU[imax_n]; double tempImg = dataLU[imax_n+1]; dataLU[imax_n] = dataLU[k_n]; dataLU[imax_n+1] = dataLU[k_n+1]; dataLU[k_n] = tempReal; dataLU[k_n+1] = tempImg; } pivsign = -pivsign; vv[imax*2] = vv[k*2]; vv[imax*2+1] = vv[k*2+1]; int z = pivot[imax]; pivot[imax] = pivot[k]; pivot[k] = z; } indx[k] = imax; // for some applications it is better to have this set to tiny even though // it is singular. see the book double element_kk_real = dataLU[k*stride +k*2]; double element_kk_img = dataLU[k*stride +k*2+1]; double mag = element_kk_real*element_kk_real + element_kk_img*element_kk_img; if( mag == 0.0) { dataLU[k*stride +k*2] = element_kk_real = TINY; dataLU[k*stride +k*2+1] = element_kk_img = 0; } double element_kk_norm2 = element_kk_real*element_kk_real + element_kk_img*element_kk_img; // the large majority of the processing time is spent in the code below for( int i =k+1; i < m; i++ ) { int i_n=i*stride; // divide the pivot element double luReal = dataLU[i_n + k*2]; double luImg = dataLU[i_n + k*2+1]; double tmpReal = (luReal*element_kk_real + luImg*element_kk_img)/element_kk_norm2; double tmpImg = (luImg*element_kk_real - luReal*element_kk_img)/element_kk_norm2; dataLU[i_n + k*2] = tmpReal; dataLU[i_n + k*2+1] = tmpImg; int k_n = k*stride + k*2+2; int end = i_n+n*2; i_n += k*2+2; // reduce remaining submatrix // j = k+1:n-1 for( ; i_n * This implementation of LU Decomposition uses the algorithm specified below: * * "Numerical Recipes The Art of Scientific Computing", Third Edition, Pages 48-55
*

* * @param orig The matrix that is to be decomposed. Not modified. * @return true If the matrix can be decomposed and false if it can not. It can * return true and still be singular. */ @Override public boolean decompose( DenseMatrix64F orig ) { // if( orig.numCols != orig.numRows ) // throw new RuntimeException("Must be square"); decomposeCommonInit(orig); // loop over the rows to get implicit scaling information for( int i = 0; i < m; i++ ) { double big = 0.0; for( int j = 0; j < n; j++ ) { double temp = Math.abs(dataLU[i* n +j]); if( big < temp ) big = temp; } // see if it is singular if( big == 0.0 ) big = 1.0; vv[i] = 1.0/big; } // outermost kij loop for( int k = 0; k < n; k++ ) { int imax=-1; // start search by row for largest pivot element double big = 0.0; for( int i=k; i< m; i++ ) { double temp = vv[i]* dataLU[i* n +k]; if( temp < 0 ) temp = -temp; if( temp > big ) { big = temp; imax=i; } } // see if it is singular if( imax < 0 ) { indx[k] = -1; return true; } else { // check to see if rows need to be interchanged if( k != imax ) { int imax_n = imax*n; int k_n = k*n; int end = k_n+n; // j=0:n-1 for( ; k_n < end; imax_n++,k_n++) { double temp = dataLU[imax_n]; dataLU[imax_n] = dataLU[k_n]; dataLU[k_n] = temp; } pivsign = -pivsign; vv[imax] = vv[k]; int z = pivot[imax]; pivot[imax] = pivot[k]; pivot[k] = z; } indx[k] = imax; // for some applications it is better to have this set to tiny even though // it is singular. see the book double element_kk = dataLU[k* n +k]; if( element_kk == 0.0) { dataLU[k* n +k] = TINY; element_kk = TINY; } // the large majority of the processing time is spent in the code below for( int i =k+1; i < m; i++ ) { int i_n=i*n; // divide the pivot element double temp = dataLU[i_n +k] /= element_kk; int k_n = k*n + k+1; int end = i_n+n; i_n += k+1; // reduce remaining submatrix // j = k+1:n-1 for( ; i_n * Similar to {@link SvdImplicitQrDecompose_D64} but it employs the * ultimate shift strategy. Ultimate shift involves first computing singular values then uses those * to quickly compute the U and W matrices. For EVD this strategy seems to work very well, but for * this problem it needs to have little benefit and makes the code more complex. *

* * NOTE: This code is much faster for 2x2 matrices since it computes the eigenvalues in one step. * * @author Peter Abeles */ public class SvdImplicitQrDecompose_Ultimate implements SingularValueDecomposition { private int numRows; private int numCols; private int smallSide; private BidiagonalDecompositionRow_D64 bidiag = new BidiagonalDecompositionRow_D64(); private SvdImplicitQrAlgorithm qralg = new SvdImplicitQrAlgorithm(); private double diag[]; private double off[]; private DenseMatrix64F Ut; private DenseMatrix64F Vt; private double singularValues[]; private int numSingular; // compute a compact SVD private boolean compact; // What is actually computed private boolean computeU; private boolean computeV; // What the user requested to be computed // If the transpose is computed instead then what is actually computed is swapped private boolean prefComputeU; private boolean prefComputeV; // stores the results of bidiagonalization private double diagOld[]; private double offOld[]; // Either a copy of the input matrix or a copy of it transposed private DenseMatrix64F A_mod = new DenseMatrix64F(1,1); public SvdImplicitQrDecompose_Ultimate( boolean compact , boolean computeU , boolean computeV ) { this.compact = compact; this.prefComputeU = computeU; this.prefComputeV = computeV; } @Override public double[] getSingularValues() { return singularValues; } @Override public int numberOfSingularValues() { return numSingular; } @Override public boolean isCompact() { return compact; } @Override public DenseMatrix64F getU(DenseMatrix64F U , boolean transpose) { if( !prefComputeU ) throw new IllegalArgumentException("As requested U was not computed."); if( transpose ) return Ut; U = new DenseMatrix64F(Ut.numCols,Ut.numRows); CommonOps.transpose(Ut,U); return U; } @Override public DenseMatrix64F getV( DenseMatrix64F V , boolean transpose ) { if( !prefComputeV ) throw new IllegalArgumentException("As requested V was not computed."); if( transpose ) return Vt; V = new DenseMatrix64F(Vt.numCols,Vt.numRows); CommonOps.transpose(Vt,V); return V; } @Override public DenseMatrix64F getW( DenseMatrix64F W ) { int m = compact ? numSingular : numRows; int n = compact ? numSingular : numCols; if( W == null ) W = new DenseMatrix64F(m,n); else { W.reshape(m,n, false); W.zero(); } for( int i = 0; i < numSingular; i++ ) { W.data[i*W.numCols+i] = singularValues[i]; } return W; } @Override public boolean decompose(DenseMatrix64F orig) { boolean transposed = orig.numCols > orig.numRows; init(orig, transposed); if (computeSingularValues(orig, transposed)) return false; if( computeU || computeV ) { if (computeUandV(transposed)) return false; } // make sure all the singular values or positive makeSingularPositive(); return true; } @Override public boolean inputModified() { return false; } private void init(DenseMatrix64F orig, boolean transposed) { if( transposed ) { computeU = prefComputeV; computeV = prefComputeU; } else { computeU = prefComputeU; computeV = prefComputeV; } numRows = orig.numRows; numCols = orig.numCols; smallSide = Math.min(numRows,numCols); if( diagOld == null || diagOld.length < smallSide ) { diagOld = new double[ smallSide ]; offOld = new double[ smallSide -1]; diag = new double[ smallSide ]; off = new double[ smallSide -1]; } } private boolean computeUandV(boolean transposed) { // System.out.println("-------------- Computing U and V --------------------"); // long pointA = System.currentTimeMillis(); // compute U and V matrices if( computeU ) Ut = bidiag.getU(Ut,true,compact); if( computeV ) Vt = bidiag.getV(Vt,true,compact); // set up the qr algorithm, reusing the previous extraction if( transposed ) qralg.initParam(numCols,numRows); else qralg.initParam(numRows,numCols); diagOld = qralg.swapDiag(diagOld); offOld = qralg.swapOff(offOld); // set it up to compute both U and V matrices qralg.setFastValues(false); if( computeU ) qralg.setUt(Ut); if( computeV ) qralg.setVt(Vt); // long pointB = System.currentTimeMillis(); if( !qralg.process(diagOld) ) return true; // long pointC = System.currentTimeMillis(); // System.out.println(" bidiag UV "+(pointB-pointA)+" qr UV "+(pointC-pointB)); if( transposed ) { DenseMatrix64F temp = Vt; Vt = Ut; Ut = temp; } return false; } private boolean computeSingularValues(DenseMatrix64F orig, boolean transposed) { // long pointA = System.currentTimeMillis(); // change the matrix to bidiagonal form if (bidiagonalization(orig, transposed)) return false; // long pointB = System.currentTimeMillis(); // compute singular values bidiag.getDiagonal(diag,off); qralg.setMatrix(numRows,numCols,diag,off); // copy the diagonal elements // this way it doesn't need to be copied twice and will slightly speed it up System.arraycopy(diag,0, diagOld,0,smallSide); System.arraycopy(off,0, offOld,0,smallSide-1); qralg.setFastValues(true); qralg.setUt(null); qralg.setVt(null); boolean ret = !qralg.process(); // long pointC = System.currentTimeMillis(); // System.out.println(" bidiag "+(pointB-pointA)+" qr W "+(pointC-pointB)); return ret; } private boolean bidiagonalization(DenseMatrix64F orig, boolean transposed) { if( transposed ) { A_mod.reshape(orig.numCols,orig.numRows,false); CommonOps.transpose(orig,A_mod); } else { A_mod.reshape(orig.numRows,orig.numCols,false); A_mod.set(orig); } if( !bidiag.decompose(A_mod) ) return true; return false; } /** * With the QR algorithm it is possible for the found singular values to be native. This * makes them all positive by multiplying it by a diagonal matrix that has */ private void makeSingularPositive() { numSingular = qralg.getNumberOfSingularValues(); singularValues = qralg.getSingularValues(); for( int i = 0; i < numSingular; i++ ) { double val = singularValues[i]; if( val < 0 ) { singularValues[i] = -val; if( computeU ) { // compute the results of multiplying it by an element of -1 at this location in // a diagonal matrix. int start = i* Ut.numCols; int stop = start+ Ut.numCols; for( int j = start; j < stop; j++ ) { Ut.data[j] = -Ut.data[j]; } } } } } @Override public int numRows() { return numRows; } @Override public int numCols() { return numCols; } } SvdImplicitQrDecompose_UltimateS.java000066400000000000000000000221721256171534400350110ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/dense/decomposition/svd/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decomposition.svd; import org.ejml.alg.dense.decomposition.bidiagonal.BidiagonalDecompositionRow_D64; import org.ejml.alg.dense.decomposition.svd.implicitqr.SvdImplicitQrAlgorithm; import org.ejml.data.DenseMatrix64F; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.CommonOps; /** *

* Similar to {@link SvdImplicitQrDecompose_D64} but it employs the * ultimate shift strategy. Ultimate shift involves first computing singular values then uses those * to quickly compute the U and W matrices. For EVD this strategy seems to work very well, but for * this problem it needs to have little benefit and makes the code more complex. *

* * NOTE: This code is much faster for 2x2 matrices since it computes the eigenvalues in one step. * * @author Peter Abeles */ public class SvdImplicitQrDecompose_UltimateS implements SingularValueDecomposition { private int numRows; private int numCols; private int smallSide; private BidiagonalDecompositionRow_D64 bidiag = new BidiagonalDecompositionRow_D64(); private SvdImplicitQrAlgorithm qralg = new SvdImplicitQrAlgorithmSmart(); private double diag[]; private double off[]; private DenseMatrix64F Ut; private DenseMatrix64F Vt; private double singularValues[]; private int numSingular; // compute a compact SVD private boolean compact; // What is actually computed private boolean computeU; private boolean computeV; // What the user requested to be computed // If the transpose is computed instead then what is actually computed is swapped private boolean prefComputeU; private boolean prefComputeV; // stores the results of bidiagonalization private double diagOld[]; private double offOld[]; // Either a copy of the input matrix or a copy of it transposed private DenseMatrix64F A_mod = new DenseMatrix64F(1,1); public SvdImplicitQrDecompose_UltimateS( boolean compact , boolean computeU , boolean computeV ) { this.compact = compact; this.prefComputeU = computeU; this.prefComputeV = computeV; } @Override public double[] getSingularValues() { return singularValues; } @Override public int numberOfSingularValues() { return numSingular; } @Override public boolean isCompact() { return compact; } @Override public DenseMatrix64F getU( DenseMatrix64F U ,boolean transpose) { if( !prefComputeU ) throw new IllegalArgumentException("As requested U was not computed."); if( transpose ) return Ut; U = new DenseMatrix64F(Ut.numCols,Ut.numRows); CommonOps.transpose(Ut,U); return U; } @Override public DenseMatrix64F getV( DenseMatrix64F V , boolean transpose ) { if( !prefComputeV ) throw new IllegalArgumentException("As requested V was not computed."); if( transpose ) return Vt; V = new DenseMatrix64F(Vt.numCols,Vt.numRows); CommonOps.transpose(Vt,V); return V; } @Override public DenseMatrix64F getW( DenseMatrix64F W ) { int m = compact ? numSingular : numRows; int n = compact ? numSingular : numCols; if( W == null ) W = new DenseMatrix64F(m,n); else { W.reshape(m,n, false); W.zero(); } for( int i = 0; i < numSingular; i++ ) { W.data[i*W.numCols+i] = singularValues[i]; } return W; } @Override public boolean decompose(DenseMatrix64F orig) { boolean transposed = orig.numCols > orig.numRows; init(orig, transposed); if (computeSingularValues(orig, transposed)) return false; if( computeU || computeV ) { if (computeUandV(transposed)) return false; } // make sure all the singular values or positive makeSingularPositive(); return true; } @Override public boolean inputModified() { return false; } private void init(DenseMatrix64F orig, boolean transposed) { if( transposed ) { computeU = prefComputeV; computeV = prefComputeU; } else { computeU = prefComputeU; computeV = prefComputeV; } numRows = orig.numRows; numCols = orig.numCols; smallSide = Math.min(numRows,numCols); if( diagOld == null || diagOld.length < smallSide ) { diagOld = new double[ smallSide ]; offOld = new double[ smallSide -1]; diag = new double[ smallSide ]; off = new double[ smallSide -1]; } } private boolean computeUandV(boolean transposed) { // System.out.println("-------------- Computing U and V --------------------"); long pointA = System.currentTimeMillis(); // compute U and V matrices if( computeU ) Ut = bidiag.getU(Ut,true,compact); if( computeV ) Vt = bidiag.getV(Vt,true,compact); // set up the qr algorithm, reusing the previous extraction if( transposed ) qralg.initParam(numCols,numRows); else qralg.initParam(numRows,numCols); diagOld = qralg.swapDiag(diagOld); offOld = qralg.swapOff(offOld); // set it up to compute both U and V matrices qralg.setFastValues(false); if( computeU ) qralg.setUt(Ut); if( computeV ) qralg.setVt(Vt); CommonOps.setIdentity(Ut); CommonOps.setIdentity(Vt); long pointB = System.currentTimeMillis(); if( !qralg.process(diagOld) ) return true; long pointC = System.currentTimeMillis(); System.out.println(" bidiag UV "+(pointB-pointA)+" qr UV "+(pointC-pointB)); if( transposed ) { DenseMatrix64F temp = Vt; Vt = Ut; Ut = temp; } return false; } private boolean computeSingularValues(DenseMatrix64F orig, boolean transposed) { long pointA = System.currentTimeMillis(); // change the matrix to bidiagonal form if (bidiagonalization(orig, transposed)) return false; long pointB = System.currentTimeMillis(); // compute singular values bidiag.getDiagonal(diag,off); qralg.setMatrix(numRows,numCols,diag,off); // copy the diagonal elements // this way it doesn't need to be copied twice and will slightly speed it up System.arraycopy(diag,0, diagOld,0,smallSide); System.arraycopy(off,0, offOld,0,smallSide-1); qralg.setFastValues(true); qralg.setUt(null); qralg.setVt(null); boolean ret = !qralg.process(); long pointC = System.currentTimeMillis(); System.out.println(" bidiag "+(pointB-pointA)+" qr W "+(pointC-pointB)); return ret; } private boolean bidiagonalization(DenseMatrix64F orig, boolean transposed) { if( transposed ) { A_mod.reshape(orig.numCols,orig.numRows,false); CommonOps.transpose(orig,A_mod); } else { A_mod.reshape(orig.numRows,orig.numCols,false); A_mod.set(orig); } if( !bidiag.decompose(A_mod) ) return true; return false; } /** * With the QR algorithm it is possible for the found singular values to be native. This * makes them all positive by multiplying it by a diagonal matrix that has */ private void makeSingularPositive() { numSingular = qralg.getNumberOfSingularValues(); singularValues = qralg.getSingularValues(); for( int i = 0; i < numSingular; i++ ) { double val = singularValues[i]; if( val < 0 ) { singularValues[i] = -val; if( computeU ) { // compute the results of multiplying it by an element of -1 at this location in // a diagonal matrix. int start = i* Ut.numCols; int stop = start+ Ut.numCols; for( int j = start; j < stop; j++ ) { Ut.data[j] = -Ut.data[j]; } } } } } @Override public int numRows() { return numRows; } @Override public int numCols() { return numCols; } }ejml-0.28/main/experimental/src/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400231245ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/dense/misc/NaiveDeterminant.java000066400000000000000000000073041256171534400272300ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; /** * Computes the determinant using different very simple and computationally expensive algorithms. * * @author Peter Abeles */ public class NaiveDeterminant { /** *

* Computes the determinant of the matrix using Leibniz's formula *

* *

* A direct implementation of Leibniz determinant equation. This is of little practical use * because of its slow runtime of O(n!) where n is the width of the matrix. LU decomposition * should be used instead. One advantage of Leibniz's equation is how simplistic it is. *

*

* det(A) = Sum( σ in Sn ; sgn(σ) Prod( i = 1 to n ; ai,σ(i)) )
*

*
    *
  • sgn is the sign function of permutations. +1 or -1 for even and odd permutations
  • *
  • a set of permutations. if n=3 then the possible permutations are (1,2,3) (1,3,2), (3,2,1), ... etc
  • *
* * @param mat The matrix whose determinant is computed. * @return The value of the determinant */ public static double leibniz( DenseMatrix64F mat ) { PermuteArray perm = new PermuteArray( mat.numCols ); double total = 0; int p[] = perm.next(); while( p != null ) { double prod = 1; for( int i = 0; i < mat.numRows; i++ ) { prod *= mat.get(i,p[i]); } total += perm.sgn()*prod; p = perm.next(); } return total; } /** *

* A simple and inefficient algorithm for computing the determinant. This should never be used. * It is at least two orders of magnitude slower than {@link DeterminantFromMinor}. This is included * to provide a point of comparison for other algorithms. *

* @param mat The matrix that the determinant is to be computed from * @return The determinant. */ public static double recursive( DenseMatrix64F mat ) { if(mat.numRows == 1) { return mat.get(0); } else if(mat.numRows == 2) { return mat.get(0) * mat.get(3) - mat.get(1) * mat.get(2); } else if( mat.numRows == 3 ) { return UnrolledDeterminantFromMinor.det3(mat); } double result = 0; for(int i = 0; i < mat.numRows; i++) { DenseMatrix64F minorMat = new DenseMatrix64F(mat.numRows-1,mat.numRows-1); for(int j = 1; j < mat.numRows; j++) { for(int k = 0; k < mat.numRows; k++) { if(k < i) { minorMat.set(j-1,k,mat.get(j,k)); } else if(k > i) { minorMat.set(j-1,k-1,mat.get(j,k)); } } } if( i % 2 == 0 ) result += mat.get(0,i) * recursive(minorMat); else result -= mat.get(0,i) * recursive(minorMat); } return result; } } ejml-0.28/main/experimental/src/org/ejml/alg/dense/misc/PermuteArray.java000066400000000000000000000114211256171534400264060ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import java.util.ArrayList; import java.util.List; /** * Generates a permutations of an integer set from 0 to N-1. This can either be generated * all at once as a list of one at a time. * * @author Peter Abeles */ public class PermuteArray { // used by next private int level; private int data[]; private int iter[]; private int valk[]; private int ret[]; public PermuteArray( int N ) { level = 0; iter = new int[ N ]; valk = new int[ N ]; data = new int[ N ]; ret = new int[ N ]; for( int i = 0; i < data.length; i++ ) { data[i] = -1; } } /** *

* Returns signature of the permutation. This is the sgn() operator and returns * -1 or 1 depending on it being odd or even. *
* sgn(σ) = ( − 1)m
*
* where m is the number of inversions. *

*

* NOTE: This implementation is painfully slow O(N!). There is probably another algorithm out there * which is much faster. *

* * @return -1 or 1 for odd or even permutations. */ public int sgn() { // Is there a way to compute the parity while performing the permutations // making this much less expensive int total = 0; for( int i = 0; i < ret.length; i++ ) { int val = ret[i]; for( int j = i+1; j < ret.length; j++ ) { if( val > ret[j] ) { total++; } } } if( total % 2 == 1 ) return -1; return 1; } /** * Computes N factorial */ public static int fact( int N ) { int ret = 1; while( N > 0 ) { ret *= N--; } return ret; } /** * Creates a list of all permutations for a set with N elements. * * @param N Number of elements in the list being permuted. * @return A list containing all the permutations. */ public static List createList( int N ) { int data[] = new int[ N ]; for( int i = 0; i < data.length; i++ ) { data[i] = -1; } List ret = new ArrayList(); createList(data,0,-1,ret); return ret; } /** * Internal function that uses recursion to create the list */ private static void createList( int data[], int k , int level , List ret ) { data[k] = level; if( level < data.length-1 ) { for( int i = 0; i < data.length; i++ ) { if( data[i] == -1 ) { createList(data,i,level+1,ret); } } } else { int []copy = new int[data.length]; System.arraycopy(data,0,copy,0,data.length); ret.add(copy); } data[k] = -1; } /** * Creates the next permutation in the sequence. * * @return An array containing the permutation. The returned array is modified each time this function is called. */ public int[] next() { boolean hasNewPerm = false; escape:while( level >= 0) { // boolean foundZero = false; for( int i = iter[level]; i < data.length; i = iter[level] ) { iter[level]++; if( data[i] == -1 ) { level++; data[i] = level-1; if( level >= data.length ) { // a new permutation has been created return the results. hasNewPerm = true; System.arraycopy(data,0,ret,0,ret.length); level = level-1; data[i] = -1; break escape; } else { valk[level] = i; } } } data[valk[level]] = -1; iter[level] = 0; level = level-1; } if( hasNewPerm ) return ret; return null; } } ejml-0.28/main/experimental/src/org/ejml/alg/dense/mult/000077500000000000000000000000001256171534400231525ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/dense/mult/MatrixMultQuad.java000066400000000000000000000047201256171534400267410ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.mult; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; /** * @author Peter Abeles */ public class MatrixMultQuad { /** *

* Performs matrix multiplication on an equation in quadratic form with a transpose on the second A:
*
* out = A*B*AT *

* @param A Left and right matrix. * @param B Middle square matrix. Size = (A.numCols,A.numCols) * @param out Output matrix. Size = (A.numRows,A.numRows); */ public static void multQuad1( DenseMatrix64F A , DenseMatrix64F B , DenseMatrix64F out ) { if( A.numCols != B.numCols || A.numCols != B.numRows || A.numRows != out.numRows || A.numRows != out.numCols ) throw new IllegalArgumentException("Incompatible matrix shapes"); CommonOps.fill(out, 0); for (int i = 0; i < A.numRows; i++) { for (int j = 0; j < A.numCols; j++) { double total = 0; int indexA = i*A.numCols; int indexB = j; int end = indexA + A.numCols; for (; indexA < end; indexA++ , indexB += B.numCols ) { // for (int k = 0; k < A.numCols; k++) { // total += A.get(i,k)*B.get(k,j); total += A.data[indexA] * B.data[indexB]; } int indexOut = i*out.numCols; indexA = j; end = indexOut + A.numRows; for (; indexOut < end; indexOut++, indexA += A.numCols) { // for (int l = 0; l < A.numRows; l++) { // out.data[ out.getIndex(i,l) ] += total*A.get(l,j); out.data[ indexOut] += total*A.data[indexA]; } } } } } ejml-0.28/main/experimental/src/org/ejml/alg/densed2/000077500000000000000000000000001256171534400224175ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/densed2/mult/000077500000000000000000000000001256171534400234005ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/alg/densed2/mult/MatrixMatrixMult_D2.java000066400000000000000000000063331256171534400300700ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.densed2.mult; import org.ejml.data.DenseD2Matrix64F; import org.ejml.ops.MatrixDimensionException; /** * @author Peter Abeles */ public class MatrixMatrixMult_D2 { /** * @see org.ejml.ops.CommonOps#mult(org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F) */ public static void mult_small( DenseD2Matrix64F a , DenseD2Matrix64F b , DenseD2Matrix64F c ) { if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } double dataA[][] = a.data; double dataB[][] = b.data; double dataR[][] = c.data; for( int i = 0; i < a.numRows; i++ ) { double dataAi[] = dataA[i]; double dataRi[] = dataR[i]; for( int j = 0; j < b.numCols; j++ ) { double total = 0; for( int k = 0; k < a.numCols; k++ ) { total += dataAi[k] * dataB[k][j]; } dataRi[j] = total; } } } /** * @see org.ejml.ops.CommonOps#mult(org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F) */ public static void mult_aux( DenseD2Matrix64F a , DenseD2Matrix64F b , DenseD2Matrix64F c , double []aux ) { if( a.numCols != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } else if( a.numRows != c.numRows || b.numCols != c.numCols ) { throw new MatrixDimensionException("The results matrix does not have the desired dimensions"); } if( aux == null ) aux = new double[ b.numRows ]; double dataA[][] = a.data; double dataB[][] = b.data; double dataR[][] = c.data; for( int j = 0; j < b.numCols; j++ ) { // create a copy of the column in B to avoid cache issues for( int k = 0; k < b.numRows; k++ ) { aux[k] = dataB[k][j]; } for( int i = 0; i < a.numRows; i++ ) { double dataAi[] = dataA[i]; double total = 0; for( int k = 0; k < b.numRows; ) { total += dataAi[k]*aux[k++]; } dataR[i][j] = total; } } } } ejml-0.28/main/experimental/src/org/ejml/data/000077500000000000000000000000001256171534400212415ustar00rootroot00000000000000ejml-0.28/main/experimental/src/org/ejml/data/BlockD3Matrix64F.java000066400000000000000000000067251256171534400250040ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.ejml.EjmlParameters; import org.ejml.ops.MatrixIO; /** * Row-major block matrix declared using 3D array. * * @author Peter Abeles */ public class BlockD3Matrix64F implements ReshapeMatrix, RealMatrix64F { public int blockLength; public double[][][] blocks; /** * Number of rows in the matrix. */ public int numRows; /** * Number of columns in the matrix. */ public int numCols; public BlockD3Matrix64F( int numRows , int numCols , int blockLength) { this.blockLength = blockLength; reshape(numRows,numCols); } public BlockD3Matrix64F( int numRows , int numCols ) { this(numRows,numCols, EjmlParameters.BLOCK_WIDTH); } public double[][][] getData() { return blocks; } @Override public void reshape(int numRows, int numCols ) { this.numRows = numRows; this.numCols = numCols; int blockM = numRows / blockLength; int blockN = numCols / blockLength; if( numRows % blockLength > 0) blockM++; if( numCols % blockLength > 0) blockN++; this.blocks = new double[blockM][blockN][]; for( int i = 0; i < numRows; i += blockLength ) { int ii = i/blockLength; for( int j = 0; j < numCols; j += blockLength ) { int jj = j/blockLength; blocks[ii][jj] = new double[ blockLength*blockLength ]; } } } @Override public double get( int row, int col) { int blockM = row / blockLength; int blockN = col / blockLength; int m = row % blockLength; int n = col % blockLength; int index = m*blockLength + n; return blocks[blockM][blockN][index]; } @Override public void set( int row, int col, double val) { int blockM = row / blockLength; int blockN = col / blockLength; int m = row % blockLength; int n = col % blockLength; int index = m*blockLength + n; blocks[blockM][blockN][index] = val; } @Override public double unsafe_get( int row, int col) { return get(row,col); } @Override public void unsafe_set( int row, int col, double val) { set(row,col,val); } @Override public int getNumRows() { return numRows; } @Override public int getNumCols() { return numCols; } @Override public int getNumElements() { return numRows*numCols; } @Override public void print() { MatrixIO.print(System.out,this); } @Override public T copy() { return null; } @Override public void set(Matrix original) { throw new RuntimeException("Not supported yet"); } }ejml-0.28/main/experimental/src/org/ejml/data/DenseD2Matrix64F.java000066400000000000000000000053741256171534400250060ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import java.io.Serializable; /** * A dense matrix where the array is stored as a 2D array. * * @author Peter Abeles */ public class DenseD2Matrix64F implements Serializable, ReshapeMatrix, RealMatrix64F { /** * Where the raw data for the matrix is stored. The format is type dependent. */ public double[][] data; /** * Number of rows in the matrix. */ public int numRows; /** * Number of columns in the matrix. */ public int numCols; public DenseD2Matrix64F( int numRows , int numCols ) { data = new double[ numRows ][numCols]; this.numRows = numRows; this.numCols = numCols; } // public double[][] getData() { // return data; // } @Override public void reshape(int numRows, int numCols ) { if( numRows <= data.length ) { this.numRows = numRows; } else { throw new IllegalArgumentException("Requested number of rows is too great."); } if( numCols <= data[0].length ) { this.numCols = numCols; } else { throw new IllegalArgumentException("Requested number of columns is too great."); } } @Override public double get(int row, int col) { return data[row][col]; } @Override public void set(int row, int col, double val) { data[row][col] = val; } @Override public double unsafe_get( int row, int col) { return get(row,col); } @Override public void unsafe_set( int row, int col, double val) { set(row,col,val); } @Override public int getNumElements() { return numRows*numCols; } @Override public int getNumRows() { return numRows; } @Override public int getNumCols() { return numCols; } @Override public void print() { } @Override public T copy() { return null; } @Override public void set(Matrix original) { throw new RuntimeException("Not yet supported"); } }ejml-0.28/main/experimental/test/000077500000000000000000000000001256171534400170025ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/000077500000000000000000000000001256171534400175715ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/000077500000000000000000000000001256171534400205205ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/000077500000000000000000000000001256171534400212635ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/blockd3/000077500000000000000000000000001256171534400226045ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/blockd3/TestBlockD3MatrixOps.java000066400000000000000000000102341256171534400273770ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.blockd3; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.BlockD3Matrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestBlockD3MatrixOps { final static int BLOCK_LENGTH = 10; Random rand = new Random(234); @Test public void convert_dense_to_block() { checkConvert_dense_to_block(10,10); checkConvert_dense_to_block(5,8); checkConvert_dense_to_block(12,16); checkConvert_dense_to_block(16,12); checkConvert_dense_to_block(21,27); checkConvert_dense_to_block(28,5); checkConvert_dense_to_block(5,28); checkConvert_dense_to_block(20,20); } private void checkConvert_dense_to_block( int m , int n ) { DenseMatrix64F A = RandomMatrices.createRandom(m,n,rand); BlockD3Matrix64F B = new BlockD3Matrix64F(A.numRows,A.numCols,BLOCK_LENGTH); BlockD3MatrixOps.convert(A,B); assertTrue( GenericMatrixOps.isEquivalent(A,B,1e-8)); } @Test public void convert_block_to_dense() { checkBlockToDense(10,10); checkBlockToDense(5,8); checkBlockToDense(12,16); checkBlockToDense(16,12); checkBlockToDense(21,27); checkBlockToDense(28,5); checkBlockToDense(5,28); checkBlockToDense(20,20); } private void checkBlockToDense( int m , int n ) { DenseMatrix64F A = new DenseMatrix64F(m,n); BlockD3Matrix64F B = BlockD3MatrixOps.random(m,n,-1,1,rand,BLOCK_LENGTH); BlockD3MatrixOps.convert(B,A); assertTrue( GenericMatrixOps.isEquivalent(A,B,1e-8)); } @Test public void mult() { // trivial case checkMult(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH); // stuff larger than the block size checkMult(BLOCK_LENGTH+1, BLOCK_LENGTH, BLOCK_LENGTH); checkMult(BLOCK_LENGTH, BLOCK_LENGTH+1, BLOCK_LENGTH); checkMult(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH+1); checkMult(BLOCK_LENGTH+1, BLOCK_LENGTH+1, BLOCK_LENGTH+1); // stuff smaller than the block size checkMult(BLOCK_LENGTH-1, BLOCK_LENGTH, BLOCK_LENGTH); checkMult(BLOCK_LENGTH, BLOCK_LENGTH-1, BLOCK_LENGTH); checkMult(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH-1); checkMult(BLOCK_LENGTH-1, BLOCK_LENGTH-1, BLOCK_LENGTH-1); // stuff multiple blocks checkMult(BLOCK_LENGTH*2, BLOCK_LENGTH, BLOCK_LENGTH); checkMult(BLOCK_LENGTH, BLOCK_LENGTH*2, BLOCK_LENGTH); checkMult(BLOCK_LENGTH, BLOCK_LENGTH, BLOCK_LENGTH*2); checkMult(BLOCK_LENGTH*2, BLOCK_LENGTH*2, BLOCK_LENGTH*2); checkMult(BLOCK_LENGTH*2+4, BLOCK_LENGTH*2+3, BLOCK_LENGTH*2+2); } private void checkMult(int m, int n, int o) { DenseMatrix64F A_d = RandomMatrices.createRandom(m, n,rand); DenseMatrix64F B_d = RandomMatrices.createRandom(n, o,rand); DenseMatrix64F C_d = new DenseMatrix64F(m, o); BlockD3Matrix64F A_b = BlockD3MatrixOps.convert(A_d,BLOCK_LENGTH); BlockD3Matrix64F B_b = BlockD3MatrixOps.convert(B_d,BLOCK_LENGTH); BlockD3Matrix64F C_b = BlockD3MatrixOps.random(m, o, -1 , 1 , rand , BLOCK_LENGTH); CommonOps.mult(A_d,B_d,C_d); BlockD3MatrixOps.mult(A_b,B_b,C_b); assertTrue( GenericMatrixOps.isEquivalent(C_d,C_b,1e-8)); } } ejml-0.28/main/experimental/test/org/ejml/alg/dense/000077500000000000000000000000001256171534400223615ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/dense/decompose/000077500000000000000000000000001256171534400243375ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/dense/decompose/bidiagonal/000077500000000000000000000000001256171534400264305ustar00rootroot00000000000000TestBidiagonalDecompositionNaive_D64.java000066400000000000000000000040501256171534400362410ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/dense/decompose/bidiagonal/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.bidiagonal; import org.ejml.alg.dense.decomposition.bidiagonal.BidiagonalDecompositionNaive_D64; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.MatrixFeatures; import org.ejml.ops.RandomMatrices; import org.ejml.simple.SimpleMatrix; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestBidiagonalDecompositionNaive_D64 { Random rand = new Random(6455); @Test public void testItAll() { checkAgainstRandom(7, 5); checkAgainstRandom(5, 7); checkAgainstRandom(2, 3); } private void checkAgainstRandom(int m, int n) { SimpleMatrix A = SimpleMatrix.wrap(RandomMatrices.createRandom(m,n,rand)); BidiagonalDecompositionNaive_D64 decomp = new BidiagonalDecompositionNaive_D64(); assertTrue(decomp.decompose(A.getMatrix())); SimpleMatrix U = decomp.getU(); SimpleMatrix B = decomp.getB(); SimpleMatrix V = decomp.getV(); // U.print(); // B.print(); // V.print(); // U.mult(A).mult(V).print(); // check the decomposition DenseMatrix64F foundA = U.mult(B).mult(V.transpose()).getMatrix(); // A.print(); // foundA.print(); assertTrue(MatrixFeatures.isIdentical(A.getMatrix(), foundA, 1e-8)); } }ejml-0.28/main/experimental/test/org/ejml/alg/dense/decompose/lu/000077500000000000000000000000001256171534400247575ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/dense/decompose/lu/TestLUDecompositionNR_CD64.java000066400000000000000000000020371256171534400325210ustar00rootroot00000000000000/* * Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.lu; import org.ejml.alg.dense.decomposition.lu.LUDecompositionNR_CD64; /** * @author Peter Abeles */ public class TestLUDecompositionNR_CD64 extends GeneralLuDecompositionChecks_CD64 { @Override public LUDecompositionBase_CD64 create(int numRows, int numCols) { return new LUDecompositionNR_CD64(); } }ejml-0.28/main/experimental/test/org/ejml/alg/dense/decompose/lu/TestLUDecompositionNR_D64.java000066400000000000000000000022441256171534400324160ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.decompose.lu; import org.ejml.alg.dense.decomposition.lu.GeneralLuDecompositionChecks; import org.ejml.alg.dense.decomposition.lu.LUDecompositionBase_D64; import org.ejml.alg.dense.decomposition.lu.LUDecompositionNR_D64; /** * @author Peter Abeles */ public class TestLUDecompositionNR_D64 extends GeneralLuDecompositionChecks { @Override public LUDecompositionBase_D64 create(int numRows, int numCols) { return new LUDecompositionNR_D64(); } }ejml-0.28/main/experimental/test/org/ejml/alg/dense/misc/000077500000000000000000000000001256171534400233145ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/alg/dense/misc/TestNaiveDeterminant.java000066400000000000000000000033021256171534400302520ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestNaiveDeterminant { @Test public void detRecursive() { double[] d = new double[]{5 ,-2 ,-4 ,0.5, 0.1, 91, 8, 66, 1, -2, 10, -4, -0.2, 7, -4, 0.8}; DenseMatrix64F mat = new DenseMatrix64F(4,4, true, d); double val = NaiveDeterminant.recursive(mat); assertEquals(-27288.86,val,1e-6); } /** * Compares this formuation to the naive recursive formulation */ @Test public void det() { Random rand = new Random(0xff); for( int i = 1; i <= 5; i++ ) { DenseMatrix64F A = RandomMatrices.createRandom(i,i,rand); double expected = NaiveDeterminant.recursive(A); double found = NaiveDeterminant.leibniz(A); assertEquals(expected,found,1e-8); } } } ejml-0.28/main/experimental/test/org/ejml/alg/dense/misc/TestPermuteArray.java000066400000000000000000000047231256171534400274450ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.alg.dense.misc; import org.junit.Test; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; /** * @author Peter Abeles */ public class TestPermuteArray { int fact( int N ) { int ret = 1; while( N > 0 ) { ret *= N--; } return ret; } /** * Sees if the expected number of permutations are created and that they are all * unique */ @Test public void permuteList() { int N = 4; List perms = PermuteArray.createList(N); checkPermutationList(N, perms); } private void checkPermutationList(int n, List perms) { assertEquals(PermuteArray.fact(n),perms.size()); // make sure each permutation in the list is unique for( int i = 0; i < perms.size(); i++ ) { int a[] = perms.get(i); assertEquals(4,a.length); for( int j = i+1; j < perms.size(); j++ ) { int b[] = perms.get(j); boolean identical = true; for( int k = 0; k < n; k++ ) { if( a[k] != b[k] ) { identical = false; break; } } assertFalse(identical); } } } @Test public void next() { // create a list of all the permutations PermuteArray alg = new PermuteArray(4); List perms = new ArrayList(); for(;;) { int d[] = alg.next(); if( d == null ) break; perms.add(d.clone()); } // see if the list is correct checkPermutationList(4, perms); } } ejml-0.28/main/experimental/test/org/ejml/data/000077500000000000000000000000001256171534400214315ustar00rootroot00000000000000ejml-0.28/main/experimental/test/org/ejml/data/TestBlockD3Matrix64F.java000066400000000000000000000021451256171534400260240ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.junit.Test; /** * @author Peter Abeles */ public class TestBlockD3Matrix64F { @Test public void testGeneric() { GenericTestsMatrix64F g; g = new GenericTestsMatrix64F() { protected RealMatrix64F createMatrix(int numRows, int numCols) { return new BlockD3Matrix64F(numRows,numCols,10); } }; g.allTests(); } }ejml-0.28/main/experimental/test/org/ejml/data/TestDenseD2Matrix64F.java000066400000000000000000000021441256171534400260260ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.data; import org.junit.Test; /** * @author Peter Abeles */ public class TestDenseD2Matrix64F { @Test public void testGeneric() { GenericTestsMatrix64F g; g = new GenericTestsMatrix64F() { protected RealMatrix64F createMatrix(int numRows, int numCols) { return new DenseD2Matrix64F(numRows,numCols); } }; g.allTests(); } }ejml-0.28/main/simple/000077500000000000000000000000001256171534400146175ustar00rootroot00000000000000ejml-0.28/main/simple/EJML Simple.iml000066400000000000000000000043061256171534400172660ustar00rootroot00000000000000 ejml-0.28/main/simple/build.gradle000066400000000000000000000002771256171534400171040ustar00rootroot00000000000000dependencies { compile project(':main:core') compile project(':main:dense64') testCompile project(':main:experimental') } idea { module { name = "EJML Simple" } }ejml-0.28/main/simple/src/000077500000000000000000000000001256171534400154065ustar00rootroot00000000000000ejml-0.28/main/simple/src/org/000077500000000000000000000000001256171534400161755ustar00rootroot00000000000000ejml-0.28/main/simple/src/org/ejml/000077500000000000000000000000001256171534400171245ustar00rootroot00000000000000ejml-0.28/main/simple/src/org/ejml/simple/000077500000000000000000000000001256171534400204155ustar00rootroot00000000000000ejml-0.28/main/simple/src/org/ejml/simple/SimpleBase.java000066400000000000000000000764711256171534400233230ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.simple; import org.ejml.UtilEjml; import org.ejml.alg.dense.mult.VectorVectorMult; import org.ejml.data.DenseMatrix64F; import org.ejml.data.MatrixIterator64F; import org.ejml.data.RealMatrix64F; import org.ejml.factory.SingularMatrixException; import org.ejml.ops.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.io.Serializable; /** * Parent of {@link SimpleMatrix} implements all the standard matrix operations and uses * generics to allow the returned matrix type to be changed. This class should be extended * instead of SimpleMatrix. * * @author Peter Abeles */ @SuppressWarnings({"unchecked"}) public abstract class SimpleBase implements Serializable { /** * Internal matrix which this is a wrapper around. */ protected DenseMatrix64F mat; public SimpleBase( int numRows , int numCols ) { mat = new DenseMatrix64F(numRows, numCols); } protected SimpleBase() { } /** * Used internally for creating new instances of SimpleMatrix. If SimpleMatrix is extended * by another class this function should be overridden so that the returned matrices are * of the correct type. * * @param numRows number of rows in the new matrix. * @param numCols number of columns in the new matrix. * @return A new matrix. */ protected abstract T createMatrix( int numRows , int numCols ); /** *

* Returns a reference to the matrix that it uses internally. This is useful * when an operation is needed that is not provided by this class. *

* * @return Reference to the internal DenseMatrix64F. */ public DenseMatrix64F getMatrix() { return mat; } /** *

* Returns the transpose of this matrix.
* aT *

* * @see org.ejml.ops.CommonOps#transpose(DenseMatrix64F,DenseMatrix64F) * * @return A matrix that is n by m. */ public T transpose() { T ret = createMatrix(mat.numCols,mat.numRows); CommonOps.transpose(mat,ret.getMatrix()); return ret; } /** *

* Returns a matrix which is the result of matrix multiplication:
*
* c = a * b
*
* where c is the returned matrix, a is this matrix, and b is the passed in matrix. *

* * @see CommonOps#mult(org.ejml.data.RowD1Matrix64F , org.ejml.data.RowD1Matrix64F , org.ejml.data.RowD1Matrix64F) * * @param b A matrix that is n by bn. Not modified. * * @return The results of this operation. */ public T mult( T b ) { T ret = createMatrix(mat.numRows,b.getMatrix().numCols); CommonOps.mult(mat,b.getMatrix(),ret.getMatrix()); return ret; } /** *

* Computes the Kronecker product between this matrix and the provided B matrix:
*
* C = kron(A,B) *

* @see CommonOps#kron(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F) * * @param B The right matrix in the operation. Not modified. * @return Kronecker product between this matrix and B. */ public T kron( T B ) { T ret = createMatrix(mat.numRows*B.numRows(),mat.numCols*B.numCols()); CommonOps.kron(mat,B.getMatrix(),ret.getMatrix()); return ret; } /** *

* Returns the result of matrix addition:
*
* c = a + b
*
* where c is the returned matrix, a is this matrix, and b is the passed in matrix. *

* * @see CommonOps#mult(org.ejml.data.RowD1Matrix64F , org.ejml.data.RowD1Matrix64F , org.ejml.data.RowD1Matrix64F) * * @param b m by n matrix. Not modified. * * @return The results of this operation. */ public T plus( T b ) { T ret = copy(); CommonOps.addEquals(ret.getMatrix(),b.getMatrix()); return ret; } /** *

* Returns the result of matrix subtraction:
*
* c = a - b
*
* where c is the returned matrix, a is this matrix, and b is the passed in matrix. *

* * @see CommonOps#subtract(org.ejml.data.D1Matrix64F , org.ejml.data.D1Matrix64F , org.ejml.data.D1Matrix64F) * * @param b m by n matrix. Not modified. * * @return The results of this operation. */ public T minus( T b ) { T ret = copy(); CommonOps.subtract(getMatrix(), b.getMatrix(), ret.getMatrix()); return ret; } /** *

* Returns the result of matrix-double subtraction:
*
* c = a - b
*
* where c is the returned matrix, a is this matrix, and b is the passed in double. *

* * @see CommonOps#subtract(org.ejml.data.D1Matrix64F , double , org.ejml.data.D1Matrix64F) * * @param b Value subtracted from each element * * @return The results of this operation. */ public T minus( double b ) { T ret = copy(); CommonOps.subtract(getMatrix(), b, ret.getMatrix()); return ret; } /** *

* Performs a element-wise scale operation.
*
* c = β*a
*
* where c is the returned matrix, a is this matrix. *

* * @see CommonOps#add( org.ejml.data.D1Matrix64F , double , org.ejml.data.D1Matrix64F) * * @param beta Double value * * @return A matrix that contains the results. */ public T plus( double beta ) { T ret = createMatrix(numRows(),numCols()); CommonOps.add(getMatrix(), beta, ret.getMatrix()); return ret; } /** *

* Performs a matrix addition and scale operation.
*
* c = a + β*b
*
* where c is the returned matrix, a is this matrix, and b is the passed in matrix. *

* * @see CommonOps#add( org.ejml.data.D1Matrix64F , double , org.ejml.data.D1Matrix64F , org.ejml.data.D1Matrix64F) * * @param b m by n matrix. Not modified. * * @return A matrix that contains the results. */ public T plus( double beta , T b ) { T ret = copy(); CommonOps.addEquals(ret.getMatrix(),beta,b.getMatrix()); return ret; } /** * Computes the dot product (a.k.a. inner product) between this vector and vector 'v'. * * @param v The second vector in the dot product. Not modified. * @return dot product */ public double dot( T v ) { if( !isVector() ) { throw new IllegalArgumentException("'this' matrix is not a vector."); } else if( !v.isVector() ) { throw new IllegalArgumentException("'v' matrix is not a vector."); } return VectorVectorMult.innerProd(mat,v.getMatrix()); } /** * Returns true if this matrix is a vector. A vector is defined as a matrix * that has either one row or column. * * @return Returns true for vectors and false otherwise. */ public boolean isVector() { return mat.numRows == 1 || mat.numCols == 1; } /** *

* Returns the result of scaling each element by 'val':
* bi,j = val*ai,j *

* * @see CommonOps#scale(double, org.ejml.data.D1Matrix64F) * * @param val The multiplication factor. * @return The scaled matrix. */ public T scale( double val ) { T ret = copy(); CommonOps.scale(val,ret.getMatrix()); return ret; } /** *

* Returns the result of dividing each element by 'val': * bi,j = ai,j/val *

* * @see CommonOps#divide(org.ejml.data.D1Matrix64F,double) * * @param val Divisor. * @return Matrix with its elements divided by the specified value. */ public T divide( double val ) { T ret = copy(); CommonOps.divide(ret.getMatrix(),val); return ret; } /** *

* Returns the inverse of this matrix.
*
* b = a-1
*

* *

* If the matrix could not be inverted then SingularMatrixException is thrown. Even * if no exception is thrown the matrix could still be singular or nearly singular. *

* * @see CommonOps#invert(DenseMatrix64F, DenseMatrix64F) * * @throws org.ejml.factory.SingularMatrixException * * @return The inverse of this matrix. */ public T invert() { T ret = createMatrix(mat.numRows,mat.numCols); if( !CommonOps.invert(mat,ret.getMatrix()) ) { throw new SingularMatrixException(); } if( MatrixFeatures.hasUncountable(ret.getMatrix())) throw new SingularMatrixException("Solution has uncountable numbers"); return ret; } /** *

* Computes the Moore-Penrose pseudo-inverse *

* * @return inverse computed using the pseudo inverse. */ public T pseudoInverse() { T ret = createMatrix(mat.numCols,mat.numRows); CommonOps.pinv(mat,ret.getMatrix()); return ret; } /** *

* Solves for X in the following equation:
*
* x = a-1b
*
* where 'a' is this matrix and 'b' is an n by p matrix. *

* *

* If the system could not be solved then SingularMatrixException is thrown. Even * if no exception is thrown 'a' could still be singular or nearly singular. *

* * @see CommonOps#solve(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F) * * @throws SingularMatrixException * * @param b n by p matrix. Not modified. * @return The solution for 'x' that is n by p. */ public T solve( T b ) { T x = createMatrix(mat.numCols,b.getMatrix().numCols); if( !CommonOps.solve(mat,b.getMatrix(),x.getMatrix()) ) throw new SingularMatrixException(); if( MatrixFeatures.hasUncountable(x.getMatrix()) ) throw new SingularMatrixException("Solution contains uncountable numbers"); return x; } /** * Sets the elements in this matrix to be equal to the elements in the passed in matrix. * Both matrix must have the same dimension. * * @param a The matrix whose value this matrix is being set to. */ public void set( T a ) { mat.set(a.getMatrix()); } /** *

* Sets all the elements in this matrix equal to the specified value.
*
* aij = val
*

* * @see CommonOps#fill(org.ejml.data.D1Matrix64F , double) * * @param val The value each element is set to. */ public void set( double val ) { CommonOps.fill(mat, val); } /** * Sets all the elements in the matrix equal to zero. * * @see CommonOps#fill(org.ejml.data.D1Matrix64F , double) */ public void zero() { mat.zero(); } /** *

* Computes the Frobenius normal of the matrix:
*
* normF = Sqrt{ ∑i=1:mj=1:n { aij2} } *

* * @see org.ejml.ops.NormOps#normF(org.ejml.data.D1Matrix64F) * * @return The matrix's Frobenius normal. */ public double normF() { return NormOps.normF(mat); } /** *

* The condition p = 2 number of a matrix is used to measure the sensitivity of the linear * system Ax=b. A value near one indicates that it is a well conditioned matrix. *

* * @see NormOps#conditionP2(DenseMatrix64F) * * @return The condition number. */ public double conditionP2() { return NormOps.conditionP2(mat); } /** * Computes the determinant of the matrix. * * @see CommonOps#det(DenseMatrix64F) * * @return The determinant. */ public double determinant() { double ret = CommonOps.det(mat); // if the decomposition silently failed then the matrix is most likely singular if(UtilEjml.isUncountable(ret)) return 0; return ret; } /** *

* Computes the trace of the matrix. *

* * @see CommonOps#trace(org.ejml.data.RowD1Matrix64F) * * @return The trace of the matrix. */ public double trace() { return CommonOps.trace(mat); } /** *

* Reshapes the matrix to the specified number of rows and columns. If the total number of elements * is <= number of elements it had before the data is saved. Otherwise a new internal array is * declared and the old data lost. *

* *

* This is equivalent to calling A.getMatrix().reshape(numRows,numCols,false). *

* * @see org.ejml.data.DenseMatrix64F#reshape(int,int,boolean) * * @param numRows The new number of rows in the matrix. * @param numCols The new number of columns in the matrix. */ public void reshape( int numRows , int numCols ) { mat.reshape(numRows,numCols, false); } /** * Assigns the element in the Matrix to the specified value. Performs a bounds check to make sure * the requested element is part of the matrix. * * @param row The row of the element. * @param col The column of the element. * @param value The element's new value. */ public void set( int row , int col , double value ) { mat.set(row,col,value); } /** * Assigns an element a value based on its index in the internal array.. * * @param index The matrix element that is being assigned a value. * @param value The element's new value. */ public void set( int index , double value ) { mat.set(index,value); } /** *

* Assigns consecutive elements inside a row to the provided array.
*
* A(row,offset:(offset + values.length)) = values *

* * @param row The row that the array is to be written to. * @param offset The initial column that the array is written to. * @param values Values which are to be written to the row in a matrix. */ public void setRow( int row , int offset , double ...values ) { for( int i = 0; i < values.length; i++ ) { mat.set(row,offset+i,values[i]); } } /** *

* Assigns consecutive elements inside a column to the provided array.
*
* A(offset:(offset + values.length),column) = values *

* * @param column The column that the array is to be written to. * @param offset The initial column that the array is written to. * @param values Values which are to be written to the row in a matrix. */ public void setColumn( int column , int offset , double ...values ) { for( int i = 0; i < values.length; i++ ) { mat.set(offset+i,column,values[i]); } } /** * Returns the value of the specified matrix element. Performs a bounds check to make sure * the requested element is part of the matrix. * * @param row The row of the element. * @param col The column of the element. * @return The value of the element. */ public double get( int row , int col ) { return mat.get(row,col); } /** * Returns the value of the matrix at the specified index of the 1D row major array. * * @see org.ejml.data.DenseMatrix64F#get(int) * * @param index The element's index whose value is to be returned * @return The value of the specified element. */ public double get( int index ) { return mat.data[ index ]; } /** * Returns the index in the matrix's array. * * @see org.ejml.data.DenseMatrix64F#getIndex(int, int) * * @param row The row number. * @param col The column number. * @return The index of the specified element. */ public int getIndex( int row , int col ) { return row * mat.numCols + col; } /** * Creates a new iterator for traversing through a submatrix inside this matrix. It can be traversed * by row or by column. Range of elements is inclusive, e.g. minRow = 0 and maxRow = 1 will include rows * 0 and 1. The iteration starts at (minRow,minCol) and ends at (maxRow,maxCol) * * @param rowMajor true means it will traverse through the submatrix by row first, false by columns. * @param minRow first row it will start at. * @param minCol first column it will start at. * @param maxRow last row it will stop at. * @param maxCol last column it will stop at. * @return A new MatrixIterator */ public MatrixIterator64F iterator(boolean rowMajor, int minRow, int minCol, int maxRow, int maxCol) { return new MatrixIterator64F(mat,rowMajor, minRow, minCol, maxRow, maxCol); } /** * Creates and returns a matrix which is idential to this one. * * @return A new identical matrix. */ public T copy() { T ret = createMatrix(mat.numRows,mat.numCols); ret.getMatrix().set(this.getMatrix()); return ret; } /** * Returns the number of rows in this matrix. * * @return number of rows. */ public int numRows() { return mat.numRows; } /** * Returns the number of columns in this matrix. * * @return number of columns. */ public int numCols() { return mat.numCols; } /** * Returns the number of elements in this matrix, which is equal to * the number of rows times the number of columns. * * @return The number of elements in the matrix. */ public int getNumElements() { return mat.getNumElements(); } /** * Prints the matrix to standard out. */ public void print() { MatrixIO.print(System.out,mat); } /** * Prints the matrix to standard out with the specified precision. */ public void print(int numChar , int precision) { MatrixIO.print(System.out,mat,numChar,precision); } /** *

* Prints the matrix to standard out given a {@link java.io.PrintStream#printf) style floating point format, * e.g. print("%f"). *

*/ public void print( String format ) { MatrixIO.print(System.out,mat,format); } /** *

* Converts the array into a string format for display purposes. * The conversion is done using {@link MatrixIO#print(java.io.PrintStream, org.ejml.data.RealMatrix64F)}. *

* * @return String representation of the matrix. */ public String toString() { ByteArrayOutputStream stream = new ByteArrayOutputStream(); MatrixIO.print(new PrintStream(stream),mat); return stream.toString(); } /** *

* Creates a new SimpleMatrix which is a submatrix of this matrix. *

*

* si-y0 , j-x0 = oij for all y0 ≤ i < y1 and x0 ≤ j < x1
*
* where 'sij' is an element in the submatrix and 'oij' is an element in the * original matrix. *

* *

* If any of the inputs are set to T.END then it will be set to the last row * or column in the matrix. *

* * @param y0 Start row. * @param y1 Stop row + 1. * @param x0 Start column. * @param x1 Stop column + 1. * @return The submatrix. */ public T extractMatrix(int y0 , int y1, int x0 , int x1 ) { if( y0 == SimpleMatrix.END ) y0 = mat.numRows; if( y1 == SimpleMatrix.END ) y1 = mat.numRows; if( x0 == SimpleMatrix.END ) x0 = mat.numCols; if( x1 == SimpleMatrix.END ) x1 = mat.numCols; T ret = createMatrix(y1-y0,x1-x0); CommonOps.extract(mat,y0,y1,x0,x1,ret.getMatrix(),0,0); return ret; } /** *

* Extracts a row or column from this matrix. The returned vector will either be a row * or column vector depending on the input type. *

* * @param extractRow If true a row will be extracted. * @param element The row or column the vector is contained in. * @return Extracted vector. */ public T extractVector( boolean extractRow , int element ) { int length = extractRow ? mat.numCols : mat.numRows; T ret = extractRow ? createMatrix(1,length) : createMatrix(length,1); if( extractRow ) { SpecializedOps.subvector(mat,element,0,length,true,0,ret.getMatrix()); } else { SpecializedOps.subvector(mat,0,element,length,false,0,ret.getMatrix()); } return ret; } /** *

* Extracts the diagonal from this matrix and returns them inside a column vector. *

* * @see org.ejml.ops.CommonOps#extractDiag(DenseMatrix64F, DenseMatrix64F) * @return Diagonal elements inside a column vector. */ public T extractDiag() { int N = Math.min(mat.numCols,mat.numRows); T diag = createMatrix(N,1); CommonOps.extractDiag(mat,diag.getMatrix()); return diag; } /** * Checks to see if matrix 'a' is the same as this matrix within the specified * tolerance. * * @param a The matrix it is being compared against. * @param tol How similar they must be to be equals. * @return If they are equal within tolerance of each other. */ public boolean isIdentical(T a, double tol) { return MatrixFeatures.isIdentical(mat,a.getMatrix(),tol); } /** * Checks to see if any of the elements in this matrix are either NaN or infinite. * * @return True of an element is NaN or infinite. False otherwise. */ public boolean hasUncountable() { return MatrixFeatures.hasUncountable(mat); } /** * Computes a full Singular Value Decomposition (SVD) of this matrix with the * eigenvalues ordered from largest to smallest. * * @return SVD */ public SimpleSVD svd() { return new SimpleSVD(mat,false); } /** * Computes the SVD in either compact format or full format. * * @return SVD of this matrix. */ public SimpleSVD svd( boolean compact ) { return new SimpleSVD(mat,compact); } /** * Returns the Eigen Value Decomposition (EVD) of this matrix. */ public SimpleEVD eig() { return new SimpleEVD(mat); } /** * Copy matrix B into this matrix at location (insertRow, insertCol). * * @param insertRow First row the matrix is to be inserted into. * @param insertCol First column the matrix is to be inserted into. * @param B The matrix that is being inserted. */ public void insertIntoThis(int insertRow, int insertCol, T B) { CommonOps.insert(B.getMatrix(), mat, insertRow,insertCol); } /** *

* Creates a new matrix that is a combination of this matrix and matrix B. B is * written into A at the specified location if needed the size of A is increased by * growing it. A is grown by padding the new area with zeros. *

* *

* While useful when adding data to a matrix which will be solved for it is also much * less efficient than predeclaring a matrix and inserting data into it. *

* *

* If insertRow or insertCol is set to SimpleMatrix.END then it will be combined * at the last row or column respectively. *

* * @param insertRow Row where matrix B is written in to. * @param insertCol Column where matrix B is written in to. * @param B The matrix that is written into A. * @return A new combined matrix. */ public T combine( int insertRow, int insertCol, T B) { if( insertRow == SimpleMatrix.END ) { insertRow = mat.numRows; } if( insertCol == SimpleMatrix.END ) { insertCol = mat.numCols; } int maxRow = insertRow + B.numRows(); int maxCol = insertCol + B.numCols(); T ret; if( maxRow > mat.numRows || maxCol > mat.numCols) { int M = Math.max(maxRow,mat.numRows); int N = Math.max(maxCol,mat.numCols); ret = createMatrix(M,N); ret.insertIntoThis(0,0,this); } else { ret = copy(); } ret.insertIntoThis(insertRow,insertCol,B); return ret; } /** * Returns the maximum absolute value of all the elements in this matrix. This is * equivalent the the infinite p-norm of the matrix. * * @return Largest absolute value of any element. */ public double elementMaxAbs() { return CommonOps.elementMaxAbs(mat); } /** * Computes the sum of all the elements in the matrix. * * @return Sum of all the elements. */ public double elementSum() { return CommonOps.elementSum(mat); } /** *

* Returns a matrix which is the result of an element by element multiplication of 'this' and 'b': * ci,j = ai,j*bi,j *

* * @param b A simple matrix. * @return The element by element multiplication of 'this' and 'b'. */ public T elementMult( T b ) { T c = createMatrix(mat.numRows,mat.numCols); CommonOps.elementMult(mat,b.getMatrix(),c.getMatrix()); return c; } /** *

* Returns a matrix which is the result of an element by element division of 'this' and 'b': * ci,j = ai,j/bi,j *

* * @param b A simple matrix. * @return The element by element division of 'this' and 'b'. */ public T elementDiv( T b ) { T c = createMatrix(mat.numRows,mat.numCols); CommonOps.elementDiv(mat, b.getMatrix(), c.getMatrix()); return c; } /** *

* Returns a matrix which is the result of an element by element power of 'this' and 'b': * ci,j = ai,j ^ bi,j *

* * @param b A simple matrix. * @return The element by element power of 'this' and 'b'. */ public T elementPower( T b ) { T c = createMatrix(mat.numRows,mat.numCols); CommonOps.elementPower(mat, b.getMatrix(), c.getMatrix()); return c; } /** *

* Returns a matrix which is the result of an element by element power of 'this' and 'b': * ci,j = ai,j ^ b *

* * @param b Scalar * @return The element by element power of 'this' and 'b'. */ public T elementPower( double b ) { T c = createMatrix(mat.numRows,mat.numCols); CommonOps.elementPower(mat, b, c.getMatrix()); return c; } /** *

* Returns a matrix which is the result of an element by element exp of 'this' * ci,j = Math.exp(ai,j) *

* * @return The element by element power of 'this' and 'b'. */ public T elementExp() { T c = createMatrix(mat.numRows,mat.numCols); CommonOps.elementExp(mat, c.getMatrix()); return c; } /** *

* Returns a matrix which is the result of an element by element exp of 'this' * ci,j = Math.log(ai,j) *

* * @return The element by element power of 'this' and 'b'. */ public T elementLog() { T c = createMatrix(mat.numRows,mat.numCols); CommonOps.elementLog(mat, c.getMatrix()); return c; } /** *

* Returns a new matrix whose elements are the negative of 'this' matrix's elements.
*
* bij = -aij *

* * @return A matrix that is the negative of the original. */ public T negative() { T A = copy(); CommonOps.changeSign(A.getMatrix()); return A; } /** *

* Saves this matrix to a file as a serialized binary object. *

* * @see MatrixIO#saveBin( org.ejml.data.RealMatrix64F, String) * * @param fileName * @throws java.io.IOException */ public void saveToFileBinary( String fileName ) throws IOException { MatrixIO.saveBin(mat, fileName); } /** *

* Loads a new matrix from a serialized binary file. *

* * @see MatrixIO#loadBin(String) * * @param fileName File which is to be loaded. * @return The matrix. * @throws IOException */ public static SimpleMatrix loadBinary( String fileName ) throws IOException { RealMatrix64F mat = MatrixIO.loadBin(fileName); // see if its a DenseMatrix64F if( mat instanceof DenseMatrix64F ) { return SimpleMatrix.wrap((DenseMatrix64F)mat); } else { // if not convert it into one and wrap it return SimpleMatrix.wrap( new DenseMatrix64F(mat)); } } /** *

* Saves this matrix to a file in a CSV format. For the file format see {@link MatrixIO}. *

* * @see MatrixIO#saveBin( org.ejml.data.RealMatrix64F, String) * * @param fileName * @throws java.io.IOException */ public void saveToFileCSV( String fileName ) throws IOException { MatrixIO.saveCSV(mat, fileName); } /** *

* Loads a new matrix from a CSV file. For the file format see {@link MatrixIO}. *

* * @see MatrixIO#loadCSV(String) * * @param fileName File which is to be loaded. * @return The matrix. * @throws IOException */ public T loadCSV( String fileName ) throws IOException { RealMatrix64F mat = MatrixIO.loadCSV(fileName); T ret = createMatrix(1,1); // see if its a DenseMatrix64F if( mat instanceof DenseMatrix64F ) { ret.mat = (DenseMatrix64F)mat; } else { // if not convert it into one and wrap it ret.mat = new DenseMatrix64F(mat); } return ret; } /** * Returns true of the specified matrix element is valid element inside this matrix. * * @param row Row index. * @param col Column index. * @return true if it is a valid element in the matrix. */ public boolean isInBounds(int row, int col) { return row >= 0 && col >= 0 && row < mat.numRows && col < mat.numCols; } /** * Prints the number of rows and column in this matrix. */ public void printDimensions() { System.out.println("[rows = "+numRows()+" , cols = "+numCols()+" ]"); } } ejml-0.28/main/simple/src/org/ejml/simple/SimpleEVD.java000066400000000000000000000111251256171534400230500ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.simple; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.EigenDecomposition; /** * Wrapper around EigenDecomposition for SimpleMatrix * * @author Peter Abeles */ @SuppressWarnings({"unchecked"}) public class SimpleEVD { private EigenDecomposition eig; DenseMatrix64F mat; public SimpleEVD( DenseMatrix64F mat ) { this.mat = mat; eig = DecompositionFactory.eig(mat.numCols,true); if( !eig.decompose(mat)) throw new RuntimeException("Eigenvalue Decomposition failed"); } /** * Returns the number of eigenvalues/eigenvectors. This is the matrix's dimension. * * @return number of eigenvalues/eigenvectors. */ public int getNumberOfEigenvalues() { return eig.getNumberOfEigenvalues(); } /** *

* Returns an eigenvalue as a complex number. For symmetric matrices the returned eigenvalue will always be a real * number, which means the imaginary component will be equal to zero. *

* *

* NOTE: The order of the eigenvalues is dependent upon the decomposition algorithm used. This means that they may * or may not be ordered by magnitude. For example the QR algorithm will returns results that are partially * ordered by magnitude, but this behavior should not be relied upon. *

* * @param index Index of the eigenvalue eigenvector pair. * @return An eigenvalue. */ public Complex64F getEigenvalue( int index ) { return eig.getEigenvalue(index); } /** *

* Used to retrieve real valued eigenvectors. If an eigenvector is associated with a complex eigenvalue * then null is returned instead. *

* * @param index Index of the eigenvalue eigenvector pair. * @return If the associated eigenvalue is real then an eigenvector is returned, null otherwise. */ public T getEigenVector( int index ) { return (T)SimpleMatrix.wrap(eig.getEigenVector(index)); } /** *

* Computes the quality of the computed decomposition. A value close to or less than 1e-15 * is considered to be within machine precision. *

* *

* This function must be called before the original matrix has been modified or else it will * produce meaningless results. *

* * @return Quality of the decomposition. */ public double quality() { return DecompositionFactory.quality(mat,eig); } /** * Returns the underlying decomposition that this is a wrapper around. * * @return EigenDecomposition */ public EigenDecomposition getEVD() { return eig; } /** * Returns the index of the eigenvalue which has the largest magnitude. * * @return index of the largest magnitude eigen value. */ public int getIndexMax() { int indexMax = 0; double max = getEigenvalue(0).getMagnitude2(); final int N = getNumberOfEigenvalues(); for( int i = 1; i < N; i++ ) { double m = getEigenvalue(i).getMagnitude2(); if( m > max ) { max = m; indexMax = i; } } return indexMax; } /** * Returns the index of the eigenvalue which has the smallest magnitude. * * @return index of the smallest magnitude eigen value. */ public int getIndexMin() { int indexMin = 0; double min = getEigenvalue(0).getMagnitude2(); final int N = getNumberOfEigenvalues(); for( int i = 1; i < N; i++ ) { double m = getEigenvalue(i).getMagnitude2(); if( m < min ) { min = m; indexMin = i; } } return indexMin; } }ejml-0.28/main/simple/src/org/ejml/simple/SimpleMatrix.java000066400000000000000000000275451256171534400237130ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.simple; import org.ejml.alg.generic.GenericMatrixOps; import org.ejml.data.DenseMatrix64F; import org.ejml.data.RealMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.CovarianceRandomDraw; import org.ejml.ops.RandomMatrices; import java.util.Random; /** *

* {@link SimpleMatrix} is a wrapper around {@link org.ejml.data.DenseMatrix64F} that provides an * easy to use object oriented interface for performing matrix operations. It is designed to be * more accessible to novice programmers and provide a way to rapidly code up solutions by simplifying * memory management and providing easy to use functions. *

* *

* Most functions in SimpleMatrix do not modify the original matrix. Instead they * create a new SimpleMatrix instance which is modified and returned. This greatly simplifies memory * management and writing of code in general. It also allows operations to be chained, as is shown * below:
*
* SimpleMatrix K = P.mult(H.transpose().mult(S.invert())); *

* *

* Working with both {@link org.ejml.data.DenseMatrix64F} and SimpleMatrix in the same code base is easy. * To access the internal DenseMatrix64F in a SimpleMatrix simply call {@link SimpleMatrix#getMatrix()}. * To turn a DenseMatrix64F into a SimpleMatrix use {@link SimpleMatrix#wrap(org.ejml.data.DenseMatrix64F)}. Not * all operations in EJML are provided for SimpleMatrix, but can be accessed by extracting the internal * DenseMatrix64F. *

* *

* EXTENDING: SimpleMatrix contains a list of narrowly focused functions for linear algebra. To harness * the functionality for another application and to the number of functions it supports it is recommended * that one extends {@link SimpleBase} instead. This way the returned matrix type's of SimpleMatrix functions * will be of the appropriate types. See StatisticsMatrix inside of the examples directory. *

* *

* PERFORMANCE: The disadvantage of using this class is that it is more resource intensive, since * it creates a new matrix each time an operation is performed. This makes the JavaVM work harder and * Java automatically initializes the matrix to be all zeros. Typically operations on small matrices * or operations that have a runtime linear with the number of elements are the most affected. More * computationally intensive operations have only a slight unnoticeable performance loss. MOST PEOPLE * SHOULD NOT WORRY ABOUT THE SLIGHT LOSS IN PERFORMANCE. *

* *

* It is hard to judge how significant the performance hit will be in general. Often the performance * hit is insignificant since other parts of the application are more processor intensive or the bottle * neck is a more computationally complex operation. The best approach is benchmark and then optimize the code. *

* *

* If SimpleMatrix is extended then the protected function {link #createMatrix} should be extended and return * the child class. The results of SimpleMatrix operations will then be of the correct matrix type. *

* *

* The object oriented approach used in SimpleMatrix was originally inspired by Jama. * http://math.nist.gov/javanumerics/jama/ *

* * @author Peter Abeles */ public class SimpleMatrix extends SimpleBase { /** * A simplified way to reference the last row or column in the matrix for some functions. */ public static final int END = Integer.MAX_VALUE; /** *

* Creates a new matrix which has the same value as the matrix encoded in the * provided array. The input matrix's format can either be row-major or * column-major. *

* *

* Note that 'data' is a variable argument type, so either 1D arrays or a set of numbers can be * passed in:
* SimpleMatrix a = new SimpleMatrix(2,2,true,new double[]{1,2,3,4});
* SimpleMatrix b = new SimpleMatrix(2,2,true,1,2,3,4);
*
* Both are equivalent. *

* * @see DenseMatrix64F#DenseMatrix64F(int, int, boolean, double...) * * @param numRows The number of rows. * @param numCols The number of columns. * @param rowMajor If the array is encoded in a row-major or a column-major format. * @param data The formatted 1D array. Not modified. */ public SimpleMatrix(int numRows, int numCols, boolean rowMajor, double ...data) { mat = new DenseMatrix64F(numRows,numCols, rowMajor, data); } /** *

* Creates a matrix with the values and shape defined by the 2D array 'data'. * It is assumed that 'data' has a row-major formatting:
*
* data[ row ][ column ] *

* * @see org.ejml.data.DenseMatrix64F#DenseMatrix64F(double[][]) * * @param data 2D array representation of the matrix. Not modified. */ public SimpleMatrix(double data[][]) { mat = new DenseMatrix64F(data); } /** * Creates a new matrix that is initially set to zero with the specified dimensions. * * @see org.ejml.data.DenseMatrix64F#DenseMatrix64F(int, int) * * @param numRows The number of rows in the matrix. * @param numCols The number of columns in the matrix. */ public SimpleMatrix(int numRows, int numCols) { mat = new DenseMatrix64F(numRows, numCols); } /** * Creats a new SimpleMatrix which is identical to the original. * * @param orig The matrix which is to be copied. Not modified. */ public SimpleMatrix( SimpleMatrix orig ) { this.mat = orig.mat.copy(); } /** * Creates a new SimpleMatrix which is a copy of the DenseMatrix64F. * * @param orig The original matrix whose value is copied. Not modified. */ public SimpleMatrix( DenseMatrix64F orig ) { this.mat = orig.copy(); } /** * Creates a new SimpleMatrix which is a copy of the Matrix64F. * * @param orig The original matrix whose value is copied. Not modified. */ public SimpleMatrix( RealMatrix64F orig ) { this.mat = new DenseMatrix64F(orig.getNumRows(),orig.getNumCols()); GenericMatrixOps.copy(orig,mat); } /** * Constructor for internal library use only. Nothing is configured and is intended for serialization. */ public SimpleMatrix(){} /** * Creates a new SimpleMatrix with the specified DenseMatrix64F used as its internal matrix. This means * that the reference is saved and calls made to the returned SimpleMatrix will modify the passed in DenseMatrix64F. * * @param internalMat The internal DenseMatrix64F of the returned SimpleMatrix. Will be modified. */ public static SimpleMatrix wrap( DenseMatrix64F internalMat ) { SimpleMatrix ret = new SimpleMatrix(); ret.mat = internalMat; return ret; } /** * Creates a new identity matrix with the specified size. * * @see org.ejml.ops.CommonOps#identity(int) * * @param width The width and height of the matrix. * @return An identity matrix. */ public static SimpleMatrix identity( int width ) { SimpleMatrix ret = new SimpleMatrix(width,width); CommonOps.setIdentity(ret.mat); return ret; } /** *

* Creates a matrix where all but the diagonal elements are zero. The values * of the diagonal elements are specified by the parameter 'vals'. *

* *

* To extract the diagonal elements from a matrix see {@link #extractDiag()}. *

* * @see org.ejml.ops.CommonOps#diag(double...) * * @param vals The values of the diagonal elements. * @return A diagonal matrix. */ public static SimpleMatrix diag( double ...vals ) { DenseMatrix64F m = CommonOps.diag(vals); SimpleMatrix ret = wrap(m); return ret; } /** *

* Creates a new SimpleMatrix with random elements drawn from a uniform distribution from minValue to maxValue. *

* * @see org.ejml.ops.RandomMatrices#setRandom(DenseMatrix64F,java.util.Random) * * @param numRows The number of rows in the new matrix * @param numCols The number of columns in the new matrix * @param minValue Lower bound * @param maxValue Upper bound * @param rand The random number generator that's used to fill the matrix. @return The new random matrix. */ public static SimpleMatrix random(int numRows, int numCols, double minValue, double maxValue, Random rand) { SimpleMatrix ret = new SimpleMatrix(numRows,numCols); RandomMatrices.setRandom(ret.mat,minValue,maxValue,rand); return ret; } /** *

* Creates a new vector which is drawn from a multivariate normal distribution with zero mean * and the provided covariance. *

* * @see CovarianceRandomDraw * * @param covariance Covariance of the multivariate normal distribution * @return Vector randomly drawn from the distribution */ public static SimpleMatrix randomNormal( SimpleMatrix covariance , Random random ) { CovarianceRandomDraw draw = new CovarianceRandomDraw(random,covariance.getMatrix()); SimpleMatrix found = new SimpleMatrix(covariance.numRows(),1); draw.next(found.getMatrix()); return found; } /** * @inheritdoc */ @Override protected SimpleMatrix createMatrix( int numRows , int numCols ) { return new SimpleMatrix(numRows,numCols); } // TODO should this function be added back? It makes the code hard to read when its used // /** // *

// * Performs one of the following matrix multiplication operations:
// *
// * c = a * b
// * c = aT * b
// * c = a * b T
// * c = aT * b T
// *
// * where c is the returned matrix, a is this matrix, and b is the passed in matrix. // *

// * // * @see CommonOps#mult(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F) // * @see CommonOps#multTransA(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F) // * @see CommonOps#multTransB(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F) // * @see CommonOps#multTransAB(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F) // * // * @param tranA If true matrix A is transposed. // * @param tranB If true matrix B is transposed. // * @param b A matrix that is n by bn. Not modified. // * // * @return The results of this operation. // */ // public SimpleMatrix mult( boolean tranA , boolean tranB , SimpleMatrix b) { // SimpleMatrix ret; // // if( tranA && tranB ) { // ret = createMatrix(mat.numCols,b.mat.numRows); // CommonOps.multTransAB(mat,b.mat,ret.mat); // } else if( tranA ) { // ret = createMatrix(mat.numCols,b.mat.numCols); // CommonOps.multTransA(mat,b.mat,ret.mat); // } else if( tranB ) { // ret = createMatrix(mat.numRows,b.mat.numRows); // CommonOps.multTransB(mat,b.mat,ret.mat); // } else { // ret = createMatrix(mat.numRows,b.mat.numCols); // CommonOps.mult(mat,b.mat,ret.mat); // } // // return ret; // } } ejml-0.28/main/simple/src/org/ejml/simple/SimpleSVD.java000066400000000000000000000115401256171534400230670ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.simple; import org.ejml.UtilEjml; import org.ejml.data.DenseMatrix64F; import org.ejml.factory.DecompositionFactory; import org.ejml.interfaces.decomposition.SingularValueDecomposition; import org.ejml.ops.SingularOps; /** *

* Wrapper around SVD for simple matrix. See {@link SingularValueDecomposition} for more details. *

*

* SVD is defined as the following decomposition:
*

A = U * W * V T

* where A is m by n, and U and V are orthogonal matrices, and W is a diagonal matrix *

* *

* Tolerance for singular values is * Math.max(mat.numRows,mat.numCols) * W.get(0,0) * UtilEjml.EPS; * where W.get(0,0) is the largest singular value. *

* * @author Peter Abeles */ @SuppressWarnings({"unchecked"}) public class SimpleSVD { private SingularValueDecomposition svd; private T U; private T W; private T V; private DenseMatrix64F mat; // tolerance for singular values double tol; public SimpleSVD( DenseMatrix64F mat , boolean compact ) { this.mat = mat; svd = DecompositionFactory.svd(mat.numRows,mat.numCols,true,true,compact); if( !svd.decompose(mat) ) throw new RuntimeException("Decomposition failed"); U = (T)SimpleMatrix.wrap(svd.getU(null,false)); W = (T)SimpleMatrix.wrap(svd.getW(null)); V = (T)SimpleMatrix.wrap(svd.getV(null,false)); // order singular values from largest to smallest SingularOps.descendingOrder(U.getMatrix(),false,W.getMatrix(),V.getMatrix(),false); tol = SingularOps.singularThreshold(svd); } /** *

* Returns the orthogonal 'U' matrix. *

* * @return An orthogonal m by m matrix. */ public T getU() { return U; } /** * Returns a diagonal matrix with the singular values. The singular values are ordered * from largest to smallest. * * @return Diagonal matrix with singular values along the diagonal. */ public T getW() { return W; } /** *

* Returns the orthogonal 'V' matrix. *

* * @return An orthogonal n by n matrix. */ public T getV() { return V; } /** *

* Computes the quality of the computed decomposition. A value close to or less than 1e-15 * is considered to be within machine precision. *

* *

* This function must be called before the original matrix has been modified or else it will * produce meaningless results. *

* * @return Quality of the decomposition. */ public double quality() { return DecompositionFactory.quality(mat,U.getMatrix(),W.getMatrix(),V.transpose().getMatrix()); } /** * Computes the null space from an SVD. For more information see {@link SingularOps#nullSpace}. * @return Null space vector. */ public SimpleMatrix nullSpace() { // TODO take advantage of the singular values being ordered already return SimpleMatrix.wrap(SingularOps.nullSpace(svd,null,tol)); } /** * Returns the specified singular value. * * @param index Which singular value is to be returned. * @return A singular value. */ public double getSingleValue( int index ) { return W.get(index,index); } /** * Returns the rank of the decomposed matrix. * * @see SingularOps#rank(org.ejml.interfaces.decomposition.SingularValueDecomposition, double) * * @return The matrix's rank */ public int rank() { return SingularOps.rank(svd,tol); } /** * The nullity of the decomposed matrix. * * @see SingularOps#nullity(org.ejml.interfaces.decomposition.SingularValueDecomposition, double) * * @return The matrix's nullity */ public int nullity() { return SingularOps.nullity(svd,10.0*UtilEjml.EPS); } /** * Returns the underlying decomposition that this is a wrapper around. * * @return SingularValueDecomposition */ public SingularValueDecomposition getSVD() { return svd; } } ejml-0.28/main/simple/src/org/ejml/simple/SimpleUnitTests.java000066400000000000000000000053151256171534400244000ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.simple; import org.ejml.ops.EjmlUnitTests; /** * Unit testing functions for {@link SimpleMatrix} * * @author Peter Abeles */ public class SimpleUnitTests { /** * Checks to see if every element in A is countable. A doesn't have any element with * a value of NaN or infinite. * * @param A Matrix */ public static void assertCountable( SimpleMatrix A ) { EjmlUnitTests.assertCountable(A.getMatrix()); } /** *

* Checks to see if A and B have the same shape. *

* * @param A Matrix * @param B Matrix */ public static void assertShape( SimpleMatrix A , SimpleMatrix B ) { EjmlUnitTests.assertShape(A.getMatrix(), B.getMatrix()); } /** *

* Checks to see if each element in the matrix is within tolerance of each other: *

* *

* The two matrices are identical with in tolerance if:
* |aij - bij| ≤ tol *

* *

* In addition if an element is NaN or infinite in one matrix it must be the same in the other. *

* * @param A Matrix A * @param B Matrix B * @param tol Tolerance */ public static void assertEqualsUncountable( SimpleMatrix A , SimpleMatrix B , double tol ) { EjmlUnitTests.assertEqualsUncountable(A.getMatrix(), B.getMatrix(), tol); } /** *

* Checks to see if each element in the matrices are within tolerance of each other and countable: *

* *

* The two matrices are identical with in tolerance if:
* |aij - bij| ≤ tol *

* *

* The test will fail if any element in either matrix is NaN or infinite. *

* * @param A Matrix A * @param B Matrix B * @param tol Tolerance */ public static void assertEquals( SimpleMatrix A , SimpleMatrix B , double tol ) { EjmlUnitTests.assertEquals(A.getMatrix(), B.getMatrix(), tol); } } ejml-0.28/main/simple/src/org/ejml/simple/UtilSimpleMatrix.java000066400000000000000000000023611256171534400245360ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.simple; import org.ejml.data.BlockMatrix64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.ConvertMatrixType; /** * @author Peter Abeles */ public class UtilSimpleMatrix { /** *

Converts the block matrix into a SimpleMatrix.

* * @param A Block matrix that is being converted. Not modified. * @return Equivalent SimpleMatrix. */ public static SimpleMatrix convertSimple( BlockMatrix64F A ) { DenseMatrix64F B = ConvertMatrixType.convert(A, null); return SimpleMatrix.wrap(B); } } ejml-0.28/main/simple/test/000077500000000000000000000000001256171534400155765ustar00rootroot00000000000000ejml-0.28/main/simple/test/org/000077500000000000000000000000001256171534400163655ustar00rootroot00000000000000ejml-0.28/main/simple/test/org/ejml/000077500000000000000000000000001256171534400173145ustar00rootroot00000000000000ejml-0.28/main/simple/test/org/ejml/simple/000077500000000000000000000000001256171534400206055ustar00rootroot00000000000000ejml-0.28/main/simple/test/org/ejml/simple/TestSimpleMatrix.java000066400000000000000000000512251256171534400247330ustar00rootroot00000000000000/* * Copyright (c) 2009-2014, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ejml.simple; import org.ejml.data.Complex64F; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.EjmlUnitTests; import org.ejml.ops.NormOps; import org.ejml.ops.RandomMatrices; import org.junit.Test; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ public class TestSimpleMatrix { Random rand = new Random(76343); @Test public void randomNormal() { SimpleMatrix Q = SimpleMatrix.diag(5,3,12); Q.set(0,1,0.5); Q.set(1,0,0.5); int N = 200; double sum[] = new double[3]; for (int i = 0; i < N; i++) { SimpleMatrix x = SimpleMatrix.randomNormal(Q,rand); for (int j = 0; j < x.getNumElements(); j++) { sum[j] += x.get(j); } } for (int i = 0; i < sum.length; i++) { sum[i] /= N; assertTrue(sum[i]!=0); assertEquals(0,sum[i],0.3); } } @Test public void constructor_1d_array() { double d[] = new double[]{2,5,3,9,-2,6,7,4}; SimpleMatrix s = new SimpleMatrix(3,2, true, d); DenseMatrix64F m = new DenseMatrix64F(3,2, true, d); EjmlUnitTests.assertEquals(m,s.getMatrix(),1e-8); } @Test public void constructor_2d_array() { double d[][] = new double[][]{{1,2},{3,4},{5,6}}; SimpleMatrix s = new SimpleMatrix(d); DenseMatrix64F mat = new DenseMatrix64F(d); EjmlUnitTests.assertEquals(mat,s.getMatrix(),1e-8); } @Test public void constructor_dense() { DenseMatrix64F mat = RandomMatrices.createRandom(3,2,rand); SimpleMatrix s = new SimpleMatrix(mat); assertTrue( mat != s.getMatrix() ); EjmlUnitTests.assertEquals(mat,s.getMatrix(),1e-8); } @Test public void constructor_simple() { SimpleMatrix orig = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix copy = new SimpleMatrix(orig); assertTrue(orig.mat != copy.mat); EjmlUnitTests.assertEquals(orig.mat,copy.mat,1e-8); } @Test public void wrap() { DenseMatrix64F mat = RandomMatrices.createRandom(3,2,rand); SimpleMatrix s = SimpleMatrix.wrap(mat); assertTrue(s.mat == mat); } @Test public void identity() { SimpleMatrix s = SimpleMatrix.identity(3); DenseMatrix64F d = CommonOps.identity(3); EjmlUnitTests.assertEquals(d,s.mat,1e-8); } @Test public void getMatrix() { SimpleMatrix s = new SimpleMatrix(3,2); // make sure a new instance isn't returned assertTrue(s.mat == s.getMatrix()); } @Test public void transpose() { SimpleMatrix orig = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix tran = orig.transpose(); DenseMatrix64F dTran = new DenseMatrix64F(2,3); CommonOps.transpose(orig.mat,dTran); EjmlUnitTests.assertEquals(dTran,tran.mat,1e-8); } @Test public void mult() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(2,3, 0, 1, rand); SimpleMatrix c = a.mult(b); DenseMatrix64F c_dense = new DenseMatrix64F(3,3); CommonOps.mult(a.mat,b.mat,c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void kron() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(2,3, 0, 1, rand); SimpleMatrix c = a.kron(b); DenseMatrix64F c_dense = new DenseMatrix64F(6,6); CommonOps.kron(a.getMatrix(),b.getMatrix(),c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } // @Test // public void mult_trans() { // SimpleMatrix a = SimpleMatrix.random(3,2,rand); // SimpleMatrix b = SimpleMatrix.random(2,3,rand); // SimpleMatrix c; // // DenseMatrix64F c_dense = new DenseMatrix64F(3,3); // CommonOps.mult(a.mat,b.mat,c_dense); // // c = a.mult(false,false,b); // EjmlUnitTests.assertEquals(c_dense,c.mat); // c = a.transpose().mult(true,false,b); // EjmlUnitTests.assertEquals(c_dense,c.mat); // c = a.mult(false,true,b.transpose()); // EjmlUnitTests.assertEquals(c_dense,c.mat); // c = a.transpose().mult(true,true,b.transpose()); // EjmlUnitTests.assertEquals(c_dense,c.mat); // } @Test public void plus() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix c = a.plus(b); DenseMatrix64F c_dense = new DenseMatrix64F(3,2); CommonOps.add(a.mat,b.mat,c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void plus_scalar() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); double b = 2.5; SimpleMatrix c = a.plus(b); DenseMatrix64F c_dense = new DenseMatrix64F(3,2); CommonOps.add(a.mat,b,c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void dot() { SimpleMatrix a = SimpleMatrix.random(10,1,-1,1,rand); SimpleMatrix b = SimpleMatrix.random(10,1,-1,1,rand); double expected = 0; for( int i = 0; i < 10; i++ ) expected += a.get(i)*b.get(i); double found = a.dot(b); assertEquals(expected,found,1e-8); } @Test public void isVector() { assertTrue(new SimpleMatrix(1,1).isVector()); assertTrue(new SimpleMatrix(1,10).isVector()); assertTrue(new SimpleMatrix(10,1).isVector()); assertFalse(new SimpleMatrix(6,5).isVector()); } @Test public void minus_matrix_matrix() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix c = a.minus(b); DenseMatrix64F c_dense = new DenseMatrix64F(3,2); CommonOps.subtract(a.mat, b.mat, c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void minus_matrix_scalar() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); double b = 0.14; SimpleMatrix c = a.minus(b); DenseMatrix64F c_dense = new DenseMatrix64F(3,2); CommonOps.subtract(a.mat, b, c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void plus_beta() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix c = a.plus(2.5, b); DenseMatrix64F c_dense = new DenseMatrix64F(3,2); CommonOps.add(a.mat, 2.5, b.mat, c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void invert() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); SimpleMatrix inv = a.invert(); DenseMatrix64F d_inv = new DenseMatrix64F(3,3); CommonOps.invert(a.mat,d_inv); EjmlUnitTests.assertEquals(d_inv,inv.mat,1e-8); } @Test public void invert_NaN_INFINITY() { SimpleMatrix a = new SimpleMatrix(3,3); try { a.set(Double.NaN); a.invert(); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { a.set(Double.POSITIVE_INFINITY); a.invert(); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } @Test public void pseudoInverse() { // first test it against a non-square zero matrix SimpleMatrix inv = new SimpleMatrix(3,4).pseudoInverse(); assertEquals(0,inv.normF(),1e-8); // now try it against a more standard matrix SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); inv = a.pseudoInverse(); DenseMatrix64F d_inv = new DenseMatrix64F(3,3); CommonOps.invert(a.mat,d_inv); EjmlUnitTests.assertEquals(d_inv,inv.mat,1e-8); } @Test public void solve() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix c = a.solve(b); DenseMatrix64F c_dense = new DenseMatrix64F(3,2); CommonOps.solve(a.mat,b.mat,c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void solve_NaN_INFINITY() { SimpleMatrix a = new SimpleMatrix(3,3); SimpleMatrix b = SimpleMatrix.random(3,2, 0, 1, rand); try { a.set(Double.NaN); a.solve(b); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} try { a.set(Double.POSITIVE_INFINITY); a.solve(b); fail("Should have thrown an exception"); } catch( RuntimeException ignore ) {} } /** * See if it solves an over determined system correctly */ @Test public void solve_notsquare() { SimpleMatrix a = SimpleMatrix.random(6,3, 0, 1, rand); SimpleMatrix b = SimpleMatrix.random(6,2, 0, 1, rand); SimpleMatrix c = a.solve(b); DenseMatrix64F c_dense = new DenseMatrix64F(3,2); CommonOps.solve(a.mat,b.mat,c_dense); EjmlUnitTests.assertEquals(c_dense,c.mat,1e-8); } @Test public void set_double() { SimpleMatrix a = new SimpleMatrix(3,3); a.set(16.0); DenseMatrix64F d = new DenseMatrix64F(3,3); CommonOps.fill(d, 16.0); EjmlUnitTests.assertEquals(d,a.mat,1e-8); } @Test public void zero() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); a.zero(); DenseMatrix64F d = new DenseMatrix64F(3,3); EjmlUnitTests.assertEquals(d,a.mat,1e-8); } @Test public void normF() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); double norm = a.normF(); double dnorm = NormOps.fastNormF(a.mat); assertEquals(dnorm,norm,1e-10); } @Test public void conditionP2() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); double cond = NormOps.conditionP2(a.getMatrix()); double found = a.conditionP2(); assertTrue(cond == found); } @Test public void determinant() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); double det = a.determinant(); double ddet = CommonOps.det(a.mat); assertEquals(ddet,det,1e-10); } @Test public void trace() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); double trace = a.trace(); double dtrace = CommonOps.trace(a.mat); assertEquals(dtrace,trace,1e-10); } @Test public void reshape() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); DenseMatrix64F b = a.mat.copy(); a.reshape(2,3); b.reshape(2,3, false); EjmlUnitTests.assertEquals(b,a.mat,1e-8); } @Test public void set_element() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); a.set(0,1,10.3); assertEquals(10.3,a.get(0,1),1e-6); } @Test public void setRow() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); a.setRow(2,1,2,3); assertEquals(2,a.get(2,1),1e-6); assertEquals(3,a.get(2,2),1e-6); } @Test public void setColumn() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); a.setColumn(2,1,2,3); assertEquals(2,a.get(1,2),1e-6); assertEquals(3,a.get(2,2),1e-6); } @Test public void get_2d() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); assertEquals(a.mat.get(0,1),a.get(0,1),1e-6); } @Test public void get_1d() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); assertEquals(a.mat.get(3),a.get(3),1e-6); } @Test public void getIndex() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); assertEquals(a.mat.getIndex(0,2),a.getIndex(0,2),1e-6); } @Test public void copy() { SimpleMatrix a = SimpleMatrix.random(3,3, 0, 1, rand); SimpleMatrix b = a.copy(); assertTrue(a.mat!=b.mat); EjmlUnitTests.assertEquals(b.mat,a.mat,1e-8); } @Test public void svd() { SimpleMatrix a = SimpleMatrix.random(3,4, 0, 1, rand); SimpleSVD svd = a.svd(); SimpleMatrix U = svd.getU(); SimpleMatrix W = svd.getW(); SimpleMatrix V = svd.getV(); SimpleMatrix a_found = U.mult(W).mult(V.transpose()); EjmlUnitTests.assertEquals(a.mat,a_found.mat,1e-8); } @Test public void eig() { SimpleMatrix a = SimpleMatrix.random(4,4, 0, 1, rand); SimpleEVD evd = a.eig(); assertEquals(4,evd.getNumberOfEigenvalues()); for( int i = 0; i < 4; i++ ) { Complex64F c = evd.getEigenvalue(i); assertTrue(c != null ); evd.getEigenVector(i); } } @Test public void insertIntoThis() { SimpleMatrix A = new SimpleMatrix(6,4); SimpleMatrix B = SimpleMatrix.random(3,2, 0, 1, rand); DenseMatrix64F A_ = A.getMatrix().copy(); A.insertIntoThis(1,2,B); CommonOps.insert(B.getMatrix(), A_, 1,2); EjmlUnitTests.assertEquals(A_,A.getMatrix(),1e-8); } @Test public void combine() { SimpleMatrix A = new SimpleMatrix(6,4); SimpleMatrix B = SimpleMatrix.random(3,4, 0, 1, rand); SimpleMatrix C = A.combine(2,2,B); assertEquals(6,C.numRows()); assertEquals(6,C.numCols()); for( int i = 0; i < 6; i++ ) { for( int j = 0; j < 6; j++ ) { if( i >= 2 && i < 5 && j >= 2 && j < 6 ) { // check to see if B was overlayed assertTrue( B.get(i-2,j-2) == C.get(i,j)); } else if( i >= 5 || j >= 4 ) { // check zero padding assertTrue( C.get(i,j) == 0 ); } else { // see if the parts of A remain there assertTrue( A.get(i,j) == C.get(i,j)); } } } } @Test public void scale() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix b = a.scale(1.5); for( int i = 0; i < a.numRows(); i++ ) { for( int j = 0; j < a.numCols(); j++ ) { assertEquals( a.get(i,j)*1.5 , b.get(i,j),1e-10); } } } @Test public void div_scalar() { SimpleMatrix a = SimpleMatrix.random(3,2, 0, 1, rand); SimpleMatrix b = a.divide(1.5); for( int i = 0; i < a.numRows(); i++ ) { for( int j = 0; j < a.numCols(); j++ ) { assertEquals( a.get(i,j)/1.5 , b.get(i,j),1e-10); } } } @Test public void elementSum() { SimpleMatrix a = new SimpleMatrix(7,4); double expectedSum = 0; int index = 0; for( int i = 0; i < a.numRows(); i++ ) { for( int j = 0; j < a.numCols(); j++ , index++ ) { expectedSum += index; a.set(i,j,index); } } assertEquals( expectedSum , a.elementSum() , 1e-8); } @Test public void elementMaxAbs() { SimpleMatrix a = SimpleMatrix.random(7,5, 0, 1, rand); a.set(3,4,-5); a.set(4,4,4); assertTrue(5 == a.elementMaxAbs()); } @Test public void elementMult() { SimpleMatrix A = SimpleMatrix.random(4,5,-1,1,rand); SimpleMatrix B = SimpleMatrix.random(4,5,-1,1,rand); SimpleMatrix C = A.elementMult(B); for( int i = 0; i < A.numRows(); i++ ) { for( int j = 0; j < A.numCols(); j++ ) { double expected = A.get(i,j)*B.get(i,j); assertTrue(expected == C.get(i,j)); } } } @Test public void elementDiv() { SimpleMatrix A = SimpleMatrix.random(4,5,-1,1,rand); SimpleMatrix B = SimpleMatrix.random(4,5,-1,1,rand); SimpleMatrix C = A.elementDiv(B); for( int i = 0; i < A.numRows(); i++ ) { for( int j = 0; j < A.numCols(); j++ ) { double expected = A.get(i,j)/B.get(i,j); assertTrue(expected == C.get(i,j)); } } } @Test public void elementPower_m() { SimpleMatrix A = SimpleMatrix.random(4,5,0,1,rand); SimpleMatrix B = SimpleMatrix.random(4,5,0,1,rand); SimpleMatrix C = A.elementPower(B); for( int i = 0; i < A.numRows(); i++ ) { for( int j = 0; j < A.numCols(); j++ ) { double expected = Math.pow(A.get(i,j),B.get(i,j)); assertTrue(expected == C.get(i,j)); } } } @Test public void elementPower_s() { SimpleMatrix A = SimpleMatrix.random(4,5,0,1,rand); double b = 1.1; SimpleMatrix C = A.elementPower(b); for( int i = 0; i < A.numRows(); i++ ) { for( int j = 0; j < A.numCols(); j++ ) { double expected = Math.pow(A.get(i,j),b); assertTrue(expected == C.get(i,j)); } } } @Test public void elementLog() { SimpleMatrix A = SimpleMatrix.random(4,5,0,1,rand); SimpleMatrix C = A.elementLog(); for( int i = 0; i < A.numRows(); i++ ) { for( int j = 0; j < A.numCols(); j++ ) { double expected = Math.log(A.get(i, j)); assertTrue(expected == C.get(i,j)); } } } @Test public void elementExp() { SimpleMatrix A = SimpleMatrix.random(4,5,0,1,rand); SimpleMatrix C = A.elementExp(); for( int i = 0; i < A.numRows(); i++ ) { for( int j = 0; j < A.numCols(); j++ ) { double expected = Math.exp(A.get(i, j)); assertTrue(expected == C.get(i,j)); } } } @Test public void extractMatrix() { SimpleMatrix a = SimpleMatrix.random(7,5, 0, 1, rand); SimpleMatrix b = a.extractMatrix(2,5,3,5); for( int i = 2; i <= 4; i++ ) { for( int j = 3; j <= 4; j++ ) { double expected = a.get(i,j); double found = b.get(i-2,j-3); assertTrue( expected == found ); } } } @Test public void extractDiag() { SimpleMatrix a = SimpleMatrix.random(3,4, 0, 1, rand); DenseMatrix64F found = a.extractDiag().getMatrix(); DenseMatrix64F expected = new DenseMatrix64F(3,1); CommonOps.extractDiag(a.getMatrix(),expected); EjmlUnitTests.assertEquals(found,expected,1e-8); } @Test public void extractVector() { SimpleMatrix A = SimpleMatrix.random(10,7, 0, 1, rand); SimpleMatrix c = A.extractVector(false,2); SimpleMatrix r = A.extractVector(true,2); assertEquals(A.numCols(),r.numCols()); assertEquals(1,r.numRows()); assertEquals(A.numRows(),c.numRows()); assertEquals(1,c.numCols()); for( int i = 0; i < A.numCols(); i++ ) { assertEquals(A.get(2,i),r.get(i),1e-10); } for( int i = 0; i < A.numRows(); i++ ) { assertEquals(A.get(i,2),c.get(i),1e-10); } } @Test public void negative() { SimpleMatrix A = SimpleMatrix.random(5,7,-1,1,rand); SimpleMatrix A_neg = A.negative(); double value = A.plus(A_neg).normF(); assertEquals(0,value,1e-8); } @Test public void isInBounds() { SimpleMatrix A = new SimpleMatrix(10,15); assertTrue(A.isInBounds(0,0)); assertTrue(A.isInBounds(9,0)); assertTrue(A.isInBounds(0,14)); assertTrue(A.isInBounds(3,3)); assertFalse(A.isInBounds(-1,0)); assertFalse(A.isInBounds(0,-1)); assertFalse(A.isInBounds(10,0)); assertFalse(A.isInBounds(0,15)); assertFalse(A.isInBounds(3,1000)); } } ejml-0.28/settings.gradle000066400000000000000000000002041256171534400154160ustar00rootroot00000000000000include 'main:equation','main:core','main:experimental','main:dense64','main:denseC64', 'main:simple','examples',"main:all"