Repository: hernanponcedeleon/Dat3M
Pull request #820: Improved automatic data type conversion along rf-edges (+ related improvements)
Author: login: ThomasHaas
Created: 2025-03-07T15:40:05Z | Merged: 2025-03-08T18:53:39Z

`EncodingContext.equal(Formula f, Formula g)` encodes equality modulo type conversions, e.g., if `f` and `g` have different are BV formulas of different bit-width, then one of them is truncated or extended to the other.
Which parameter was type-converted to the other was totally unclear from the callers perspective and caused ugly issues when encoding value equality induced by rf-edges.

I added a third parameter that let's the caller how the type conversion should be done (or if it should be done at all).

I also added the ability to evaluate `TupleFormulas` over a model. This requires using the helper method `EncodingHelper.evaluate(Formula, Model)` rather than invoking `Model.evaluate(Formula)`

@hernan-poncedeleon This will fix the strange values in the witness of the benchmark in #817 



Diff:
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java
index 55a84bfe75..06227fade2 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java
@@ -1,35 +1,12 @@
 package com.dat3m.dartagnan.encoding;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.dat3m.dartagnan.expression.type.*;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.sosy_lab.common.configuration.InvalidConfigurationException;
-import org.sosy_lab.common.configuration.Option;
-import org.sosy_lab.common.configuration.Options;
-import org.sosy_lab.java_smt.api.BitvectorFormula;
-import org.sosy_lab.java_smt.api.BitvectorFormulaManager;
-import org.sosy_lab.java_smt.api.BooleanFormula;
-import org.sosy_lab.java_smt.api.BooleanFormulaManager;
-import org.sosy_lab.java_smt.api.Formula;
-import org.sosy_lab.java_smt.api.FormulaManager;
-import org.sosy_lab.java_smt.api.IntegerFormulaManager;
-import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula;
-
-import static com.dat3m.dartagnan.configuration.OptionNames.IDL_TO_SAT;
-import static com.dat3m.dartagnan.configuration.OptionNames.MERGE_CF_VARS;
-import static com.dat3m.dartagnan.configuration.OptionNames.USE_INTEGERS;
 import com.dat3m.dartagnan.configuration.ProgressModel;
 import com.dat3m.dartagnan.encoding.formulas.TupleFormula;
 import com.dat3m.dartagnan.encoding.formulas.TupleFormulaManager;
 import com.dat3m.dartagnan.expression.Expression;
 import com.dat3m.dartagnan.expression.Type;
 import com.dat3m.dartagnan.expression.integers.IntCmpOp;
+import com.dat3m.dartagnan.expression.type.*;
 import com.dat3m.dartagnan.program.Register;
 import com.dat3m.dartagnan.program.analysis.BranchEquivalence;
 import com.dat3m.dartagnan.program.analysis.ExecutionAnalysis;
@@ -37,14 +14,7 @@
 import com.dat3m.dartagnan.program.event.Event;
 import com.dat3m.dartagnan.program.event.MemoryEvent;
 import com.dat3m.dartagnan.program.event.RegWriter;
-import static com.dat3m.dartagnan.program.event.Tag.INIT;
-import static com.dat3m.dartagnan.program.event.Tag.WRITE;
-import com.dat3m.dartagnan.program.event.core.CondJump;
-import com.dat3m.dartagnan.program.event.core.Load;
-import com.dat3m.dartagnan.program.event.core.MemoryCoreEvent;
-import com.dat3m.dartagnan.program.event.core.NamedBarrier;
-import com.dat3m.dartagnan.program.event.core.Store;
-import com.dat3m.dartagnan.program.event.core.ControlBarrier;
+import com.dat3m.dartagnan.program.event.core.*;
 import com.dat3m.dartagnan.program.memory.MemoryObject;
 import com.dat3m.dartagnan.verification.Context;
 import com.dat3m.dartagnan.verification.VerificationTask;
@@ -52,6 +22,23 @@
 import com.dat3m.dartagnan.wmm.analysis.RelationAnalysis;
 import com.dat3m.dartagnan.wmm.axiom.Acyclicity;
 import com.dat3m.dartagnan.wmm.utils.graph.EventGraph;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.sosy_lab.common.configuration.InvalidConfigurationException;
+import org.sosy_lab.common.configuration.Option;
+import org.sosy_lab.common.configuration.Options;
+import org.sosy_lab.java_smt.api.*;
+import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.dat3m.dartagnan.configuration.OptionNames.*;
+import static com.dat3m.dartagnan.program.event.Tag.INIT;
+import static com.dat3m.dartagnan.program.event.Tag.WRITE;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -261,29 +248,30 @@ public Formula lastValue(MemoryObject base, int offset, int size) {
         return formulaManager.getBitvectorFormulaManager().makeVariable(size, name);
     }
 
-    public BooleanFormula equal(Formula left, Formula right) {
-        //FIXME: We should avoid the automatic conversion, or standardize what conversion we expect.
-        // For example, when encoding rf(w, r), we always want to convert the store value type to the read value type
-        // for otherwise, we might get an under-constrained value for val(r) (e.g., its upper bits might be unconstrained,
-        // if we truncate it to smaller size of the store value).
+    public enum ConversionMode {
+        NO,
+        LEFT_TO_RIGHT,
+        RIGHT_TO_LEFT,
+    }
+
+    public BooleanFormula equal(Formula left, Formula right, ConversionMode cMode) {
+        if (cMode == ConversionMode.LEFT_TO_RIGHT) {
+            return equal(right, left, ConversionMode.RIGHT_TO_LEFT);
+        } else if (cMode == ConversionMode.NO && !new EncodingHelper(formulaManager).hasSameType(left, right)) {
+            final String error = String.format("Mismatching formula types: %s and %s", left, right);
+            throw new IllegalArgumentException(error);
+        }
+
         if (left instanceof IntegerFormula l) {
             IntegerFormulaManager imgr = formulaManager.getIntegerFormulaManager();
             return imgr.equal(l, toInteger(right));
         }
-        if (right instanceof IntegerFormula r) {
-            IntegerFormulaManager imgr = formulaManager.getIntegerFormulaManager();
-            return imgr.equal(toInteger(left), r);
-        }
         if (left instanceof BitvectorFormula l) {
             BitvectorFormulaManager bvmgr = formulaManager.getBitvectorFormulaManager();
             return bvmgr.equal(l, toBitvector(right, bvmgr.getLength(l)));
         }
-        if (right instanceof BitvectorFormula r) {
-            BitvectorFormulaManager bvmgr = formulaManager.getBitvectorFormulaManager();
-            return bvmgr.equal(toBitvector(left, bvmgr.getLength(r)), r);
-        }
-        if (left instanceof BooleanFormula l && right instanceof BooleanFormula r) {
-            return booleanFormulaManager.equivalence(l, r);
+        if (left instanceof BooleanFormula l) {
+            return booleanFormulaManager.equivalence(l, toBoolean(right));
         }
         if (left instanceof TupleFormula l && right instanceof TupleFormula r) {
             return tupleFormulaManager.equal(l, r);
@@ -291,6 +279,10 @@ public BooleanFormula equal(Formula left, Formula right) {
         throw new UnsupportedOperationException(String.format("Unknown types for equal(%s,%s)", left, right));
     }
 
+    public BooleanFormula equal(Formula left, Formula right) {
+        return equal(left, right, ConversionMode.NO);
+    }
+
     public IntegerFormula toInteger(Formula formula) {
         if (formula instanceof IntegerFormula f) {
             return f;
@@ -307,6 +299,13 @@ public IntegerFormula toInteger(Formula formula) {
         throw new UnsupportedOperationException(String.format("Unknown type for toInteger(%s).", formula));
     }
 
+    private BooleanFormula toBoolean(Formula formula) {
+        if (formula instanceof BooleanFormula f) {
+            return f;
+        }
+        return booleanFormulaManager.not(equalZero(formula));
+    }
+
     private BitvectorFormula toBitvector(Formula formula, int length) {
         BitvectorFormulaManager bvmgr = formulaManager.getBitvectorFormulaManager();
         if (formula instanceof BitvectorFormula f) {
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingHelper.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingHelper.java
index 6772b52575..127c0f0630 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingHelper.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingHelper.java
@@ -1,9 +1,13 @@
 package com.dat3m.dartagnan.encoding;
 
+import com.dat3m.dartagnan.encoding.formulas.TupleFormula;
+import com.dat3m.dartagnan.encoding.formulas.TupleValue;
 import com.google.common.base.Preconditions;
 import org.sosy_lab.java_smt.api.*;
+import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula;
 
 import java.math.BigInteger;
+import java.util.stream.IntStream;
 
 public class EncodingHelper {
 
@@ -14,7 +18,7 @@ public EncodingHelper(FormulaManager fmgr) {
     }
 
     public BooleanFormula equals(Formula left, Formula right) {
-        if (left instanceof NumeralFormula.IntegerFormula iLeft && right instanceof NumeralFormula.IntegerFormula iRight) {
+        if (left instanceof IntegerFormula iLeft && right instanceof IntegerFormula iRight) {
             return fmgr.getIntegerFormulaManager().equal(iLeft, iRight);
         }
 
@@ -28,7 +32,7 @@ public BooleanFormula equals(Formula left, Formula right) {
     }
 
     public BooleanFormula greaterThan(Formula left, Formula right, boolean signed) {
-        if (left instanceof NumeralFormula.IntegerFormula iLeft && right instanceof NumeralFormula.IntegerFormula iRight) {
+        if (left instanceof IntegerFormula iLeft && right instanceof IntegerFormula iRight) {
             return fmgr.getIntegerFormulaManager().greaterThan(iLeft, iRight);
         }
 
@@ -42,7 +46,7 @@ public BooleanFormula greaterThan(Formula left, Formula right, boolean signed) {
     }
 
     public BooleanFormula greaterOrEquals(Formula left, Formula right, boolean signed) {
-        if (left instanceof NumeralFormula.IntegerFormula iLeft && right instanceof NumeralFormula.IntegerFormula iRight) {
+        if (left instanceof IntegerFormula iLeft && right instanceof IntegerFormula iRight) {
             return fmgr.getIntegerFormulaManager().greaterOrEquals(iLeft, iRight);
         }
 
@@ -56,7 +60,7 @@ public BooleanFormula greaterOrEquals(Formula left, Formula right, boolean signe
     }
 
     public Formula add(Formula left, Formula right) {
-        if (left instanceof NumeralFormula.IntegerFormula iLeft && right instanceof NumeralFormula.IntegerFormula iRight) {
+        if (left instanceof IntegerFormula iLeft && right instanceof IntegerFormula iRight) {
             return fmgr.getIntegerFormulaManager().add(iLeft, iRight);
         }
 
@@ -70,7 +74,7 @@ public Formula add(Formula left, Formula right) {
     }
 
     public Formula subtract(Formula left, Formula right) {
-        if (left instanceof NumeralFormula.IntegerFormula iLeft && right instanceof NumeralFormula.IntegerFormula iRight) {
+        if (left instanceof IntegerFormula iLeft && right instanceof IntegerFormula iRight) {
             return fmgr.getIntegerFormulaManager().subtract(iLeft, iRight);
         }
 
@@ -87,7 +91,7 @@ public Formula remainder(Formula left, Formula right) {
         //FIXME: integer modulo and BV modulo have different semantics, the former is always positive, the latter
         // returns a value whose sign depends on one of the two BVs.
         // The results in this implementation will match if the denominator <right> is positive which is the most usual case.
-        if (left instanceof NumeralFormula.IntegerFormula iLeft && right instanceof NumeralFormula.IntegerFormula iRight) {
+        if (left instanceof IntegerFormula iLeft && right instanceof IntegerFormula iRight) {
             return fmgr.getIntegerFormulaManager().modulo(iLeft, iRight);
         }
 
@@ -122,4 +126,38 @@ public int getBitSize(FormulaType<?> type) {
     public FormulaType<?> typeOf(Formula formula) {
         return fmgr.getFormulaType(formula);
     }
+
+    public boolean hasSameType(Formula left, Formula right) {
+        if (left instanceof IntegerFormula && right instanceof IntegerFormula) {
+            return true;
+        } else if (left instanceof BooleanFormula && right instanceof BooleanFormula) {
+            return true;
+        } else if (left instanceof BitvectorFormula x && right instanceof BitvectorFormula y) {
+            final BitvectorFormulaManager bvmgr = fmgr.getBitvectorFormulaManager();
+            return bvmgr.getLength(x) == bvmgr.getLength(y);
+        } else if (left instanceof TupleFormula x && right instanceof TupleFormula y) {
+            if (x.getElements().size() != y.getElements().size()) {
+                return false;
+            }
+            return IntStream.range(0, x.getElements().size()).allMatch(
+                    i -> hasSameType(x.getElements().get(i), y.getElements().get(i))
+            );
+        }
+
+        return false;
+    }
+
+
+    // ======================================== Static utility ========================================
+
+    public static Object evaluate(Formula f, Model model) {
+        if (f instanceof TupleFormula tf) {
+            return evaluate(tf, model);
+        }
+        return model.evaluate(f);
+    }
+
+    public static TupleValue evaluate(TupleFormula tupleFormula, Model model) {
+        return new TupleValue(tupleFormula.getElements().stream().map(v -> evaluate(v, model)).toList());
+    }
 }
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java
index 0b6ee44192..753071a769 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java
@@ -5,7 +5,10 @@
 import com.dat3m.dartagnan.program.Program;
 import com.dat3m.dartagnan.program.analysis.ReachingDefinitionsAnalysis;
 import com.dat3m.dartagnan.program.event.*;
-import com.dat3m.dartagnan.program.event.core.*;
+import com.dat3m.dartagnan.program.event.core.Load;
+import com.dat3m.dartagnan.program.event.core.MemoryCoreEvent;
+import com.dat3m.dartagnan.program.event.core.NamedBarrier;
+import com.dat3m.dartagnan.program.event.core.RMWStoreExclusive;
 import com.dat3m.dartagnan.utils.Utils;
 import com.dat3m.dartagnan.utils.dependable.DependencyGraph;
 import com.dat3m.dartagnan.wmm.Constraint;
@@ -33,6 +36,7 @@
 import java.util.stream.Collectors;
 
 import static com.dat3m.dartagnan.configuration.OptionNames.*;
+import static com.dat3m.dartagnan.encoding.EncodingContext.ConversionMode.LEFT_TO_RIGHT;
 import static com.dat3m.dartagnan.program.event.Tag.*;
 import static com.dat3m.dartagnan.wmm.RelationNameRepository.RF;
 import static com.google.common.base.Verify.verify;
@@ -569,7 +573,7 @@ public Void visitReadFrom(ReadFrom rfDef) {
                 MemoryCoreEvent r = (MemoryCoreEvent) e2;
                 BooleanFormula e = edge.encode(w, r);
                 BooleanFormula sameAddress = context.sameAddress(w, r);
-                BooleanFormula sameValue = context.equal(context.value(w), context.value(r));
+                BooleanFormula sameValue = context.equal(context.value(w), context.value(r), LEFT_TO_RIGHT);
                 edgeMap.computeIfAbsent(r, key -> new ArrayList<>()).add(e);
                 enc.add(bmgr.implication(e, bmgr.and(execution(w, r), sameAddress, sameValue)));
             });
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/formulas/TupleFormula.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/formulas/TupleFormula.java
index 9a97a4fa20..3a8408852f 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/formulas/TupleFormula.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/formulas/TupleFormula.java
@@ -18,6 +18,11 @@ public class TupleFormula implements Formula {
         this.elements = elements;
     }
 
+    // WARNING: Avoid using this method if possible.
+    public List<Formula> getElements() {
+        return elements;
+    }
+
     @Override
     public String toString() {
         return elements.stream()
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/formulas/TupleValue.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/formulas/TupleValue.java
new file mode 100644
index 0000000000..4db06e11ad
--- /dev/null
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/formulas/TupleValue.java
@@ -0,0 +1,14 @@
+package com.dat3m.dartagnan.encoding.formulas;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/*
+    Simple representation of values of TupleFormula
+ */
+public record TupleValue(List<?> values) {
+    @Override
+    public String toString() {
+        return values.stream().map(Object::toString).collect(Collectors.joining(", ", "( ", " )"));
+    }
+}
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/EventData.java b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/EventData.java
index 368900784f..1b61948e08 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/EventData.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/EventData.java
@@ -15,7 +15,7 @@ public class EventData implements Comparable<EventData> {
     private EventData readFrom;
     private int id = -1;
     private int localId = -1;
-    private BigInteger value;
+    private Object value;
     private BigInteger accessedAddress;
     private int coIndex = Integer.MIN_VALUE;
     private boolean wasExecuted;
@@ -52,10 +52,10 @@ void setAccessedAddress(BigInteger address) {
     	accessedAddress = address;
     }
 
-    public BigInteger getValue() {
+    public Object getValue() {
     	return value;
     }
-    void setValue(BigInteger val) {
+    void setValue(Object val) {
     	value = val;
     }
 
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModel.java b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModel.java
index b167dc20fa..2f78b0a704 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModel.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModel.java
@@ -1,43 +1,12 @@
 package com.dat3m.dartagnan.verification.model;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.Stack;
-import java.util.stream.Collectors;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.sosy_lab.common.configuration.InvalidConfigurationException;
-import org.sosy_lab.java_smt.api.BooleanFormula;
-import org.sosy_lab.java_smt.api.Formula;
-import org.sosy_lab.java_smt.api.Model;
-
 import com.dat3m.dartagnan.encoding.EncodingContext;
+import com.dat3m.dartagnan.encoding.EncodingHelper;
 import com.dat3m.dartagnan.program.Program;
 import com.dat3m.dartagnan.program.Register;
 import com.dat3m.dartagnan.program.Thread;
-import com.dat3m.dartagnan.program.event.Event;
-import com.dat3m.dartagnan.program.event.MemoryEvent;
-import com.dat3m.dartagnan.program.event.RegReader;
-import com.dat3m.dartagnan.program.event.RegWriter;
-import com.dat3m.dartagnan.program.event.Tag;
-import com.dat3m.dartagnan.program.event.core.Alloc;
-import com.dat3m.dartagnan.program.event.core.CondJump;
-import com.dat3m.dartagnan.program.event.core.ExecutionStatus;
-import com.dat3m.dartagnan.program.event.core.GenericVisibleEvent;
-import com.dat3m.dartagnan.program.event.core.IfAsJump;
-import com.dat3m.dartagnan.program.event.core.Label;
-import com.dat3m.dartagnan.program.event.core.Load;
-import com.dat3m.dartagnan.program.event.core.Local;
-import com.dat3m.dartagnan.program.event.core.MemoryCoreEvent;
+import com.dat3m.dartagnan.program.event.*;
+import com.dat3m.dartagnan.program.event.core.*;
 import com.dat3m.dartagnan.program.event.core.threading.ThreadArgument;
 import com.dat3m.dartagnan.program.event.lang.svcomp.BeginAtomic;
 import com.dat3m.dartagnan.program.event.lang.svcomp.EndAtomic;
@@ -45,14 +14,25 @@
 import com.dat3m.dartagnan.program.memory.MemoryObject;
 import com.dat3m.dartagnan.utils.dependable.DependencyGraph;
 import com.dat3m.dartagnan.verification.VerificationTask;
-import static com.dat3m.dartagnan.wmm.RelationNameRepository.CO;
-import static com.dat3m.dartagnan.wmm.RelationNameRepository.RF;
 import com.dat3m.dartagnan.wmm.Wmm;
 import com.google.common.base.Preconditions;
-import static com.google.common.base.Preconditions.checkNotNull;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.sosy_lab.common.configuration.InvalidConfigurationException;
+import org.sosy_lab.java_smt.api.BooleanFormula;
+import org.sosy_lab.java_smt.api.Formula;
+import org.sosy_lab.java_smt.api.Model;
+
+import java.math.BigInteger;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.dat3m.dartagnan.wmm.RelationNameRepository.CO;
+import static com.dat3m.dartagnan.wmm.RelationNameRepository.RF;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /*
 The ExecutionModel wraps a Model and extracts data from it in a more workable manner.
@@ -362,16 +342,7 @@ private void addEvent(Event e, int globalId, int localId) {
 
             if (data.isRead() || data.isWrite()) {
                 Formula valueFormula = encodingContext.value((MemoryCoreEvent)e);
-                assert valueFormula != null;
-                String valueString = String.valueOf(model.evaluate(valueFormula));
-                BigInteger value = switch(valueString) {
-                    // NULL case can happen if the solver optimized away a variable.
-                    // This should only happen if the value is irrelevant, so we will just pick 0.
-                    case "false", "null" -> BigInteger.ZERO;
-                    case "true" -> BigInteger.ONE;
-                    default -> new BigInteger(valueString);
-                };
-                data.setValue(value);
+                data.setValue(EncodingHelper.evaluate(valueFormula, model));
             }
 
             if (data.isRead()) {
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModelManager.java b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModelManager.java
index 8a26d90b51..cc1095c5e7 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModelManager.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ExecutionModelManager.java
@@ -1,6 +1,7 @@
 package com.dat3m.dartagnan.verification.model;
 
 import com.dat3m.dartagnan.encoding.EncodingContext;
+import com.dat3m.dartagnan.encoding.EncodingHelper;
 import com.dat3m.dartagnan.program.Register;
 import com.dat3m.dartagnan.program.Thread;
 import com.dat3m.dartagnan.program.event.Event;
@@ -269,7 +270,7 @@ private boolean isTrue(BooleanFormula formula) {
     }
 
     private Object evaluateByModel(Formula formula) {
-        return model.evaluate(formula);
+        return EncodingHelper.evaluate(formula, model);
     }
 
 
diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ValueModel.java b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ValueModel.java
index efae322724..570982d47c 100644
--- a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ValueModel.java
+++ b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/model/ValueModel.java
@@ -1,5 +1,7 @@
 package com.dat3m.dartagnan.verification.model;
 
+import com.dat3m.dartagnan.encoding.formulas.TupleValue;
+
 import java.math.BigInteger;
 
 
@@ -11,7 +13,7 @@ public class ValueModel {
     public ValueModel(Object literal) {
         if (literal == null) {
             value = null;
-        } else if (literal instanceof BigInteger || literal instanceof Boolean) {
+        } else if (literal instanceof BigInteger || literal instanceof Boolean || literal instanceof TupleValue) {
             value = literal;
         } else {
             throw new IllegalArgumentException("Unsupported value type: " + literal.getClass());


Reviews:
user: login: hernanponcedeleon
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-07T20:29:20Z
user: login: ThomasHaas
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T20:31:06Z
user: login: hernanponcedeleon
state: APPROVED
author_association: OWNER
submitted_at: 2025-03-08T18:53:22Z

Review comments:
diff_hunk: @@ -261,36 +248,40 @@ public Formula lastValue(MemoryObject base, int offset, int size) {
         return formulaManager.getBitvectorFormulaManager().makeVariable(size, name);
     }
 
-    public BooleanFormula equal(Formula left, Formula right) {
-        //FIXME: We should avoid the automatic conversion, or standardize what conversion we expect.
-        // For example, when encoding rf(w, r), we always want to convert the store value type to the read value type
-        // for otherwise, we might get an under-constrained value for val(r) (e.g., its upper bits might be unconstrained,
-        // if we truncate it to smaller size of the store value).
+    public enum ConversionMode {
+        NO,
+        LEFT_TO_RIGHT,
+        RIGHT_TO_LEFT,
+    }
+
+    public BooleanFormula equal(Formula left, Formula right, ConversionMode cMode) {
+        if (cMode == ConversionMode.LEFT_TO_RIGHT) {
+            return equal(right, left, ConversionMode.RIGHT_TO_LEFT);
+        } else if (cMode == ConversionMode.NO) {
+            new EncodingHelper(formulaManager).checkEqualTypes(left, right);
path: dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java
user: login: hernanponcedeleon
body: Either this just returns a Boolean that gets lost or I am missing something
created_at: 2025-03-07T20:28:20Z
author_association: OWNER
diff_hunk: @@ -261,36 +248,40 @@ public Formula lastValue(MemoryObject base, int offset, int size) {
         return formulaManager.getBitvectorFormulaManager().makeVariable(size, name);
     }
 
-    public BooleanFormula equal(Formula left, Formula right) {
-        //FIXME: We should avoid the automatic conversion, or standardize what conversion we expect.
-        // For example, when encoding rf(w, r), we always want to convert the store value type to the read value type
-        // for otherwise, we might get an under-constrained value for val(r) (e.g., its upper bits might be unconstrained,
-        // if we truncate it to smaller size of the store value).
+    public enum ConversionMode {
+        NO,
+        LEFT_TO_RIGHT,
+        RIGHT_TO_LEFT,
+    }
+
+    public BooleanFormula equal(Formula left, Formula right, ConversionMode cMode) {
+        if (cMode == ConversionMode.LEFT_TO_RIGHT) {
+            return equal(right, left, ConversionMode.RIGHT_TO_LEFT);
+        } else if (cMode == ConversionMode.NO) {
+            new EncodingHelper(formulaManager).checkEqualTypes(left, right);
path: dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java
user: login: ThomasHaas
body: You are right. The checking method used to throw an exception but then I moved it and changed it to return a bool and forgot to change the callsite.
created_at: 2025-03-07T20:31:06Z
author_association: COLLABORATOR

PR comments:
user: login: ThomasHaas
created_at: 2025-03-08T08:22:31Z
body: @hernanponcedeleon Can you reproduce the CI error on this branch? Locally, I get correct results. I hope this is not some strange non-deterministic bug on our side.

author_association: COLLABORATOR
user: login: hernanponcedeleon
created_at: 2025-03-08T13:18:53Z
body: I cannot reproduce locally either. This might be a flaky test. I will retrigger the CI to see what happens
author_association: OWNER