private boolean paramInBounds(Edge edge, double newValue) {
    edgeParameters.put(edge, newValue);
    Map<Node, Double> errorVariances = new HashMap<Node, Double>();
    for (Node node : semPm.getVariableNodes()) {
      Node error = semGraph.getExogenous(node);
      double d2 = calculateErrorVarianceFromParams(error);
      if (Double.isNaN(d2)) {
        return false;
      }

      errorVariances.put(error, d2);
    }

    if (!MatrixUtils.isPositiveDefinite(errCovar(errorVariances))) {
      return false;
    }

    return true;
  }
  /**
   * Computes the implied covariance matrices of the Sem. There are two: <code>implCovar </code>
   * contains the covariances of all the variables and <code>implCovarMeas</code> contains
   * covariance for the measured variables only.
   */
  private void computeImpliedCovar() {
    TetradMatrix edgeCoefT = edgeCoef().transpose();

    // Note. Since the sizes of the temp matrices in this calculation
    // never change, we ought to be able to reuse them.
    this.implCovar = MatrixUtils.impliedCovar(edgeCoefT, errCovar(errorVariances()));

    // Submatrix of implied covar for measured vars only.
    int size = getMeasuredNodes().size();
    this.implCovarMeas = new TetradMatrix(size, size);

    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        Node iNode = getMeasuredNodes().get(i);
        Node jNode = getMeasuredNodes().get(j);

        int _i = getVariableNodes().indexOf(iNode);
        int _j = getVariableNodes().indexOf(jNode);

        this.implCovarMeas.set(i, j, this.implCovar.get(_i, _j));
      }
    }
  }
  /**
   * @param sampleSize The sample size of the desired data set.
   * @param latentDataSaved True if latent variables should be included in the data set.
   * @return This returns a standardized data set simulated from the model, using the reduced form
   *     method.
   */
  public DataSet simulateDataReducedForm(int sampleSize, boolean latentDataSaved) {
    int numVars = getVariableNodes().size();

    // Calculate inv(I - edgeCoef)
    TetradMatrix edgeCoef = edgeCoef().copy().transpose();

    //        TetradMatrix iMinusB = TetradAlgebra.identity(edgeCoef.rows());
    //        iMinusB.assign(edgeCoef, Functions.minus);

    TetradMatrix iMinusB = TetradAlgebra.identity(edgeCoef.rows()).minus(edgeCoef);

    TetradMatrix inv = iMinusB.inverse();

    // Pick error values e, for each calculate inv * e.
    TetradMatrix sim = new TetradMatrix(sampleSize, numVars);

    // Generate error data with the right variances and covariances, then override this
    // with error data for varaibles that have special distributions defined. Not ideal,
    // but not sure what else to do at the moment. It's better than not taking covariances
    // into account!
    TetradMatrix cholesky = MatrixUtils.choleskyC(errCovar(errorVariances()));

    for (int i = 0; i < sampleSize; i++) {
      TetradVector e = new TetradVector(exogenousData(cholesky, RandomUtil.getInstance()));
      TetradVector ePrime = inv.times(e);
      sim.assignRow(i, ePrime); // sim.viewRow(i).assign(ePrime);
    }

    DataSet fullDataSet = ColtDataSet.makeContinuousData(getVariableNodes(), sim);

    if (latentDataSaved) {
      return fullDataSet;
    } else {
      return DataUtils.restrictToMeasured(fullDataSet);
    }
  }