Java tutorial
/* * Power Service for the GLIMMPSE Software System. Processes * incoming HTTP requests for power, sample size, and detectable * difference * * Copyright (C) 2010 Regents of the University of Colorado. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ package edu.ucdenver.bios.powersvc.resource; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.apache.commons.math3.linear.Array2DRowRealMatrix; import org.apache.commons.math3.linear.RealMatrix; import org.apache.log4j.Logger; import edu.cudenver.bios.matrix.FixedRandomMatrix; import edu.cudenver.bios.matrix.MatrixUtils; import edu.cudenver.bios.power.GLMMPower; import edu.cudenver.bios.power.Power; import edu.cudenver.bios.power.glmm.GLMMPowerConfidenceInterval.ConfidenceIntervalType; import edu.cudenver.bios.power.glmm.GLMMTestFactory; import edu.cudenver.bios.power.parameters.GLMMPowerParameters; import edu.ucdenver.bios.powersvc.application.PowerConstants; import edu.ucdenver.bios.powersvc.application.PowerLogger; import edu.ucdenver.bios.webservice.common.domain.BetaScale; import edu.ucdenver.bios.webservice.common.domain.BetweenParticipantFactor; import edu.ucdenver.bios.webservice.common.domain.Blob2DArray; import edu.ucdenver.bios.webservice.common.domain.Category; import edu.ucdenver.bios.webservice.common.domain.ClusterNode; import edu.ucdenver.bios.webservice.common.domain.ConfidenceInterval; import edu.ucdenver.bios.webservice.common.domain.ConfidenceIntervalDescription; import edu.ucdenver.bios.webservice.common.domain.Covariance; import edu.ucdenver.bios.webservice.common.domain.Hypothesis; import edu.ucdenver.bios.webservice.common.domain.HypothesisBetweenParticipantMapping; import edu.ucdenver.bios.webservice.common.domain.HypothesisRepeatedMeasuresMapping; import edu.ucdenver.bios.webservice.common.domain.NamedMatrix; import edu.ucdenver.bios.webservice.common.domain.NamedMatrixList; import edu.ucdenver.bios.webservice.common.domain.NominalPower; import edu.ucdenver.bios.webservice.common.domain.PowerMethod; import edu.ucdenver.bios.webservice.common.domain.PowerResult; import edu.ucdenver.bios.webservice.common.domain.PowerResultList; import edu.ucdenver.bios.webservice.common.domain.Quantile; import edu.ucdenver.bios.webservice.common.domain.RelativeGroupSize; import edu.ucdenver.bios.webservice.common.domain.RepeatedMeasuresNode; import edu.ucdenver.bios.webservice.common.domain.SampleSize; import edu.ucdenver.bios.webservice.common.domain.SigmaScale; import edu.ucdenver.bios.webservice.common.domain.StatisticalTest; import edu.ucdenver.bios.webservice.common.domain.StudyDesign; import edu.ucdenver.bios.webservice.common.domain.TypeIError; import edu.ucdenver.bios.webservice.common.enums.PowerMethodEnum; import edu.ucdenver.bios.webservice.common.enums.StatisticalTestTypeEnum; import edu.ucdenver.bios.webservice.common.enums.StudyDesignViewTypeEnum; /** * Helper class for conversion to/from domain layer objects * @author Sarah Kreidler * */ public final class PowerResourceHelper { /** The logger. */ private static Logger logger = PowerLogger.getInstance(); /** * Convert a study design object into a power parameters object * TODO: should be removed once modifications to java stats are complete * * @param studyDesign * @return power parameter object for use with JavaStatistics */ public static GLMMPowerParameters studyDesignToPowerParameters(StudyDesign studyDesign) throws IllegalArgumentException { GLMMPowerParameters params = new GLMMPowerParameters(); /** Build list inputs **/ // add tests if (studyDesign.getStatisticalTestList() != null) { for (StatisticalTest test : studyDesign.getStatisticalTestList()) { params.addTest(toGLMMTest(test)); } } // add alpha values if (studyDesign.getAlphaList() != null) { for (TypeIError alpha : studyDesign.getAlphaList()) { params.addAlpha(alpha.getAlphaValue()); } } // add nominal powers if (studyDesign.getNominalPowerList() != null) { for (NominalPower power : studyDesign.getNominalPowerList()) { params.addPower(power.getValue()); } } // add per group sample sizes if (studyDesign.getSampleSizeList() != null) { for (SampleSize size : studyDesign.getSampleSizeList()) { params.addSampleSize(size.getValue()); } } // add beta scale values if (studyDesign.getBetaScaleList() != null) { for (BetaScale betaScale : studyDesign.getBetaScaleList()) { params.addBetaScale(betaScale.getValue()); } } // add sigma scale values if (studyDesign.getSigmaScaleList() != null) { for (SigmaScale scale : studyDesign.getSigmaScaleList()) { params.addSigmaScale(scale.getValue()); } } /** Generate and add matrices **/ // build design matrix params.setDesignEssence(designMatrixFromStudyDesign(studyDesign)); // build beta matrix params.setBeta(betaMatrixFromStudyDesign(studyDesign)); // build the between subject contrast params.setBetweenSubjectContrast(betweenParticipantContrastFromStudyDesign(studyDesign)); // build the within subject contrast params.setWithinSubjectContrast(withinParticipantContrastFromStudyDesign(studyDesign)); // build theta null matrix params.setTheta(thetaNullMatrixFromStudyDesign(studyDesign, params.getBetweenSubjectContrast(), params.getWithinSubjectContrast())); // add matrices for either GLMM(F) or GLMM(F,g) designs if (studyDesign.isGaussianCovariate()) { RealMatrix sigmaY = sigmaOutcomesMatrixFromStudyDesign(studyDesign); RealMatrix sigmaG = sigmaCovariateMatrixFromStudyDesign(studyDesign); params.setSigmaOutcome(sigmaY); params.setSigmaGaussianRandom(sigmaG); params.setSigmaOutcomeGaussianRandom( sigmaOutcomesCovariateMatrixFromStudyDesign(studyDesign, sigmaG, sigmaY)); // add power methods if (studyDesign.getPowerMethodList() != null) { for (PowerMethod method : studyDesign.getPowerMethodList()) { params.addPowerMethod(toGLMMPowerMethod(method)); } } // add quantiles if (studyDesign.getQuantileList() != null) { for (Quantile quantile : studyDesign.getQuantileList()) { params.addQuantile(quantile.getValue()); } } } else { params.setSigmaError(sigmaErrorMatrixFromStudyDesign(studyDesign)); params.addPowerMethod(GLMMPowerParameters.PowerMethod.CONDITIONAL_POWER); // add confidence intervals if specified ConfidenceIntervalDescription CIdescr = studyDesign.getConfidenceIntervalDescriptions(); if (CIdescr != null) { params.setAlphaLowerConfidenceLimit(CIdescr.getLowerTailProbability()); params.setAlphaUpperConfidenceLimit(CIdescr.getUpperTailProbability()); params.setDesignMatrixRankForEstimates(CIdescr.getRankOfDesignMatrix()); params.setSampleSizeForEstimates(CIdescr.getSampleSize()); if (CIdescr.isBetaFixed() && !CIdescr.isSigmaFixed()) { params.setConfidenceIntervalType(ConfidenceIntervalType.BETA_KNOWN_SIGMA_ESTIMATED); } else if (!CIdescr.isBetaFixed() && !CIdescr.isSigmaFixed()) { params.setConfidenceIntervalType(ConfidenceIntervalType.BETA_SIGMA_ESTIMATED); } } } return params; } /** * Convert a domain layer PowerMethod to a GLMMPowerParameters.PowerMethod type. * @param method domain layer PowerMethod object * @return GLMM PowerMethod enum type * @throws IllegalArgumentException on unknown power methods */ private static GLMMPowerParameters.PowerMethod toGLMMPowerMethod(PowerMethod method) throws IllegalArgumentException { switch (method.getPowerMethodEnum()) { case CONDITIONAL: return GLMMPowerParameters.PowerMethod.CONDITIONAL_POWER; case QUANTILE: return GLMMPowerParameters.PowerMethod.QUANTILE_POWER; case UNCONDITIONAL: return GLMMPowerParameters.PowerMethod.CONDITIONAL_POWER; default: throw new IllegalArgumentException("unknown power method"); } } /** * Convert a domain layer PowerMethod to a GLMMPowerParameters.PowerMethod type. * @param method domain layer PowerMethod object * @return GLMM PowerMethod enum type * @throws IllegalArgumentException on unknown power methods */ private static PowerMethod toPowerMethod(GLMMPowerParameters.PowerMethod method) throws IllegalArgumentException { switch (method) { case CONDITIONAL_POWER: return new PowerMethod(PowerMethodEnum.CONDITIONAL); case QUANTILE_POWER: return new PowerMethod(PowerMethodEnum.QUANTILE); case UNCONDITIONAL_POWER: return new PowerMethod(PowerMethodEnum.CONDITIONAL); default: throw new IllegalArgumentException("unknown power method"); } } /** * Convert a domain layer statistical test to a GLMMTest enum */ private static GLMMTestFactory.Test toGLMMTest(StatisticalTest test) throws IllegalArgumentException { switch (test.getType()) { case UNIREP: return GLMMTestFactory.Test.UNIREP; case UNIREPBOX: return GLMMTestFactory.Test.UNIREP_BOX; case UNIREPGG: return GLMMTestFactory.Test.UNIREP_GEISSER_GREENHOUSE; case UNIREPHF: return GLMMTestFactory.Test.UNIREP_HUYNH_FELDT; case WL: return GLMMTestFactory.Test.WILKS_LAMBDA; case PBT: return GLMMTestFactory.Test.PILLAI_BARTLETT_TRACE; case HLT: return GLMMTestFactory.Test.HOTELLING_LAWLEY_TRACE; default: throw new IllegalArgumentException("unknown test"); } } /** * Convert a domain layer statistical test to a GLMMTest enum */ private static StatisticalTest toStatisticalTest(GLMMTestFactory.Test test) throws IllegalArgumentException { switch (test) { case UNIREP: return new StatisticalTest(StatisticalTestTypeEnum.UNIREP); case UNIREP_BOX: return new StatisticalTest(StatisticalTestTypeEnum.UNIREPBOX); case UNIREP_GEISSER_GREENHOUSE: return new StatisticalTest(StatisticalTestTypeEnum.UNIREPGG); case UNIREP_HUYNH_FELDT: return new StatisticalTest(StatisticalTestTypeEnum.UNIREPHF); case WILKS_LAMBDA: return new StatisticalTest(StatisticalTestTypeEnum.WL); case PILLAI_BARTLETT_TRACE: return new StatisticalTest(StatisticalTestTypeEnum.PBT); case HOTELLING_LAWLEY_TRACE: return new StatisticalTest(StatisticalTestTypeEnum.HLT); default: throw new IllegalArgumentException("unknown test"); } } /** * Return the design matrix if present, or generate a cell means coded * design essence matrix for "guided" study designs * @param studyDesign study design object * @return design essence matrix */ public static RealMatrix designMatrixFromStudyDesign(StudyDesign studyDesign) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { // matrix based design return toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_DESIGN)); } else { /* For Guided study designs, we assume a cell means coding. Thus, the design matrix is * simply an identity matrix with dimension equal to the product of the number of levels * of each between subject factor * We add additional rows for unequal group sizes */ int totalColumns = 1; // calculate the product of the #levels of each between participant factor List<BetweenParticipantFactor> factorList = studyDesign.getBetweenParticipantFactorList(); if (factorList != null) { for (BetweenParticipantFactor factor : factorList) { List<Category> categoryList = factor.getCategoryList(); if (categoryList != null) { totalColumns *= categoryList.size(); } } } int totalRows = 0; List<RelativeGroupSize> groupSizeList = studyDesign.getRelativeGroupSizeList(); if (totalColumns > 1) { // we have multiple groups, so check for unequal group sizes if (groupSizeList != null) { if (groupSizeList.size() != totalColumns) { // invalid relative group size list throw new IllegalArgumentException("Invalid list of relative group sizes"); } for (RelativeGroupSize relativeSize : groupSizeList) { totalRows += relativeSize.getValue(); } } else { totalRows = totalColumns; } } else { // only 1 column, so the X matrix must be 1x1 totalRows = 1; } RealMatrix designEssenceMatrix = null; // make sure we didn't produce bad dimensions if (totalRows <= 0 || totalColumns <= 0) { throw new IllegalArgumentException("Unable to produce a valid design matrix"); } // now build the actual matrix if (totalRows == totalColumns) { // equal group sizes, so just a basic cell means coding (i.e. identity) designEssenceMatrix = org.apache.commons.math3.linear.MatrixUtils .createRealIdentityMatrix(totalRows); } else { // unequal group sizes, so start with a zero matrix designEssenceMatrix = MatrixUtils.getRealMatrixWithFilledValue(totalRows, totalColumns, 0); // now set 1's in the appropriate places int col = 0; int row = 0; for (RelativeGroupSize relativeSize : groupSizeList) { for (int counter = 0; counter < relativeSize.getValue(); counter++) { designEssenceMatrix.setEntry(row, col, 1); row++; } col++; } } return designEssenceMatrix; } } /** * Create a fixed/random beta matrix from the study design. * @param studyDesign study design object * @return fixed/random beta matrix */ public static FixedRandomMatrix betaMatrixFromStudyDesign(StudyDesign studyDesign) { double[][] betaFixedData = null; double[][] betaRandomData = null; int rows = 0; NamedMatrix betaFixed = studyDesign.getNamedMatrix(PowerConstants.MATRIX_BETA); NamedMatrix betaRandom = studyDesign.getNamedMatrix(PowerConstants.MATRIX_BETA_RANDOM); // get the beta information from the study design matrices if (betaFixed != null) { betaFixedData = betaFixed.getData().getData(); rows = betaFixed.getRows(); } if (betaRandom != null) { betaRandomData = betaRandom.getData().getData(); } // for guided mode designs, we need to adjust for clustering if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.GUIDED_MODE) { List<ClusterNode> clusterNodeList = studyDesign.getClusteringTree(); if (clusterNodeList != null && clusterNodeList.size() > 0) { int totalColumns = 1; for (ClusterNode node : clusterNodeList) { totalColumns *= node.getGroupSize(); } // direct product the beta matrix with a matrix of ones to // generate the proper dimensions for a cluster sample RealMatrix oneMatrix = MatrixUtils.getRealMatrixWithFilledValue(1, totalColumns, 1); RealMatrix betaFixedMatrix = new Array2DRowRealMatrix(betaFixedData); betaFixedMatrix = MatrixUtils.getKroneckerProduct(oneMatrix, betaFixedMatrix); // reset the data betaFixedData = betaFixedMatrix.getData(); // now repeat for the beta random matrix if (betaRandom != null) { oneMatrix = MatrixUtils.getRealMatrixWithFilledValue(1, totalColumns, 1); RealMatrix betaRandomMatrix = new Array2DRowRealMatrix(betaRandomData); betaRandomMatrix = MatrixUtils.getKroneckerProduct(oneMatrix, betaRandomMatrix); // reset the data betaRandomData = betaRandomMatrix.getData(); } } } FixedRandomMatrix betaFixedRandom = new FixedRandomMatrix(betaFixedData, betaRandomData, false); return betaFixedRandom; } /** * Create a fixed/random between participant contrast (C matrix) * from the study design. * @param studyDesign study design object * @return fixed/random C matrix */ public static FixedRandomMatrix betweenParticipantContrastFromStudyDesign(StudyDesign studyDesign) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { // matrix based design NamedMatrix cFixed = studyDesign.getNamedMatrix(PowerConstants.MATRIX_BETWEEN_CONTRAST); NamedMatrix cRandom = studyDesign.getNamedMatrix(PowerConstants.MATRIX_BETWEEN_CONTRAST_RANDOM); return new FixedRandomMatrix((cFixed != null ? cFixed.getData().getData() : null), (cRandom != null ? cRandom.getData().getData() : null), true); } else { // Guided design Set<Hypothesis> hypothesisSet = studyDesign.getHypothesis(); if (hypothesisSet != null) { // only consider the primary hypothesis at present (i.e. the first one) Hypothesis hypothesis = hypothesisSet.iterator().next(); if (hypothesis != null) { RealMatrix cFixed = null; RealMatrix cRandom = null; // get the factor of interest List<HypothesisBetweenParticipantMapping> betweenMap = hypothesis .getBetweenParticipantFactorMapList(); if (betweenMap != null && betweenMap.size() > 0) { // build the fixed part of the contrast based on the hypothesis of interest switch (hypothesis.getType()) { case MAIN_EFFECT: // between subject factor of interest cFixed = ContrastHelper.mainEffectBetween( betweenMap.get(0).getBetweenParticipantFactor(), studyDesign.getBetweenParticipantFactorList()); break; case INTERACTION: cFixed = ContrastHelper.interactionBetween(betweenMap, studyDesign.getBetweenParticipantFactorList()); break; case TREND: HypothesisBetweenParticipantMapping trendFactor = betweenMap.get(0); cFixed = ContrastHelper.trendBetween(trendFactor, studyDesign.getBetweenParticipantFactorList()); } } else { cFixed = ContrastHelper.grandMeanBetween(studyDesign.getBetweenParticipantFactorList()); } // build the random contrast if the design has a baseline covariate if (studyDesign.isGaussianCovariate()) { if (cFixed != null) { cRandom = MatrixUtils.getRealMatrixWithFilledValue(cFixed.getRowDimension(), 1, 0); } } return new FixedRandomMatrix((cFixed != null ? cFixed.getData() : null), (cRandom != null ? cRandom.getData() : null), true); } // no hypothesis specified return null; } } // unknown view type return null; } /** * Create the within participant contrast (U matrix) * from the study design. * @param studyDesign study design object * @return U matrix */ public static RealMatrix withinParticipantContrastFromStudyDesign(StudyDesign studyDesign) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { return toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_WITHIN_CONTRAST)); } else { // Guided design Set<Hypothesis> hypothesisSet = studyDesign.getHypothesis(); if (hypothesisSet != null) { // only consider the primary hypothesis at present (i.e. the first one) Hypothesis hypothesis = hypothesisSet.iterator().next(); if (hypothesis != null) { RealMatrix withinContrast = null; // get the factor of interest List<HypothesisRepeatedMeasuresMapping> withinMap = hypothesis.getRepeatedMeasuresMapTree(); if (withinMap != null && withinMap.size() > 0) { // build the fixed part of the contrast based on the hypothesis of interest switch (hypothesis.getType()) { case MAIN_EFFECT: // between subject factor of interest withinContrast = ContrastHelper.mainEffectWithin( withinMap.get(0).getRepeatedMeasuresNode(), studyDesign.getRepeatedMeasuresTree(), studyDesign.getResponseList()); break; case INTERACTION: withinContrast = ContrastHelper.interactionWithin(withinMap, studyDesign.getRepeatedMeasuresTree(), studyDesign.getResponseList()); break; case TREND: HypothesisRepeatedMeasuresMapping trendFactor = withinMap.get(0); withinContrast = ContrastHelper.trendWithin(trendFactor, studyDesign.getRepeatedMeasuresTree(), studyDesign.getResponseList()); } } else { withinContrast = ContrastHelper.grandMeanWithin(studyDesign.getRepeatedMeasuresTree(), studyDesign.getResponseList()); } // expand rows if clustering is present if (withinContrast != null) { List<ClusterNode> clusterNodeList = studyDesign.getClusteringTree(); if (clusterNodeList != null && clusterNodeList.size() > 0) { int totalRows = 1; for (ClusterNode node : clusterNodeList) { totalRows *= node.getGroupSize(); } // direct product the U matrix with a matrix of ones to // generate the proper dimensions for a cluster sample RealMatrix oneMatrix = MatrixUtils.getRealMatrixWithFilledValue(totalRows, 1, 1); withinContrast = MatrixUtils.getKroneckerProduct(oneMatrix, withinContrast); } } return withinContrast; } // no hypothesis specified return null; } } // unknown view type return null; } /** * Create a sigma error matrix from the study design. * @param studyDesign study design object * @return sigma error matrix */ private static RealMatrix sigmaErrorMatrixFromStudyDesign(StudyDesign studyDesign) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { return toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_SIGMA_ERROR)); } else { // guided mode, so we need to decode the covariance objects // first, allocate a list of matrices to build the overall kronecker covariance ArrayList<RealMatrix> kroneckerMatrixList = new ArrayList<RealMatrix>(); // add covariance information for clustering List<ClusterNode> clusterNodeList = studyDesign.getClusteringTree(); if (clusterNodeList != null) { for (ClusterNode clusterNode : clusterNodeList) { int rows = clusterNode.getGroupSize(); int columns = rows; double rho = clusterNode.getIntraClusterCorrelation(); // build a compound symmetric matrix double[][] data = new double[rows][columns]; for (int row = 0; row < rows; row++) { for (int col = row; col < columns; col++) { if (row == col) { data[row][col] = 1; } else { data[row][col] = rho; data[col][row] = rho; } } } // add the matrix to the kronecker product list kroneckerMatrixList.add(new Array2DRowRealMatrix(data)); } } // add covariance for repeated measures List<RepeatedMeasuresNode> rmNodeList = studyDesign.getRepeatedMeasuresTree(); if (rmNodeList != null) { for (RepeatedMeasuresNode rmNode : rmNodeList) { Covariance covariance = studyDesign.getCovarianceFromSet(rmNode.getDimension()); if (covariance != null) { RealMatrix kroneckerMatrix = CovarianceHelper.covarianceToRealMatrix(covariance, rmNode); if (kroneckerMatrix != null) { kroneckerMatrixList.add(kroneckerMatrix); } else { throw new IllegalArgumentException( "Invalid covariance information for factor: " + rmNode.getDimension()); } } else { throw new IllegalArgumentException( "Missing covariance information for factor: " + rmNode.getDimension()); } } } // lastly, we need to add the covariance of responses Covariance covariance = studyDesign.getCovarianceFromSet(PowerConstants.RESPONSES_COVARIANCE_LABEL); RealMatrix kroneckerMatrix = CovarianceHelper.covarianceToRealMatrix(covariance, studyDesign.getResponseList()); if (kroneckerMatrix != null) { kroneckerMatrixList.add(kroneckerMatrix); } else { throw new IllegalArgumentException("Invalid covariance information for response variables"); } return MatrixUtils.getKroneckerProduct(kroneckerMatrixList); } } /** * Create a sigma outcomes matrix from the study design. * @param studyDesign study design object * @return sigma outcomes matrix */ public static RealMatrix sigmaOutcomesMatrixFromStudyDesign(StudyDesign studyDesign) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { return toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_SIGMA_OUTCOME)); } else { return sigmaErrorMatrixFromStudyDesign(studyDesign); } } /** * Create a sigma outcomes/covariate matrix from the study design. * @param studyDesign study design object * @return sigma outcomes/covariate matrix */ public static RealMatrix sigmaOutcomesCovariateMatrixFromStudyDesign(StudyDesign studyDesign, RealMatrix sigmaG, RealMatrix sigmaY) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { return toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_SIGMA_OUTCOME_GAUSSIAN)); } else { RealMatrix sigmaYG = toRealMatrix( studyDesign.getNamedMatrix(PowerConstants.MATRIX_SIGMA_OUTCOME_GAUSSIAN)); /* * In guided mode, sigmaYG is specified as correlation values. We adjust * to make it into a covariance matrix. We also expand for clustering */ if (sigmaYG != null) { /* * Make into a covariance. We first make sure the other sigma matrices are * of appropriate dimension to allow this */ if (sigmaG == null || sigmaG.getRowDimension() <= 0 || sigmaG.getColumnDimension() <= 0) { throw new IllegalArgumentException("Invalid covariance for Gaussian covariate"); } if (sigmaY == null || sigmaY.getRowDimension() < sigmaYG.getRowDimension() || sigmaY.getColumnDimension() != sigmaY.getRowDimension()) { throw new IllegalArgumentException("Invalid covariance for outcome"); } // assumes sigmaG is already updated to be a variance double varG = sigmaG.getEntry(0, 0); for (int row = 0; row < sigmaYG.getRowDimension(); row++) { double corrYG = sigmaYG.getEntry(row, 0); double varY = sigmaY.getEntry(row, row); sigmaYG.setEntry(row, 0, corrYG * Math.sqrt(varG * varY)); } // calculate cluster size List<ClusterNode> clusterNodeList = studyDesign.getClusteringTree(); if (clusterNodeList != null && clusterNodeList.size() > 0) { int totalRows = 1; for (ClusterNode node : clusterNodeList) { totalRows *= node.getGroupSize(); } // kronecker product the sigmaYG matrix with a matrix of ones to // generate the proper dimensions for a cluster sample RealMatrix oneMatrix = MatrixUtils.getRealMatrixWithFilledValue(totalRows, 1, 1); sigmaYG = MatrixUtils.getKroneckerProduct(oneMatrix, sigmaYG); } } return sigmaYG; } } /** * Create a sigma covariate matrix from the study design. * @param studyDesign study design object * @return sigma covariate matrix */ public static RealMatrix sigmaCovariateMatrixFromStudyDesign(StudyDesign studyDesign) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { return toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_SIGMA_GAUSSIAN)); } else { // in Guided Mode, the user specifies this as a standard deviation, so we square it RealMatrix sigmaG = toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_SIGMA_GAUSSIAN)); if (sigmaG != null && sigmaG.getRowDimension() > 0 && sigmaG.getColumnDimension() > 0) { double stddev = sigmaG.getEntry(0, 0); sigmaG.setEntry(0, 0, stddev * stddev); } return sigmaG; } } /** * Create a null hypothesis matrix from the study design. * @param studyDesign study design object * @return theta null matrix */ public static RealMatrix thetaNullMatrixFromStudyDesign(StudyDesign studyDesign, FixedRandomMatrix C, RealMatrix U) { if (studyDesign.getViewTypeEnum() == StudyDesignViewTypeEnum.MATRIX_MODE) { return toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_THETA_NULL)); } else { RealMatrix thetaNull = toRealMatrix(studyDesign.getNamedMatrix(PowerConstants.MATRIX_THETA_NULL)); if (thetaNull == null) { if (C != null && C.getFixedMatrix() != null && U != null) { int rows = C.getFixedMatrix().getRowDimension(); int columns = U.getColumnDimension(); thetaNull = MatrixUtils.getRealMatrixWithFilledValue(rows, columns, 0); } } return thetaNull; } } /** * Create the list of matrices generated by the specified study design * @param studyDesign study design object * @return list of matrices used to compute power */ public static NamedMatrixList namedMatrixListFromStudyDesign(StudyDesign studyDesign) { if (studyDesign == null) { return null; } // allocate a result list NamedMatrixList matrixList = new NamedMatrixList(); // parse the study design into matrices // build design matrix NamedMatrix X = toNamedMatrix(designMatrixFromStudyDesign(studyDesign), PowerConstants.MATRIX_DESIGN); if (X != null) matrixList.add(X); // build beta matrix FixedRandomMatrix beta = betaMatrixFromStudyDesign(studyDesign); if (beta != null) { matrixList.add(toNamedMatrix(beta.getFixedMatrix(), PowerConstants.MATRIX_BETA)); if (studyDesign.isGaussianCovariate()) { matrixList.add(toNamedMatrix(beta.getRandomMatrix(), PowerConstants.MATRIX_BETA_RANDOM)); } } // build the between subject contrast FixedRandomMatrix C = betweenParticipantContrastFromStudyDesign(studyDesign); if (C != null) { matrixList.add(toNamedMatrix(C.getFixedMatrix(), PowerConstants.MATRIX_BETWEEN_CONTRAST)); if (studyDesign.isGaussianCovariate()) { matrixList.add(toNamedMatrix(C.getRandomMatrix(), PowerConstants.MATRIX_BETWEEN_CONTRAST_RANDOM)); } } // build the within subject contrast RealMatrix U = withinParticipantContrastFromStudyDesign(studyDesign); if (U != null) { matrixList.add(toNamedMatrix(U, PowerConstants.MATRIX_WITHIN_CONTRAST)); } // build theta null matrix NamedMatrix thetaNull = toNamedMatrix(thetaNullMatrixFromStudyDesign(studyDesign, C, U), PowerConstants.MATRIX_THETA_NULL); matrixList.add(thetaNull); // add matrices for either GLMM(F) or GLMM(F,g) designs if (studyDesign.isGaussianCovariate()) { NamedMatrix sigmaY = toNamedMatrix(sigmaOutcomesMatrixFromStudyDesign(studyDesign), PowerConstants.MATRIX_SIGMA_OUTCOME); if (sigmaY != null) matrixList.add(sigmaY); NamedMatrix sigmaG = toNamedMatrix(sigmaCovariateMatrixFromStudyDesign(studyDesign), PowerConstants.MATRIX_SIGMA_GAUSSIAN); if (sigmaG != null) matrixList.add(sigmaG); NamedMatrix sigmaYG = toNamedMatrix(sigmaOutcomesCovariateMatrixFromStudyDesign(studyDesign, toRealMatrix(sigmaG), toRealMatrix(sigmaY)), PowerConstants.MATRIX_SIGMA_OUTCOME_GAUSSIAN); if (sigmaYG != null) matrixList.add(sigmaYG); } else { NamedMatrix sigmaE = toNamedMatrix(sigmaErrorMatrixFromStudyDesign(studyDesign), PowerConstants.MATRIX_SIGMA_ERROR); if (sigmaE != null) matrixList.add(sigmaE); } return matrixList; } /** * This method takes Named Matrix and converts it into a RealMatrix and * returns a Real Matrix. * * @param namedMatrix * The matrix is a input matrix of type NamedMatrix which is to * be converted to type RealMatrix. * @return RealMatrix Returns a RealMatrix which is obtained by converting * the input matrix to a RealMatrix. */ public static RealMatrix toRealMatrix(final NamedMatrix namedMatrix) { RealMatrix realMatrix = null; if (namedMatrix != null) { Blob2DArray blob = namedMatrix.getData(); if (blob != null) { realMatrix = new Array2DRowRealMatrix(blob.getData()); } } return realMatrix; } /** * This method takes a Real Matrix and converts it into a Named Matrix and * returns that Named Matrix. * * @param matrix * The matrix is a input matrix of type RealMatrix and is to be * converted to a NamedMatrix. * @param name * the name is a String, which is to be assigned to named matrix. * @return namedMatrix Returns a NamedMatrix which is obtained by converting * the input matrix to NamedMatrix */ public static NamedMatrix toNamedMatrix(final RealMatrix matrix, final String name) { if (matrix == null || name == null || name.isEmpty()) { logger.error("failed to create NamedMatrix object name=[" + (name != null ? name : "NULL") + "]"); return null; } NamedMatrix namedMatrix = new NamedMatrix(); namedMatrix.setDataFromArray(matrix.getData()); namedMatrix.setName(name); namedMatrix.setColumns(matrix.getColumnDimension()); namedMatrix.setRows(matrix.getRowDimension()); return namedMatrix; } /** * Convert a list of GLMMPower objects to a list of PowerResult objects * @param powerList GLMMPower object list * @return list of PowerResult objects */ public static PowerResultList toPowerResultList(List<Power> powerList) { PowerResultList resultList = new PowerResultList(); for (Power power : powerList) { resultList.add(toPowerResult((GLMMPower) power)); } return resultList; } /** * Convert a GLMMPower object to PowerResult objects * @param glmmPower GLMMPower object * @return PowerResult object */ public static PowerResult toPowerResult(GLMMPower glmmPower) { Quantile quantile = null; if (!Double.isNaN(glmmPower.getQuantile())) { quantile = new Quantile(glmmPower.getQuantile()); } return new PowerResult(toStatisticalTest(glmmPower.getTest()), new TypeIError(glmmPower.getAlpha()), new NominalPower(glmmPower.getNominalPower()), glmmPower.getActualPower(), glmmPower.getTotalSampleSize(), new BetaScale(glmmPower.getBetaScale()), new SigmaScale(glmmPower.getSigmaScale()), toPowerMethod(glmmPower.getPowerMethod()), quantile, toConfidenceInterval(glmmPower.getConfidenceInterval())); } /** * Convert a JavaStatistics confidence interval into a domain layer * confidence interval * @param ci * @return domain layer confidence interval object */ private static ConfidenceInterval toConfidenceInterval(edu.cudenver.bios.utils.ConfidenceInterval ci) { if (ci == null) { return null; } else { return new ConfidenceInterval(ci.getLowerLimit(), ci.getUpperLimit(), ci.getAlphaLower(), ci.getAlphaUpper()); } } }