From 0225b3ccedb25a1ae13b12e0652d37cfe0d63cc1 Mon Sep 17 00:00:00 2001
From: Nicolas Descamps <nicolas.descamps@theodo.com>
Date: Tue, 1 Apr 2025 16:22:45 +0200
Subject: [PATCH] =?UTF-8?q?R=C3=A9duction=20d'un=20=C3=A9tat=20et=20Foncti?=
 =?UTF-8?q?ons=20de=20transfert?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 TP2/example_sign.py        |  4 ++
 TP2/example_sign_reduce.py | 33 +++++++++++++++
 TP2/sign_analysis.py       | 82 +++++++++++++++++++++++++++++++++++---
 3 files changed, 114 insertions(+), 5 deletions(-)
 create mode 100644 TP2/example_sign.py
 create mode 100644 TP2/example_sign_reduce.py

diff --git a/TP2/example_sign.py b/TP2/example_sign.py
new file mode 100644
index 0000000..6aa6de3
--- /dev/null
+++ b/TP2/example_sign.py
@@ -0,0 +1,4 @@
+from sign_analysis import analyze
+from example_opsem import factorial
+
+analyze(factorial)
diff --git a/TP2/example_sign_reduce.py b/TP2/example_sign_reduce.py
new file mode 100644
index 0000000..17ed636
--- /dev/null
+++ b/TP2/example_sign_reduce.py
@@ -0,0 +1,33 @@
+from syntax import *
+from sign_analysis import state, abstract_env, sign, reduce_state
+
+x: ArithExpr = AEVar("x")
+y: ArithExpr = AEVar("y")
+
+test_eq: BoolExpr = BEEq(x,y)
+
+test_neq: BoolExpr = BENeg(test_eq)
+
+test_leq: BoolExpr = BELeq(x,y)
+
+test_gt: BoolExpr = BENeg(test_leq)
+
+def test(env: abstract_env) -> None:
+    res_eq = reduce_state(env,test_eq)
+    res_neq = reduce_state(env,test_neq)
+    res_leq = reduce_state(env,test_leq)
+    res_gt = reduce_state(env,test_gt)
+    print(f'In environment { {var: str(sign) for (var,sign) in env.items()} }')
+    print(f"{test_eq} -> {res_eq}")
+    print(f"{test_neq} -> {res_neq}")
+    print(f"{test_leq} -> {res_leq}")
+    print(f"{test_gt} -> {res_gt}")
+
+test({ 'x': sign.POS, 'y': sign.NEG })
+
+test({ 'x': sign.NZ, 'y': sign.NEG })
+
+test({ 'x': sign.POS, 'y': sign.SNEG })
+
+test({ 'x': sign.Z, 'y': sign.POS })
+
diff --git a/TP2/sign_analysis.py b/TP2/sign_analysis.py
index fdb2a92..60f8d0d 100644
--- a/TP2/sign_analysis.py
+++ b/TP2/sign_analysis.py
@@ -501,7 +501,49 @@ def reduce_state(s: state, c: BoolExpr) -> state:
     if s is None:
         return s
     match c:
-        # To be completed (see course's slides)
+        case BEPlain(aexpr):
+            return reduce_eq_sign(s, "x", aexpr)
+        case BEEq(left_expr, right_expr):
+            if isinstance(left_expr, AEVar) and isinstance(right_expr, AEVar):
+                v1 = s[left_expr.var]
+                v2 = s[right_expr.var]
+                if (v1 == sign.SPOS and v2 == sign.SNEG) or (v1 == sign.SNEG and v2 == sign.SPOS):
+                    return None
+                return reduce_eq_sign(s, left_expr.var, right_expr)
+            elif isinstance(left_expr, AEVar):
+                return reduce_eq_sign(s, left_expr.var, right_expr)
+            elif isinstance(right_expr, AEVar):
+                return reduce_eq_sign(s, right_expr.var, left_expr)
+            return s
+        case BENeg(expr):
+            if isinstance(expr, BEEq):
+                left_expr, right_expr = expr.left_expr, expr.right_expr
+                if isinstance(left_expr, AEVar) and isinstance(right_expr, AEVar):
+                    return reduce_neq_sign(s, left_expr.var, right_expr)
+                elif isinstance(left_expr, AEVar):
+                    return reduce_neq_sign(s, left_expr.var, right_expr)
+                elif isinstance(right_expr, AEVar):
+                    return reduce_neq_sign(s, right_expr.var, left_expr)
+            elif isinstance(expr, BELeq):
+                left_expr, right_expr = expr.left_expr, expr.right_expr
+                if isinstance(left_expr, AEVar):
+                    return reduce_strict_lower_bound(s, left_expr.var, right_expr)
+                elif isinstance(right_expr, AEVar):
+                    return reduce_strict_upper_bound(s, right_expr.var, left_expr)
+            return s
+        case BELeq(left_expr, right_expr):
+            if isinstance(left_expr, AEVar) and isinstance(right_expr, AEVar):
+                v1 = s[left_expr.var]
+                v2 = s[right_expr.var]
+                if v1 == sign.SPOS and v2 == sign.SNEG:
+                    return None
+                if v1 == sign.POS and v2 == sign.NEG:
+                    return None
+            if isinstance(left_expr, AEVar):
+                return reduce_upper_bound(s, left_expr.var, right_expr)
+            elif isinstance(right_expr, AEVar):
+                return reduce_lower_bound(s, right_expr.var, left_expr)
+            return s
         case _:
             return s
 
@@ -544,18 +586,48 @@ class Sign_interp(Transfer[state]):
         return s
 
     def tr_set(self, s: state, v: str, e: ArithExpr) -> state:
-        raise NotImplementedError
+        """transfer function for assignment instructions"""
+        if s is None:
+            return None
+        res = eval_aexp(s, e)
+        if res is None:
+            return None
+        if isinstance(res, Top):
+            return s | {v: sign.INT}
+        return s | {v: res}
 
     def tr_test(self, s: state, c: BoolExpr) -> state:
-        raise NotImplementedError
+        """transfer function for test instructions"""
+        if s is None:
+            return None
+        res = eval_bexp(s, c)
+        if res is None:
+            return None
+        if isinstance(res, BTop):
+            return s
+        if res:
+            return reduce_state(s, c)
+        return None
 
     def tr_err(self, s: state, e: Expr) -> state:
+        """transfer function for error instructions"""
         if s is None:
             return s
         if isinstance(e, ArithExpr):
-            raise NotImplementedError
+            res = eval_aexp(s, e)
+            if res is None:
+                return None
+            if isinstance(res, Top):
+                return s
+            return s
         if isinstance(e, BoolExpr):
-            raise NotImplementedError
+            res = eval_bexp(s, e)
+            if res is None:
+                return None
+            if isinstance(res, BTop):
+                return s
+            return s
+        return s
 
 
 def analyze(i: Instr) -> None:
-- 
GitLab