Jo Devriendt
Online editor @ manyworlds.site
declare S,E,N,D,M,O,R,Y: -> {0..9}.
1000*S() + 100*E() + 10*N() + D()
+ 1000*M() + 100*O() + 10*R() + E()
//---------------------------------------------
= 10000*M() + 1000*O() + 100*N() + 10*E() + Y().
M() > 0.
distinct(S(),E(),N(),D(),M(),O(),R(),Y()).
declare some 0-arity functions
function that takes arbitrary number of arguments
My mother can understand this. Yours too! :p
write constraints using normal operators
functions
= != > < >= =< + - * / %
not and or xor implies
abs min max count
distinct same if-then-else
Strongly typed and total along bool, int, string
to-do
overloading for multiple types
Builtin functions
declare <name>: <type>, <type>, ... -> <finite range>.
User functions
declare prime: int -> {true, false}.
declare distance: string, string -> {0..1000}.
declare cities: string -> bool.
declare state: int -> {"busy", "ready", "down"}.
declare edge_color: string, string -> {"r", "g", "b"}.
signature
all ranges have a clear type, but are finite no int or string
declare n: -> {0..9}.
declare color: string -> {"r", "g", "b", "y"}.
color("NL") != color("BE").
color("NL") != color("DE").
color("BE") != color("LU").
color("BE") != color("DE").
color("BE") != color("FR").
color("FR") != color("LU").
color("FR") != color("DE").
color("LU") != color("DE").
There must be a better way...
declare color: string -> {"r", "g", "b", "y"}.
declare border: string, string -> bool.
define border as {("NL","BE"), ("NL","DE"),
("BE","LU"), ("BE","DE"), ("BE","FR"),
("FR","LU"), ("FR","DE"), ("LU","DE")} else false.
all [ color(x)!=color(y) for x,y where border(x,y) ].
definition fixes meaning of function
FMF expression
total definition
compiling / flattening / unrolling / grounding / instantiating
yields previous disequalities
max(f(1), f(2), f(3))
all
any
none
count
sum
product
min
max
distinct
same
odd
even
and
or
not( or )
count
+
*
min
max
distinct
same
xor
not( xor )
max [ f(x) for x where x in {1..3} ]
all [ color(x)!=color(y) for x,y where border(x,y) ].
Filter: select all x,y
where border(x,y)
holds
Fold: reduce those color(x)!=color(y)
to true
iff all
are true
Map: map those x,y
to color(x)!=color(y)
all [ color(x)!=color(y) for x,y where border(x,y) ].
list comprehension
aggregate function converting list to one expression
Flexible!
sum [
weight(x)
for x where Item(x) and inKnapsack(x)
] <= capacity().
Captures global constraints and global functions.
distinct [
color(x)
for x where Country(x) and not color(x)="r"
].
"allDiff except 0"
decdef num as {1..9}.
declare cell: int,int -> num.
all [
distinct [ cell(r,c) for c where num(c) ]
for r where num(r) ].
all [
distinct [ cell(r,c) for r where num(r) ]
for c where num(c) ].
declare square: int,int,int -> bool.
define square as ...
all [
distinct [ cell(r,c) for r,c where square(r,c,s)]
for s where num(s) ].
define cell as ...
Circuit constraint in TSP
decdef City as {"city_" 1..n}.
declare next: string -> City.
declare order: string -> {1..n}.
order("city_1") = 1.
all [ order(next(x)) = order(x) + 1
for x where City(x) and next(x) != "city_1" ].
decdef City as {"city_" 1..n}.
declare next: string -> City.
declare order: string -> {1..n}.
order("city_1") = 1.
all [ order(next(x)) = order(x) + 1
for x where City(x) and next(x) != "city_1" ].
City limits instantations of x as it is a finite set of strings.
Online editor @ manyworlds.site
FOUND WORLD
color as {("DE","b"), ("BE","g"), ("FR","r"), ("LU","y"), ("NL","r")}.
declare color: string -> {"r", "g", "b", "y"}.
declare border: string, string -> bool.
define border as {("NL","BE"), ("NL","DE"),
("BE","LU"), ("BE","DE"), ("BE","FR"),
("FR","LU"), ("FR","DE"), ("LU","DE")} else false.
all [ color(x)!=color(y) for x,y where border(x,y) ].
FOUND BLOCKERS
Line 9: not color("BE")=color("DE")
Line 9: not color("BE")=color("FR")
Line 9: not color("BE")=color("LU")
Line 9: not color("DE")=color("FR")
Line 9: not color("DE")=color("LU")
Line 9: not color("FR")=color("LU")
declare color: string -> {"r", "g", "b", "y"}.
declare border: string, string -> bool.
define border as {("NL","BE"), ("NL","DE"),
("BE","LU"), ("BE","DE"), ("BE","FR"),
("FR","LU"), ("FR","DE"), ("LU","DE")} else false.
all [ color(x)!=color(y) for x,y where border(x,y) ].
NL is not involved, as it only borders two other countries
minimize sum [ distance(x,next(x)) for x where City(x) ].
find a world now returns
declare man: string -> bool.
declare mortal: string -> bool.
all [ man(x) implies mortal(x)
for x where
x in {"Socrates","Athens","poison cup","Zeus"}
].
man("Socrates").
not mortal("Zeus").
FOUND INTERSECTION
man as {("Socrates",true), ("Zeus",false)}.
mortal as {("Socrates",true), ("Zeus",false)}.
Goal
Means
Bad: in each step, full expression tree is rebuilt...
Good: minimal set of compiled constraints
Combinatorial programming is simpler than imperative programming. Why are the languages so hard?
Successful when a 12-year old can do their math homework with ManyWorlds and when a lawyer can recognize ManyWorld-encoded laws.
Caveat: no silver bullet!
But simple problems should have simple solutions.
Problem domain description should match code.
Both focus on
Differences
Summer 2024:
Stateful ManyWorlds with Python interface. New backend? ;)
sum [ distance(x,next(x)) for x where City(x) ]
declare fib: int -> {0..1e21}.
define fib(x) as
0 if x=0 else
1 if x=1 else
fib(x-1) + fib(x-2)
where x in {0..100} else 0.
declare fib: int -> {0..1e21}.
declare a,b: -> {0..10}.
define fib(x) as
a() if x=0 else
b() if x=1 else
fib(x-1) + fib(x-2)
where x in {0..100} else 0.
fib(10)=144.