/**
     * Gradient
     *
     * @param x a <code>double[]</code> input vector
     * @return
     */
    @Override
    public double[] gradient(double[] x) {
      double[] sqrtPsi = new double[nVariables];
      double[] invSqrtPsi = new double[nVariables];
      for (int i = 0; i < nVariables; i++) {
        x[i] = Math.max(0.005, x[i]); // ensure that no parameters are negative
        sqrtPsi[i] = Math.sqrt(x[i]);
        invSqrtPsi[i] = 1.0 / Math.sqrt(x[i]);
      }
      DiagonalMatrix diagPsi = new DiagonalMatrix(x);
      DiagonalMatrix diagSqtPsi = new DiagonalMatrix(sqrtPsi);
      DiagonalMatrix SC = new DiagonalMatrix(invSqrtPsi);

      RealMatrix Sstar = SC.multiply(R2).multiply(SC);

      EigenDecomposition E = new EigenDecomposition(Sstar);
      RealMatrix L = E.getV().getSubMatrix(0, nVariables - 1, 0, nFactors - 1);
      double[] ev = new double[nFactors];
      for (int i = 0; i < nFactors; i++) {
        ev[i] = Math.sqrt(Math.max(E.getRealEigenvalue(i) - 1, 0));
      }
      DiagonalMatrix M = new DiagonalMatrix(ev);
      RealMatrix LOAD = L.multiply(M);

      RealMatrix LL = diagSqtPsi.multiply(LOAD);
      RealMatrix G = LL.multiply(LL.transpose()).add(diagPsi).subtract(R2);

      double[] gradient = new double[nVariables];
      for (int i = 0; i < nVariables; i++) {
        gradient[i] = G.getEntry(i, i) / (x[i] * x[i]);
      }
      return gradient;
    }
    public double valueAt(double[] param) {
      double[] sdInv = new double[nVariables];

      for (int i = 0; i < nVariables; i++) {
        R.setEntry(i, i, 1.0 - param[i]);
        sdInv[i] = 1.0 / Sinv.getEntry(i, i);
      }

      DiagonalMatrix diagSdInv = new DiagonalMatrix(sdInv);

      EigenDecomposition eigen = new EigenDecomposition(R);
      RealMatrix eigenVectors = eigen.getV().getSubMatrix(0, nVariables - 1, 0, nFactors - 1);

      double[] ev = new double[nFactors];
      for (int i = 0; i < nFactors; i++) {
        ev[i] = Math.sqrt(eigen.getRealEigenvalue(i));
      }
      DiagonalMatrix evMatrix =
          new DiagonalMatrix(
              ev); // USE Apache version of Diagonal matrix when upgrade to version 3.2
      RealMatrix LAMBDA = eigenVectors.multiply(evMatrix);
      RealMatrix SIGMA = (LAMBDA.multiply(LAMBDA.transpose()));

      double value = 0.0;
      RealMatrix DIF = R.subtract(SIGMA);
      for (int i = 0; i < DIF.getRowDimension(); i++) {
        for (int j = 0; j < DIF.getColumnDimension(); j++) {
          value = DIF.getEntry(i, j);
          DIF.setEntry(i, j, Math.pow(value, 2));
        }
      }

      RealMatrix RESID = diagSdInv.multiply(DIF).multiply(diagSdInv);

      double sum = 0.0;
      for (int i = 0; i < RESID.getRowDimension(); i++) {
        for (int j = 0; j < RESID.getColumnDimension(); j++) {
          sum += RESID.getEntry(i, j);
        }
      }
      return sum;
    }
예제 #3
0
 public RealMatrix makeZta(RealMatrix userFeature, RealMatrix articleFeature) {
   RealMatrix product = userFeature.multiply(articleFeature.transpose());
   double[][] productData = product.getData();
   double[] productVector = new double[36];
   int count = 0;
   for (int row = 0; row < 6; row++) {
     for (int col = 0; col < 6; col++) {
       productVector[count] = productData[row][col];
       count++;
     }
   }
   return MatrixUtils.createColumnRealMatrix(productVector);
 }
 private double prediction(long user, long item) {
   double baseline = baselineScorer.score(user, item);
   try {
     RealMatrix userFeature = model.getUserVector(user);
     RealMatrix featureWeights = model.getFeatureWeights();
     RealMatrix itemFeature = model.getItemVector(item);
     double product =
         userFeature.multiply(featureWeights).multiply(itemFeature.transpose()).getEntry(0, 0);
     return baseline + product;
   } catch (NullPointerException npe) {
     return baseline;
   }
 }
예제 #5
0
  @Override
  public void updateReward(User user, Article a, boolean clicked) {
    String aId = a.getId();
    // Collect Variables
    RealMatrix xta = MatrixUtils.createColumnRealMatrix(a.getFeatures());
    RealMatrix zta = makeZta(MatrixUtils.createColumnRealMatrix(user.getFeatures()), xta);

    RealMatrix Aa = AMap.get(aId);
    RealMatrix ba = bMap.get(aId);
    RealMatrix Ba = BMap.get(aId);

    // Find common transpose/inverse to save computation
    RealMatrix AaInverse = MatrixUtils.inverse(Aa);
    RealMatrix BaTranspose = Ba.transpose();
    RealMatrix xtaTranspose = xta.transpose();
    RealMatrix ztaTranspose = zta.transpose();

    // Update
    A0 = A0.add(BaTranspose.multiply(AaInverse).multiply(Ba));
    b0 = b0.add(BaTranspose.multiply(AaInverse).multiply(ba));
    Aa = Aa.add(xta.multiply(xtaTranspose));
    AMap.put(aId, Aa);
    Ba = Ba.add(xta.multiply(ztaTranspose));
    BMap.put(aId, Ba);
    if (clicked) {
      ba = ba.add(xta);
      bMap.put(aId, ba);
    }

    // Update A0 and b0 with the new values
    A0 =
        A0.add(zta.multiply(ztaTranspose))
            .subtract(Ba.transpose().multiply(MatrixUtils.inverse(Aa).multiply(Ba)));
    b0 = b0.subtract(Ba.transpose().multiply(MatrixUtils.inverse(Aa)).multiply(ba));
    if (clicked) {
      b0 = b0.add(zta);
    }
  }
예제 #6
0
  @Override
  public Article chooseArm(User user, List<Article> articles) {
    Article bestA = null;
    double bestArmP = Double.MIN_VALUE;

    RealMatrix Aa;
    RealMatrix Ba;
    RealMatrix ba;

    for (Article a : articles) {
      String aId = a.getId();
      if (!AMap.containsKey(aId)) {
        Aa = MatrixUtils.createRealIdentityMatrix(6);
        AMap.put(aId, Aa); // set as identity for now and we will update
        // in reward

        double[] zeros = {0, 0, 0, 0, 0, 0};
        ba = MatrixUtils.createColumnRealMatrix(zeros);
        bMap.put(aId, ba);

        double[][] BMapZeros = new double[6][36];
        for (double[] row : BMapZeros) {
          Arrays.fill(row, 0.0);
        }
        Ba = MatrixUtils.createRealMatrix(BMapZeros);
        BMap.put(aId, Ba);
      } else {
        Aa = AMap.get(aId);
        ba = bMap.get(aId);
        Ba = BMap.get(aId);
      }

      // Make column vector out of features
      RealMatrix xta = MatrixUtils.createColumnRealMatrix(a.getFeatures());
      RealMatrix zta = makeZta(MatrixUtils.createColumnRealMatrix(user.getFeatures()), xta);

      // Set up common variables
      RealMatrix A0Inverse = MatrixUtils.inverse(A0);
      RealMatrix AaInverse = MatrixUtils.inverse(Aa);
      RealMatrix ztaTranspose = zta.transpose();
      RealMatrix BaTranspose = Ba.transpose();
      RealMatrix xtaTranspose = xta.transpose();

      // Find theta
      RealMatrix theta = AaInverse.multiply(ba.subtract(Ba.multiply(BetaHat)));
      // Find sta
      RealMatrix staMatrix = ztaTranspose.multiply(A0Inverse).multiply(zta);
      staMatrix =
          staMatrix.subtract(
              ztaTranspose
                  .multiply(A0Inverse)
                  .multiply(BaTranspose)
                  .multiply(AaInverse)
                  .multiply(xta)
                  .scalarMultiply(2));
      staMatrix = staMatrix.add(xtaTranspose.multiply(AaInverse).multiply(xta));
      staMatrix =
          staMatrix.add(
              xtaTranspose
                  .multiply(AaInverse)
                  .multiply(Ba)
                  .multiply(A0Inverse)
                  .multiply(BaTranspose)
                  .multiply(AaInverse)
                  .multiply(xta));

      // Find pta for arm
      RealMatrix ptaMatrix = ztaTranspose.multiply(BetaHat);
      ptaMatrix = ptaMatrix.add(xtaTranspose.multiply(theta));
      double ptaVal = ptaMatrix.getData()[0][0];
      double staVal = staMatrix.getData()[0][0];
      ptaVal = ptaVal + alpha * Math.sqrt(staVal);

      // Update argmax
      if (ptaVal > bestArmP) {
        bestArmP = ptaVal;
        bestA = a;
      }
    }
    return bestA;
  }
예제 #7
0
  @Override
  protected Object execute(Object[] data) {
    if (data[0] == null) {
      throw new ExecutionPlanRuntimeException(
          "Invalid input given to kf:kalmanFilter() "
              + "function. First argument should be a double");
    }
    if (data[1] == null) {
      throw new ExecutionPlanRuntimeException(
          "Invalid input given to kf:kalmanFilter() "
              + "function. Second argument should be a double");
    }
    if (data.length == 2) {
      double measuredValue = (Double) data[0]; // to remain as the initial state
      if (prevEstimatedValue == 0) {
        transition = 1;
        variance = 1000;
        measurementNoiseSD = (Double) data[1];
        prevEstimatedValue = measuredValue;
      }
      prevEstimatedValue = transition * prevEstimatedValue;
      double kalmanGain = variance / (variance + measurementNoiseSD);
      prevEstimatedValue = prevEstimatedValue + kalmanGain * (measuredValue - prevEstimatedValue);
      variance = (1 - kalmanGain) * variance;
      return prevEstimatedValue;
    } else {
      if (data[2] == null) {
        throw new ExecutionPlanRuntimeException(
            "Invalid input given to kf:kalmanFilter() "
                + "function. Third argument should be a double");
      }
      if (data[3] == null) {
        throw new ExecutionPlanRuntimeException(
            "Invalid input given to kf:kalmanFilter() "
                + "function. Fourth argument should be a long");
      }

      double measuredXValue = (Double) data[0];
      double measuredChangingRate = (Double) data[1];
      double measurementNoiseSD = (Double) data[2];
      long timestamp = (Long) data[3];
      long timestampDiff;
      double[][] measuredValues = {{measuredXValue}, {measuredChangingRate}};

      if (measurementMatrixH == null) {
        timestampDiff = 1;
        double[][] varianceValues = {{1000, 0}, {0, 1000}};
        double[][] measurementValues = {{1, 0}, {0, 1}};
        measurementMatrixH = MatrixUtils.createRealMatrix(measurementValues);
        varianceMatrixP = MatrixUtils.createRealMatrix(varianceValues);
        prevMeasuredMatrix = MatrixUtils.createRealMatrix(measuredValues);
      } else {
        timestampDiff = (timestamp - prevTimestamp);
      }
      double[][] Rvalues = {{measurementNoiseSD, 0}, {0, measurementNoiseSD}};
      RealMatrix rMatrix = MatrixUtils.createRealMatrix(Rvalues);
      double[][] transitionValues = {{1d, timestampDiff}, {0d, 1d}};
      RealMatrix transitionMatrixA = MatrixUtils.createRealMatrix(transitionValues);
      RealMatrix measuredMatrixX = MatrixUtils.createRealMatrix(measuredValues);

      // Xk = (A * Xk-1)
      prevMeasuredMatrix = transitionMatrixA.multiply(prevMeasuredMatrix);

      // Pk = (A * P * AT) + Q
      varianceMatrixP =
          (transitionMatrixA.multiply(varianceMatrixP)).multiply(transitionMatrixA.transpose());

      // S = (H * P * HT) + R
      RealMatrix S =
          ((measurementMatrixH.multiply(varianceMatrixP)).multiply(measurementMatrixH.transpose()))
              .add(rMatrix);
      RealMatrix S_1 = new LUDecomposition(S).getSolver().getInverse();

      // P * HT * S-1
      RealMatrix kalmanGainMatrix =
          (varianceMatrixP.multiply(measurementMatrixH.transpose())).multiply(S_1);

      // Xk = Xk + kalmanGainMatrix (Zk - HkXk )
      prevMeasuredMatrix =
          prevMeasuredMatrix.add(
              kalmanGainMatrix.multiply(
                  (measuredMatrixX.subtract(measurementMatrixH.multiply(prevMeasuredMatrix)))));

      // Pk = Pk - K.Hk.Pk
      varianceMatrixP =
          varianceMatrixP.subtract(
              (kalmanGainMatrix.multiply(measurementMatrixH)).multiply(varianceMatrixP));

      prevTimestamp = timestamp;
      return prevMeasuredMatrix.getRow(0)[0];
    }
  }
  private void computeFactorLoadings(double[] x) {
    uniqueness = x;
    communality = new double[nVariables];

    for (int i = 0; i < nVariables; i++) {
      R.setEntry(i, i, 1.0 - x[i]);
    }

    EigenDecomposition E = new EigenDecomposition(R);
    RealMatrix L = E.getV().getSubMatrix(0, nVariables - 1, 0, nFactors - 1);
    double[] ev = new double[nFactors];
    for (int i = 0; i < nFactors; i++) {
      ev[i] = Math.sqrt(E.getRealEigenvalue(i));
    }
    DiagonalMatrix M = new DiagonalMatrix(ev);
    RealMatrix LOAD = L.multiply(M);

    // rotate factor loadings
    if (rotationMethod != RotationMethod.NONE) {
      GPArotation gpa = new GPArotation();
      RotationResults results = gpa.rotate(LOAD, rotationMethod);
      LOAD = results.getFactorLoadings();
    }

    Sum[] colSums = new Sum[nFactors];
    Sum[] colSumsSquares = new Sum[nFactors];

    for (int j = 0; j < nFactors; j++) {
      colSums[j] = new Sum();
      colSumsSquares[j] = new Sum();
    }

    factorLoading = new double[nVariables][nFactors];

    for (int i = 0; i < nVariables; i++) {
      for (int j = 0; j < nFactors; j++) {
        factorLoading[i][j] = LOAD.getEntry(i, j);
        colSums[j].increment(factorLoading[i][j]);
        colSumsSquares[j].increment(Math.pow(factorLoading[i][j], 2));
        communality[i] += Math.pow(factorLoading[i][j], 2);
      }
    }

    // check sign of factor
    double sign = 1.0;
    for (int i = 0; i < nVariables; i++) {
      for (int j = 0; j < nFactors; j++) {
        if (colSums[j].getResult() < 0) {
          sign = -1.0;
        } else {
          sign = 1.0;
        }
        factorLoading[i][j] = factorLoading[i][j] * sign;
      }
    }

    double totSumOfSquares = 0.0;
    sumsOfSquares = new double[nFactors];
    proportionOfExplainedVariance = new double[nFactors];
    proportionOfVariance = new double[nFactors];
    for (int j = 0; j < nFactors; j++) {
      sumsOfSquares[j] = colSumsSquares[j].getResult();
      totSumOfSquares += sumsOfSquares[j];
    }
    for (int j = 0; j < nFactors; j++) {
      proportionOfExplainedVariance[j] = sumsOfSquares[j] / totSumOfSquares;
      proportionOfVariance[j] = sumsOfSquares[j] / nVariables;
    }
  }
  @Override
  public List<MLCallbackResult> detect(
      final String user,
      final String algorithm,
      UserActivityAggModel userActivity,
      UserProfileEigenModel aModel) {
    RealMatrix inputData = userActivity.matrix();
    LOG.warn(
        "EigenBasedAnomalyDetection predictAnomaly called with dimension: "
            + inputData.getRowDimension()
            + "x"
            + inputData.getColumnDimension());

    if (aModel == null) {
      LOG.warn(
          "nothing to do as the input model does not have required values, returning from evaluating this algorithm..");
      return null;
    }

    List<MLCallbackResult> mlCallbackResults = new ArrayList<MLCallbackResult>();
    RealMatrix normalizedMat = normalizeData(inputData, aModel);

    UserCommandStatistics[] listStats = aModel.statistics();
    int colWithHighVariant = 0;

    for (int j = 0; j < normalizedMat.getColumnDimension(); j++) {
      if (listStats[j].isLowVariant() == false) {
        colWithHighVariant++;
      }
    }

    final Map<String, String> context =
        new HashMap<String, String>() {
          {
            put(UserProfileConstants.USER_TAG, user);
            put(UserProfileConstants.ALGORITHM_TAG, algorithm);
          }
        };

    Map<Integer, String> lineNoWithVariantBasedAnomalyDetection = new HashMap<Integer, String>();
    for (int i = 0; i < normalizedMat.getRowDimension(); i++) {
      MLCallbackResult aResult = new MLCallbackResult();
      aResult.setContext(context);

      for (int j = 0; j < normalizedMat.getColumnDimension(); j++) {
        // LOG.info("mean for j=" + j + " is:" + listStats[j].getMean());
        // LOG.info("stddev for j=" + j + " is:" + listStats[j].getStddev());
        if (listStats[j].isLowVariant() == true) {
          // LOG.info(listOfCmds[j] + " is low variant");
          if (normalizedMat.getEntry(i, j) > listStats[j].getMean()) {
            lineNoWithVariantBasedAnomalyDetection.put(i, "lowVariantAnomaly");
            aResult.setAnomaly(true);
            aResult.setTimestamp(userActivity.timestamp());
            aResult.setFeature(listStats[j].getCommandName());
            aResult.setAlgorithm(UserProfileConstants.EIGEN_DECOMPOSITION_ALGORITHM);
            List<String> datapoints = new ArrayList<String>();
            double[] rowVals = inputData.getRow(i);
            for (double rowVal : rowVals) datapoints.add(rowVal + "");
            aResult.setDatapoints(datapoints);
            aResult.setId(user);
            mlCallbackResults.add(aResult);
          } else {
            aResult.setAnomaly(false);
            aResult.setTimestamp(userActivity.timestamp());
            mlCallbackResults.add(aResult);
          }
        }
      }
      // return results;
    }

    // LOG.info("results size here: " + results.length);

    // LOG.info("col with high variant: " + colWithHighVariant);
    RealMatrix finalMatWithoutLowVariantFeatures =
        new Array2DRowRealMatrix(normalizedMat.getRowDimension(), colWithHighVariant);
    // LOG.info("size of final test data: " + finalMatWithoutLowVariantFeatures.getRowDimension()
    // +"x"+ finalMatWithoutLowVariantFeatures.getColumnDimension());
    int finalMatrixRow = 0;
    int finalMatrixCol = 0;
    for (int i = 0; i < normalizedMat.getRowDimension(); i++) {
      for (int j = 0; j < normalizedMat.getColumnDimension(); j++) {
        if (listStats[j].isLowVariant() == false) {
          finalMatWithoutLowVariantFeatures.setEntry(
              finalMatrixRow, finalMatrixCol, normalizedMat.getEntry(i, j));
          finalMatrixCol++;
        }
      }
      finalMatrixCol = 0;
      finalMatrixRow++;
    }
    RealVector[] pcs = aModel.principalComponents();
    // LOG.info("pc size: " + pcs.getRowDimension() +"x" + pcs.getColumnDimension());

    RealMatrix finalInputMatTranspose = finalMatWithoutLowVariantFeatures.transpose();

    for (int i = 0; i < finalMatWithoutLowVariantFeatures.getRowDimension(); i++) {
      if (lineNoWithVariantBasedAnomalyDetection.get(i) == null) {
        MLCallbackResult result = new MLCallbackResult();
        result.setContext(context);
        for (int sz = 0; sz < pcs.length; sz++) {
          double[] pc1 = pcs[sz].toArray();
          RealMatrix pc1Mat = new Array2DRowRealMatrix(pc1);
          RealMatrix transposePC1Mat = pc1Mat.transpose();
          RealMatrix testData =
              pc1Mat.multiply(transposePC1Mat).multiply(finalInputMatTranspose.getColumnMatrix(i));
          // LOG.info("testData size: " + testData.getRowDimension() + "x" +
          // testData.getColumnDimension());
          RealMatrix testDataTranspose = testData.transpose();
          // LOG.info("testData transpose size: " + testDataTranspose.getRowDimension() + "x" +
          // testDataTranspose.getColumnDimension());
          RealVector iRowVector = testDataTranspose.getRowVector(0);
          // RealVector pc1Vector = transposePC1Mat.getRowVector(sz);
          RealVector pc1Vector = transposePC1Mat.getRowVector(0);
          double distanceiRowAndPC1 = iRowVector.getDistance(pc1Vector);
          // LOG.info("distance from pc sz: " + sz + " " + distanceiRowAndPC1 + " " +
          // model.getMaxL2Norm().getEntry(sz));
          // LOG.info("model.getMaxL2Norm().getEntry(sz):" + model.getMaxL2Norm().getEntry(sz));
          if (distanceiRowAndPC1 > aModel.maximumL2Norm().getEntry(sz)) {
            // LOG.info("distance from pc sz: " + sz + " " + distanceiRowAndPC1 + " " +
            // model.getMaxL2Norm().getEntry(sz));
            result.setAnomaly(true);
            result.setFeature(aModel.statistics()[sz].getCommandName());
            result.setTimestamp(System.currentTimeMillis());
            result.setAlgorithm(UserProfileConstants.EIGEN_DECOMPOSITION_ALGORITHM);
            List<String> datapoints = new ArrayList<String>();
            double[] rowVals = inputData.getRow(i);
            for (double rowVal : rowVals) datapoints.add(rowVal + "");
            result.setDatapoints(datapoints);
            result.setId(user);
          }
        }
        mlCallbackResults.add(result);
      }
    }
    return mlCallbackResults;
  }
예제 #10
0
  private double generalizedCorrelationRatio(SampleIterator it, int inputDim, int out) {
    Map<Double, Integer> n_y = new HashMap<>();
    Map<Double, MultivariateSummaryStatistics> stat_y = new HashMap<>();
    List<RealMatrix> x = new ArrayList<>();
    MultivariateSummaryStatistics stat = new MultivariateSummaryStatistics(inputDim, unbiased);

    for (int i = 0; i < maxSamples && it.hasNext(); i++) {
      Sample sample = it.next();
      double[] input = sample.getEncodedInput().toArray();
      double output = sample.getEncodedOutput().getEntry(out);
      if (!n_y.containsKey(output)) {
        n_y.put(output, 0);
        stat_y.put(output, new MultivariateSummaryStatistics(inputDim, unbiased));
      }

      injectNoise(input);
      n_y.put(output, n_y.get(output) + 1);
      stat_y.get(output).addValue(input);
      x.add(new Array2DRowRealMatrix(input));
      stat.addValue(input);
    }

    RealMatrix x_sum = new Array2DRowRealMatrix(stat.getSum());
    Map<Double, RealMatrix> x_y_sum = new HashMap<>();
    for (Entry<Double, MultivariateSummaryStatistics> entry : stat_y.entrySet()) {
      x_y_sum.put(entry.getKey(), new Array2DRowRealMatrix(entry.getValue().getSum()));
    }

    RealMatrix H = new Array2DRowRealMatrix(inputDim, inputDim);
    RealMatrix temp = new Array2DRowRealMatrix(inputDim, inputDim);

    for (double key : n_y.keySet()) {
      temp =
          temp.add(
              x_y_sum
                  .get(key)
                  .multiply(x_y_sum.get(key).transpose())
                  .scalarMultiply(1.0 / n_y.get(key)));
    }
    H = temp.subtract(x_sum.multiply(x_sum.transpose()).scalarMultiply(1.0 / x.size()));

    RealMatrix E = new Array2DRowRealMatrix(inputDim, inputDim);
    for (RealMatrix m : x) {
      E = E.add(m.multiply(m.transpose()));
    }
    E = E.subtract(temp);

    List<Integer> zeroColumns = findZeroColumns(E);
    E = removeZeroColumns(E, zeroColumns);
    H = removeZeroColumns(H, zeroColumns);

    Matrix JE = new Matrix(E.getData());
    Matrix JH = new Matrix(H.getData());

    if (JE.rank() < JE.getRowDimension()) {
      Log.write(this, "Some error occurred (E matrix is singular)");
      return -1;
    } else {
      double lambda;
      if (useEigenvalues) {
        Matrix L = JE.inverse().times(JH);
        double[] eigs = L.eig().getRealEigenvalues();
        Arrays.sort(eigs);

        lambda = 1;
        int nonNullEigs = n_y.keySet().size() - 1;
        for (int i = eigs.length - nonNullEigs; i < eigs.length; i++) {
          if (Math.abs(eigs[i]) < zeroThreshold) {
            Log.write(this, "Some error occurred (E matrix has too many null eigenvalues)");
            return -1;
          }
          lambda *= 1.0 / (1.0 + eigs[i]);
        }
      } else {
        Matrix sum = JE.plus(JH);
        if (sum.rank() < sum.getRowDimension()) {
          Log.write(this, "Some error occourred (E+H is singular");
          return -1;
        }
        lambda = JE.det() / sum.det();
      }

      return Math.sqrt(1 - lambda);
    }
  }