From 42b68a69ce8df1ab034d2823eb75fe9690733689 Mon Sep 17 00:00:00 2001 From: Phil Steitz Date: Thu, 12 Feb 2009 11:21:54 +0000 Subject: [PATCH] Added correlation package, Covariance class. JIRA: MATH-114 git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@743688 13f79535-47bb-0310-9956-ffa450edef68 --- .../math/stat/correlation/Covariance.java | 205 ++++++++++++++++ src/site/xdoc/changes.xml | 10 +- src/test/R/covarianceTestCases | 146 ++++++++++++ src/test/R/testAll | 3 + .../math/stat/correlation/CovarianceTest.java | 225 ++++++++++++++++++ 5 files changed, 586 insertions(+), 3 deletions(-) create mode 100644 src/java/org/apache/commons/math/stat/correlation/Covariance.java create mode 100644 src/test/R/covarianceTestCases create mode 100644 src/test/org/apache/commons/math/stat/correlation/CovarianceTest.java diff --git a/src/java/org/apache/commons/math/stat/correlation/Covariance.java b/src/java/org/apache/commons/math/stat/correlation/Covariance.java new file mode 100644 index 000000000..2066fb26a --- /dev/null +++ b/src/java/org/apache/commons/math/stat/correlation/Covariance.java @@ -0,0 +1,205 @@ +/* + * 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. + */ +package org.apache.commons.math.stat.correlation; + +import org.apache.commons.math.MathRuntimeException; +import org.apache.commons.math.linear.RealMatrix; +import org.apache.commons.math.linear.DenseRealMatrix; +import org.apache.commons.math.stat.descriptive.moment.Mean; +import org.apache.commons.math.stat.descriptive.moment.Variance; + +/** + * Computes covariances for pairs of arrays or columns of a matrix. + * + *

The constructors that take RealMatrix or + * double[][] arguments generate correlation matrices. The + * columns of the input matrices are assumed to represent variable values.

+ * + *

The constructor argument biasCorrected determines whether or + * not computed covariances are bias-corrected.

+ * + *

Unbiased covariances are given by the formula

+ * cov(X, Y) = Σ[(xi - E(X))(yi - E(Y))] / (n - 1) + * where E(x) is the mean of X and E(Y) + * is the mean of the Y values. + * + *

Non-bias-corrected estimates use n in place of n - 1 + * + * @version $Revision$ $Date$ + * @since 2.0 + */ +public class Covariance { + + /** covariance matrix */ + private final RealMatrix covarianceMatrix; + + public Covariance() { + super(); + covarianceMatrix = null; + } + + /** + * Create a Covariance matrix from a rectangular array + * whose columns represent covariates. + * + *

The biasCorrected parameter determines whether or not + * covariance estimates are bias-corrected.

+ * + *

The input array must be rectangular with at least two columns + * and two rows.

+ * + * @param data rectangular array with columns representing covariates + * @param biasCorrected true means covariances are bias-corrected + * @throws IllegalArgumentException if the input data array is not + * rectangular with at least two rows and two columns. + */ + public Covariance(double[][] data, boolean biasCorrected) { + this(new DenseRealMatrix(data), biasCorrected); + } + + /** + * Create a Covariance matrix from a rectangular array + * whose columns represent covariates. + * + *

The input array must be rectangular with at least two columns + * and two rows

+ * + * @param data rectangular array with columns representing covariates + * @throws IllegalArgumentException if the input data array is not + * rectangular with at least two rows and two columns. + */ + public Covariance(double[][] data) { + this(data, true); + } + + /** + * Create a covariance matrix from a matrix whose columns + * represent covariates. + * + *

The biasCorrected parameter determines whether or not + * covariance estimates are bias-corrected.

+ * + *

The matrix must have at least two columns and two rows

+ * + * @param matrix matrix with columns representing covariates + * @param biasCorrected true means covariances are bias-corrected + * @throws IllegalArgumentException if the input matrix does not have + * at least two rows and two columns + */ + public Covariance(RealMatrix matrix, boolean biasCorrected) { + checkSufficientData(matrix); + covarianceMatrix = computeCovariance(matrix, biasCorrected); + } + + /** + * Create a covariance matrix from a matrix whose columns + * represent covariates. + * + *

The matrix must have at least two columns and two rows

+ * + * @param matrix matrix with columns representing covariates + * @throws IllegalArgumentException if the input matrix does not have + * at least two rows and two columns + */ + public Covariance(RealMatrix matrix) { + this(matrix, true); + } + + /** + * Returns the covariance matrix + * + * @return covariance matrix + */ + public RealMatrix getCovarianceMatrix() { + return covarianceMatrix; + } + + /** + * Create a covariance matrix from a matrix whose columns represent + * covariates. + * + *

The input matrix must have at least two columns and two rows

+ * + *

The biasCorrected parameter determines whether or not + * covariance estimates are bias-corrected.

+ * + * @return covariance matrix + */ + protected RealMatrix computeCovariance(RealMatrix matrix, boolean biasCorrected) { + int dimension = matrix.getColumnDimension(); + Variance variance = new Variance(biasCorrected); + RealMatrix outMatrix = new DenseRealMatrix(dimension, dimension); + for (int i = 0; i < dimension; i++) { + for (int j = 0; j < i; j++) { + double cov = covariance(matrix.getColumn(i), matrix.getColumn(j), biasCorrected); + outMatrix.setEntry(i, j, cov); + outMatrix.setEntry(j, i, cov); + } + outMatrix.setEntry(i, i, variance.evaluate(matrix.getColumn(i))); + } + return outMatrix; + } + + /** + * Computes the covariance between the two arrays. + * + *

Array lengths must match and the common length must be at least 2.

+ * + * @param xArray first data array + * @param yArray second data array + * @param biasCorrected if true, returned value will be bias-corrected + * @return returns the covariance for the two arrays + * @throws IllegalArgumentException if the arrays lengths do not match or + * there is insufficient data + */ + public double covariance(final double[] xArray, final double[] yArray, boolean biasCorrected) + throws IllegalArgumentException { + Mean mean = new Mean(); + double result = 0d; + long length = xArray.length; + if(length == yArray.length && length > 1) { + double xMean = mean.evaluate(xArray); + double yMean = mean.evaluate(yArray); + for (int i = 0; i < xArray.length; i++) { + double xDev = xArray[i] - xMean; + double yDev = yArray[i] - yMean; + result += (xDev * yDev - result) / (i + 1); + } + } + else { + throw MathRuntimeException.createIllegalArgumentException( + "Arrays must have the same length and both must have at " + + "least two elements. xArray has size {0}, yArray has {1} elements", + new Object[] {xArray.length, yArray.length}); + } + return biasCorrected ? result * ((double) length / (double)(length - 1)) : result; + } + + /** + * Throws IllegalArgumentException of the matrix does not have at least + * two columns and two rows + */ + private void checkSufficientData(final RealMatrix matrix) { + int nRows = matrix.getRowDimension(); + int nCols = matrix.getColumnDimension(); + if (nRows < 2 || nCols < 2) { + throw MathRuntimeException.createIllegalArgumentException( + "Insufficient data: only {0} rows and {1} columns.", + new Object[]{nRows, nCols}); + } + } +} diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml index e222a1f31..6802795c5 100644 --- a/src/site/xdoc/changes.xml +++ b/src/site/xdoc/changes.xml @@ -39,9 +39,16 @@ The type attribute can be add,update,fix,remove. + + Added Covariance class to compute variance-covariance matrices in new + correlation package. + Improved fast Fourier transform efficiency. + + Added a SparseRealVector class that implements a sparse vector for the RealVector interface. + Added factory methods to create Chebyshev, Hermite, Laguerre and Legendre polynomials. @@ -303,9 +310,6 @@ The type attribute can be add,update,fix,remove. Added root checks for the endpoints. - - Added a SparseRealVector class that implements a sparse vector for the RealVector interface. - ") +# +#------------------------------------------------------------------------------ +tol <- 1E-9 # error tolerance for tests +#------------------------------------------------------------------------------ +# Function definitions + +source("testFunctions") # utility test functions +options(digits=16) # override number of digits displayed + +# function to verify covariance computations +verifyCovariance <- function(matrix, expectedCovariance, name) { + covariance <- cov(matrix) + output <- c("Covariance test dataset = ", name) + if (assertEquals(expectedCovariance,covariance,tol,"Covariances")) { + displayPadded(output, SUCCEEDED, WIDTH) + } else { + displayPadded(output, FAILED, WIDTH) + } +} + +#-------------------------------------------------------------------------- +cat("Covariance test cases\n") + +# Longley + +longley <- matrix(c(60323,83.0,234289,2356,1590,107608,1947, + 61122,88.5,259426,2325,1456,108632,1948, + 60171,88.2,258054,3682,1616,109773,1949, + 61187,89.5,284599,3351,1650,110929,1950, + 63221,96.2,328975,2099,3099,112075,1951, + 63639,98.1,346999,1932,3594,113270,1952, + 64989,99.0,365385,1870,3547,115094,1953, + 63761,100.0,363112,3578,3350,116219,1954, + 66019,101.2,397469,2904,3048,117388,1955, + 67857,104.6,419180,2822,2857,118734,1956, + 68169,108.4,442769,2936,2798,120445,1957, + 66513,110.8,444546,4681,2637,121950,1958, + 68655,112.6,482704,3813,2552,123366,1959, + 69564,114.2,502601,3931,2514,125368,1960, + 69331,115.7,518173,4806,2572,127852,1961, + 70551,116.9,554894,4007,2827,130081,1962), + nrow = 16, ncol = 7, byrow = TRUE) + +expectedCovariance <- matrix(c( + 12333921.73333333246, 3.679666000000000e+04, 343330206.333333313, + 1649102.666666666744, 1117681.066666666651, 23461965.733333334, 16240.93333333333248, + 36796.66000000000, 1.164576250000000e+02, 1063604.115416667, + 6258.666250000000, 3490.253750000000, 73503.000000000, 50.92333333333334, + 343330206.33333331347, 1.063604115416667e+06, 9879353659.329166412, + 56124369.854166664183, 30880428.345833335072, 685240944.600000024, 470977.90000000002328, + 1649102.66666666674, 6.258666250000000e+03, 56124369.854166664, + 873223.429166666698, -115378.762499999997, 4462741.533333333, 2973.03333333333330, + 1117681.06666666665, 3.490253750000000e+03, 30880428.345833335, + -115378.762499999997, 484304.095833333326, 1764098.133333333, 1382.43333333333339, + 23461965.73333333433, 7.350300000000000e+04, 685240944.600000024, + 4462741.533333333209, 1764098.133333333302, 48387348.933333330, 32917.40000000000146, + 16240.93333333333, 5.092333333333334e+01, 470977.900000000, + 2973.033333333333, 1382.433333333333, 32917.40000000, 22.66666666666667), + nrow = 7, ncol = 7, byrow = TRUE) + + verifyCovariance(longley, expectedCovariance, "longley") + + # Swiss Fertility + + fertility <- matrix(c(80.2,17.0,15,12,9.96, + 83.1,45.1,6,9,84.84, + 92.5,39.7,5,5,93.40, + 85.8,36.5,12,7,33.77, + 76.9,43.5,17,15,5.16, + 76.1,35.3,9,7,90.57, + 83.8,70.2,16,7,92.85, + 92.4,67.8,14,8,97.16, + 82.4,53.3,12,7,97.67, + 82.9,45.2,16,13,91.38, + 87.1,64.5,14,6,98.61, + 64.1,62.0,21,12,8.52, + 66.9,67.5,14,7,2.27, + 68.9,60.7,19,12,4.43, + 61.7,69.3,22,5,2.82, + 68.3,72.6,18,2,24.20, + 71.7,34.0,17,8,3.30, + 55.7,19.4,26,28,12.11, + 54.3,15.2,31,20,2.15, + 65.1,73.0,19,9,2.84, + 65.5,59.8,22,10,5.23, + 65.0,55.1,14,3,4.52, + 56.6,50.9,22,12,15.14, + 57.4,54.1,20,6,4.20, + 72.5,71.2,12,1,2.40, + 74.2,58.1,14,8,5.23, + 72.0,63.5,6,3,2.56, + 60.5,60.8,16,10,7.72, + 58.3,26.8,25,19,18.46, + 65.4,49.5,15,8,6.10, + 75.5,85.9,3,2,99.71, + 69.3,84.9,7,6,99.68, + 77.3,89.7,5,2,100.00, + 70.5,78.2,12,6,98.96, + 79.4,64.9,7,3,98.22, + 65.0,75.9,9,9,99.06, + 92.2,84.6,3,3,99.46, + 79.3,63.1,13,13,96.83, + 70.4,38.4,26,12,5.62, + 65.7,7.7,29,11,13.79, + 72.7,16.7,22,13,11.22, + 64.4,17.6,35,32,16.92, + 77.6,37.6,15,7,4.97, + 67.6,18.7,25,7,8.65, + 35.0,1.2,37,53,42.34, + 44.7,46.6,16,29,50.43, + 42.8,27.7,22,29,58.33), + nrow = 47, ncol = 5, byrow = TRUE) + + expectedCovariance <- matrix(c( + 156.0424976873265, 100.1691489361702, -64.36692876965772, -79.7295097132285, 241.5632030527289, + 100.169148936170251, 515.7994172062905, -124.39283071230344, -139.6574005550416, 379.9043755781684, + -64.3669287696577, -124.3928307123034, 63.64662349676226, 53.5758556891767, -190.5606105457909, + -79.7295097132285, -139.6574005550416, 53.57585568917669, 92.4560592044403, -61.6988297872340, + 241.5632030527289, 379.9043755781684, -190.56061054579092, -61.6988297872340, 1739.2945371877890), + nrow = 5, ncol = 5, byrow = TRUE) + + verifyCovariance(fertility, expectedCovariance, "swiss fertility") + + displayDashes(WIDTH) \ No newline at end of file diff --git a/src/test/R/testAll b/src/test/R/testAll index e7f66bf29..1e63a144e 100644 --- a/src/test/R/testAll +++ b/src/test/R/testAll @@ -47,6 +47,9 @@ source("descriptiveTestCases") # multiple regression source("multipleOLSRegressionTestCases") +# covariance +source("covarianceTestCases") + #------------------------------------------------------------------------------ # if output has been diverted, change it back if (sink.number()) { diff --git a/src/test/org/apache/commons/math/stat/correlation/CovarianceTest.java b/src/test/org/apache/commons/math/stat/correlation/CovarianceTest.java new file mode 100644 index 000000000..59a6e397d --- /dev/null +++ b/src/test/org/apache/commons/math/stat/correlation/CovarianceTest.java @@ -0,0 +1,225 @@ +/* + * 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. + */ +package org.apache.commons.math.stat.correlation; + +import org.apache.commons.math.TestUtils; +import org.apache.commons.math.linear.RealMatrix; +import org.apache.commons.math.linear.RealMatrixImpl; +import org.apache.commons.math.stat.descriptive.moment.Variance; + +import junit.framework.TestCase; + +public class CovarianceTest extends TestCase { + + protected final double[] longleyData = new double[] { + 60323,83.0,234289,2356,1590,107608,1947, + 61122,88.5,259426,2325,1456,108632,1948, + 60171,88.2,258054,3682,1616,109773,1949, + 61187,89.5,284599,3351,1650,110929,1950, + 63221,96.2,328975,2099,3099,112075,1951, + 63639,98.1,346999,1932,3594,113270,1952, + 64989,99.0,365385,1870,3547,115094,1953, + 63761,100.0,363112,3578,3350,116219,1954, + 66019,101.2,397469,2904,3048,117388,1955, + 67857,104.6,419180,2822,2857,118734,1956, + 68169,108.4,442769,2936,2798,120445,1957, + 66513,110.8,444546,4681,2637,121950,1958, + 68655,112.6,482704,3813,2552,123366,1959, + 69564,114.2,502601,3931,2514,125368,1960, + 69331,115.7,518173,4806,2572,127852,1961, + 70551,116.9,554894,4007,2827,130081,1962 + }; + + protected final double[] swissData = new double[] { + 80.2,17.0,15,12,9.96, + 83.1,45.1,6,9,84.84, + 92.5,39.7,5,5,93.40, + 85.8,36.5,12,7,33.77, + 76.9,43.5,17,15,5.16, + 76.1,35.3,9,7,90.57, + 83.8,70.2,16,7,92.85, + 92.4,67.8,14,8,97.16, + 82.4,53.3,12,7,97.67, + 82.9,45.2,16,13,91.38, + 87.1,64.5,14,6,98.61, + 64.1,62.0,21,12,8.52, + 66.9,67.5,14,7,2.27, + 68.9,60.7,19,12,4.43, + 61.7,69.3,22,5,2.82, + 68.3,72.6,18,2,24.20, + 71.7,34.0,17,8,3.30, + 55.7,19.4,26,28,12.11, + 54.3,15.2,31,20,2.15, + 65.1,73.0,19,9,2.84, + 65.5,59.8,22,10,5.23, + 65.0,55.1,14,3,4.52, + 56.6,50.9,22,12,15.14, + 57.4,54.1,20,6,4.20, + 72.5,71.2,12,1,2.40, + 74.2,58.1,14,8,5.23, + 72.0,63.5,6,3,2.56, + 60.5,60.8,16,10,7.72, + 58.3,26.8,25,19,18.46, + 65.4,49.5,15,8,6.10, + 75.5,85.9,3,2,99.71, + 69.3,84.9,7,6,99.68, + 77.3,89.7,5,2,100.00, + 70.5,78.2,12,6,98.96, + 79.4,64.9,7,3,98.22, + 65.0,75.9,9,9,99.06, + 92.2,84.6,3,3,99.46, + 79.3,63.1,13,13,96.83, + 70.4,38.4,26,12,5.62, + 65.7,7.7,29,11,13.79, + 72.7,16.7,22,13,11.22, + 64.4,17.6,35,32,16.92, + 77.6,37.6,15,7,4.97, + 67.6,18.7,25,7,8.65, + 35.0,1.2,37,53,42.34, + 44.7,46.6,16,29,50.43, + 42.8,27.7,22,29,58.33 + }; + + + /** + * Test Longley dataset against R. + * Data Source: J. Longley (1967) "An Appraisal of Least Squares + * Programs for the Electronic Computer from the Point of View of the User" + * Journal of the American Statistical Association, vol. 62. September, + * pp. 819-841. + * + * Data are from NIST: + * http://www.itl.nist.gov/div898/strd/lls/data/LINKS/DATA/Longley.dat + */ + public void testLongly() { + RealMatrix matrix = createRealMatrix(longleyData, 16, 7); + RealMatrix covarianceMatrix = new Covariance(matrix).getCovarianceMatrix(); + double[] rData = new double[] { + 12333921.73333333246, 3.679666000000000e+04, 343330206.333333313, + 1649102.666666666744, 1117681.066666666651, 23461965.733333334, 16240.93333333333248, + 36796.66000000000, 1.164576250000000e+02, 1063604.115416667, + 6258.666250000000, 3490.253750000000, 73503.000000000, 50.92333333333334, + 343330206.33333331347, 1.063604115416667e+06, 9879353659.329166412, + 56124369.854166664183, 30880428.345833335072, 685240944.600000024, 470977.90000000002328, + 1649102.66666666674, 6.258666250000000e+03, 56124369.854166664, + 873223.429166666698, -115378.762499999997, 4462741.533333333, 2973.03333333333330, + 1117681.06666666665, 3.490253750000000e+03, 30880428.345833335, + -115378.762499999997, 484304.095833333326, 1764098.133333333, 1382.43333333333339, + 23461965.73333333433, 7.350300000000000e+04, 685240944.600000024, + 4462741.533333333209, 1764098.133333333302, 48387348.933333330, 32917.40000000000146, + 16240.93333333333, 5.092333333333334e+01, 470977.900000000, + 2973.033333333333, 1382.433333333333, 32917.40000000, 22.66666666666667 + }; + + TestUtils.assertEquals("covariance matrix", createRealMatrix(rData, 7, 7), covarianceMatrix, 10E-9); + + } + + /** + * Test R Swiss fertility dataset against R. + * Data Source: R datasets package + */ + public void testSwissFertility() { + RealMatrix matrix = createRealMatrix(swissData, 47, 5); + RealMatrix covarianceMatrix = new Covariance(matrix).getCovarianceMatrix(); + double[] rData = new double[] { + 156.0424976873265, 100.1691489361702, -64.36692876965772, -79.7295097132285, 241.5632030527289, + 100.169148936170251, 515.7994172062905, -124.39283071230344, -139.6574005550416, 379.9043755781684, + -64.3669287696577, -124.3928307123034, 63.64662349676226, 53.5758556891767, -190.5606105457909, + -79.7295097132285, -139.6574005550416, 53.57585568917669, 92.4560592044403, -61.6988297872340, + 241.5632030527289, 379.9043755781684, -190.56061054579092, -61.6988297872340, 1739.2945371877890 + }; + + TestUtils.assertEquals("covariance matrix", createRealMatrix(rData, 5, 5), covarianceMatrix, 10E-13); + } + + /** + * Constant column + */ + public void testConstant() { + double[] noVariance = new double[] {1, 1, 1, 1}; + double[] values = new double[] {1, 2, 3, 4}; + assertEquals(0d, new Covariance().covariance(noVariance, values, true), Double.MIN_VALUE); + assertEquals(0d, new Covariance().covariance(noVariance, noVariance, true), Double.MIN_VALUE); + } + + + /** + * Insufficient data + */ + public void testInsufficientData() { + double[] one = new double[] {1}; + double[] two = new double[] {2}; + try { + new Covariance().covariance(one, two, false); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // Expected + } + RealMatrix matrix = new RealMatrixImpl(new double[][] {{0},{1}}); + try { + new Covariance(matrix); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // Expected + } + } + + /** + * Verify that diagonal entries are consistent with Variance computation and matrix matches + * column-by-column covariances + */ + public void testConsistency() { + RealMatrix matrix = createRealMatrix(swissData, 47, 5); + RealMatrix covarianceMatrix = new Covariance(matrix).getCovarianceMatrix(); + + // Variances on the diagonal + Variance variance = new Variance(); + for (int i = 0; i < 5; i++) { + assertEquals(variance.evaluate(matrix.getColumn(i)), covarianceMatrix.getEntry(i,i), 10E-14); + } + + // Symmetry, column-consistency + assertEquals(covarianceMatrix.getEntry(2, 3), + new Covariance().covariance(matrix.getColumn(2), matrix.getColumn(3), true), 10E-14); + assertEquals(covarianceMatrix.getEntry(2, 3), covarianceMatrix.getEntry(3, 2), Double.MIN_VALUE); + + // All columns same -> all entries = column variance + RealMatrix repeatedColumns = new RealMatrixImpl(47, 3); + for (int i = 0; i < 3; i++) { + repeatedColumns.setColumnMatrix(i, matrix.getColumnMatrix(0)); + } + covarianceMatrix = new Covariance(repeatedColumns).getCovarianceMatrix(); + double columnVariance = variance.evaluate(matrix.getColumn(0)); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + assertEquals(columnVariance, covarianceMatrix.getEntry(i, j), 10E-14); + } + } + + } + + protected RealMatrix createRealMatrix(double[] data, int nRows, int nCols) { + double[][] matrixData = new double[nRows][nCols]; + int ptr = 0; + for (int i = 0; i < nRows; i++) { + System.arraycopy(data, ptr, matrixData[i], 0, nCols); + ptr += nCols; + } + return new RealMatrixImpl(matrixData); + } +}