@Override
  public double[] getLogLikelihoods(List<Beacon> beacons, State[] locations) {
    List<Beacon> beaconsCleansed = Beacon.filterBeacons(beacons, minRssi, maxRssi);

    beaconsCleansed = beaconFilter.setBLEBeacon(bleBeacons).filter(beaconsCleansed, locations);
    BLEBeacon.setBLEBeaconIdsToMeasuredBeacons(bleBeacons, beaconsCleansed);
    int[] activeBeaconList = ModelAdaptUtils.beaconsToActiveBeaconArray(beaconsCleansed);

    final double[] ySub = ModelAdaptUtils.beaconsToVecSubset(beaconsCleansed);
    final double[][] X = ModelAdaptUtils.locationsToMat(locations);

    // Adjust bias by average bias
    final double[] rssiBiases = ModelAdaptUtils.biasesToVec(locations);

    double logLLs[] = null;
    try {
      Class<?> cls = gpLDPL.getClass();
      Constructor<?> cst = cls.getConstructor(gpLDPL.getClass());
      final GaussianProcessLDPLMean gpLDPLtmp = (GaussianProcessLDPLMean) cst.newInstance(gpLDPL);
      gpLDPLtmp.updateByActiveBeaconList(activeBeaconList);
      int n = X.length;
      final double logpro[] = new double[n];
      Future<?>[] futures = new Future<?>[n];
      for (int i = 0; i < n; i++) {
        final int idx = i;
        futures[idx] =
            ExecutorServiceHolder.getExecutorService()
                .submit(
                    new Runnable() {
                      public void run() {
                        // Subtract bias from an observation vector.
                        double[] ySubAdjusted = ArrayUtils.addScalar(ySub, -rssiBiases[idx]);
                        logpro[idx] = gpLDPLtmp.logProbaygivenx(X[idx], ySubAdjusted);
                      }
                    });
      }
      for (int i = 0; i < n; i++) {
        futures[i].get();
      }
      logLLs = logpro;
    } catch (InstantiationException
        | IllegalAccessException
        | IllegalArgumentException
        | InvocationTargetException
        | NoSuchMethodException
        | SecurityException e) {
      e.printStackTrace();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    return logLLs;
  }
  @Override
  public List<Beacon> filter(List<Beacon> beacons, State[] states) {

    int n = beacons.size();
    if (n < kBeacons) {
      return beacons;
    }

    final boolean doNormalize = this.doNormalize;
    final BLEBeaconConfig ibconfig = getBLEBeaconConfig();

    Collections.sort(
        beacons,
        new Comparator<Beacon>() {
          int DEC = -1;

          @Override
          public int compare(Beacon b1, Beacon b2) {
            int major1 = b1.getMajor();
            int minor1 = b1.getMinor();
            double rssi1 = b1.getRssi();

            int major2 = b2.getMajor();
            int minor2 = b2.getMinor();
            double rssi2 = b2.getRssi();

            double msdPower1 = 0;
            double msdPower2 = 0;
            if (doNormalize) {
              msdPower1 = ibconfig.getMsdPower(major1, minor1);
              msdPower2 = ibconfig.getMsdPower(major2, minor2);
            }

            double normedRssi1 = rssi1 - msdPower1;
            double normedRssi2 = rssi2 - msdPower2;

            if (normedRssi1 > normedRssi2) {
              return 1 * DEC;
            } else if (normedRssi1 == normedRssi2) {
              return 0;
            } else {
              return -1 * DEC;
            }
          }
        });
    int m = kBeacons < n ? kBeacons : n;

    List<Beacon> beaconsTmp = beacons.subList(0, m);

    final StringBuilder sb = new StringBuilder();
    if (n != m) {
      sb.setLength(0);
      sb.append("NormedStrongestBeaconFilter #beacons " + n + ">>" + m + ". ");
      sb.append("RSSI: ");
      for (Beacon b : beaconsTmp) {
        sb.append(b.getRssi() + ",");
      }
      System.out.println(sb.toString());
    }
    return beaconsTmp;
  }