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 LowerBoundCore 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 // min1 < min2 < min3 032 public long min1 = Long.MAX_VALUE; 033 public int num_min1 = 0; 034 public long min2 = Long.MAX_VALUE; 035 public int num_min2 = 0; 036 public long min3 = Long.MAX_VALUE; 037 public int num_min3 = 0; 038 public long max = Long.MIN_VALUE; 039 040 int samples = 0; 041 042 public Invariant wrapper; 043 044 public LowerBoundCore(Invariant wrapper) { 045 this.wrapper = wrapper; 046 } 047 048 public long min() { 049 return min1; 050 } 051 052 @SideEffectFree 053 @Override 054 public LowerBoundCore clone(@GuardSatisfied LowerBoundCore this) { 055 try { 056 return (LowerBoundCore) 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 LowerBoundCore 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 "min1=" + min1 069 + ", num_min1=" + num_min1 070 + ", min2=" + min2 071 + ", num_min2=" + num_min2 072 + ", min3=" + min3 073 + ", num_min3=" + num_min3 074 + ", max=" + max + ", range=" + range + ", " 075 + "avg_samp=" + two_decimals.format(avg_samples_per_val); 076 } 077 078 private double calc_avg_samples_per_val(@GuardSatisfied LowerBoundCore 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 if (min1 == 0) { 086 avg_samples_per_val /= 5; 087 } 088 089 return avg_samples_per_val; 090 } 091 092 private long calc_range(@GuardSatisfied LowerBoundCore this) { 093 // If I used Math.abs, the order of arguments to minus would not matter. 094 return (max - min1) + 1; 095 } 096 097 private long calc_modulus(@GuardSatisfied LowerBoundCore this) { 098 // Need to reinstate this at some point. 099 // { 100 // for (Invariant inv : wrapper.ppt.invs) { 101 // if ((inv instanceof Modulus) && inv.enoughSamples()) { 102 // modulus = ((Modulus) inv).modulus; 103 // break; 104 // } 105 // } 106 // } 107 return 1; 108 } 109 110 /** 111 * Whether this would change if the given value was seen. Used to test for need of cloning and 112 * flowing before this would be changed. 113 */ 114 public boolean wouldChange(long value) { 115 return (value < min1); 116 } 117 118 public InvariantStatus add_modified(long value, int count) { 119 samples += count; 120 121 // System.out.println("LowerBoundCore" + varNames() + ": " 122 // + "add(" + value + ", " + modified + ", " + count + ")"); 123 124 long v = value; 125 126 if (v > max) { 127 max = v; 128 } 129 130 if (v == min1) { 131 num_min1 += count; 132 } else if (v < min1) { 133 min3 = min2; 134 num_min3 = num_min2; 135 min2 = min1; 136 num_min2 = num_min1; 137 min1 = v; 138 num_min1 = count; 139 return InvariantStatus.WEAKENED; 140 } else if (v == min2) { 141 num_min2 += count; 142 } else if (v < min2) { 143 min3 = min2; 144 num_min3 = num_min2; 145 min2 = v; 146 num_min2 = count; 147 } else if (v == min3) { 148 num_min3 += count; 149 } else if (v < min3) { 150 min3 = v; 151 num_min3 = count; 152 } 153 return InvariantStatus.NO_CHANGE; 154 } 155 156 public InvariantStatus check(long value) { 157 if (value < min1) { 158 return InvariantStatus.WEAKENED; 159 } else { 160 return InvariantStatus.NO_CHANGE; 161 } 162 } 163 164 public boolean enoughSamples(@GuardSatisfied LowerBoundCore this) { 165 return samples > required_samples; 166 } 167 168 // Convenience methods; avoid need for "Invariant." prefix. 169 private final double prob_is_ge(double x, double goal) { 170 return Invariant.prob_is_ge(x, goal); 171 } 172 private final double prob_and(double p1, double p2) { 173 return Invariant.prob_and(p1, p2); 174 } 175 private final double prob_or(double p1, double p2) { 176 return Invariant.prob_or(p1, p2); 177 } 178 179 public double computeConfidence() { 180 if (PrintInvariants.dkconfig_static_const_infer && matchConstant()) { 181 return Invariant.CONFIDENCE_JUSTIFIED; 182 } 183 184 return 1 - computeProbability(); 185 } 186 187 public boolean matchConstant() { 188 PptTopLevel pptt = wrapper.ppt.parent; 189 190 for (VarInfo vi : pptt.var_infos) { 191 if (vi.isStaticConstant()) { 192 if (vi.rep_type == ProglangType.DOUBLE) { 193 // If variable is a double, then use fuzzy comparison 194 Double constantVal = (Double)vi.constantValue(); 195 if (Global.fuzzy.eq(constantVal, (double)(min1)) || false) { 196 return true; 197 } 198 } else { 199 // Otherwise just use the equals method 200 Object constantVal = vi.constantValue(); 201 if (constantVal.equals(min1)) { 202 return true; 203 } 204 } 205 } 206 } 207 208 return false; 209 } 210 211 // used by computeConfidence 212 public double computeProbability() { 213 // The bound is justified if both of two conditions is satisfied: 214 // 1. there are at least required_samples_at_bound samples at the bound 215 // 2. one of the following holds: 216 // 2a. the bound has five times the expected number of samples (the 217 // number it would have if the values were uniformly distributed) 218 // 2b. the bound and the two next elements all have at least half 219 // the expected number of samples. 220 // The expected number of samples is the total number of samples 221 // divided by the range of the samples; it is the average number 222 // of samples at each point. 223 224 // Value "1" from above. 225 double bound_samples_prob = prob_is_ge(num_min1, required_samples_at_bound); 226 227 long modulus = calc_modulus(); 228 229 double range = calc_range(); 230 double avg_samples_per_val = calc_avg_samples_per_val(modulus, range); 231 232 // Value "2a" from above 233 double trunc_prob = prob_is_ge(num_min1, 5 * avg_samples_per_val); 234 235 // Value "2b" from above 236 double unif_prob; 237 boolean unif_mod_OK = (((min3 - min2) == modulus) 238 && ((min2 - min1) == modulus)); 239 if (unif_mod_OK) { 240 double half_avg_samp = avg_samples_per_val / 2; 241 double unif_prob_1 = prob_is_ge(num_min1, half_avg_samp); 242 double unif_prob_2 = prob_is_ge(num_min2, half_avg_samp); 243 double unif_prob_3 = prob_is_ge(num_min3, half_avg_samp); 244 unif_prob = Invariant.prob_and(unif_prob_1, unif_prob_2, unif_prob_3); 245 // System.out.println("Unif_probs: " + unif_prob + " <-- " + unif_prob_1 + " " + unif_prob_2 + " " + unif_prob_3); 246 } else { 247 unif_prob = 1; 248 } 249 250 // Value "2" from above 251 double bound_prob = prob_or(trunc_prob, unif_prob); 252 253 // Final result 254 return prob_and(bound_samples_prob, bound_prob); 255 256 // System.out.println("LowerBoundCore.computeProbability(): "); 257 // System.out.println(" " + repr()); 258 // System.out.println(" ppt=" + wrapper.ppt.name() 259 // + ", wrapper.ppt.num_mod_samples()=" 260 // + wrapper.ppt.num_mod_samples() 261 // // + ", values=" + values 262 // + ", avg_samples_per_val=" + avg_samples_per_val 263 // + ", result = " + result 264 // + ", bound_samples_prob=" + bound_samples_prob 265 // + ", bound_prob=" + bound_prob 266 // + ", trunc_prob=" + trunc_prob 267 // + ", unif_prob=" + unif_prob); 268 // PptSlice pptsg = (PptSlice) ppt; 269 // System.out.println(" " + ppt.name()); 270 271 } 272 273 @Pure 274 public boolean isSameFormula(LowerBoundCore other) { 275 return min1 == other.min1; 276 } 277 278 @Pure 279 public boolean isExact() { 280 return false; 281 } 282 283 // Merge lbc into this. 284 public void add(LowerBoundCore lbc) { 285 286 // Pass each value and its count to this invariant's add_modified. Since 287 // bound is never destroyed, we don't need to check the results. 288 if (lbc.num_min1 > 0) { 289 add_modified(lbc.min1, lbc.num_min1); 290 } 291 if (lbc.num_min2 > 0) { 292 add_modified(lbc.min2, lbc.num_min2); 293 } 294 if (lbc.num_min3 > 0) { 295 add_modified(lbc.min3, lbc.num_min3); 296 } 297 // num_min1 will be positive if and only if we've ever seen any 298 // real samples. Only then does max represent a real sample. 299 if (lbc.num_min1 > 0) { 300 add_modified(lbc.max, 1); 301 } 302 if (Debug.logDetail()) { 303 wrapper.log("Added vals %s of %s, %s of %s, %s of %s, %s from ppt %s", 304 lbc.num_min1, lbc.min1, lbc.num_min2, lbc.min2, 305 lbc.num_min3, lbc.min3, 306 ((lbc.num_min1 > 0) ? "1 of " + lbc.max : ""), 307 lbc.wrapper.ppt.parent.ppt_name); 308 } 309 } 310}