001package daikon.tools;
002
003import daikon.Daikon;
004import daikon.FileIO;
005import daikon.Global;
006import daikon.PptMap;
007import daikon.PptSlice;
008import daikon.PptSliceEquality;
009import daikon.PptTopLevel;
010import daikon.VarInfo;
011import daikon.inv.Invariant;
012import daikon.inv.binary.twoScalar.IntGreaterThan;
013import daikon.inv.binary.twoScalar.IntLessThan;
014import daikon.inv.unary.scalar.OneOfScalar;
015import gnu.getopt.*;
016import java.io.File;
017import java.io.IOException;
018import java.util.ArrayList;
019import java.util.HashSet;
020import java.util.Iterator;
021import java.util.LinkedHashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025import org.checkerframework.checker.nullness.qual.NonNull;
026import org.checkerframework.checker.nullness.qual.Nullable;
027import org.checkerframework.dataflow.qual.Pure;
028
029/**
030 * Functions that look for relationships between the invariants at different program points.
031 * Relationships between individual invariants are created with InvTranslate. Currently, only
032 * invariants of the same class can be related to one another.
033 */
034public class InvMatch {
035
036  /**
037   * Main program for testing purposes.
038   *
039   * @param args command-line arguments, ignored
040   */
041  @SuppressWarnings("nullness") // testing method, not worth type-checking
042  public static void main(String[] args) throws IOException {
043
044    // Read in the sample decls file
045    Set<File> decl_files = new HashSet<>(1);
046    decl_files.add(new File("daikon/test/SampleTester.decls"));
047    PptMap all_ppts = FileIO.read_declaration_files(decl_files);
048
049    // Setup everything to run
050    PptSliceEquality.dkconfig_set_per_var = true;
051    Daikon.setup_NISuppression();
052
053    // Get the exit ppts
054    PptTopLevel ppt35 = all_ppts.get("foo.f():::EXIT35");
055    PptTopLevel ppt40 = all_ppts.get("foo.g():::EXIT40");
056
057    // Get variables at both program points
058    VarInfo ppt35_x = ppt35.var_infos[0];
059    VarInfo ppt35_y = ppt35.var_infos[1];
060    VarInfo ppt35_z = ppt35.var_infos[2];
061    VarInfo ppt40_p = ppt40.var_infos[0];
062    VarInfo ppt40_q = ppt40.var_infos[1];
063    VarInfo ppt40_r = ppt40.var_infos[2];
064
065    // Build EXIT35 slices
066    PptSlice slice_xy_35 = ppt35.get_or_instantiate_slice(new VarInfo[] {ppt35_x, ppt35_y});
067    PptSlice slice_yz_35 = ppt35.get_or_instantiate_slice(new VarInfo[] {ppt35_y, ppt35_z});
068    PptSlice slice_x_35 = ppt35.get_or_instantiate_slice(new VarInfo[] {ppt35_x});
069
070    // Build EXIT40 slices
071    PptSlice slice_pq_40 = ppt40.get_or_instantiate_slice(new VarInfo[] {ppt40_p, ppt40_q});
072    PptSlice slice_qr_40 = ppt40.get_or_instantiate_slice(new VarInfo[] {ppt40_q, ppt40_r});
073    PptSlice slice_pr_40 = ppt40.get_or_instantiate_slice(new VarInfo[] {ppt40_p, ppt40_r});
074    PptSlice slice_p_40 = ppt40.get_or_instantiate_slice(new VarInfo[] {ppt40_p});
075
076    // Create invariants at EXIT35
077    Invariant inv_x_lt_y = IntLessThan.get_proto().instantiate(slice_xy_35);
078    slice_xy_35.addInvariant(inv_x_lt_y);
079    OneOfScalar inv_x_eq_5 = (OneOfScalar) OneOfScalar.get_proto().instantiate(slice_x_35);
080    inv_x_eq_5.add_modified(5, 1);
081    slice_x_35.addInvariant(inv_x_eq_5);
082    Invariant inv_y_gt_z = IntGreaterThan.get_proto().instantiate(slice_yz_35);
083    slice_yz_35.addInvariant(inv_y_gt_z);
084
085    // Create invariants at EXIT40
086    Invariant inv_p_lt_q = IntLessThan.get_proto().instantiate(slice_pq_40);
087    slice_pq_40.addInvariant(inv_p_lt_q);
088    OneOfScalar inv_p_eq_3 = (OneOfScalar) OneOfScalar.get_proto().instantiate(slice_p_40);
089    inv_p_eq_3.add_modified(3, 1);
090    slice_p_40.addInvariant(inv_p_eq_3);
091    Invariant inv_q_gt_r = IntGreaterThan.get_proto().instantiate(slice_qr_40);
092    slice_qr_40.addInvariant(inv_q_gt_r);
093    Invariant inv_p_gt_r = IntGreaterThan.get_proto().instantiate(slice_pr_40);
094    slice_pr_40.addInvariant(inv_p_gt_r);
095
096    // InvTranslate xlate = new InvTranslate(inv_x_lt_y, inv_p_lt_q);
097
098    // Try to matchup the program points
099    List<List<InvTranslate>> valid_translations = match_ppt(ppt35, ppt40);
100
101    // Dump all of the valid translations
102    System.out.println("Valid Translations:");
103    for (List<InvTranslate> current_translation : valid_translations) {
104      System.out.println("  Translation: ");
105      for (InvTranslate xlate : current_translation) {
106        System.out.printf("    %s%n", xlate);
107      }
108    }
109
110    List<InvTranslate> best_translation = best_translation(valid_translations);
111    System.out.println(Global.lineSep + "Best Translation");
112    for (InvTranslate xlate : best_translation) {
113      System.out.printf("  %s%n", xlate);
114    }
115  }
116
117  /**
118   * Compares the invariants between the two program points specified and returns a list of possible
119   * translations. A possible translation is a consistent set of translations (one for each
120   * invariant in ppt1) A set of translations is consistent if all of the variable mappings are
121   * consistent (i.e., no variable maps to more than one variable).
122   */
123  static List<List<InvTranslate>> match_ppt(PptTopLevel ppt1, PptTopLevel ppt2) {
124
125    List<List<InvTranslate>> xlate_list = new ArrayList<>();
126
127    for (Iterator<Invariant> i = ppt1.invariants_iterator(); i.hasNext(); ) {
128      Invariant inv1 = i.next();
129      List<InvTranslate> inv_xlate_list = new ArrayList<>();
130      xlate_list.add(inv_xlate_list);
131      for (Iterator<Invariant> j = ppt2.invariants_iterator(); j.hasNext(); ) {
132        Invariant inv2 = j.next();
133        InvTranslate xlate = new InvTranslate(inv1, inv2);
134        if (xlate.quality > 0) {
135          inv_xlate_list.add(xlate);
136        }
137      }
138      // What is the purpose of this?  Maybe it separates the translation
139      // results for different invariants.  How/where is it used/checked?
140      // I see places where a null is just skipped over, but not where it
141      // has an effect.
142      @SuppressWarnings(
143          "nullness") // can't figure out what this is for; maybe change the declaration
144      @NonNull InvTranslate dummy = null;
145      inv_xlate_list.add(dummy);
146    }
147
148    // Debug print all of the translations
149    if (true) {
150      Iterator<Invariant> invi = ppt1.invariants_iterator();
151      for (List<InvTranslate> inv_xlate_list : xlate_list) {
152        Invariant inv = invi.next();
153        System.out.printf("%s translations:%n", inv.format());
154        for (InvTranslate xlate : inv_xlate_list) {
155          System.out.printf("  %s%n", xlate);
156        }
157      }
158    }
159
160    List<List<InvTranslate>> valid_translations = new ArrayList<>();
161    List<InvTranslate> current_translation = new ArrayList<>();
162    consider_xlate(valid_translations, current_translation, xlate_list, 0);
163
164    return valid_translations;
165  }
166
167  /**
168   * Recursive routine that tries all possible combination of translations.
169   *
170   * @param valid_translations list of valid translations (updated)
171   * @param current_translation the current translation that is being built
172   * @param xlate_list the list of possible translations for each invariant
173   * @param index the current index in xlate_list
174   */
175  public static void consider_xlate(
176      List<List<InvTranslate>> valid_translations,
177      List<InvTranslate> current_translation,
178      List<List<InvTranslate>> xlate_list,
179      int index) {
180
181    List<InvTranslate> inv_xlate_list = xlate_list.get(index);
182    for (InvTranslate xlate : inv_xlate_list) {
183
184      List<InvTranslate> new_translation = new ArrayList<>();
185      new_translation.addAll(current_translation);
186      new_translation.add(xlate);
187      if (!is_good_translation(new_translation)) {
188        continue;
189      }
190
191      if ((index + 1) == xlate_list.size()) {
192        valid_translations.add(new_translation);
193      } else {
194        consider_xlate(valid_translations, new_translation, xlate_list, index + 1);
195      }
196    }
197  }
198
199  @Pure
200  public static boolean is_good_translation(List<InvTranslate> translation_list) {
201
202    Map<String, String> var_map = new LinkedHashMap<>();
203
204    for (InvTranslate xlate : translation_list) {
205      if (xlate == null) {
206        continue;
207      }
208      for (String key : xlate.var_map.keySet()) {
209        String val = xlate.var_map.get(key);
210        String cur_val = var_map.get(key);
211        if (cur_val == null) {
212          var_map.put(key, val);
213        } else if (!cur_val.equals(val)) {
214          return false;
215        }
216      }
217    }
218    return true;
219  }
220
221  public static @Nullable List<InvTranslate> best_translation(
222      List<List<InvTranslate>> valid_translations) {
223
224    // Determine the best translation and print it out.
225    List<InvTranslate> best_translation = null;
226    int best_quality = 0;
227    for (List<InvTranslate> current_translation : valid_translations) {
228      int quality = 0;
229      for (InvTranslate xlate : current_translation) {
230        if (xlate != null) {
231          quality += xlate.quality;
232        }
233      }
234      if (quality > best_quality) {
235        best_translation = current_translation;
236        best_quality = quality;
237      }
238    }
239    return best_translation;
240  }
241}