001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.demos.sandbox.geom; 031 032import org.openimaj.data.RandomData; 033import org.openimaj.math.matrix.MatrixUtils; 034import org.openimaj.math.matrix.ThinSingularValueDecomposition; 035 036import Jama.Matrix; 037import Jama.QRDecomposition; 038 039public class IncrementalSVD{ 040 private static final double DEFAULT_DAMPENING = 1.f; 041 private int updateK; 042 private Matrix Rworkspace; 043 public IncrementalSVD(int updateK) { 044 this.updateK = updateK; 045 this.Rworkspace = new Matrix(updateK*2, updateK*2); 046 } 047 048 Matrix U; 049 double[] S; 050 Matrix Sdiag; 051 private double defaultDamp = DEFAULT_DAMPENING ; 052 /** 053 * @param m new data to update the SVD with 054 */ 055 public void update(Matrix m){ 056 update(m,this.defaultDamp); 057 } 058 /** 059 * @param m new data to update the SVD with 060 * @param dampening each current eigen vector is weighted by this amount 061 */ 062 public void update(Matrix m, double dampening){ 063 Matrix d = Matrix.identity(this.updateK, this.updateK); 064 update(m,d.timesEquals(dampening)); 065 } 066 /** 067 * @param m 068 * @param dampening multiplied by the current eigen values (see the paper) 069 */ 070 public void update(Matrix m, Matrix dampening){ 071 ThinSingularValueDecomposition inputSVD = new ThinSingularValueDecomposition(m, updateK); 072 Matrix U2 = inputSVD.U; 073 double[] S2 = inputSVD.S; 074 if(S2.length < updateK){ 075 double[] rep = new double[updateK]; 076 for (int i = 0; i < S2.length; i++) { 077 rep[i] = S2[i]; 078 } 079 S2 = rep; 080 } 081 Matrix S2diag = MatrixUtils.diag(S2); 082 if(U == null){ 083 U = U2; 084 S = S2; 085 Sdiag = S2diag; 086 return; 087 } 088 089 Matrix Z = U.transpose().times(U2); 090 Matrix U1U2Delta = U2.minus(U.times(Z)); 091 QRDecomposition qr = new QRDecomposition(U1U2Delta); 092 Matrix R = qr.getR(); 093 Matrix Uprime = qr.getQ(); 094 this.Rworkspace.setMatrix(0,this.updateK-1, 0,this.updateK-1, dampening.times(Sdiag)); // top left 095 this.Rworkspace.setMatrix(0,this.updateK-1, this.updateK,this.updateK*2 -1, Z.times(S2diag)); // top right 096 this.Rworkspace.setMatrix(this.updateK,this.updateK*2 -1, this.updateK,this.updateK*2 -1, R.times(S2diag)); // bottom right 097 // this.Rworkspace bottom left = 0 098 099 ThinSingularValueDecomposition rWorkspaceSVD = new ThinSingularValueDecomposition(this.Rworkspace, updateK); 100 S = rWorkspaceSVD.S; 101 Sdiag = MatrixUtils.diag(S); 102 Matrix UR = rWorkspaceSVD.U; 103 104 Matrix topUR = UR.getMatrix(0,this.updateK-1,0,this.updateK-1); 105 Matrix bottomUR = UR.getMatrix(this.updateK,this.updateK*2-1,0,this.updateK-1); 106 U = U.times(topUR); 107 U.plus(Uprime.times(bottomUR)); 108 } 109 110 public static void main(String[] args) { 111 IncrementalSVD incSVD = new IncrementalSVD(3); 112 113 Matrix A = new Matrix(RandomData.getRandomDoubleArray(3, 8, 0d, 1d,1)); 114 System.out.println("This is A: "); 115 A.print(8, 8); 116 Matrix A1 = A.getMatrix(0, 2, 0, 3); 117 Matrix A2 = A.getMatrix(0, 2, 4, 6); 118 Matrix A3 = A.getMatrix(0, 2, 7, 7); 119 System.out.println("This is A1: "); 120 A1.print(8, 8); 121 System.out.println("This is A2: "); 122 A2.print(8, 8); 123 System.out.println("This is A3: "); 124 A3.print(8, 8); 125 126 incSVD.update(A1); 127 System.out.println("From IncSVD (A1): "); 128 incSVD.U.print(5, 5); 129 incSVD.Sdiag.print(5, 5); 130 131 System.out.println("From Thinsvd: "); 132 ThinSingularValueDecomposition A1SVD = new ThinSingularValueDecomposition(A1, incSVD.updateK); 133 A1SVD.U.print(5, 5); 134 MatrixUtils.diag(A1SVD.S).print(5, 5); 135 136 incSVD.update(A2); 137 System.out.println("From IncSVD (A1,A2): "); 138 incSVD.U.print(5, 5); 139 incSVD.Sdiag.print(5, 5); 140 System.out.println("From Thinsvd: "); 141 ThinSingularValueDecomposition A1A2SVD = new ThinSingularValueDecomposition(MatrixUtils.hstack(A1,A2), incSVD.updateK); 142 A1A2SVD.U.print(5, 5); 143 MatrixUtils.diag(A1A2SVD.S).print(5, 5); 144 145 incSVD.update(A3); 146 System.out.println("From IncSVD (A1,A2,A3): "); 147 incSVD.U.print(5, 5); 148 incSVD.Sdiag.print(5, 5); 149 System.out.println("From Thinsvd: "); 150 ThinSingularValueDecomposition ASVD = new ThinSingularValueDecomposition(A, incSVD.updateK); 151 ASVD.U.print(5, 5); 152 MatrixUtils.diag(ASVD.S).print(5, 5); 153 154 155 156 } 157 158 public void setDefaultWeighting(double d) { 159 this.defaultDamp = d; 160 } 161}