protected void handleVariableChangedEvent(
      Variable variable, int index, Parameter.ChangeType type) {
    if (variable == traitParameter) { // A tip value got updated
      if (index > dimTrait * treeModel.getExternalNodeCount()) {
        throw new RuntimeException("Attempting to update an invalid index");
      }

      if (index != -1) {
        cacheHelper.setMeanCache(index, traitParameter.getValue(index));
      } else {
        for (int idx = 0; idx < traitParameter.getDimension(); ++idx) {
          cacheHelper.setMeanCache(idx, traitParameter.getValue(idx));
        }
      }
      // meanCache[index] = traitParameter.getValue(index);
      likelihoodKnown = false;
      //            if (!cacheBranches) {
      //                throw new RuntimeException("Must cache means in IMTL if they are random");
      //            }
      // TODO Need better solution.  If tips are random, cacheBranches should be true (to get
      // reset).
      // TODO However, jitter calls setParameterValue() on the tips at initialization
    }
    super.handleVariableChangedEvent(variable, index, type);
  }
 /**
  * Create a region with the given region description name.
  *
  * @param regDescriptName The name of a region description.
  */
 protected void initializeRegion(String regDescriptName) {
   CacheHelper.createCache("cache1");
   String key = VmIDStr + RemoteTestModule.getMyVmid();
   String xmlFile = key + ".xml";
   try {
     CacheHelper.generateCacheXmlFile("cache1", regDescriptName, xmlFile);
   } catch (HydraRuntimeException e) {
     if (e.toString().indexOf("Cache XML file was already created") >= 0) {
       // this can occur when reinitializing after a stop-start because
       // the cache xml file is written during the first init tasks
     } else {
       throw new TestException(TestHelper.getStackTrace(e));
     }
   }
   aRegion = RegionHelper.createRegion(regDescriptName);
 }
 public void setTipDataValuesForNode(int index, double[] traitValue) {
   // Set tip data values
   // cacheHelper.copyToMeanCache(traitValue, dim*index, dim);
   cacheHelper.setTipMeans(traitValue, dim, index);
   // System.arraycopy(traitValue, 0, meanCache, dim * index, dim);
   makeDirty();
 }
 /**
  * Returns the async event queues for the current cache, or null if no async event queues or cache
  * exists.
  */
 public static Set<AsyncEventQueue> getAsyncEventQueues() {
   Cache cache = CacheHelper.getCache();
   if (cache == null) {
     return null;
   } else {
     Set<AsyncEventQueue> queues = cache.getAsyncEventQueues();
     return (queues == null || queues.size() == 0) ? null : queues;
   }
 }
  private void setTipDataValuesForNode(NodeRef node) {
    // Set tip data values
    int index = node.getNumber();
    double[] traitValue = traitParameter.getParameter(index).getParameterValues();
    if (traitValue.length < dim) {
      throw new RuntimeException(
          "The trait parameter for the tip with index, " + index + ", is too short");
    }

    cacheHelper.setTipMeans(traitValue, dim, index, node);
    //        System.arraycopy(traitValue, 0, meanCache
    ////                cacheHelper.getMeanCache()
    //                , dim * index, dim);
  }
  private void incrementOuterProducts(
      int thisOffset, int childOffset0, int childOffset1, double precision0, double precision1) {

    final double[][] outerProduct = wishartStatistics.getScaleMatrix();

    for (int k = 0; k < numData; k++) {

      for (int i = 0; i < dimTrait; i++) {

        // final double wChild0i = meanCache[childOffset0 + k * dimTrait + i] * precision0;
        // final double wChild1i = meanCache[childOffset1 + k * dimTrait + i] * precision1;
        final double wChild0i =
            cacheHelper.getCorrectedMeanCache()[childOffset0 + k * dimTrait + i] * precision0;
        final double wChild1i =
            cacheHelper.getCorrectedMeanCache()[childOffset1 + k * dimTrait + i] * precision1;

        for (int j = 0; j < dimTrait; j++) {

          // final double child0j = meanCache[childOffset0 + k * dimTrait + j];
          // final double child1j = meanCache[childOffset1 + k * dimTrait + j];
          final double child0j =
              cacheHelper.getCorrectedMeanCache()[childOffset0 + k * dimTrait + j];
          final double child1j =
              cacheHelper.getCorrectedMeanCache()[childOffset1 + k * dimTrait + j];

          outerProduct[i][j] += wChild0i * child0j;
          outerProduct[i][j] += wChild1i * child1j;

          // outerProduct[i][j] -= (wChild0i + wChild1i) * meanCache[thisOffset + k * dimTrait + j];
          outerProduct[i][j] -=
              (wChild0i + wChild1i) * cacheHelper.getMeanCache()[thisOffset + k * dimTrait + j];
        }
      }
    }
    wishartStatistics.incrementDf(1); // Peeled one node
  }
 protected void initializeQueryService() {
   try {
     String usingPool = TestConfig.tab().stringAt(CQUtilPrms.QueryServiceUsingPool, "false");
     boolean queryServiceUsingPool = Boolean.valueOf(usingPool).booleanValue();
     if (queryServiceUsingPool) {
       Pool pool = PoolHelper.createPool(CQUtilPrms.getQueryServicePoolName());
       qService = pool.getQueryService();
       Log.getLogWriter()
           .info("Initializing QueryService using Pool. PoolName: " + pool.getName());
     } else {
       qService = CacheHelper.getCache().getQueryService();
       Log.getLogWriter().info("Initializing QueryService using Cache.");
     }
   } catch (Exception e) {
     throw new TestException(TestHelper.getStackTrace(e));
   }
 }
  public void storeState() {
    super.storeState();

    if (cacheBranches) {
      //     System.arraycopy(meanCache, 0, storedMeanCache, 0, meanCache.length);
      cacheHelper.store();
      System.arraycopy(
          upperPrecisionCache, 0, storedUpperPrecisionCache, 0, upperPrecisionCache.length);
      System.arraycopy(
          lowerPrecisionCache, 0, storedLowerPrecisionCache, 0, lowerPrecisionCache.length);
      System.arraycopy(
          logRemainderDensityCache,
          0,
          storedLogRemainderDensityCache,
          0,
          logRemainderDensityCache.length);
    }
  }
  /**
   * Creates and starts an async event queue in the current cache. The queue is configured using the
   * {@link AsyncEventQueueDescription} corresponding to the given configuration from {@link
   * AsyncEventQueuePrms#names}. The id for the queue is the same as the queue configuration name.
   *
   * <p>This method is thread-safe. The async event queues for a given logical queue configuration
   * will only be created once.
   *
   * @throws HydraRuntimeException if an attempt is made to reconfigure an existing async event
   *     queue.
   */
  public static synchronized AsyncEventQueue createAndStartAsyncEventQueue(
      String asyncEventQueueConfig) {
    AsyncEventQueue queue = getAsyncEventQueue(asyncEventQueueConfig);
    if (queue == null) {

      // get the cache
      Cache cache = CacheHelper.getCache();
      if (cache == null) {
        String s = "Cache has not been created yet";
        throw new HydraRuntimeException(s);
      }

      // look up the async event queue configuration
      AsyncEventQueueDescription aeqd = getAsyncEventQueueDescription(asyncEventQueueConfig);

      // create the disk store
      DiskStoreHelper.createDiskStore(aeqd.getDiskStoreDescription().getName());

      // create the async event queue
      queue = createAsyncEventQueue(aeqd, cache);
    }
    return queue;
  }
  public void restoreState() {
    super.restoreState();

    if (cacheBranches) {
      double[] tmp;

      cacheHelper.restore();
      //  tmp = storedMeanCache;
      //  storedMeanCache = meanCache;
      //  meanCache = tmp;

      tmp = storedUpperPrecisionCache;
      storedUpperPrecisionCache = upperPrecisionCache;
      upperPrecisionCache = tmp;

      tmp = storedLowerPrecisionCache;
      storedLowerPrecisionCache = lowerPrecisionCache;
      lowerPrecisionCache = tmp;

      tmp = storedLogRemainderDensityCache;
      storedLogRemainderDensityCache = logRemainderDensityCache;
      logRemainderDensityCache = tmp;
    }
  }
  private void preOrderTraverseSample(
      MultivariateTraitTree treeModel,
      NodeRef node,
      int parentIndex,
      double[][] treePrecision,
      double[][] treeVariance) {

    final int thisIndex = node.getNumber();

    if (treeModel.isRoot(node)) {
      // draw root

      double[] rootMean = new double[dimTrait];
      final int rootIndex = treeModel.getRoot().getNumber();
      double rootPrecision = lowerPrecisionCache[rootIndex];

      for (int datum = 0; datum < numData; datum++) {
        // System.arraycopy(meanCache, thisIndex * dim + datum * dimTrait, rootMean, 0, dimTrait);
        System.arraycopy(
            cacheHelper.getMeanCache(), thisIndex * dim + datum * dimTrait, rootMean, 0, dimTrait);

        double[][] variance =
            computeMarginalRootMeanAndVariance(
                rootMean, treePrecision, treeVariance, rootPrecision);

        double[] draw =
            MultivariateNormalDistribution.nextMultivariateNormalVariance(rootMean, variance);

        if (DEBUG_PREORDER) {
          Arrays.fill(draw, 1.0);
        }

        System.arraycopy(draw, 0, drawnStates, rootIndex * dim + datum * dimTrait, dimTrait);

        if (DEBUG) {
          System.err.println("Root mean: " + new Vector(rootMean));
          System.err.println("Root var : " + new Matrix(variance));
          System.err.println("Root draw: " + new Vector(draw));
        }
      }
    } else { // draw conditional on parentState

      if (!missingTraits.isCompletelyMissing(thisIndex)
          && !missingTraits.isPartiallyMissing(thisIndex)) {

        // System.arraycopy(meanCache, thisIndex * dim, drawnStates, thisIndex * dim, dim);
        System.arraycopy(
            cacheHelper.getMeanCache(), thisIndex * dim, drawnStates, thisIndex * dim, dim);

      } else {

        if (missingTraits.isPartiallyMissing(thisIndex)) {
          throw new RuntimeException("Partially missing values are not yet implemented");
        }
        // This code should work for sampling a missing tip trait as well, but needs testing

        // parent trait at drawnStates[parentOffset]
        double precisionToParent = 1.0 / getRescaledBranchLengthForPrecision(node);
        double precisionOfNode = lowerPrecisionCache[thisIndex];
        double totalPrecision = precisionOfNode + precisionToParent;

        double[] mean = Ay; // temporary storage
        double[][] var = tmpM; // temporary storage

        for (int datum = 0; datum < numData; datum++) {

          int parentOffset = parentIndex * dim + datum * dimTrait;
          int thisOffset = thisIndex * dim + datum * dimTrait;

          if (DEBUG) {
            double[] parentValue = new double[dimTrait];
            System.arraycopy(drawnStates, parentOffset, parentValue, 0, dimTrait);
            System.err.println("Parent draw: " + new Vector(parentValue));
            if (parentValue[0] != drawnStates[parentOffset]) {
              throw new RuntimeException("Error in setting indices");
            }
          }

          for (int i = 0; i < dimTrait; i++) {
            mean[i] =
                (drawnStates[parentOffset + i] * precisionToParent
                        //  + meanCache[thisOffset + i] * precisionOfNode) / totalPrecision;
                        + cacheHelper.getMeanCache()[thisOffset + i] * precisionOfNode)
                    / totalPrecision;
            for (int j = 0; j < dimTrait; j++) {
              var[i][j] = treeVariance[i][j] / totalPrecision;
            }
          }
          double[] draw = MultivariateNormalDistribution.nextMultivariateNormalVariance(mean, var);
          System.arraycopy(draw, 0, drawnStates, thisOffset, dimTrait);

          if (DEBUG) {
            System.err.println("Int prec: " + totalPrecision);
            System.err.println("Int mean: " + new Vector(mean));
            System.err.println("Int var : " + new Matrix(var));
            System.err.println("Int draw: " + new Vector(draw));
            System.err.println("");
          }
        }
      }
    }

    if (peel() && !treeModel.isExternal(node)) {
      preOrderTraverseSample(
          treeModel, treeModel.getChild(node, 0), thisIndex, treePrecision, treeVariance);
      preOrderTraverseSample(
          treeModel, treeModel.getChild(node, 1), thisIndex, treePrecision, treeVariance);
    }
  }
  private void incrementRemainderDensities(
      double[][] precisionMatrix,
      double logDetPrecisionMatrix,
      int thisIndex,
      int thisOffset,
      int childOffset0,
      int childOffset1,
      double precision0,
      double precision1,
      double OUFactor0,
      double OUFactor1,
      boolean cacheOuterProducts) {

    final double remainderPrecision = precision0 * precision1 / (precision0 + precision1);

    if (cacheOuterProducts) {
      incrementOuterProducts(thisOffset, childOffset0, childOffset1, precision0, precision1);
    }

    for (int k = 0; k < numData; k++) {

      double childSS0 = 0;
      double childSS1 = 0;
      double crossSS = 0;

      for (int i = 0; i < dimTrait; i++) {

        // In case of no drift, getCorrectedMeanCache() simply returns mean cache
        // final double wChild0i = meanCache[childOffset0 + k * dimTrait + i] * precision0;
        final double wChild0i =
            cacheHelper.getCorrectedMeanCache()[childOffset0 + k * dimTrait + i] * precision0;
        // final double wChild1i = meanCache[childOffset1 + k * dimTrait + i] * precision1;
        final double wChild1i =
            cacheHelper.getCorrectedMeanCache()[childOffset1 + k * dimTrait + i] * precision1;

        for (int j = 0; j < dimTrait; j++) {

          // subtract "correction"
          // final double child0j = meanCache[childOffset0 + k * dimTrait + j];
          final double child0j =
              cacheHelper.getCorrectedMeanCache()[childOffset0 + k * dimTrait + j];
          // subtract "correction"
          // final double child1j = meanCache[childOffset1 + k * dimTrait + j];
          final double child1j =
              cacheHelper.getCorrectedMeanCache()[childOffset1 + k * dimTrait + j];

          childSS0 += wChild0i * precisionMatrix[i][j] * child0j;
          childSS1 += wChild1i * precisionMatrix[i][j] * child1j;

          // make sure meanCache in following is not "corrected"
          // crossSS += (wChild0i + wChild1i) * precisionMatrix[i][j] * meanCache[thisOffset + k *
          // dimTrait + j];
          crossSS +=
              (wChild0i + wChild1i)
                  * precisionMatrix[i][j]
                  * cacheHelper.getMeanCache()[thisOffset + k * dimTrait + j];
        }
      }

      logRemainderDensityCache[thisIndex] +=
          -dimTrait * LOG_SQRT_2_PI
              + 0.5 * (dimTrait * Math.log(remainderPrecision) + logDetPrecisionMatrix)
              - 0.5 * (childSS0 + childSS1 - crossSS)
              - dimTrait * (Math.log(OUFactor0) + Math.log(OUFactor1));
    }
  }
  void postOrderTraverse(
      MultivariateTraitTree treeModel,
      NodeRef node,
      double[][] precisionMatrix,
      double logDetPrecisionMatrix,
      boolean cacheOuterProducts) {

    final int thisNumber = node.getNumber();

    if (treeModel.isExternal(node)) {

      // Fill in precision scalar, traitValues already filled in

      if (missingTraits.isCompletelyMissing(thisNumber)) {
        upperPrecisionCache[thisNumber] = 0;
        lowerPrecisionCache[thisNumber] = 0; // Needed in the pre-order traversal
      } else { // not missing tip trait
        upperPrecisionCache[thisNumber] =
            (1.0 / getRescaledBranchLengthForPrecision(node))
                * Math.pow(cacheHelper.getOUFactor(node), 2);
        lowerPrecisionCache[thisNumber] = Double.POSITIVE_INFINITY;
      }
      return;
    }

    final NodeRef childNode0 = treeModel.getChild(node, 0);
    final NodeRef childNode1 = treeModel.getChild(node, 1);

    postOrderTraverse(
        treeModel, childNode0, precisionMatrix, logDetPrecisionMatrix, cacheOuterProducts);
    postOrderTraverse(
        treeModel, childNode1, precisionMatrix, logDetPrecisionMatrix, cacheOuterProducts);

    final int childNumber0 = childNode0.getNumber();
    final int childNumber1 = childNode1.getNumber();
    final int meanOffset0 = dim * childNumber0;
    final int meanOffset1 = dim * childNumber1;
    final int meanThisOffset = dim * thisNumber;

    final double precision0 = upperPrecisionCache[childNumber0];
    final double precision1 = upperPrecisionCache[childNumber1];
    final double totalPrecision = precision0 + precision1;

    lowerPrecisionCache[thisNumber] = totalPrecision;

    // Multiply child0 and child1 densities

    // Delegate this!
    cacheHelper.computeMeanCaches(
        meanThisOffset,
        meanOffset0,
        meanOffset1,
        totalPrecision,
        precision0,
        precision1,
        missingTraits,
        node,
        childNode0,
        childNode1);
    //        if (totalPrecision == 0) {
    //            System.arraycopy(zeroDimVector, 0, meanCache, meanThisOffset, dim);
    //        } else {
    //            // Delegate in case either child is partially missing
    //            // computeCorrectedWeightedAverage
    //            missingTraits.computeWeightedAverage(meanCache,
    //                    meanOffset0, precision0,
    //                    meanOffset1, precision1,
    //                    meanThisOffset, dim);
    //        }
    // In this delegation, you can call
    // getShiftForBranchLength(node);

    if (!treeModel.isRoot(node)) {
      // Integrate out trait value at this node
      double thisPrecision = 1.0 / getRescaledBranchLengthForPrecision(node);
      if (Double.isInfinite(thisPrecision)) {
        upperPrecisionCache[thisNumber] = totalPrecision;
      } else {
        upperPrecisionCache[thisNumber] =
            (totalPrecision * thisPrecision / (totalPrecision + thisPrecision))
                * Math.pow(cacheHelper.getOUFactor(node), 2);
      }
    }

    // Compute logRemainderDensity

    logRemainderDensityCache[thisNumber] = 0;

    if (precision0 != 0 && precision1 != 0) {

      incrementRemainderDensities(
          precisionMatrix,
          logDetPrecisionMatrix,
          thisNumber,
          meanThisOffset,
          meanOffset0,
          meanOffset1,
          precision0,
          precision1,
          cacheHelper.getOUFactor(childNode0),
          cacheHelper.getOUFactor(childNode1),
          cacheOuterProducts);
    }
  }
  public double calculateLogLikelihood() {

    double logLikelihood = 0;
    double[][] traitPrecision = diffusionModel.getPrecisionmatrix();
    double logDetTraitPrecision = Math.log(diffusionModel.getDeterminantPrecisionMatrix());
    double[] conditionalRootMean = tmp2;

    final boolean computeWishartStatistics = getComputeWishartSufficientStatistics();

    if (computeWishartStatistics) {
      //            if (wishartStatistics == null) {
      wishartStatistics = new WishartSufficientStatistics(dimTrait);
      //            } else {
      //                wishartStatistics.clear();
      //            }
    }

    // Use dynamic programming to compute conditional likelihoods at each internal node
    postOrderTraverse(
        treeModel,
        treeModel.getRoot(),
        traitPrecision,
        logDetTraitPrecision,
        computeWishartStatistics);

    if (DEBUG) {
      System.err.println("mean: " + new Vector(cacheHelper.getMeanCache()));
      System.err.println("correctedMean: " + new Vector(cacheHelper.getCorrectedMeanCache()));
      System.err.println("upre: " + new Vector(upperPrecisionCache));
      System.err.println("lpre: " + new Vector(lowerPrecisionCache));
      System.err.println("cach: " + new Vector(logRemainderDensityCache));
    }

    // Compute the contribution of each datum at the root
    final int rootIndex = treeModel.getRoot().getNumber();

    // Precision scalar of datum conditional on root
    double conditionalRootPrecision = lowerPrecisionCache[rootIndex];

    for (int datum = 0; datum < numData; datum++) {

      double thisLogLikelihood = 0;

      // Get conditional mean of datum conditional on root
      // System.arraycopy(meanCache, rootIndex * dim + datum * dimTrait, conditionalRootMean, 0,
      // dimTrait);
      System.arraycopy(
          cacheHelper.getMeanCache(),
          rootIndex * dim + datum * dimTrait,
          conditionalRootMean,
          0,
          dimTrait);

      if (DEBUG) {
        System.err.println("Datum #" + datum);
        System.err.println("root mean: " + new Vector(conditionalRootMean));
        System.err.println("root prec: " + conditionalRootPrecision);
        System.err.println("diffusion prec: " + new Matrix(traitPrecision));
      }

      // B = root prior precision
      // z = root prior mean
      // A = likelihood precision
      // y = likelihood mean

      // y'Ay
      double yAy =
          computeWeightedAverageAndSumOfSquares(
              conditionalRootMean,
              Ay,
              traitPrecision,
              dimTrait,
              conditionalRootPrecision); // Also fills in Ay

      if (conditionalRootPrecision != 0) {
        thisLogLikelihood +=
            -LOG_SQRT_2_PI * dimTrait
                + 0.5
                    * (logDetTraitPrecision + dimTrait * Math.log(conditionalRootPrecision) - yAy);
      }

      if (DEBUG) {
        double[][] T = new double[dimTrait][dimTrait];
        for (int i = 0; i < dimTrait; i++) {
          for (int j = 0; j < dimTrait; j++) {
            T[i][j] = traitPrecision[i][j] * conditionalRootPrecision;
          }
        }
        System.err.println("Conditional root MVN precision = \n" + new Matrix(T));
        System.err.println(
            "Conditional root MVN density = "
                + MultivariateNormalDistribution.logPdf(
                    conditionalRootMean,
                    new double[dimTrait],
                    T,
                    Math.log(MultivariateNormalDistribution.calculatePrecisionMatrixDeterminate(T)),
                    1.0));
      }

      if (integrateRoot) {
        // Integrate root trait out against rootPrior
        thisLogLikelihood +=
            integrateLogLikelihoodAtRoot(
                conditionalRootMean,
                Ay,
                tmpM,
                traitPrecision,
                conditionalRootPrecision); // Ay is destroyed
      }

      if (DEBUG) {
        System.err.println("yAy = " + yAy);
        System.err.println(
            "logLikelihood (before remainders) = "
                + thisLogLikelihood
                + " (should match conditional root MVN density when root not integrated out)");
      }

      logLikelihood += thisLogLikelihood;
    }

    logLikelihood += sumLogRemainders();
    if (DEBUG) {
      System.out.println("logLikelihood is " + logLikelihood);
    }

    if (DEBUG) { // Root trait is univariate!!!
      System.err.println("logLikelihood (final) = " + logLikelihood);
      //            checkViaLargeMatrixInversion();
    }

    if (DEBUG_PNAS) {
      checkLogLikelihood(
          logLikelihood,
          sumLogRemainders(),
          conditionalRootMean,
          conditionalRootPrecision,
          traitPrecision);
    }

    areStatesRedrawn = false; // Should redraw internal node states when needed
    return logLikelihood;
  }
 public double[] getTipDataValues(int index) {
   double[] traitValue = new double[dim];
   System.arraycopy(cacheHelper.getMeanCache(), dim * index, traitValue, 0, dim);
   return traitValue;
 }