logic

package
v1.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2021 License: MIT Imports: 2 Imported by: 12

Documentation

Overview

Package logic provides representation of Boolean combinational and sequential logic.

Package logic uses a standard https://en.wikipedia.org/wiki/And-inverter_graph (and-inverter graph) to represent circuits. They are simplified using some rules and structural hashing, implemented in the type C. Additionally, Cardinality constraints are supported.

Unlike most AIG libraries, package logic uses the same variables and literals as an associated SAT solver. This means that there is no need to maintain maps for AIG<->SAT flows.

Package logic also supports simple sequential logic (with latches and unrolling) in the type S.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type C

type C struct {
	F z.Lit // false literal
	T z.Lit
	// contains filtered or unexported fields
}

C represents a formula or combinational circuit.

Example (Equiv)
package main

import (
	"fmt"

	"github.com/go-air/gini"
	"github.com/go-air/gini/logic"
)

func main() {
	L := logic.NewC()
	a, b, c := L.Lit(), L.Lit(), L.Lit()
	c1 := L.Ors(a, b, c)
	c2 := L.Ors(a, b, c.Not())
	g1 := L.And(c1, c2)
	g2 := L.Or(a, b)
	// create a "miter", test whether "(a b c) and (a b -c)" is equivalent to "(a b)",
	// by testing whether there is an assignment to {a,b,c} which makes the respective
	// circuits have a different value.
	m := L.Xor(g1, g2)

	// encode to sat
	s := gini.New()
	L.ToCnfFrom(s, m)

	// assume the miter
	s.Assume(m)
	r := s.Solve()
	if r == 1 {
		// not equivalent, model is a witness to different valuations.
		fmt.Printf("sat\n")
	} else {
		// equivalent.
		fmt.Printf("unsat\n")
	}
}
Output:

unsat

func NewC

func NewC() *C

NewC create a new circuit.

func NewCCap

func NewCCap(capHint int) *C

NewCCap creates a new combinational circuit with initial capacity capHint.

func (*C) And

func (p *C) And(a, b z.Lit) z.Lit

And returns a literal equivalent to "a and b", which may be a new variable.

func (*C) Ands

func (c *C) Ands(ms ...z.Lit) z.Lit

Ands constructs a conjunction of a sequence of literals. If ms is empty, then Ands returns p.T.

func (*C) At

func (c *C) At(i int) z.Lit

At returns the i'th element. Elements from 0..Len(c) are in topological order: if i < j then c.At(j) is not reachable from c.At(i) via the edge relation defined by c.Ins(). All elements are positive literals.

One variable for internal use, with index 1, is created when c is created. All other variables created by NewIn, And, ... are created in sequence starting with index 2. Internal variables may be created by c. c.Len() - 1 is the maximal index of a variable.

Hence, the implementation of At(i) is simply z.Var(i).Pos().

func (*C) CardSort added in v1.0.2

func (c *C) CardSort(ms []z.Lit) *CardSort

CardSort creates a CardSort object whose cardinality predicates over ms are encoded in c.

func (*C) Choice

func (c *C) Choice(i, t, e z.Lit) z.Lit

Choice constructs a literal which is equivalent to

if i then t else e

func (*C) CnfSince added in v1.0.2

func (c *C) CnfSince(dst inter.Adder, mark []int8, roots ...z.Lit) ([]int8, int)

CnfSince adds the circuit rooted at roots to dst assuming mark marks all already added nodes in the circuit`. CnfSince returns marks from previously marked nodes and the total number of nodes added. If mark is nil or does not have sufficient capacity, then new storage is created with a copy of mark.

func (*C) Copy added in v0.9.0

func (c *C) Copy() *C

Copy makes a copy of `c`.

func (*C) Eval

func (c *C) Eval(vs []bool)

Eval evaluates the circuit with values vs, where for each literal m in the circuit, vs[i] contains the value for m's variable if m.Var() == i.

vs should contain values for all inputs. In case `c` is embedded in a sequential circuit `s`, then the inputs include the latches of `s`.

func (*C) Eval64

func (c *C) Eval64(vs []uint64)

Eval64 is like Eval but evaluates 64 different inputs in parallel as the bits of a uint64.

func (*C) Implies

func (c *C) Implies(a, b z.Lit) z.Lit

Implies constructs a literal which is equivalent to (a implies b).

func (*C) InPos

func (c *C) InPos(dst []int) []int

InPos returns the positions of all inputs in c in the sequence attainable via Len() and At(). The result is placed in dst if there is space.

If c is part of S, then latches are not included.

func (*C) Ins

func (c *C) Ins(m z.Lit) (z.Lit, z.Lit)

Ins returns the children/ operands of m.

If m is an input, then, Ins returns z.LitNull, z.LitNull
If m is an and, then Ins returns the two conjuncts

func (*C) Len

func (c *C) Len() int

Len returns the length of C, the number of internal nodes used to represent C.

func (*C) Lit added in v1.0.2

func (c *C) Lit() z.Lit

Lit returns a new variable/input to p.

func (*C) Or

func (c *C) Or(a, b z.Lit) z.Lit

Or constructs a literal which is the disjunction of a and b.

func (*C) Ors

func (c *C) Ors(ms ...z.Lit) z.Lit

Ors constructs a literal which is the disjuntion of the literals in ms. If ms is empty, then Ors returns p.F

func (*C) ToCnf

func (c *C) ToCnf(dst inter.Adder)

ToCnf creates a conjunctive normal form of p in adder.

Adder uses basic Tseitinization.

func (*C) ToCnfFrom

func (c *C) ToCnfFrom(dst inter.Adder, roots ...z.Lit)

ToCnfFrom creates a conjunctive normal form of p in adder, including only the part of the circuit reachable from some root in roots.

func (*C) Xor

func (c *C) Xor(a, b z.Lit) z.Lit

Xor constructs a literal which is equivalent to (a xor b).

type Card added in v0.9.0

type Card interface {
	Leq() z.Lit
	Geq() z.Lit
	Less() z.Lit
	Gr() z.Lit
	N() int
}

Card provides an interface for different implementations of cardinality constraints.

type CardSort added in v0.9.0

type CardSort struct {
	// contains filtered or unexported fields
}

CardSort provides cardinality constraints via sorting networks.

Sorting Networks

CardSort uses sorting networks which implement O log(|ms|)**2 compare/swap to sort |ms| literals. Each compare/swap is coded symbolically and generates 6 clauses with 2 new variables. The resulting network helps the solver achieve arc consistency w.r.t. the variables in ms and the output cardinality constraints. Namely, any partial valuation of ms will cause the solver to deduce the corresponding valid and unsat card constraints by unit propagation.

While not a best fit coding mechanism for all cases, sorting networks are a good choice for a general use single mechanism for coding cardinality constraints and hence solving Boolean optimisation problems.

The idea was originally presented by Nicolas Sorensson and Nicolas Een in "Translating Pseudo-Boolean Constraints into SAT" Journal on Satisfiability, Boolean Modelng, and Computation.

func NewCardSort added in v0.9.0

func NewCardSort(ms []z.Lit, c *C) *CardSort

NewCardSort creates a new Card object which gives access to unary Cardinality constraints over ms. The resulting predicates reflect how many of the literals in ms are true.

func (*CardSort) Geq added in v0.9.0

func (c *CardSort) Geq(b int) z.Lit

Geq implements Card.Geq.

func (*CardSort) Gr added in v0.9.0

func (c *CardSort) Gr(b int) z.Lit

Gr implements Card.Gr.

func (*CardSort) Leq added in v0.9.0

func (c *CardSort) Leq(b int) z.Lit

Leq implemets Card.Leq.

func (*CardSort) Less added in v0.9.0

func (c *CardSort) Less(b int) z.Lit

Less returns a literal which is true iff and only if the number of true literals over the set to be counted does not exceed b

func (*CardSort) N added in v0.9.0

func (c *CardSort) N() int

N returns the number of literals whose cardinality is tested. N is len(ms) when the caller calls

NewCard(ms, va)

type Roll added in v1.0.2

type Roll struct {
	S *S // the sequential circuit
	C *C // the resulting comb circuit
	// contains filtered or unexported fields
}

Roll creates an unroller of sequential logic into combinational logic.

Example
package main

import (
	"fmt"

	"github.com/go-air/gini/logic"
)

func main() {
	// create a new sequential circuit, a 16 bit counter
	s := logic.NewS()
	N := 16
	c := s.T
	for i := 0; i < N; i++ {
		n := s.Latch(s.F)
		s.SetNext(n, s.Choice(c, n.Not(), n))
		c = s.And(c, n)
	}

	// create an unroller.
	u := logic.NewRoll(s)
	// unroll until all 1s
	D := (1 << uint(N)) - 1
	errs := 0
	for i := 0; i < N; i++ {
		m := s.Latches[i]
		u.At(m, D)
		if u.At(m, D) != s.T {
			errs++
		}
	}
	fmt.Printf("%d errs\n", errs)
}
Output:

0 errs

func NewRoll added in v1.0.2

func NewRoll(s *S) *Roll

NewRoll creates a new unroller for s

func (*Roll) At added in v1.0.2

func (u *Roll) At(m z.Lit, d int) z.Lit

At returns the value of literal m from sequential circuit u.S at time/depth d as a literal in u.C

If d < 0, then At panics.

func (*Roll) Len added in v1.0.2

func (u *Roll) Len(m z.Lit) int

Len returns the length of the unrolling for literal m.

func (*Roll) MaxLen added in v1.0.2

func (u *Roll) MaxLen() int

MaxLen returns the maximum length of any literal in the unrolling.

type S

type S struct {
	C               // the combinational circuit, logic.C
	Latches []z.Lit // the memory elements/state variables
}

S adds sequential elements to C, gini's combinational logic representation.

func NewS

func NewS() *S

NewS creates a new sequential circuit, with latches.

func NewSCap

func NewSCap(capHint int) *S

NewSCap creates a new sequential circuit with initial capacity capHint.

func (*S) Copy added in v0.9.0

func (s *S) Copy() *S

Copy make a copy of s.

func (*S) Init

func (s *S) Init(latch z.Lit) z.Lit

Init returns the initial state of the latch latch.

  • s.F if false
  • s.T if true
  • z.LitNull if X

func (*S) Latch

func (s *S) Latch(init z.Lit) z.Lit

Latch returns a new "latch", which is a value that evolves over time.

The definition of the value of a latch is in discrete time, in which at time 0, the value of the latch is init The value of a latch at time i is the value of the next state literal of the latch at time i-1. By default, this literal is the latch itself. It may be set using SetNext below.

init must be one of the following

s.T
s.F
z.LitNull

or Latch will panic. z.LitNull means uninitialized, or unknown or 'X' in ternary logic.

func (*S) Next

func (s *S) Next(m z.Lit) z.Lit

Next returns the next state literal for m.

func (*S) SetInit added in v0.9.0

func (s *S) SetInit(latch, init z.Lit)

SetInit sets the initial state of 'latch' to 'nxt'. 'nxt' should be either z.LitNull, s.T, or s.F. If it is not, SetInit panics. If 'latch' is not a latch, then subsequent operations on s are undefined.

func (*S) SetNext

func (s *S) SetNext(m, nxt z.Lit)

SetNext sets the next state literal for m to nxt. m should be returned from s.Latch() or SetNext will panic. nxt should be a literal returned by P.Latch, s.In or s.And or the subsequent behavior of p is undefined.

func (*S) Type added in v0.9.0

func (s *S) Type(m z.Lit) SNodeType

Type returns the node type of m.

type SNodeType added in v0.9.0

type SNodeType int

SNodeType is the type of a node in an S.

const (
	SInput SNodeType = iota
	SAnd
	SLatch
	SConst
)

and the types are constants

func (SNodeType) String added in v0.9.0

func (t SNodeType) String() string

Directories

Path Synopsis
Package aiger implements aiger format version 1.9 ascii and binary readers and writers.
Package aiger implements aiger format version 1.9 ascii and binary readers and writers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL