001// ***** This file is automatically generated from BoundCore.java.jpp 002 003package daikon.inv.unary; 004 005import org.checkerframework.checker.lock.qual.GuardSatisfied; 006import org.checkerframework.dataflow.qual.Pure; 007import org.checkerframework.dataflow.qual.SideEffectFree; 008import daikon.*; 009import daikon.inv.*; 010import java.io.Serializable; 011import java.text.DecimalFormat; 012 013// One reason not to combine LowerBound and Upperbound is that they have 014// separate justifications: one may be justified when the other is not. 015 016// What should we do if there are few values in the range? 017// This can make justifying that invariant easier, because with few values 018// naturally there are more instances of each value. 019// This might also make justifying that invariant harder, because to get more 020// than (say) twice the expected number of samples (under the assumption of 021// uniform distribution) requires many samples. 022// Which of these dominates? Is the behavior what I want? 023 024@SuppressWarnings("UnnecessaryParentheses") // code generated by macros 025public class UpperBoundCore implements Serializable, Cloneable { 026 static final long serialVersionUID = 20030822L; 027 028 static final int required_samples = 5; // for enoughSamples 029 static final int required_samples_at_bound = 3; // for justification 030 031 // max1 > max2 > max3 032 public long max1 = Long.MIN_VALUE; 033 public int num_max1 = 0; 034 public long max2 = Long.MIN_VALUE; 035 public int num_max2 = 0; 036 public long max3 = Long.MIN_VALUE; 037 public int num_max3 = 0; 038 public long min = Long.MAX_VALUE; 039 040 int samples = 0; 041 042 public Invariant wrapper; 043 044 public UpperBoundCore(Invariant wrapper) { 045 this.wrapper = wrapper; 046 } 047 048 public long max() { 049 return max1; 050 } 051 052 @SideEffectFree 053 @Override 054 public UpperBoundCore clone(@GuardSatisfied UpperBoundCore this) { 055 try { 056 return (UpperBoundCore) super.clone(); 057 } catch (CloneNotSupportedException e) { 058 throw new Error(); // can't happen 059 } 060 } 061 062 private static DecimalFormat two_decimals = new java.text.DecimalFormat("#.##"); 063 064 public String repr(@GuardSatisfied UpperBoundCore this) { 065 long modulus = calc_modulus(); 066 long range = calc_range(); 067 double avg_samples_per_val = calc_avg_samples_per_val(modulus, (double)(range)); 068 return "max1=" + max1 069 + ", num_max1=" + num_max1 070 + ", max2=" + max2 071 + ", num_max2=" + num_max2 072 + ", max3=" + max3 073 + ", num_max3=" + num_max3 074 + ", min=" + min + ", range=" + range + ", " 075 + "avg_samp=" + two_decimals.format(avg_samples_per_val); 076 } 077 078 private double calc_avg_samples_per_val(@GuardSatisfied UpperBoundCore this, long modulus, double range) { 079 // int num_samples = wrapper.ppt.num_mod_samples(); 080 int num_samples = wrapper.ppt.num_samples(); 081 double avg_samples_per_val = 082 ((double) num_samples) * modulus / range; 083 avg_samples_per_val = Math.min(avg_samples_per_val, 100); 084 085 return avg_samples_per_val; 086 } 087 088 private long calc_range(@GuardSatisfied UpperBoundCore this) { 089 // If I used Math.abs, the order of arguments to minus would not matter. 090 return -(min - max1) + 1; 091 } 092 093 private long calc_modulus(@GuardSatisfied UpperBoundCore this) { 094 // Need to reinstate this at some point. 095 // { 096 // for (Invariant inv : wrapper.ppt.invs) { 097 // if ((inv instanceof Modulus) && inv.enoughSamples()) { 098 // modulus = ((Modulus) inv).modulus; 099 // break; 100 // } 101 // } 102 // } 103 return 1; 104 } 105 106 /** 107 * Whether this would change if the given value was seen. Used to test for need of cloning and 108 * flowing before this would be changed. 109 */ 110 public boolean wouldChange(long value) { 111 return (value > max1); 112 } 113 114 public InvariantStatus add_modified(long value, int count) { 115 samples += count; 116 117 // System.out.println("UpperBoundCore" + varNames() + ": " 118 // + "add(" + value + ", " + modified + ", " + count + ")"); 119 120 long v = value; 121 122 if (v < min) { 123 min = v; 124 } 125 126 if (v == max1) { 127 num_max1 += count; 128 } else if (v > max1) { 129 max3 = max2; 130 num_max3 = num_max2; 131 max2 = max1; 132 num_max2 = num_max1; 133 max1 = v; 134 num_max1 = count; 135 return InvariantStatus.WEAKENED; 136 } else if (v == max2) { 137 num_max2 += count; 138 } else if (v > max2) { 139 max3 = max2; 140 num_max3 = num_max2; 141 max2 = v; 142 num_max2 = count; 143 } else if (v == max3) { 144 num_max3 += count; 145 } else if (v > max3) { 146 max3 = v; 147 num_max3 = count; 148 } 149 return InvariantStatus.NO_CHANGE; 150 } 151 152 public InvariantStatus check(long value) { 153 if (value > max1) { 154 return InvariantStatus.WEAKENED; 155 } else { 156 return InvariantStatus.NO_CHANGE; 157 } 158 } 159 160 public boolean enoughSamples(@GuardSatisfied UpperBoundCore this) { 161 return samples > required_samples; 162 } 163 164 // Convenience methods; avoid need for "Invariant." prefix. 165 private final double prob_is_ge(double x, double goal) { 166 return Invariant.prob_is_ge(x, goal); 167 } 168 private final double prob_and(double p1, double p2) { 169 return Invariant.prob_and(p1, p2); 170 } 171 private final double prob_or(double p1, double p2) { 172 return Invariant.prob_or(p1, p2); 173 } 174 175 public double computeConfidence() { 176 if (PrintInvariants.dkconfig_static_const_infer && matchConstant()) { 177 return Invariant.CONFIDENCE_JUSTIFIED; 178 } 179 180 return 1 - computeProbability(); 181 } 182 183 public boolean matchConstant() { 184 PptTopLevel pptt = wrapper.ppt.parent; 185 186 for (VarInfo vi : pptt.var_infos) { 187 if (vi.isStaticConstant()) { 188 if (vi.rep_type == ProglangType.DOUBLE) { 189 // If variable is a double, then use fuzzy comparison 190 Double constantVal = (Double)vi.constantValue(); 191 if (Global.fuzzy.eq(constantVal, (double)(max1)) || false) { 192 return true; 193 } 194 } else { 195 // Otherwise just use the equals method 196 Object constantVal = vi.constantValue(); 197 if (constantVal.equals(max1)) { 198 return true; 199 } 200 } 201 } 202 } 203 204 return false; 205 } 206 207 // used by computeConfidence 208 public double computeProbability() { 209 // The bound is justified if both of two conditions is satisfied: 210 // 1. there are at least required_samples_at_bound samples at the bound 211 // 2. one of the following holds: 212 // 2a. the bound has five times the expected number of samples (the 213 // number it would have if the values were uniformly distributed) 214 // 2b. the bound and the two next elements all have at least half 215 // the expected number of samples. 216 // The expected number of samples is the total number of samples 217 // divided by the range of the samples; it is the average number 218 // of samples at each point. 219 220 // Value "1" from above. 221 double bound_samples_prob = prob_is_ge(num_max1, required_samples_at_bound); 222 223 long modulus = calc_modulus(); 224 225 double range = calc_range(); 226 double avg_samples_per_val = calc_avg_samples_per_val(modulus, range); 227 228 // Value "2a" from above 229 double trunc_prob = prob_is_ge(num_max1, 5 * avg_samples_per_val); 230 231 // Value "2b" from above 232 double unif_prob; 233 boolean unif_mod_OK = ((-(max3 - max2) == modulus) 234 && (-(max2 - max1) == modulus)); 235 if (unif_mod_OK) { 236 double half_avg_samp = avg_samples_per_val / 2; 237 double unif_prob_1 = prob_is_ge(num_max1, half_avg_samp); 238 double unif_prob_2 = prob_is_ge(num_max2, half_avg_samp); 239 double unif_prob_3 = prob_is_ge(num_max3, half_avg_samp); 240 unif_prob = Invariant.prob_and(unif_prob_1, unif_prob_2, unif_prob_3); 241 // System.out.println("Unif_probs: " + unif_prob + " <-- " + unif_prob_1 + " " + unif_prob_2 + " " + unif_prob_3); 242 } else { 243 unif_prob = 1; 244 } 245 246 // Value "2" from above 247 double bound_prob = prob_or(trunc_prob, unif_prob); 248 249 // Final result 250 return prob_and(bound_samples_prob, bound_prob); 251 252 // System.out.println("UpperBoundCore.computeProbability(): "); 253 // System.out.println(" " + repr()); 254 // System.out.println(" ppt=" + wrapper.ppt.name() 255 // + ", wrapper.ppt.num_mod_samples()=" 256 // + wrapper.ppt.num_mod_samples() 257 // // + ", values=" + values 258 // + ", avg_samples_per_val=" + avg_samples_per_val 259 // + ", result = " + result 260 // + ", bound_samples_prob=" + bound_samples_prob 261 // + ", bound_prob=" + bound_prob 262 // + ", trunc_prob=" + trunc_prob 263 // + ", unif_prob=" + unif_prob); 264 // PptSlice pptsg = (PptSlice) ppt; 265 // System.out.println(" " + ppt.name()); 266 267 } 268 269 @Pure 270 public boolean isSameFormula(UpperBoundCore other) { 271 return max1 == other.max1; 272 } 273 274 @Pure 275 public boolean isExact() { 276 return false; 277 } 278 279 // Merge lbc into this. 280 public void add(UpperBoundCore lbc) { 281 282 // Pass each value and its count to this invariant's add_modified. Since 283 // bound is never destroyed, we don't need to check the results. 284 if (lbc.num_max1 > 0) { 285 add_modified(lbc.max1, lbc.num_max1); 286 } 287 if (lbc.num_max2 > 0) { 288 add_modified(lbc.max2, lbc.num_max2); 289 } 290 if (lbc.num_max3 > 0) { 291 add_modified(lbc.max3, lbc.num_max3); 292 } 293 // num_max1 will be positive if and only if we've ever seen any 294 // real samples. Only then does min represent a real sample. 295 if (lbc.num_max1 > 0) { 296 add_modified(lbc.min, 1); 297 } 298 if (Debug.logDetail()) { 299 wrapper.log("Added vals %s of %s, %s of %s, %s of %s, %s from ppt %s", 300 lbc.num_max1, lbc.max1, lbc.num_max2, lbc.max2, 301 lbc.num_max3, lbc.max3, 302 ((lbc.num_max1 > 0) ? "1 of " + lbc.min : ""), 303 lbc.wrapper.ppt.parent.ppt_name); 304 } 305 } 306}