private Double contourError(Contour c1, Contour c2) { double error = 0.0; for (Pair<Double, Double> p : c1) { error += (p.second - c2.get(p.first)); } error /= c1.contentSize(); return error; }
private Double contourRMSE(Contour c1, Contour c2) { double rmse = 0.0; for (Pair<Double, Double> p : c1) { rmse += (p.second - c2.get(p.first)) * (p.second - c2.get(p.first)); } rmse /= c1.contentSize(); rmse = Math.sqrt(rmse); return rmse; }
private CurveShape smooth(int p, boolean isPeak, Contour c) { CurveShape curve = new CurveShape(p, isPeak); if (p > 0 && p < c.size() && c.isEmpty(p)) { curve.rmse = Double.MAX_VALUE; return curve; } // reflect values around the peak double[] v = new double[c.size()]; for (int i = 0; i < c.size(); ++i) { if (!c.isEmpty(i)) { if (i >= p) { if (p < 0) { v[i] = -c.get(i); } else { v[i] = 2 * c.get(p) - c.get(i); } } else { v[i] = c.get(i); } if (!isPeak) { v[i] = -v[i]; } } else { v[i] = Double.NaN; } } ArrayList<Block> pava_blocks = new ArrayList<Block>(); // initialize blocks for (int i = 0; i < c.size(); ++i) { if (!Double.isNaN(v[i])) { pava_blocks.add(new Block(i, i, v[i])); } } // Merge blocks using PAVA boolean done = false; boolean increasing = true; int idx = 1; int start_merge = -1, end_merge = -1; while (!done) { while (idx < pava_blocks.size()) { // monotonically increasing. if (pava_blocks.get(idx - 1).x < pava_blocks.get(idx).x) { if (!increasing) { // merge break; } } else if (pava_blocks.get(idx - 1).x > pava_blocks.get(idx).x) { if (increasing) { start_merge = idx - 1; } end_merge = idx; increasing = false; } idx++; } done = true; if (start_merge != end_merge) { // merge blocks double value = 0.0; for (int i = start_merge; i <= end_merge; ++i) { value += pava_blocks.get(i).x * (pava_blocks.get(i).high_idx - pava_blocks.get(i).low_idx + 1); } value /= (pava_blocks.get(end_merge).high_idx - pava_blocks.get(start_merge).low_idx + 1); Block new_block = new Block( pava_blocks.get(start_merge).low_idx, pava_blocks.get(end_merge).high_idx, value); // remove the old blocks while (start_merge <= end_merge) { pava_blocks.remove(start_merge); end_merge--; } // replace with the new, merged block pava_blocks.add(start_merge, new_block); done = false; // Reset idx = 1; start_merge = -1; end_merge = -1; increasing = true; } } // Generate a smooth contour from block representation double[] smoothed = new double[c.size()]; for (Block b : pava_blocks) { for (int i = b.low_idx; i <= b.high_idx; ++i) { if (!c.isEmpty(i)) { if (i >= p) { if (p < 0) { smoothed[i] = -b.x; } else { if (!isPeak) { smoothed[i] = 2 * -c.get(p) - b.x; } else { smoothed[i] = 2 * c.get(p) - b.x; } } } else { smoothed[i] = b.x; } } if (!isPeak) { smoothed[i] = -smoothed[i]; } } } // Calculate RMSE double rmse = 0.0; for (int i = 0; i < c.size(); ++i) { if (!c.isEmpty(i)) { rmse += (c.get(i) - smoothed[i]) * (c.get(i) - smoothed[i]); } } rmse /= c.contentSize(); rmse = Math.sqrt(rmse); curve.rmse = rmse; curve.smoothed_curve = smoothed; return curve; }