Skip to content

Commit 1d33a49

Browse files
author
Jonathan Ellis
committed
householder try apache#2, also fail
1 parent ec2158e commit 1d33a49

2 files changed

Lines changed: 44 additions & 14 deletions

File tree

lucene/core/src/java/org/apache/lucene/util/hnsw/EigenvalueDecomposition.java

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,26 +118,56 @@ static float magnitude(float[] v) {
118118
/**
119119
* Compute Q and R for QR decomposition of A such that A=QR.
120120
* Q and R should be matrices of the same size as A; their contents will be overwritten by the computation.
121+
* R's contents are ignored but
121122
*/
122123
static void qrDecomp(float[][] A, float[][] Q, float[][] R) {
123124
int m = A.length; // rows
124125
int n = A[0].length; // columns
125126

126-
// Modified Gram-Schmidt
127-
for (int i = 0; i < n; i++) {
128-
float[] ai = getColumn(A, i);
129-
float[] ui = copyVector(ai);
130-
131-
for (int j = 0; j < i; j++) {
132-
float[] qj = getColumn(Q, j);
133-
float proj = dotProduct(ai, qj); // Project on already-orthogonalized vectors
134-
R[j][i] = proj; // Fill the upper-triangular matrix R
135-
ui = subtract(ui, scale(qj, proj)); // Orthogonalize with respect to already-orthogonalized vectors
127+
// Householder decomposition
128+
for (int k = 0; k < n; k++) {
129+
float[] x = getColumn(A, k);
130+
float[] e = new float[x.length];
131+
e[0] = 1;
132+
float[] v_k = subtract(x, scale(e, x[0] >= 0 ? -magnitude(x) : magnitude(x)));
133+
float[][] H_k = subtract(identity(m), scaleOuterProduct(v_k, v_k, 2 / dotProduct(v_k, v_k)));
134+
float[][] A_next = multiply(H_k, A);
135+
136+
for (int i = 0; i < m; i++) {
137+
System.arraycopy(A_next[i], 0, A[i], 0, n);
136138
}
137139

138-
R[i][i] = magnitude(ui);
139-
insertColumn(Q, normalize(ui), i);
140+
updateColumn(Q, getColumn(H_k, k), k);
141+
updateColumn(R, getColumn(A, k), k);
142+
}
143+
}
144+
145+
static float[][] subtract(float[][] mat1, float[][] mat2) {
146+
int rows = mat1.length;
147+
int cols = mat1[0].length;
148+
float[][] result = new float[rows][cols];
149+
150+
for (int i = 0; i < rows; i++) {
151+
for (int j = 0; j < cols; j++) {
152+
result[i][j] = mat1[i][j] - mat2[i][j];
153+
}
140154
}
155+
156+
return result;
157+
}
158+
159+
static float[][] scaleOuterProduct(float[] u, float[] v, float scale) {
160+
int rows = u.length;
161+
int cols = v.length;
162+
float[][] result = new float[rows][cols];
163+
164+
for (int i = 0; i < rows; i++) {
165+
for (int j = 0; j < cols; j++) {
166+
result[i][j] = u[i] * v[j] * scale;
167+
}
168+
}
169+
170+
return result;
141171
}
142172

143173
private static float[] copyVector(float[] orig) {
@@ -154,7 +184,7 @@ private static float[] getColumn(float[][] mat, int columnIndex) {
154184
return column;
155185
}
156186

157-
private static void insertColumn(float[][] mat, float[] col, int colIndex) {
187+
private static void updateColumn(float[][] mat, float[] col, int colIndex) {
158188
for (int i = 0; i < mat.length; i++) {
159189
mat[i][colIndex] = col[i];
160190
}

lucene/core/src/test/org/apache/lucene/util/hnsw/TestEigenvalueDecomposition.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public void testQrDecomp() {
8787

8888
private void testOneQr(float[][] A) {
8989
float[][] R = new float[A.length][A.length];
90-
float[][] Q = new float[A.length][A.length];
90+
float[][] Q = EigenvalueDecomposition.identity(A.length);
9191
EigenvalueDecomposition.qrDecomp(A, Q, R);
9292

9393
// Check if R is upper triangular

0 commit comments

Comments
 (0)