Repository: incubator-systemml
Updated Branches:
  refs/heads/master 5aa6fb75b -> 7ce130855


[SYSTEMML-1213] Scalable linear algebra

DML implementations and accompanying DML tests for
Cholesky, LU, QR, Solve, Inverse and util functions.

Closes #368.


Project: http://git-wip-us.apache.org/repos/asf/incubator-systemml/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-systemml/commit/7ce13085
Tree: http://git-wip-us.apache.org/repos/asf/incubator-systemml/tree/7ce13085
Diff: http://git-wip-us.apache.org/repos/asf/incubator-systemml/diff/7ce13085

Branch: refs/heads/master
Commit: 7ce130855d66d94b79f1dabcb4eb584eccc9663c
Parents: 5aa6fb7
Author: Imran Younus <imranyou...@gmail.com>
Authored: Mon May 1 12:02:27 2017 -0700
Committer: Deron Eriksson <de...@us.ibm.com>
Committed: Mon May 1 12:02:27 2017 -0700

----------------------------------------------------------------------
 scripts/staging/scalable_linalg/cholesky.dml    | 45 +++++++++++
 scripts/staging/scalable_linalg/inverse.dml     | 35 +++++++++
 scripts/staging/scalable_linalg/lu.dml          | 51 +++++++++++++
 scripts/staging/scalable_linalg/qr.dml          | 61 +++++++++++++++
 scripts/staging/scalable_linalg/solve.dml       | 35 +++++++++
 .../scalable_linalg/test/scalable_linalg        |  1 +
 .../scalable_linalg/test/test_Cholesky.dml      | 44 +++++++++++
 .../staging/scalable_linalg/test/test_LU.dml    | 44 +++++++++++
 .../staging/scalable_linalg/test/test_QR.dml    | 44 +++++++++++
 .../staging/scalable_linalg/test/test_all.dml   | 32 ++++++++
 .../scalable_linalg/test/test_inverse.dml       | 49 ++++++++++++
 .../staging/scalable_linalg/test/test_solve.dml | 44 +++++++++++
 .../test/test_triangular_inv.dml                | 62 +++++++++++++++
 scripts/staging/scalable_linalg/test/utils.dml  | 38 ++++++++++
 .../staging/scalable_linalg/triangular_inv.dml  | 80 ++++++++++++++++++++
 15 files changed, 665 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/cholesky.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/cholesky.dml 
b/scripts/staging/scalable_linalg/cholesky.dml
new file mode 100644
index 0000000..1bac1b2
--- /dev/null
+++ b/scripts/staging/scalable_linalg/cholesky.dml
@@ -0,0 +1,45 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/triangular_inv.dml") as inv
+
+Choleskey = function(Matrix[double] A, int nb)
+  return(Matrix[double] L) {
+    n = ncol(A)
+
+    if (n <= nb) {
+      L = cholesky(A)
+    } else {
+      k = as.integer(floor(n/2))
+      A11 = A[1:k,1:k]
+      A21 = A[k+1:n,1:k]
+      A22 = A[k+1:n,k+1:n]
+
+      L11 = Choleskey(A11, nb)
+      L11inv = inv::U_triangular_inv(t(L11))
+      L21 = A21 %*% L11inv
+      A22 = A22 - L21 %*% t(L21)
+      L22 = Choleskey(A22, nb)
+      L12 = matrix(0, rows=nrow(L11), cols=ncol(L22))
+
+      L = rbind(cbind(L11, L12), cbind(L21, L22))
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/inverse.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/inverse.dml 
b/scripts/staging/scalable_linalg/inverse.dml
new file mode 100644
index 0000000..112e351
--- /dev/null
+++ b/scripts/staging/scalable_linalg/inverse.dml
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/triangular_inv.dml") as tinv
+source("scalable_linalg/qr.dml") as decomp
+
+Inverse = function(Matrix[double] A, int nb)
+  return(Matrix[double] X) {
+    # TODO: Some recent papers discuss Block-Recursive algorithm for
+    # matrix inverse which can be explored instead of QR decomposition
+
+    [Q, R] = decomp::QR(A, nb)
+
+    Rinv = tinv::U_triangular_inv(R)
+
+    X = R %*% t(Q)
+}

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/lu.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/lu.dml 
b/scripts/staging/scalable_linalg/lu.dml
new file mode 100644
index 0000000..d1ad306
--- /dev/null
+++ b/scripts/staging/scalable_linalg/lu.dml
@@ -0,0 +1,51 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/triangular_inv.dml") as inv
+
+LU = function(Matrix[double] A, int nb)
+  return(Matrix[double] P, Matrix[double] L, Matrix[double] U) {
+    n = ncol(A)
+    if (n <= nb) {
+      [P, L, U] = lu(A)
+    } else {
+      k = as.integer(floor(n/2))
+      A11 = A[1:k,1:k]
+      A12 = A[1:k,k+1:n]
+      A21 = A[k+1:n,1:k]
+      A22 = A[k+1:n,k+1:n]
+
+      [P11, L11, U11] = LU(A11, nb)
+      L11inv = inv::L_triangular_inv(L11)
+      U11inv = inv::U_triangular_inv(U11)
+      U12 = L11inv %*% (P11 %*% A12)
+      A22 = A22 - A21 %*% U11inv %*% U12
+      [P22, L22, U22] = LU(A22, nb)
+      L21 = P22 %*% A21 %*% U11inv
+
+      Z12 = matrix(0, rows=nrow(A11), cols=ncol(A22))
+      Z21 = matrix(0, rows=nrow(A22), cols=ncol(A11))
+
+      L = rbind(cbind(L11, Z12), cbind(L21, L22))
+      U = rbind(cbind(U11, U12), cbind(Z21, U22))
+      P = rbind(cbind(P11, Z12), cbind(Z21, P22))
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/qr.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/qr.dml 
b/scripts/staging/scalable_linalg/qr.dml
new file mode 100644
index 0000000..7417a33
--- /dev/null
+++ b/scripts/staging/scalable_linalg/qr.dml
@@ -0,0 +1,61 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+# calculate Q from Housholder matrix
+QfromH = function(Matrix[double] H)
+  return(Matrix[double] Q) {
+    m = nrow(H);
+    n = ncol(H);
+    ones = matrix(1, m, 1);
+    eye = diag(ones);
+    Q = eye[,1:n];
+
+    for (j in n:1) {
+      v = H[j:m,j]
+      b = as.scalar(2/(t(v) %*% v))
+      Q[j:m, j:n] = Q[j:m, j:n] - (b * v) %*% (t(v) %*% Q[j:m, j:n])
+    }
+}
+
+QR = function(Matrix[double] A, int nb)
+  return(Matrix[double] Q, Matrix[double] R) {
+    n = ncol(A)
+
+    if (n <= nb) {
+      [H, R] = qr(A)
+      Q = QfromH(H)
+      R = R[1:n, 1:n]
+    }
+    else {
+      k = floor(n/2)
+      A1 = A[,1:k]
+      A2 = A[,k+1:n]
+
+      [Q1, R11] = QR(A1, nb)
+      R12 = t(Q1) %*% A2
+      A2 = A2 - Q1 %*% R12
+      [Q2, R22] = QR(A2, nb)
+      R21 = matrix(0, rows = nrow(R22), cols = ncol(R11))
+
+      Q = cbind(Q1, Q2)
+      R = rbind(cbind(R11, R12), cbind(R21, R22))
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/solve.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/solve.dml 
b/scripts/staging/scalable_linalg/solve.dml
new file mode 100644
index 0000000..8dd07d2
--- /dev/null
+++ b/scripts/staging/scalable_linalg/solve.dml
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/triangular_inv.dml") as inv
+source("scalable_linalg/qr.dml") as decomp
+
+Solve = function(Matrix[double] A, Matrix[double] b, int nb)
+  return(Matrix[double] x) {
+    # TODO: using thin QR may accumulate higher numerical erros.
+    # Some modifications as suggested by Golub may be explored
+
+    [Q, R] = decomp::QR(A, nb)
+
+    Rinv = inv::U_triangular_inv(R)
+
+    x = Rinv %*% t(Q) %*% b
+}

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/scalable_linalg
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/scalable_linalg 
b/scripts/staging/scalable_linalg/test/scalable_linalg
new file mode 120000
index 0000000..b0e1ab9
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/scalable_linalg
@@ -0,0 +1 @@
+../../scalable_linalg
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/test_Cholesky.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/test_Cholesky.dml 
b/scripts/staging/scalable_linalg/test/test_Cholesky.dml
new file mode 100644
index 0000000..f602e93
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/test_Cholesky.dml
@@ -0,0 +1,44 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/cholesky.dml") as decomp
+
+test_Cholesky = function() {
+  print("Testing Choleskey Decomposition.")
+  n = 1000
+  b = 100 # smallest block size
+  eps = n*n*1e-12 # for lareger matrices eps should be larger
+
+  # create a symmetric random matrix
+  A = rand(rows=n, cols=n, min=-1.0, max=1.0, pdf="uniform")
+  X = t(A) %*% A
+
+  L = decomp::Choleskey(X, b)
+
+  # check if X = LL^T. Infinity norm of (X - LL^T) must be close to zero
+  diff = X - L %*% t(L)
+  sup_norm = max(abs(diff))
+  if (sup_norm > eps) {
+    print("ERROR: Cholesky decomposition does not reproduce original matrix")
+  }
+}
+
+tmp = test_Cholesky()

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/test_LU.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/test_LU.dml 
b/scripts/staging/scalable_linalg/test/test_LU.dml
new file mode 100644
index 0000000..307535e
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/test_LU.dml
@@ -0,0 +1,44 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/lu.dml") as decomp
+
+test_LU = function() {
+  print("Testing LU Decomposition.")
+  n = 1000
+  b = 100 # smallest block size
+  eps = n*n*1e-12 # for lareger matrices eps should be larger
+
+  # create random square matrix
+  A = rand(rows=n, cols=n, min=-1.0, max=1.0, pdf="uniform")
+
+  [P, L, U] = decomp::LU(A, b)
+
+  # check if PA = LU. Infinity norm of (PA - LU) must be close to zero
+  diff = P %*% A - L %*% U
+  sup_norm = max(abs(diff))
+  print(sup_norm)
+  if (sup_norm > eps) {
+    print("ERROR: LU decomposition does not reproduce original matrix")
+  }
+}
+
+tmp = test_LU()

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/test_QR.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/test_QR.dml 
b/scripts/staging/scalable_linalg/test/test_QR.dml
new file mode 100644
index 0000000..83f2214
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/test_QR.dml
@@ -0,0 +1,44 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/qr.dml") as decomp
+
+test_QR = function() {
+  print("Testing QR Decomposition.")
+  n = 1000
+  m = 2000
+  b = 100 # smallest block size
+  eps = n*m*1e-12 # for lareger matrices eps should be larger
+
+  # create a symmetric random matrix
+  A = rand(rows=m, cols=n, min=-1.0, max=1.0, pdf="uniform")
+
+  [Q, R] = decomp::QR(A, b)
+
+  # check if A = QR. Infinity norm of (A - QR) must be close to zero
+  diff = A - Q %*% R
+  sup_norm = max(abs(diff))
+  if (sup_norm > eps) {
+    print("ERROR: QR decomposition does not reproduce original matrix")
+  }
+}
+
+tmp = test_QR()

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/test_all.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/test_all.dml 
b/scripts/staging/scalable_linalg/test/test_all.dml
new file mode 100644
index 0000000..bba391c
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/test_all.dml
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("test_inverse.dml") as test1
+source("test_LU.dml") as test2
+source("test_QR.dml") as test3
+source("test_Cholesky.dml") as test4
+
+print("Testing Scalable Linalg")
+
+tmp = test1::test_inverse()
+tmp = test2::test_LU()
+#tmp = test3::test_QR()
+tmp = test4::test_Cholesky()

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/test_inverse.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/test_inverse.dml 
b/scripts/staging/scalable_linalg/test/test_inverse.dml
new file mode 100644
index 0000000..2bd0f5d
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/test_inverse.dml
@@ -0,0 +1,49 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/inverse.dml") as inv
+
+test_inverse = function() {
+  print("Testing inverse of square matrices")
+  n = 1000
+  b = 100 # smallest block size
+  eps = n*n*1e-12
+
+  A = rand(rows=n, cols=n, min=-1.0, max=1.0, pdf="uniform")
+
+  Ainv = inv::Inverse(A, b)
+
+  # this product should produce identity matrix
+  AAinv = A %*% Ainv
+
+  # create identity matrix
+  ones = matrix(1.0, n, 1);
+  I = diag(ones);
+
+  # check if AA^-1 = I. Infinity norm of (I - AA^-1) must be close to zero
+  diff = I - AAinv
+  sup_norm = max(abs(diff))
+  if (sup_norm > eps) {
+    print("ERROR: inverse of square matrix fails")
+  }
+}
+
+tmp = test_inverse()

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/test_solve.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/test_solve.dml 
b/scripts/staging/scalable_linalg/test/test_solve.dml
new file mode 100644
index 0000000..f741c0f
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/test_solve.dml
@@ -0,0 +1,44 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/solve.dml") as lsq
+
+test_solve = function() {
+  print("Testing linear Solve function.")
+  n = 1000
+  m = 2000
+  b = 100
+  eps = 1e-9
+
+  # generate data for test
+  A = rand(rows=m, cols=n, min=-2, max=2)
+  x = rand(rows=n, cols=1, min=-5, max=5)
+  y = A %*% x
+  x1 = lsq::Solve(A, y, b)
+
+  diff = abs(x - x1)
+  sup_norm = max(diff)
+  if (sup_norm > eps) {
+    print("ERROR: least squares solve fails")
+  }
+}
+
+tmp = test_solve()

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/test_triangular_inv.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/test_triangular_inv.dml 
b/scripts/staging/scalable_linalg/test/test_triangular_inv.dml
new file mode 100644
index 0000000..13d730a
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/test_triangular_inv.dml
@@ -0,0 +1,62 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("scalable_linalg/triangular_inv.dml") as inv
+
+test_inverse = function() {
+  print("Testing inverse of triangular matrices")
+  n = 1000
+  eps = n*n*1e-12
+
+  A = rand(rows=n, cols=n, min=-1.0, max=1.0, pdf="uniform")
+
+  # create lower/upper triangular matrices using lu deomposition
+  [P,L,U] = lu(A)
+
+  # calculate inverse
+  Linv = inv::L_triangular_inv(L)
+  Uinv = inv::U_triangular_inv(U)
+
+  # these products should produce identity matrices
+  LLinv = L %*% Linv
+  UUinv = U %*% Uinv
+
+  # create identity matrix
+  ones = matrix(1.0, n, 1);
+  I = diag(ones);
+
+  # check if LL^-1 = I. Infinity norm of (I - LL^-1) must be close to zero
+  diff = I - LLinv
+  sup_norm = max(abs(diff))
+  if (sup_norm > eps) {
+    print("ERROR: inverse of lower triangular matrix fails")
+  }
+
+  # check if UU^-1 = I. Inifinity norm of (I - UU^-1) must be close to zero
+  diff = I - UUinv
+  sup_norm = max(abs(diff))
+
+  if (sup_norm > eps) {
+    print("ERROR: inverse of upper triangular matrix fails")
+  }
+}
+
+tmp = test_inverse()

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/test/utils.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/test/utils.dml 
b/scripts/staging/scalable_linalg/test/utils.dml
new file mode 100644
index 0000000..765c97a
--- /dev/null
+++ b/scripts/staging/scalable_linalg/test/utils.dml
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+
+rel_error = function(double true_val, double approx)
+  return(double err) {
+    err = abs(true_val - approx)/max(abs(true_val), 1e-9)
+  }
+
+check_equal = function(double x1, double x2, double eps)
+  return (boolean eq) {
+    eq = TRUE
+    diff = abs(x1 - x2)
+    largest = max(abs(x2), abs(x2))
+
+    if (diff > largest*eps) {
+      print("ERROR: vlaues not equal: " + x1 + " != " + x2 )
+      eq = FALSE
+    }
+  }

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/7ce13085/scripts/staging/scalable_linalg/triangular_inv.dml
----------------------------------------------------------------------
diff --git a/scripts/staging/scalable_linalg/triangular_inv.dml 
b/scripts/staging/scalable_linalg/triangular_inv.dml
new file mode 100644
index 0000000..75ff09e
--- /dev/null
+++ b/scripts/staging/scalable_linalg/triangular_inv.dml
@@ -0,0 +1,80 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+
+# Inverse of lower triangular matrix
+L_triangular_inv = function(Matrix[double] L)
+  return(Matrix[double] A) {
+    n = ncol(L)
+
+    if (n == 1) {
+      A = 1/L[1,1]
+    } else if (n == 2) {
+      A = matrix(0, rows=2, cols=2)
+      A[1,1] = L[2,2]
+      A[2,2] = L[1,1]
+      A[2,1] = -L[2,1]
+      A = A/(as.scalar(L[1,1] * L[2,2]))
+    } else {
+      k = as.integer(floor(n/2))
+
+      L11 = L[1:k,1:k]
+      L21 = L[k+1:n,1:k]
+      L22 = L[k+1:n,k+1:n]
+
+      A11 = L_triangular_inv(L11)
+      A22 = L_triangular_inv(L22)
+      A12 = matrix(0, rows=nrow(A11), cols=ncol(A22))
+      A21 = -A22 %*% L21 %*% A11
+
+      A = rbind(cbind(A11, A12), cbind(A21, A22))
+    }
+  }
+
+# Inverse of upper triangular matrix
+U_triangular_inv = function(Matrix[double] U)
+  return(Matrix[double] A) {
+    n = ncol(U)
+
+    if (n == 1) {
+      A = 1/U[1,1]
+    } else if (n == 2) {
+      A = matrix(0, rows=2, cols=2)
+      A[1,1] = U[2,2]
+      A[2,2] = U[1,1]
+
+      A[1,2] = -U[1,2]
+      A = A/(as.scalar(U[1,1] * U[2,2]))
+    } else {
+      k = as.integer(floor(n/2))
+
+      U11 = U[1:k,1:k]
+      U12 = U[1:k,k+1:n]
+      U22 = U[k+1:n,k+1:n]
+
+      A11 = U_triangular_inv(U11)
+      A22 = U_triangular_inv(U22)
+      A12 = -A11 %*% U12 %*% A22
+      A21 = matrix(0, rows=nrow(A22), cols=ncol(A11))
+
+      A = rbind(cbind(A11, A12), cbind(A21, A22))
+    }
+  }

Reply via email to