artdag: Phase 7 optimisation laws as confluent maude module + 11 tests

lib/artdag/optimize-rules.sx — the effect-pipeline optimisation passes (identity
elim, no-op/zero-radius elim, adjacent fusion, idempotent over dedup) as a maude
module. Radius algebra is _+_ [assoc comm id: 0] (NOT Peano successor rules, which
are non-confluent here); mau/confluent? certifies 0 non-joinable critical pairs, so
the optimised pipeline's normal form / content id is rewrite-order stable. Consumes
lib/maude/confluence.sx. maude-optimize 25/25, total 183/183.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-19 13:48:17 +00:00
parent aec83f0aac
commit 1fd3aea81b
6 changed files with 156 additions and 8 deletions

View File

@@ -35,13 +35,15 @@ run_suite() {
(load "lib/maude/matching.sx")
(load "lib/maude/conditional.sx")
(load "lib/maude/fire.sx")
(load "lib/maude/confluence.sx")
(load "lib/maude/rewrite.sx")
(load "lib/maude/searchpath.sx")
(load "lib/maude/strategy.sx")
(load "lib/maude/meta.sx")
(load "lib/maude/pretty.sx")
(load "lib/maude/run.sx")'
BRIDGE_LOAD='(load "lib/artdag/maude-bridge.sx")'
BRIDGE_LOAD='(load "lib/artdag/maude-bridge.sx")
(load "lib/artdag/optimize-rules.sx")'
fi
cat > "$TMP" << EPOCHS
(epoch 1)

View File

@@ -0,0 +1,69 @@
; lib/artdag/optimize-rules.sx — Phase 7: optimisation laws as a confluent maude module.
; The optimised effect pipeline IS the normal form of the rule set, so confluence
; (mau/confluent?) is exactly content-id stability: every rewrite order reaches the
; same normal form. Media ops (blur/bright/id/over) are the opaque-op model from
; lib/maude/tests/effects.sx — the engine reasons about the pipeline algebra, never
; pixels. The radius algebra is an AC operator with identity 0 (unary 1s): Peano
; successor rules (s M + N = s(M+N), 0 + N = N) are NOT confluent here (the symbolic
; critical pairs M + 0 and (A+B)+C vs A+(B+C) stick), whereas [assoc comm id: 0]
; joins them via canonical form. maude (lib/maude) is a READ-ONLY consumed substrate:
; mau/parse-module, mau/creduce-term, mau/creduce->str, mau/ccanon, mau/confluent?,
; mau/non-joinable-pairs, mau/cp->str.
(define
artdag/opt-module-src
(str
"fmod ARTDAGOPT is\n"
" sorts Img Num .\n"
" op 0 : -> Num .\n"
" op 1 : -> Num .\n"
" op _+_ : Num Num -> Num [assoc comm id: 0] .\n"
" op blur : Img Num -> Img .\n"
" op bright : Img Num -> Img .\n"
" op id : Img -> Img .\n"
" op over : Img Img -> Img [comm] .\n"
" vars I J : Img .\n"
" vars M N : Num .\n"
" eq id(I) = I .\n"
" eq blur(I, 0) = I .\n"
" eq bright(I, 0) = I .\n"
" eq blur(blur(I, M), N) = blur(I, M + N) .\n"
" eq bright(bright(I, M), N) = bright(I, M + N) .\n"
" eq over(I, I) = I .\n"
"endfm"))
(define artdag/opt-module (mau/parse-module artdag/opt-module-src))
; ---- reduce a surface pipeline to its optimised normal form ----
(define
artdag/opt-reduce-term
(fn (src) (mau/creduce-term artdag/opt-module src)))
(define
artdag/opt-normal-form
(fn (src) (mau/creduce->str artdag/opt-module src)))
(define artdag/opt-canon (fn (src) (mau/ccanon artdag/opt-module src)))
; two surface pipelines optimise to the same pipeline (=> same content id) iff
; their normal forms coincide.
(define
artdag/opt-same-form?
(fn (a b) (= (artdag/opt-normal-form a) (artdag/opt-normal-form b))))
; ---- confluence / content-id stability (consume lib/maude/confluence.sx) ----
(define artdag/opt-confluent? (fn () (mau/confluent? artdag/opt-module)))
(define
artdag/opt-non-joinable
(fn () (mau/non-joinable-pairs artdag/opt-module)))
(define
artdag/opt-non-joinable->strs
(fn
()
(map
(fn (cp) (mau/cp->str artdag/opt-module cp))
(artdag/opt-non-joinable))))

View File

@@ -10,9 +10,9 @@
"serialize": {"pass": 13, "fail": 0},
"stats": {"pass": 12, "fail": 0},
"fault": {"pass": 14, "fail": 0},
"maude-optimize": {"pass": 14, "fail": 0}
"maude-optimize": {"pass": 25, "fail": 0}
},
"total_pass": 172,
"total_pass": 183,
"total_fail": 0,
"total": 172
"total": 183
}

View File

@@ -14,5 +14,5 @@ _Generated by `lib/artdag/conformance.sh`_
| serialize | 13 | 0 | 13 |
| stats | 12 | 0 | 12 |
| fault | 14 | 0 | 14 |
| maude-optimize | 14 | 0 | 14 |
| **Total** | **172** | **0** | **172** |
| maude-optimize | 25 | 0 | 25 |
| **Total** | **183** | **0** | **183** |

View File

@@ -110,3 +110,60 @@
(artdag/dag-id mo-diamond "a")
(keys (artdag/dag-nodes mo-diamond-rt)))
true)
; ---- optimisation laws as a confluent maude module (optimize-rules.sx) ----
; The optimised pipeline is the normal form; confluence => stable content id.
(artdag-test "opt module is confluent" (artdag/opt-confluent?) true)
(artdag-test
"opt module has no non-joinable critical pairs"
(len (artdag/opt-non-joinable))
0)
(artdag-test
"law: identity elimination"
(artdag/opt-normal-form "id(src)")
"src")
(artdag-test
"law: zero-radius blur is a no-op"
(artdag/opt-normal-form "blur(src, 0)")
"src")
(artdag-test
"law: zero-radius bright is a no-op"
(artdag/opt-normal-form "bright(src, 0)")
"src")
(artdag-test
"law: adjacent blur fusion adds radii"
(artdag/opt-normal-form "blur(blur(src, 1), 1)")
"blur(src, _+_(1, 1))")
(artdag-test
"fusion normal form is rewrite-order stable"
(artdag/opt-same-form?
"blur(blur(blur(src, 1), 1), 1)"
"blur(blur(src, 1 + 1), 1)")
true)
(artdag-test
"laws compose: id + no-op + fusion"
(artdag/opt-normal-form "bright(id(blur(blur(src, 1), 1)), 0)")
"blur(src, _+_(1, 1))")
(artdag-test
"law: idempotent over dedup (CSE)"
(artdag/opt-normal-form "over(blur(src, 1), blur(src, 1))")
"blur(src, 1)")
(artdag-test
"distinct over operands do not dedup"
(artdag/opt-same-form? "over(blur(src, 1), blur(src, 1 + 1))" "blur(src, 1)")
false)
(artdag-test
"distinct pipelines stay distinct"
(artdag/opt-same-form? "blur(src, 1)" "bright(src, 1)")
false)