α Rby : An Embedding of Alloy in Ruby Aleksandar Milicevic , Ido Efrati, and Daniel Jackson {aleks,idoe,dnj}@csail.mit.edu 1
What exactly is this embedding? 2
What exactly is this embedding? alloy API for ruby? 2
What exactly is this embedding? alloy API for ruby? ✗ alloy-backed constraint solver for ruby? 2
What exactly is this embedding? alloy API for ruby? ✗ alloy-backed constraint solver for ruby? ✗ alloy-like syntax in ruby (embedded DSL)? 2
What exactly is this embedding? alloy API for ruby? ✗ alloy-backed constraint solver for ruby? ✗ alloy-like syntax in ruby (embedded DSL)? ✔ abstract sig Person { abstract sig Person [ father: lone Man, father: ( lone Man), mother: lone Woman mother: ( lone Woman) ] } sig Man extends Person { sig Man extends Person [ wife: lone Woman wife: ( lone Woman) } ] sig Woman extends Person { sig Woman extends Person [ husband: lone Man husband: ( lone Man) } ] fact terminology_biology { fact TerminologyBiology { wife = ~husband wife == ~ husband and no p: Person | no (p: Person) { p in p.^(mother + father) p .in? p . ^(mother + father) } } } 2
What exactly is this embedding? alloy API for ruby? ✔ alloy-backed constraint solver for ruby? ✔ alloy-like syntax in ruby (embedded DSL)? ✔ abstract sig Person { abstract sig Person [ father: lone Man, father: ( lone Man), mother: lone Woman mother: ( lone Woman) ] } sig Man extends Person { sig Man extends Person [ wife: lone Woman wife: ( lone Woman) } ] sig Woman extends Person { sig Woman extends Person [ husband: lone Man husband: ( lone Man) } ] fact terminology_biology { fact TerminologyBiology { wife = ~husband wife == ~ husband and no p: Person | no (p: Person) { p in p.^(mother + father) p .in? p . ^(mother + father) } } } 2
Why Embedding? main goal : full-blown imperative shell around alloy 3
Why Embedding? main goal : full-blown imperative shell around alloy retain the same alloy modeling environment write and analyze the same old alloy models 3
Why Embedding? main goal : full-blown imperative shell around alloy retain the same alloy modeling environment write and analyze the same old alloy models add general-purpose scripting layer around it 3
Why Scripting? 4
Why Scripting? practical reasons automate multiple model finding tasks pre-processing (e.g., prompt for analysis parameters) post-processing (e.g., display the results of the analysis) build tools more easily 4
Why Scripting? practical reasons automate multiple model finding tasks pre-processing (e.g., prompt for analysis parameters) post-processing (e.g., display the results of the analysis) build tools more easily s = SudokuModel :: Sudoku . parse("0,0,1; 0,3,4; 3,1,1; 2,2,3") s . solve # invokes Alloy to solve the sudoku embodied in ‘s‘ s . display # draws some fancy graphical grid displaying the solution 4
Why Scripting? practical reasons automate multiple model finding tasks pre-processing (e.g., prompt for analysis parameters) post-processing (e.g., display the results of the analysis) build tools more easily s = SudokuModel :: Sudoku . parse("0,0,1; 0,3,4; 3,1,1; 2,2,3") s . solve # invokes Alloy to solve the sudoku embodied in ‘s‘ s . display # draws some fancy graphical grid displaying the solution fundamental reasons quest for a synergy between imperative and declarative 4
Why Scripting? practical reasons automate multiple model finding tasks pre-processing (e.g., prompt for analysis parameters) post-processing (e.g., display the results of the analysis) build tools more easily s = SudokuModel :: Sudoku . parse("0,0,1; 0,3,4; 3,1,1; 2,2,3") s . solve # invokes Alloy to solve the sudoku embodied in ‘s‘ s . display # draws some fancy graphical grid displaying the solution fundamental reasons quest for a synergy between imperative and declarative imperative generation of declarative specifications → can this change the way we write specifications? → can this simplify specification languages? 4
Why Scripting? practical reasons automate multiple model finding tasks pre-processing (e.g., prompt for analysis parameters) post-processing (e.g., display the results of the analysis) build tools more easily s = SudokuModel :: Sudoku . parse("0,0,1; 0,3,4; 3,1,1; 2,2,3") s . solve # invokes Alloy to solve the sudoku embodied in ‘s‘ s . display # draws some fancy graphical grid displaying the solution fundamental reasons quest for a synergy between imperative and declarative imperative generation of declarative specifications not studied → can this change the way we write specifications? as much → can this simplify specification languages? 4
Implementation Choices 5
Implementation Choices extend alloy with a new programming language around it → challenge: a lot of engineering → potential drawbacks: generality, lack of existing libraries 5
Implementation Choices extend alloy with a new programming language around it → challenge: a lot of engineering → potential drawbacks: generality, lack of existing libraries recreate the alloy modeling environment in an existing language → challenges: achieving alloy’s relational semantics achieving alloy’s “non-standard” operators achieving alloy’s complex syntax reconcile two different paradigms 5
Implementation Choices extend alloy with a new programming language around it → challenge: a lot of engineering → potential drawbacks: generality, lack of existing libraries recreate the alloy modeling environment in an existing language → challenges: achieving alloy’s relational semantics achieving alloy’s “non-standard” operators achieving alloy’s complex syntax reconcile two different paradigms α Rby 5
α Rby by example: Sudoku 6
Example: Sudoku in α Rby alloy :SudokuModel do sig Sudoku [ # cell coordinate -> cell value grid: Int ** Int ** ( lone Int) ] # ... end 7
Example: Sudoku in α Rby alloy :SudokuModel do sig Sudoku [ # cell coordinate -> cell value grid: Int ** Int ** ( lone Int) ] pred solved [ s: Sudoku ] { # each row contains 1..N # each column contains 1..N # each matrix contains 1..N } end 7
Example: Sudoku in α Rby alloy :SudokuModel do 1. translates ruby to classes/methods module SudokuModel sig Sudoku [ class Sudoku < Arby :: Ast :: Sig # cell coordinate -> cell value attr_accessor :grid grid: Int ** Int ** ( lone Int) end ] def self.solved (s) pred solved [ s: Sudoku ] { # exactly the same body in the # each row contains 1..N # spec as on the left # each column contains 1..N end # each matrix contains 1..N end } end 7
Example: Sudoku in α Rby alloy :SudokuModel do 2. can be used in regular OOP monkey patch classes with utility methods sig Sudoku [ class SudokuModel:: Sudoku # cell coordinate -> cell value def display grid: Int ** Int ** ( lone Int) puts grid # or draw fancy grid ] end pred solved [ s: Sudoku ] { def self.parse (str) # each row contains 1..N Sudoku . new grid: # each column contains 1..N str . split(/;\s*/) . map{ | x | x . split(/,/) . map( & :to_i) } # each matrix contains 1..N } end end end create objects, get/set fields, call methods s = SudokuModel :: Sudoku . new s . grid = [[ 0, 0, 1 ] , [ 1, 3, 2 ]] puts s . grid s = SudokuModel :: Sudoku . parse( "0,0,1; 0,3,4; 3,1,1; 2,2,3") s . display 7
Sudoku in α Rby : Mixed Execution alloy :SudokuModel do goal : parameterize the spec by sudoku size sig Sudoku [ # cell coordinate -> cell value grid: Int ** Int ** ( lone Int) ] pred solved [ s: Sudoku ] { # each row contains 1..N # each column contains 1..N # each matrix contains 1..N } end 8
Sudoku in α Rby : Mixed Execution alloy :SudokuModel do goal : parameterize the spec by sudoku size SudokuModel :: N = 9 3. specification parameterized by sudoku size sig Sudoku [ # cell coordinate -> cell value grid: Int ** Int ** ( lone Int) ] pred solved [ s: Sudoku ] { # each row contains 1..N # each column contains 1..N # each matrix contains 1..N } end 8
Sudoku in α Rby : Mixed Execution alloy :SudokuModel do goal : parameterize the spec by sudoku size SudokuModel :: N = 9 3. specification parameterized by sudoku size sig Sudoku [ # cell coordinate -> cell value grid: Int ** Int ** ( lone Int) ] pred solved [ s: Sudoku ] { 4. mixed concrete and symbolic execution # concrete the spec is the return value of the method m = Integer(Math . sqrt(N)) special α Rby methods return symbolic rng = lambda {| i | m * i . . . m * (i + 1) } values (e.g., all , overloaded operators, ...) everything else executes concretely # symbolic all (r: 0 . . . N) { executed lazily: s . grid [ r ][ Int ] == (1 . .N) and this ruby code s . grid [ Int ][ r ] == (1 . .N) SudokuModel . N = 4 } and puts SudokuModel . to_als all (c, r: 0 . . . m) { and this code s . grid [ rng [ c ]][ rng [ r ]] == (1 . .N) } SudokuModel . N = 9 } puts SudokuModel . to_als end produce different alloy specifications. 8
Recommend
More recommend