Skip to content

Commit c1031b1

Browse files
authored
Merge pull request #88 from VariantSync/develop
Release: Variation Trees
2 parents 24abf6e + fd164c8 commit c1031b1

27 files changed

Lines changed: 1339 additions & 87 deletions

.projectile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
;; This file stores project information for the Projectile package in Emacs.
2+
;; If you do not use emacs, you can ignore this file.
3+
4+
;; ignore some files from indexing:
5+
-.agdai
6+
-src/MAlonzo

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ This library formalizes all results in our paper:
2727
Additionally, our library comes with a small **demo**, and **tutorials** for getting to know the library and for formalizing your own variability languages (see "Tutorials" section below).
2828
When run in a terminal, our demo will show a translation roundtrip, showcasing the circle of compilers developed for identifying the map of variability languages (Section 5).
2929

30-
## Overview: What is Static Variability and What is Vatras?
30+
## What is Static Variability and What is Vatras?
3131

3232
Vatras is a library to study and compare meta-languages for specifying variability in source code and data.
3333
Some software systems are configurable _before_ they are compiled, i.e., statically.

default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
},
1010
}:
1111
pkgs.agdaPackages.mkDerivation {
12-
version = "2.0";
12+
version = "2.1";
1313
pname = "Vatras";
1414
src = with pkgs.lib.fileset;
1515
toSource {

src/Vatras/Data/Prop.agda

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module Vatras.Data.Prop where
2+
3+
open import Data.Bool as Bool using (Bool)
4+
5+
data Prop (F : Set) : Set where
6+
true : Prop F
7+
false : Prop F
8+
var : F Prop F
9+
¬_ : Prop F Prop F
10+
_∧_ : Prop F Prop F Prop F
11+
12+
infix 23 ¬_
13+
infix 22 _∧_
14+
15+
_∨_ : {F} Prop F Prop F Prop F
16+
a ∨ b = ¬ (¬ a ∧ ¬ b)
17+
18+
_⇒_ : {F} Prop F Prop F Prop F
19+
a ⇒ b = ¬ a ∨ b
20+
21+
_⇔_ : {F} Prop F Prop F Prop F
22+
a ⇔ b = (a ⇒ b) ∧ (b ⇒ a)
23+
24+
Assignment : Set Set
25+
Assignment F = F Bool
26+
27+
eval : {F} Prop F Assignment F Bool
28+
eval true _ = Bool.true
29+
eval false _ = Bool.false
30+
eval (var p) c = c p
31+
eval (¬ p) c = Bool.not (eval p c)
32+
eval (p ∧ q) c = (eval p c) Bool.∧ (eval q c)
33+
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
module Vatras.Data.Prop.Properties {F : Set} where
2+
3+
import Data.Bool as Bool
4+
open import Data.Bool.Properties using (∧-comm; ∧-zeroˡ; ∧-zeroʳ)
5+
open import Data.Empty using (⊥)
6+
open import Data.Product as Product using (Σ; _×_; ∃-syntax; _,_)
7+
open import Data.Sum using (_⊎_; inj₁; inj₂)
8+
9+
open import Relation.Nullary.Negation renaming (¬_ to negate)
10+
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl; cong; sym; trans)
11+
open Eq.≡-Reasoning
12+
13+
open import Vatras.Data.Prop
14+
open import Vatras.Util.AuxProofs using (true≢false)
15+
16+
all-true : Assignment F
17+
all-true _ = Bool.true
18+
19+
all-false : Assignment F
20+
all-false _ = Bool.false
21+
22+
NonContradiction :
23+
{b} {p : Prop F} (a : Assignment F)
24+
eval p a ≡ b
25+
eval (¬ p) a ≡ Bool.not b
26+
NonContradiction _ eq = cong Bool.not eq
27+
28+
NonContradiction' :
29+
(p : Prop F) (a : Assignment F)
30+
eval p a ≡ Bool.true
31+
eval p a ≡ Bool.false
32+
33+
NonContradiction' _ _ = true≢false
34+
35+
Satisfying : Prop F Assignment F Set
36+
Satisfying p a = eval p a ≡ Bool.true
37+
38+
Unsatisfying : Prop F Assignment F Set
39+
Unsatisfying p a = eval p a ≡ Bool.false
40+
41+
Satisfiable : Prop F Set
42+
Satisfiable p = Σ (Assignment F) (Satisfying p)
43+
44+
Falsifiable : Prop F Set
45+
Falsifiable p = Σ (Assignment F) (Unsatisfying p)
46+
47+
Tautology : Prop F Set
48+
Tautology p = a Satisfying p a
49+
50+
Contradiction : Prop F Set
51+
Contradiction p = a Unsatisfying p a
52+
53+
Const : Prop F Set
54+
Const p = Tautology p ⊎ Contradiction p
55+
56+
Const' : Prop F Set
57+
Const' p = ∃[ b ] ( a eval p a ≡ b)
58+
59+
Const→Const' : {p} Const p Const' p
60+
Const→Const' (inj₁ taut ) = Bool.true , taut
61+
Const→Const' (inj₂ contr) = Bool.false , contr
62+
63+
Const'→Const : {p} Const' p Const p
64+
Const'→Const (Bool.true , taut ) = inj₁ taut
65+
Const'→Const (Bool.false , contr) = inj₂ contr
66+
67+
Nonconst : Prop F Set
68+
Nonconst p = Satisfiable p × Falsifiable p
69+
70+
Nonconst' : Prop F Set
71+
Nonconst' p = negate (Const p)
72+
73+
Nonconst→Nonconst' : {p} Nonconst p Nonconst' p
74+
Nonconst→Nonconst' {p} (_ , (a , a-makes-false)) (inj₁ taut ) = NonContradiction' p a (taut a) a-makes-false
75+
Nonconst→Nonconst' {p} ((a , a-makes-true) , _) (inj₂ contr) = NonContradiction' p a a-makes-true (contr a)
76+
77+
sat-∧ˡ : p q
78+
Tautology p
79+
Satisfiable q
80+
Satisfiable (p ∧ q)
81+
sat-∧ˡ p q taut-p (a , sat) = a , (
82+
eval (p ∧ q) a ≡⟨⟩
83+
eval p a Bool.∧ eval q a ≡⟨ cong (Bool._∧ eval q a) (taut-p a) ⟩
84+
Bool.true Bool.∧ eval q a ≡⟨⟩
85+
eval q a ≡⟨ sat ⟩
86+
Bool.true ∎)
87+
88+
sat-∧ʳ : p q
89+
Tautology q
90+
Satisfiable p
91+
Satisfiable (p ∧ q)
92+
sat-∧ʳ p q taut-q (a , sat) = a , (
93+
eval (p ∧ q) a ≡⟨⟩
94+
eval p a Bool.∧ eval q a ≡⟨ cong (eval p a Bool.∧_) (taut-q a) ⟩
95+
eval p a Bool.∧ Bool.true ≡⟨ cong (Bool._∧ Bool.true) sat ⟩
96+
Bool.true ∎)
97+
98+
fal-∧ˡ : p q
99+
Falsifiable p
100+
Falsifiable (p ∧ q)
101+
fal-∧ˡ p q (a , unsat) = a , (
102+
eval (p ∧ q) a ≡⟨⟩
103+
eval p a Bool.∧ eval q a ≡⟨ cong (Bool._∧ eval q a) unsat ⟩
104+
Bool.false Bool.∧ eval q a ≡⟨ ∧-zeroˡ (eval q a) ⟩
105+
Bool.false ∎)
106+
107+
fal-∧ʳ : p q
108+
Falsifiable q
109+
Falsifiable (p ∧ q)
110+
fal-∧ʳ p q (a , unsat) = a , (
111+
eval (p ∧ q) a ≡⟨⟩
112+
eval p a Bool.∧ eval q a ≡⟨ cong (eval p a Bool.∧_) unsat ⟩
113+
eval p a Bool.∧ Bool.false ≡⟨ ∧-zeroʳ (eval p a) ⟩
114+
Bool.false ∎)
115+
116+
-- generalize?
117+
fal-∧-cong : p q
118+
Falsifiable (p ∧ q)
119+
Falsifiable (q ∧ p)
120+
fal-∧-cong p q (a , unsat) rewrite ∧-comm (eval p a) (eval q a) = a , unsat
121+
122+
taut-∧ : p q
123+
Tautology p
124+
Tautology q
125+
Tautology (p ∧ q)
126+
taut-∧ p q taut-p taut-q a rewrite taut-p a | taut-q a = refl
127+
128+
contr-∧ˡ : p q
129+
Contradiction p
130+
Contradiction (p ∧ q)
131+
contr-∧ˡ p q contr-p a rewrite contr-p a = refl
132+
133+
contr-∧ʳ : p q
134+
Contradiction q
135+
Contradiction (p ∧ q)
136+
contr-∧ʳ p q contr-q a =
137+
eval (p ∧ q) a ≡⟨⟩
138+
eval p a Bool.∧ eval q a ≡⟨ cong (eval p a Bool.∧_) (contr-q a) ⟩
139+
eval p a Bool.∧ Bool.false ≡⟨ ∧-comm (eval p a) Bool.false ⟩
140+
Bool.false ∎
141+

src/Vatras/Data/Prop/Rename.agda

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{-|
2+
This module renames variables in Prop expressions.
3+
4+
The idea of this translation is to apply a renaming function `f : F₁ → F₂` to
5+
all elements of `F₁` in the datastructure `Prop F₁` to obtain a new datastructure
6+
`Prop F₂`. To prove preservation of the semantics, we also require a left inverse
7+
`f⁻¹ : D₂ → D₁` of `f` as a proof that `f` is injective. This precondition is
8+
necessary because a non-injective rename could reduce the number of variables.
9+
-}
10+
module Vatras.Data.Prop.Rename where
11+
12+
import Data.Bool as Bool
13+
open import Function using (_∘_; id)
14+
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl; _≗_)
15+
16+
open import Vatras.Data.Prop
17+
18+
rename : {F₁ F₂ : Set} (F₁ F₂) Prop F₁ Prop F₂
19+
rename f true = true
20+
rename f false = false
21+
rename f (var v) = var (f v)
22+
rename f (¬ p) = ¬ (rename f p)
23+
rename f (p ∧ q) = rename f p ∧ rename f q
24+
25+
rename-spec
26+
: {F₁ F₂ : Set}
27+
(f : F₁ F₂)
28+
(p : Prop F₁)
29+
(c : Assignment F₂)
30+
eval (rename f p) c ≡ eval p (c ∘ f)
31+
rename-spec f true c = refl
32+
rename-spec f false c = refl
33+
rename-spec f (var v) c = refl
34+
rename-spec f (¬ p) c = Eq.cong Bool.not (rename-spec f p c)
35+
rename-spec f (p ∧ q) c = Eq.cong₂ Bool._∧_ (rename-spec f p c) (rename-spec f q c)
36+
37+
rename-preserves
38+
: {F₁ F₂ : Set}
39+
(f : F₁ F₂)
40+
(f⁻¹ : F₂ F₁)
41+
f⁻¹ ∘ f ≗ id
42+
(p : Prop F₁)
43+
(c : Assignment F₁)
44+
eval (rename f p) (c ∘ f⁻¹) ≡ eval p c
45+
rename-preserves f f⁻¹ f∘f⁻¹≗id true c = refl
46+
rename-preserves f f⁻¹ f∘f⁻¹≗id false c = refl
47+
rename-preserves f f⁻¹ f∘f⁻¹≗id (var v) c = Eq.cong c (f∘f⁻¹≗id v)
48+
rename-preserves f f⁻¹ f∘f⁻¹≗id (¬ p) c = Eq.cong Bool.not (rename-preserves f f⁻¹ f∘f⁻¹≗id p c)
49+
rename-preserves f f⁻¹ f∘f⁻¹≗id (p ∧ q) c = Eq.cong₂ Bool._∧_ (rename-preserves f f⁻¹ f∘f⁻¹≗id p c) (rename-preserves f f⁻¹ f∘f⁻¹≗id q c)

src/Vatras/Framework/Annotation/IndexedDimension.agda

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ IndexedDimension is used for conversions from NCC to NCC with lower arity (in pa
66
module Vatras.Framework.Annotation.IndexedDimension where
77

88
open import Data.Fin using (Fin)
9+
open import Data.Nat using (ℕ)
910
open import Data.Product using (_×_)
1011
open import Vatras.Util.Nat.AtLeast using (ℕ≥; toℕ; pred)
1112
open import Vatras.Framework.Definitions using (𝔽)
@@ -16,3 +17,6 @@ D with indices i ∈ ℕ, where 2 ≤ n.
1617
-}
1718
IndexedDimension : (D : 𝔽) (n : ℕ≥ 2) 𝔽
1819
IndexedDimension D n = D × Fin (toℕ (pred n))
20+
21+
Indexed : 𝔽 𝔽
22+
Indexed F = F × ℕ

src/Vatras/Framework/Definitions.agda

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,16 @@ and hence expressions are parameterized in the type of this atomic data.
6161
-}
6262
𝔼 : Set₂
6363
𝔼 = 𝔸 Set₁
64+
65+
-- some default atoms
66+
module _ where
67+
open import Data.String using (String; _≟_)
68+
69+
STRING : 𝔸
70+
STRING = String and _≟_
71+
72+
module _ where
73+
open import Data.Nat using (ℕ; _≟_)
74+
75+
NAT : 𝔸
76+
NAT = ℕ and _≟_

src/Vatras/Framework/Variants.agda

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Rose trees are sized for termination checking.
3232
data Rose : Size 𝕍 where
3333
_-<_>- : {i} {A : 𝔸} atoms A List (Rose i A) Rose (↑ i) A
3434

35+
Forest : 𝕍
36+
Forest A = List (Rose ∞ A)
37+
3538
{-|
3639
Variants for gruler's language also form trees but opposed to rose trees,
3740
nodes are binary and data is stored only in leaves.
@@ -50,6 +53,12 @@ data GrulerVariant : 𝕍 where
5053
rose-leaf : {A : 𝔸} atoms A Rose ∞ A
5154
rose-leaf {A} a = a -< [] >-
5255

56+
forest-leaf : {A : 𝔸} atoms A Forest A
57+
forest-leaf a = rose-leaf a ∷ []
58+
59+
forest-singleton : {A : 𝔸} atoms A Forest A Forest A
60+
forest-singleton a l = a -< l >- ∷ []
61+
5362
{-|
5463
Interestingly, variants are also variability languages
5564
(and it does not matter how variants actually look like).

src/Vatras/Lang/ADT/Merge.agda

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
open import Vatras.Framework.Definitions
2+
module Vatras.Lang.ADT.Merge
3+
(V : 𝕍)
4+
(_+ᵥ_ : {A} V A V A V A)
5+
where
6+
7+
open import Data.Bool using (if_then_else_; true; false)
8+
open import Data.Bool.Properties using (if-float)
9+
open import Relation.Binary.PropositionalEquality using (refl; _≡_; _≗_)
10+
open Relation.Binary.PropositionalEquality.≡-Reasoning
11+
12+
open import Vatras.Util.AuxProofs using (if-cong)
13+
14+
import Vatras.Lang.ADT
15+
16+
module Named (F : 𝔽) where
17+
open Vatras.Lang.ADT F V
18+
19+
{-|
20+
Merges two ADTs.
21+
The resulting ADT denotes all possible compositions of variants, such that configuring the resulting ADT
22+
is equivalent to configuring both input ADTs and composing the resulting variants (see ⊕-spec below).
23+
This operations inherits all properties of the variant composition (e.g., commutativity, associativity etc).
24+
-}
25+
_⊕_ : {A} ADT A ADT A ADT A
26+
leaf l ⊕ leaf r = leaf (l +ᵥ r)
27+
leaf l ⊕ (E ⟨ el , er ⟩) = E ⟨ leaf l ⊕ el , leaf l ⊕ er ⟩
28+
(D ⟨ dl , dr ⟩) ⊕ r = D ⟨ dl ⊕ r , dr ⊕ r ⟩
29+
30+
⊕-spec : {A} (l r : ADT A) (c : Configuration)
31+
⟦ l ⊕ r ⟧ c ≡ ⟦ l ⟧ c +ᵥ ⟦ r ⟧ c
32+
⊕-spec (leaf l) (leaf r) c = refl
33+
⊕-spec (leaf l) (E ⟨ el , er ⟩) c with c E
34+
... | true = ⊕-spec (leaf l) el c
35+
... | false = ⊕-spec (leaf l) er c
36+
⊕-spec (D ⟨ dl , dr ⟩) r c with c D
37+
... | true = ⊕-spec dl r c
38+
... | false = ⊕-spec dr r c
39+
40+
---- Properties ----
41+
-- The merge operator inherits
42+
-- properties of the variant composition operator.
43+
--------------------
44+
45+
-- import Algebra.Definitions
46+
-- module Eq (A : 𝔸) where
47+
-- open Algebra.Definitions (_≡_ {A = V A}) using (Commutative) public
48+
49+
-- module Sem (A : 𝔸) where
50+
-- open Algebra.Definitions (_⊢_≣₁_ {A} ADTL) using (Commutative) public
51+
52+
-- ⊕-comm : {A} Eq.Commutative A _+ᵥ_ -> Sem.Commutative A _⊕_
53+
⊕-comm :
54+
( {A} (v w : V A) v +ᵥ w ≡ w +ᵥ v)
55+
---------------------------------------------
56+
( {A} (l r : ADT A) ⟦ l ⊕ r ⟧ ≗ ⟦ r ⊕ l ⟧)
57+
⊕-comm +ᵥ-comm l r c =
58+
⟦ l ⊕ r ⟧ c
59+
≡⟨ ⊕-spec l r c ⟩
60+
⟦ l ⟧ c +ᵥ ⟦ r ⟧ c
61+
≡⟨ +ᵥ-comm (⟦ l ⟧ c) (⟦ r ⟧ c) ⟩
62+
⟦ r ⟧ c +ᵥ ⟦ l ⟧ c
63+
≡⟨ ⊕-spec r l c ⟨
64+
⟦ r ⊕ l ⟧ c
65+
66+
67+
module Prop (F : 𝔽) where
68+
open import Vatras.Data.Prop
69+
open Vatras.Lang.ADT (Prop F) V
70+
open import Vatras.Lang.ADT.Prop F V
71+
open Named (Prop F)
72+
73+
⊕-specₚ : {A} (l r : ADT A) (c : Assignment F)
74+
⟦ l ⊕ r ⟧ₚ c ≡ ⟦ l ⟧ₚ c +ᵥ ⟦ r ⟧ₚ c
75+
⊕-specₚ (leaf v) (leaf r) c = refl
76+
⊕-specₚ (leaf l) (E ⟨ el , er ⟩) c with eval E c
77+
... | true = ⊕-specₚ (leaf l) el c
78+
... | false = ⊕-specₚ (leaf l) er c
79+
⊕-specₚ (D ⟨ dl , dr ⟩) r c with eval D c
80+
... | true = ⊕-specₚ dl r c
81+
... | false = ⊕-specₚ dr r c

0 commit comments

Comments
 (0)