32
IDP : conga/Minisat(ID)

IDP : GidL/Minisat(ID) - University of Kentuckyprotocols.netlab.uky.edu/~davidb/conga/conga_presentation.pdf · What is conga? 7/28/2011 2 Grounder developed here at the University

Embed Size (px)

Citation preview

IDP : conga/Minisat(ID)

What is conga?

7/28/2011

2

Grounder developed here at the University of Kentucky that implements a subset of the IDP language

Creates output for MinisatID to solve

What is IDP?

7/28/2011

3

IDP is a subset of the FO(.) logic

It extends first order logic with inductive definitions

It enforces some declaration rules for entities used within logic programs

It allows strong typing in logic programs

(and other syntactic sugar)

Which leads to…

7/28/2011

4

More readable logic programs

More manageable logic programs

(at least, in theory)

So why is this important?

It is an effective tool for describing solutions to problems

And then we let the solver, Minisat(ID), due the heavy lifting

The problems we throw at it tend to be difficult (or, at least, non-trivial) to solve, but have commonalities

Advantages?

We describe the problem, and then let a (hopefully highly!) optimized program do the model searches for us

These programs are fast; they have annual competitions for speed

And this means that we can take advantage of work done in the field optimizing these types of problems without having to re-implement complex algorithms as the state of the art is advanced

And as you’ll see, we can describe pretty interesting problems very quickly compared to using a procedural approach

So what does it actually look like?

7/28/2011

7

Input files separated into blocks

Blocks determine how declarations are interpreted

Implication and “For each/There exists” semantics

Let’s get to a simple example…

A puzzle…

Does this look familiar? ∀𝑥 ∀𝑦 ∃𝑡 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡 . ∀𝑥 ∀𝑡 ∃𝑦 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡 . ∀𝑦 ∀𝑡 ∃𝑥 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡 .

∀𝑥∀𝑦∀𝑡0∀𝑡1 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡0 ∧ 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡1

→ 𝑡0 = 𝑡1

Latin Square

Given: type int Size = {1..8} Initial(Size, Size, Size) Find: Location(Size, Size, Size) Satisfying: ! x : ! y : ? t : Location(x, y, t). ! x : ! t : ? y : Location(x, y, t). ! y : ! t : ? x : Location(x, y, t). ! x y t1 t2 : Location(x,y,t1) & Location(x,y,t2) => t1 = t2. ! x y t : Initial(x, y, t) => Location(x, y, t). Data: Initial = { }

Input files are divided into blocks

Sixish of them

Given

Declare

Find

Satisfying

Data

Maximize/Minimize

Given block

Begins with “Given:”

NOTE: Lines in the Given block are newline delimited.

No, I don’t know why they are newline delimited.

From the Latin Square problem:

Given:

type int Size = {1..8}

Given (cont’d)

The block is used to declare types, predicates (pre-determined only), and some other values.

“type int Size = {1..8}” tells us:

We have a type called Size we use in the program

It is an integer (although this only really matters if we’re doing math on it)

It has values that range from 1 to 8

Given (cont’d)

Anything in the block is treated as fixed.

We can only modify values here in the Data block (which we’ll get to much later)

But, basically, it’s just here to tell the program what types to use and what constant values to expect in the program

Declare & Find

These blocks have the same syntax.

Again, they are newline delimited

There is only one difference between the two: visibility.

Anything declared in the Declare block is known to the program, but will not be shown as part of the output

While anything in the Find block will be shown as output

Declare & Find (cont’d)

From the Latin Square problem:

Find:

Location(Size, Size, Size)

This declares (and it’s in the Find block, so it will show up on output) a predicate called Size which accepts three parameters, all of which are of the type Size.

Declare & Find (cont’d)

These blocks just declare the values

It’s still up to us to actually define them, this is what the Satisfying block is for

Satisfying

This is where the real logic happens. From our Latin Square implementation: Satisfying: ! x : ! y : ? t : Location(x, y, t). ! x : ! t : ? y : Location(x, y, t). ! y : ! t : ? x : Location(x, y, t). ! x y t0 t1 : Location(x,y,t0) & Location(x,y,t1) => t0 = t1. ! x y t : Initial(x, y, t) => Location(x, y, t).

Basic semantics

Most IDP statements are very easily translated from a standard representation of logic

But since our inputs are plain ASCII files, we don’t have fancy rotated A’s and E’s

So we make do with !’s and ?’s

A note on case…

You might have noticed by now that all predicates (relations) and types (Location, Size) start with capital letters and all quantified variables (x, y, t) start with lower case letters.

This is more than a convention, it is a requirement – predicates and types start with upper case letters, and quantified variables start with lower case letters.

Satisfying (cont’d)

Does this look familiar? ∀𝑥 ∀𝑦 ∃𝑡 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡 . ∀𝑥 ∀𝑡 ∃𝑦 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡 . ∀𝑦 ∀𝑡 ∃𝑥 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡 .

∀𝑥∀𝑦∀𝑡0∀𝑡1 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡0 ∧ 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡1

→ 𝑡0 = 𝑡1

Satisfying (cont’d)

In IDP:

! x : ! y : ? t : Location(x, y, t).

! x : ! t : ? y : Location(x, y, t).

! y : ! t : ? x : Location(x, y, t).

! x y t0 t1 : Location(x,y,t0) & Location(x,y,t1)

=> t0 = t1.

Encoding logic

7/28/2011

22

Furthermore…

Some more conversions from formal logic to IDP:

∀𝑥 ! x : (“for all x”)

∃𝑥 ? x : (“there exists at least one x”)

Which gives you

∀𝑥 ∀𝑦 ∃𝑡 𝐿𝑜𝑐𝑎𝑡𝑖𝑜𝑛 𝑥, 𝑦, 𝑡 .

“For all x, for all y, there exists at least one t such that Location(x,y,t) holds.”

! x : ! y : ? t : Location(x, y, t).

This is pretty neat.

An important line in the program…

! x y t : Initial(x, y, t) => Location(x, y, t).

Literally, “For all x, y, t, Initial(x,y,t) holding implies Location(x,y,t) holds.”

This is how we load initial state data into the problem – we define Location as a given predicate, define it in the data block

A modified program

Given: type int Size Initial(Size, Size, Size) Find: Location(Size, Size, Size) Satisfying: ! x : ! y : ? t : Location(x, y, t). ! x : ! t : ? y : Location(x, y, t). ! y : ! t : ? x : Location(x, y, t). ! x y t0 t1 : Location(x,y,t0) & Location(x,y,t1) => t0 = t1. ! x y t : Initial(x, y, t) => Location(x, y, t). Data: Size = {1..8} Initial = { 1,1,1; 1,2,2; 1,3,3; 1,4,4; 1,5,5; 1,6,6; 1,7,7; 1,8,8; }

Two things to note

“type int Size” in the Given, instead of “type int Size = {1..8}”

This lets us define Size in the data block

“Initial = { 1,1,1; 1,2,2; …”

This explicitly defines the Initial predicate as the listed tuples

Individual values separated by commas, tuples separated by semicolons, nothing exciting here.

Rules vs. Data

The Data block allows us to separate the rules and declaration from our program from the data set

This means we can have the same program easily run on multiple data sets

conga can take multiple files as input, so we can have the rules and data in separate files This is useful for your homework!

For example…

Given: type int Size Initial(Size, Size, Size) Find: Location(Size, Size, Size) Satisfying: ! x : ! y : ? t : Location(x, y, t). ! x : ! t : ? y : Location(x, y, t). ! y : ! t : ? x : Location(x, y, t). ! x y t0 t1 : Location(x,y,t0) & Location(x,y,t1) => t0 = t1. ! x y t : Initial(x, y, t) => Location(x, y, t). Data: Size = {1..8} Initial = { 1,1,1; 1,2,2; 1,3,3; 1,4,4; 1,5,5; 1,6,6; 1,7,7; 1,8,8; }

latin.cng

latin.dat

And then…

To run both of these files through conga and minisatid:

conga latin.cng latin.dat | minisatid

And, of course, you can have multiple data files working with the same rules file

(Again, this is going to be helpful for your homework…)

Some more semantics…

Sometimes, especially if you are using mathematical operators, conga will complain about being unable to find the bounds of variables

The way to get around this is explicitly declaring the type of quantified variables:

! x : ! y : ? t : Location(x, y, t).

Becomes:

! x [Size] : ! y [Size] : ? t [Size] : Location(x, y, t).

This is not needed in most cases, as conga can infer types from the statement, but using math (especially with equivalence) can confuse it

Implication vs. Equivalence

IDP supports both implication (=>) and equivalence (<=>).

It’s important to know when one or the other is needed

Equivalence, of course, is a stronger relationship

We use implication to move knowledge from our data set (the Initial predicate in the example) to our solution set (the Location predicate in the example)

But if we’re using something like a formula – where one statement defines a predicate exactly – we want to use equivalence Like, say, if we were using a predicate to test if two squares on a

chess board were diagonal to each other…