示例#1
0
  @Override
  public Map<Long, Long> findFS() {
    int[] usedCounts = Arrays.copyOfRange(counts, 0, capwidth);

    // initial frequency is the same as what we see from counters
    Map<Integer, Long> freq =
        Arrays.stream(usedCounts)
            .boxed()
            .collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()));
    Long zeroNum = freq.get(0);
    if (zeroNum != null && zeroNum == capwidth) {
      return new HashMap<>();
    }

    // estimate the number of items
    int num = (int) (capwidth * Math.log(1.0 * capwidth / zeroNum));

    Distribution newDistribution = new Distribution(freq);
    Distribution oldDistribution = new Distribution();

    // A pattern is a setting of itmes+frequencies that sum to sumI
    // All patterns in this list will map to a common number sumI
    List<Map<Integer, Integer>> patterns = new ArrayList<>();
    List<Double> probabilities = new ArrayList<>();
    int iterations = 0;

    // iteratively update the distribution
    // while (notConverged()) {
    while (iterations < MAXIMUM_ITERATIONS) {
      oldDistribution.fillFrom(newDistribution);
      newDistribution.clear();
      for (Map.Entry<Integer, Long> entry : freq.entrySet()) {
        int sumI = entry.getKey();
        int freqI = entry.getValue().intValue();
        if (sumI == 0) { // skip key=0
          continue;
        }
        // find new probable patterns, get their probabilities and update the distribution
        getPatterns(patterns, sumI, freqI, oldDistribution);
        computeProbabilities(patterns, oldDistribution, probabilities);
        Iterator<Double> probabilityIterator = probabilities.iterator();
        for (Map<Integer, Integer> pattern : patterns) { // for each pattern
          double probability = probabilityIterator.next();
          for (Map.Entry<Integer, Integer> patternEntry : pattern.entrySet()) {
            newDistribution.addFreq(
                patternEntry.getKey(), freqI * patternEntry.getValue() * probability);
          }
        }
      }

      // scale factor to make sum of distribution equal to 1
      double scale = num / newDistribution.sumFreq();
      pw.println(
          String.format(
              DISTRIBUTION_TRACE_FORMATTER,
              getStep() + 1,
              iterations + 1,
              newDistribution.toString(scale)));
      iterations++;
    }
    pw.flush();
    System.out.println(getStep());

    Map<Long, Long> output = new HashMap<>();
    double freqSum = newDistribution.sumFreq();

    for (Map.Entry<Integer, Double> entry : newDistribution.freq.entrySet()) {
      output.put(entry.getKey().longValue(), (long) (entry.getValue() / freqSum * num));
    }
    return output;
  }