diff --git a/codego/aussagenlogik/formulae/formulae_advanced.go b/codego/aussagenlogik/formulae/formulae_advanced.go index d62a7fe..14c0d74 100644 --- a/codego/aussagenlogik/formulae/formulae_advanced.go +++ b/codego/aussagenlogik/formulae/formulae_advanced.go @@ -1,5 +1,7 @@ package formulae +import "logik/core/utils" + /* ---------------------------------------------------------------- * * METHOD Get Atoms * ---------------------------------------------------------------- */ @@ -21,3 +23,156 @@ var fnGetAtoms = CreateFromSchemeFmlsValued(schemeGetAtoms) func (fml Formula) GetAtoms() []Formula { return *fnGetAtoms(fml) } + +/* ---------------------------------------------------------------- * + * TYPE FormulaPair, FormulaPairs + * ---------------------------------------------------------------- */ + +type FormulaPair struct { + Pos Formula + Neg Formula +} + +type FormulaPairs []FormulaPair + +/* ---------------------------------------------------------------- * + * Methods for FormulaPairs + * ---------------------------------------------------------------- */ + +func NewFormulaPairs(pairs []FormulaPair) FormulaPairs { return pairs } + +func (pairs FormulaPairs) Pos() []Formula { + var fmls = make([]Formula, len(pairs)) + for i, pair := range pairs { + fmls[i] = pair.Pos + } + return fmls +} + +func (pairs FormulaPairs) Neg() []Formula { + var fmls = make([]Formula, len(pairs)) + for i, pair := range pairs { + fmls[i] = pair.Neg + } + return fmls +} + +/* ---------------------------------------------------------------- * + * TYPE KNF, DNF, Horn + * ---------------------------------------------------------------- */ + +type FormulaConjunct []Formula +type FormulaDisjunct []Formula +type FormulaKNF []FormulaDisjunct +type FormulaDNF []FormulaConjunct +type FormulaHornClause struct { + Pos FormulaDisjunct + Neg FormulaConjunct +} +type FormulaHorn []FormulaHornClause + +/* ---------------------------------------------------------------- * + * Methods for KNF, DNF, Horn + * ---------------------------------------------------------------- */ + +func (fml FormulaDisjunct) ToFormula() Formula { + return Disjunction(fml) +} + +func (fml FormulaConjunct) ToFormula() Formula { + return Conjunction(fml) +} + +func (fml FormulaKNF) ToFormula() Formula { + var termsAsFormulae = make([]Formula, len(fml)) + for i, term := range fml { + termsAsFormulae[i] = term.ToFormula() + } + return Conjunction(termsAsFormulae) +} + +func (fml FormulaDNF) ToFormula() Formula { + var termsAsFormulae = make([]Formula, len(fml)) + for i, term := range fml { + termsAsFormulae[i] = term.ToFormula() + } + return Disjunction(termsAsFormulae) +} + +func (fml FormulaHornClause) ToFormula() Formula { + return Implies(fml.Neg.ToFormula(), fml.Pos.ToFormula()) +} + +func (fml FormulaHorn) ToFormula() Formula { + var hornclausesAsFormulae = make([]Formula, len(fml)) + for i, hornclause := range fml { + hornclausesAsFormulae[i] = hornclause.ToFormula() + } + return Conjunction(hornclausesAsFormulae) +} + +func getAtomsFromArrayOfLiterals(fmls []Formula) []string { + var atoms = []string{} + var m = map[string]bool{} + for _, fml := range fmls { + if fml.IsLiteral() { + m[fml.GetName()] = true + } + } + for name, _ := range m { + atoms = append(atoms, name) + } + utils.SortStrings(&atoms) + return atoms +} + +func getAtomsFromArrayOfArraysOfLiterals(fmlArrays [][]Formula) []string { + var atoms = []string{} + var m = map[string]bool{} + for _, fmls := range fmlArrays { + for _, atom := range getAtomsFromArrayOfLiterals(fmls) { + m[atom] = true + } + } + for name, _ := range m { + atoms = append(atoms, name) + } + utils.SortStrings(&atoms) + return atoms +} + +func (fml FormulaConjunct) GetAtoms() []string { + return getAtomsFromArrayOfLiterals(fml) +} + +func (fml FormulaDisjunct) GetAtoms() []string { + return getAtomsFromArrayOfLiterals(fml) +} + +func (fml FormulaHornClause) GetAtoms() []string { + return getAtomsFromArrayOfArraysOfLiterals([][]Formula{fml.Pos, fml.Neg}) +} + +func (fml FormulaKNF) GetAtoms() []string { + var fmlArrays = make([][]Formula, len(fml)) + for i, term := range fml { + fmlArrays[i] = term + } + return getAtomsFromArrayOfArraysOfLiterals(fmlArrays) +} + +func (fml FormulaDNF) GetAtoms() []string { + var fmlArrays = make([][]Formula, len(fml)) + for i, term := range fml { + fmlArrays[i] = term + } + return getAtomsFromArrayOfArraysOfLiterals(fmlArrays) +} + +func (fml FormulaHorn) GetAtoms() []string { + var fmlArrays = make([][]Formula, 2*len(fml)) + for i, hornclause := range fml { + fmlArrays[i] = append(hornclause.Neg, hornclause.Pos...) + } + return getAtomsFromArrayOfArraysOfLiterals(fmlArrays) +} diff --git a/codego/aussagenlogik/formulae/formulae_basic.go b/codego/aussagenlogik/formulae/formulae_basic.go index d01f644..5c0fb8a 100644 --- a/codego/aussagenlogik/formulae/formulae_basic.go +++ b/codego/aussagenlogik/formulae/formulae_basic.go @@ -31,33 +31,33 @@ func (fml Formula) GetExpr() string { return fml.expr } func (fml Formula) GetName() string { return fml.name } -func (fml *Formula) SetSubformulae(subfmls [](*Formula)) { - fml.subformulae = subfmls - fml.valence = len(subfmls) +func (fml *Formula) SetSubformulae(subFmls [](*Formula)) { + fml.subformulae = subFmls + fml.valence = len(subFmls) } func (fml Formula) GetSubFormulae() []Formula { var n int = fml.valence - var subfmls = make([]Formula, n) - for i, subfml := range fml.subformulae { - subfmls[i] = *subfml + var subFmls = make([]Formula, n) + for i, subFml := range fml.subformulae { + subFmls[i] = *subFml } - return subfmls + return subFmls } func (fml Formula) GetAllSubFormulae() []Formula { - var subfml = fml.GetSubFormulae() + var subFml = fml.GetSubFormulae() var result = []Formula{fml.Copy()} - for _, child := range subfml { + for _, child := range subFml { result = append(result, child.GetAllSubFormulae()...) } return result } func (fml Formula) GetAllSubFormulaeStrict() []Formula { - var subfml = fml.GetSubFormulae() + var subFml = fml.GetSubFormulae() var result = []Formula{} - for _, child := range subfml { + for _, child := range subFml { result = append(result, child.GetAllSubFormulae()...) } return result @@ -68,13 +68,13 @@ func (fml Formula) GetChild(indexOpt ...int) Formula { if len(indexOpt) > 0 { index = indexOpt[0] } - var subfml Formula + var subFml Formula if 0 <= index && index < fml.valence { - subfml = *(fml.subformulae[index]) + subFml = *(fml.subformulae[index]) } else { panic(fmt.Sprintf("Instance has no child of index %d !", index)) } - return subfml + return subFml } func (fml Formula) Pretty(preindentOpt ...string) string { @@ -98,8 +98,8 @@ func (fml Formula) pretty(preindent string, tab string, prepend string, depth in default: var lines string = indent + prepend + fml.kind prepend = "|__ " - for _, subfml := range fml.subformulae { - lines += "\n" + subfml.pretty(preindent, tab, prepend, depth+1) + for _, subFml := range fml.subformulae { + lines += "\n" + subFml.pretty(preindent, tab, prepend, depth+1) } return lines } @@ -116,16 +116,16 @@ func (fml Formula) Copy() Formula { } func (fml Formula) Deepcopy() Formula { - var subfmls = make([](*Formula), len(fml.subformulae)) - for i, subfml := range fml.subformulae { - subfmlCopy := subfml.Deepcopy() - subfmls[i] = &subfmlCopy + var subFmls = make([](*Formula), len(fml.subformulae)) + for i, subFml := range fml.subformulae { + subFmlCopy := subFml.Deepcopy() + subFmls[i] = &subFmlCopy } return Formula{ expr: fml.expr, kind: fml.kind, valence: fml.valence, - subformulae: subfmls, + subformulae: subFmls, } } diff --git a/codego/aussagenlogik/formulae/formulae_construction.go b/codego/aussagenlogik/formulae/formulae_construction.go index c81d50a..1681c12 100644 --- a/codego/aussagenlogik/formulae/formulae_construction.go +++ b/codego/aussagenlogik/formulae/formulae_construction.go @@ -47,9 +47,16 @@ func Generic(name string) Formula { } func Negation(fml Formula) Formula { + var name string + if fml.IsAtom() { + name = fml.GetName() + } + var expr = fml.expr + expr = "!" + expr return Formula{ kind: "not", - expr: "!" + " " + fml.expr, + name: name, // preserves name of negated atoms + expr: expr, valence: 1, subformulae: [](*Formula){&fml}, } @@ -65,20 +72,26 @@ func Conjunction2(fml1 Formula, fml2 Formula) Formula { } func Conjunction(fmls []Formula) Formula { + switch len(fmls) { + case 0: + return Tautology + case 1: + return fmls[0] + } var expr string = "" - var children = make([](*Formula), len(fmls)) + var subFmls = make([](*Formula), len(fmls)) for i, fml := range fmls { + (func(i int, subFml Formula) { subFmls[i] = &subFml })(i, fml) if i > 0 { expr += " && " } expr += fml.expr - children[i] = &fml } return Formula{ kind: "and", expr: "(" + expr + ")", - valence: len(children), - subformulae: children, + valence: len(subFmls), + subformulae: subFmls, } } @@ -92,20 +105,26 @@ func Disjunction2(fml1 Formula, fml2 Formula) Formula { } func Disjunction(fmls []Formula) Formula { + switch len(fmls) { + case 0: + return Contradiction + case 1: + return fmls[0] + } var expr string = "" - var children = make([](*Formula), len(fmls)) + var subFmls = make([](*Formula), len(fmls)) for i, fml := range fmls { + (func(i int, subFml Formula) { subFmls[i] = &subFml })(i, fml) if i > 0 { expr += " || " } expr += fml.expr - children[i] = &fml } return Formula{ kind: "or", expr: "(" + expr + ")", - valence: len(children), - subformulae: children, + valence: len(subFmls), + subformulae: subFmls, } } diff --git a/codego/aussagenlogik/formulae/formulae_generate.go b/codego/aussagenlogik/formulae/formulae_generate.go index 63183c1..5e238cd 100644 --- a/codego/aussagenlogik/formulae/formulae_generate.go +++ b/codego/aussagenlogik/formulae/formulae_generate.go @@ -8,16 +8,16 @@ package formulae func CreateFromSchemeIntValued(scheme func(fml Formula, prevValues []int) int) func(fml Formula) int { var fn func(fml Formula) int - var subFn = func(ch chan int, subfml Formula) { ch <- fn(subfml) } + var subFn = func(ch chan int, subFml Formula) { ch <- fn(subFml) } fn = func(fml Formula) int { - var subfmls = fml.GetSubFormulae() - var n = len(subfmls) + var subFmls = fml.GetSubFormulae() + var n = len(subFmls) var subChan = make([](chan int), n) - var prevValues = make([]int, len(subfmls)) + var prevValues = make([]int, len(subFmls)) // start parallel computations on subformulas - for i, subfml := range subfmls { + for i, subFml := range subFmls { subChan[i] = make(chan int) // create Channel, since currently nil - go subFn(subChan[i], subfml) + go subFn(subChan[i], subFml) } // successively read values for i := 0; i < n; i++ { @@ -35,16 +35,16 @@ func CreateFromSchemeIntValued(scheme func(fml Formula, prevValues []int) int) f func CreateFromSchemeStringValued(scheme func(fml Formula, prevValues []string) string) func(fml Formula) string { var fn func(fml Formula) string - var subFn = func(ch chan string, subfml Formula) { ch <- fn(subfml) } + var subFn = func(ch chan string, subFml Formula) { ch <- fn(subFml) } fn = func(fml Formula) string { - var subfmls = fml.GetSubFormulae() - var n = len(subfmls) + var subFmls = fml.GetSubFormulae() + var n = len(subFmls) var subChan = make([](chan string), n) - var prevValues = make([]string, len(subfmls)) + var prevValues = make([]string, len(subFmls)) // start parallel computations on subformulas - for i, subfml := range subfmls { + for i, subFml := range subFmls { subChan[i] = make(chan string) // create Channel, since currently nil - go subFn(subChan[i], subfml) + go subFn(subChan[i], subFml) } // successively read values for i := 0; i < n; i++ { @@ -62,16 +62,16 @@ func CreateFromSchemeStringValued(scheme func(fml Formula, prevValues []string) func CreateFromSchemeStringsValued(scheme func(fml Formula, prevValues [][]string) []string) func(fml Formula) []string { var fn func(fml Formula) []string - var subFn = func(ch chan []string, subfml Formula) { ch <- fn(subfml) } + var subFn = func(ch chan []string, subFml Formula) { ch <- fn(subFml) } fn = func(fml Formula) []string { - var subfmls = fml.GetSubFormulae() - var n = len(subfmls) + var subFmls = fml.GetSubFormulae() + var n = len(subFmls) var subChan = make([](chan []string), n) - var prevValues = make([][]string, len(subfmls)) + var prevValues = make([][]string, len(subFmls)) // start parallel computations on subformulas - for i, subfml := range subfmls { + for i, subFml := range subFmls { subChan[i] = make(chan []string) // create Channel, since currently nil - go subFn(subChan[i], subfml) + go subFn(subChan[i], subFml) } // successively read values for i := 0; i < n; i++ { @@ -89,16 +89,16 @@ func CreateFromSchemeStringsValued(scheme func(fml Formula, prevValues [][]strin func CreateFromSchemeFmlValued(scheme func(fml Formula, prevValues []Formula) Formula) func(fml Formula) Formula { var fn func(fml Formula) Formula - var subFn = func(ch chan Formula, subfml Formula) { ch <- fn(subfml) } + var subFn = func(ch chan Formula, subFml Formula) { ch <- fn(subFml) } fn = func(fml Formula) Formula { - var subfmls = fml.GetSubFormulae() - var n = len(subfmls) + var subFmls = fml.GetSubFormulae() + var n = len(subFmls) var subChan = make([](chan Formula), n) - var prevValues = make([]Formula, len(subfmls)) + var prevValues = make([]Formula, len(subFmls)) // start parallel computations on subformulas - for i, subfml := range subfmls { + for i, subFml := range subFmls { subChan[i] = make(chan Formula) // create Channel, since currently nil - go subFn(subChan[i], subfml) + go subFn(subChan[i], subFml) } // successively read values for i := 0; i < n; i++ { @@ -116,16 +116,16 @@ func CreateFromSchemeFmlValued(scheme func(fml Formula, prevValues []Formula) Fo func CreateFromSchemeFmlsValued(scheme func(fml Formula, prevValues [](*[]Formula)) *[]Formula) func(fml Formula) *[]Formula { var fn func(fml Formula) *[]Formula - var subFn = func(ch chan *[]Formula, subfml Formula) { ch <- fn(subfml) } + var subFn = func(ch chan *[]Formula, subFml Formula) { ch <- fn(subFml) } fn = func(fml Formula) *[]Formula { - var subfmls = fml.GetSubFormulae() - var n = len(subfmls) + var subFmls = fml.GetSubFormulae() + var n = len(subFmls) var subChan = make([](chan *[]Formula), n) - var prevValues = make([](*[]Formula), len(subfmls)) + var prevValues = make([](*[]Formula), len(subFmls)) // start parallel computations on subformulas - for i, subfml := range subfmls { + for i, subFml := range subFmls { subChan[i] = make(chan *[]Formula) // create Channel, since currently nil - go subFn(subChan[i], subfml) + go subFn(subChan[i], subFml) } // successively read values for i := 0; i < n; i++ { @@ -143,16 +143,16 @@ func CreateFromSchemeFmlsValued(scheme func(fml Formula, prevValues [](*[]Formul func CreateFromSchemeFmlPairValued(scheme func(fml Formula, prevValues []FormulaPair) FormulaPair) func(fml Formula) FormulaPair { var fn func(fml Formula) FormulaPair - var subFn = func(ch chan FormulaPair, subfml Formula) { ch <- fn(subfml) } + var subFn = func(ch chan FormulaPair, subFml Formula) { ch <- fn(subFml) } fn = func(fml Formula) FormulaPair { - var subfmls = fml.GetSubFormulae() - var n = len(subfmls) + var subFmls = fml.GetSubFormulae() + var n = len(subFmls) var subChan = make([](chan FormulaPair), n) - var prevValues = make([]FormulaPair, len(subfmls)) + var prevValues = make([]FormulaPair, len(subFmls)) // start parallel computations on subformulas - for i, subfml := range subfmls { + for i, subFml := range subFmls { subChan[i] = make(chan FormulaPair) // create Channel, since currently nil - go subFn(subChan[i], subfml) + go subFn(subChan[i], subFml) } // successively read values for i := 0; i < n; i++ { diff --git a/codego/aussagenlogik/formulae/formulae_normalforms.go b/codego/aussagenlogik/formulae/formulae_normalforms.go new file mode 100644 index 0000000..054807b --- /dev/null +++ b/codego/aussagenlogik/formulae/formulae_normalforms.go @@ -0,0 +1,151 @@ +package formulae + +/* ---------------------------------------------------------------- * + * METHODS: get KNF/DNF + * ---------------------------------------------------------------- */ + +func (fml Formula) GetKNFparts() FormulaKNF { + var subFmls []Formula + if fml.IsDisjunctOfLiterals() { + subFmls = []Formula{fml} + } else if fml.IsKNF() { + subFmls = fml.GetSubFormulae() + } else { + panic("Formula not in KNF!") + } + var terms = make([]FormulaDisjunct, len(subFmls)) + for i, subFml := range subFmls { + if subFml.IsLiteral() { + terms[i] = []Formula{subFml} + } else { + terms[i] = subFml.GetSubFormulae() + } + } + return terms +} + +func (fml Formula) GetDNFparts() FormulaDNF { + var subFmls []Formula + if fml.IsDisjunctOfLiterals() { + subFmls = []Formula{fml} + } else if fml.IsKNF() { + subFmls = fml.GetSubFormulae() + } else { + panic("Formula not in DNF!") + } + var terms = make([]FormulaConjunct, len(subFmls)) + for i, subFml := range subFmls { + if subFml.IsLiteral() { + terms[i] = []Formula{subFml} + } else { + terms[i] = subFml.GetSubFormulae() + } + } + return terms +} + +func (fml Formula) GetHornParts() FormulaHorn { + var subFmls []Formula + if fml.IsHornClause() { + subFmls = []Formula{fml} + } else if fml.IsHornFml() { + subFmls = fml.GetSubFormulae() + } else { + panic("Formula not a Horn-Formula!") + } + var parts = make([]FormulaHornClause, len(subFmls)) + for i, subFml := range subFmls { + Pos := []Formula{} + Neg := []Formula{} + var subSubFml []Formula + if subFml.IsLiteral() { + subSubFml = []Formula{subFml} + } else { + subSubFml = subFml.GetSubFormulae() + } + for _, L := range subSubFml { + if L.IsPositiveLiteral() { + Pos = append(Pos, L) + } else { + Neg = append(Neg, L.GetChild()) + } + } + parts[i] = FormulaHornClause{Pos, Neg} + } + return parts +} + +/* ---------------------------------------------------------------- * + * METHODS: check if KNF/DNF + * ---------------------------------------------------------------- */ + +func onlyLiterals(fmls []Formula) bool { + for _, fml := range fmls { + if !fml.IsLiteral() { + return false + } + } + return true +} + +func numPositiveLiterals(fmls []Formula) int { + var n = 0 + for _, fml := range fmls { + if fml.IsPositiveLiteral() { + n++ + } + } + return n +} + +func (fml Formula) IsConjunctOfLiterals() bool { + return fml.IsLiteral() || (fml.IsConjunction() && onlyLiterals(fml.GetSubFormulae())) +} + +func (fml Formula) IsDisjunctOfLiterals() bool { + return fml.IsLiteral() || (fml.IsDisjunction() && onlyLiterals(fml.GetSubFormulae())) +} + +func (fml Formula) IsHornClause() bool { + var literals = fml.GetSubFormulae() + return fml.IsLiteral() || (fml.IsDisjunction() && onlyLiterals(literals) && (numPositiveLiterals(literals) <= 1)) +} + +func (fml Formula) IsKNF() bool { + if fml.IsConjunction() { + for _, subFml := range fml.GetSubFormulae() { + if !subFml.IsDisjunctOfLiterals() { + return false + } + } + return true + } else { + return fml.IsDisjunctOfLiterals() + } +} + +func (fml Formula) IsDNF() bool { + if fml.IsDisjunction() { + for _, subFml := range fml.GetSubFormulae() { + if !subFml.IsConjunctOfLiterals() { + return false + } + } + return true + } else { + return fml.IsConjunctOfLiterals() + } +} + +func (fml Formula) IsHornFml() bool { + if fml.IsConjunction() { + for _, subFml := range fml.GetSubFormulae() { + if !subFml.IsHornClause() { + return false + } + } + return true + } else { + return fml.IsHornClause() + } +} diff --git a/codego/aussagenlogik/formulae/formulae_pairs.go b/codego/aussagenlogik/formulae/formulae_pairs.go deleted file mode 100644 index 2a493f4..0000000 --- a/codego/aussagenlogik/formulae/formulae_pairs.go +++ /dev/null @@ -1,34 +0,0 @@ -package formulae - -/* ---------------------------------------------------------------- * - * TYPE FormulaPair, FormulaPairs - * ---------------------------------------------------------------- */ - -type FormulaPair struct { - Pos Formula - Neg Formula -} - -type FormulaPairs []FormulaPair - -/* ---------------------------------------------------------------- * - * Methods for FormulaPairs - * ---------------------------------------------------------------- */ - -func NewFormulaPairs(pairs []FormulaPair) FormulaPairs { return pairs } - -func (pairs FormulaPairs) Pos() []Formula { - var fmls = make([]Formula, len(pairs)) - for i, pair := range pairs { - fmls[i] = pair.Pos - } - return fmls -} - -func (pairs FormulaPairs) Neg() []Formula { - var fmls = make([]Formula, len(pairs)) - for i, pair := range pairs { - fmls[i] = pair.Neg - } - return fmls -} diff --git a/codego/aussagenlogik/formulae/formulae_test.go b/codego/aussagenlogik/formulae/formulae_test.go new file mode 100644 index 0000000..5b7225d --- /dev/null +++ b/codego/aussagenlogik/formulae/formulae_test.go @@ -0,0 +1,158 @@ +package formulae_test + +/* ---------------------------------------------------------------- * + * UNIT TESTING + * ---------------------------------------------------------------- */ + +import ( + "logik/aussagenlogik/formulae" + "logik/aussagenlogik/schema" + "testing" + + "github.com/stretchr/testify/assert" +) + +/* ---------------------------------------------------------------- * + * TESTCASE KNF + * ---------------------------------------------------------------- */ + +func TestRecogniseKNF(test *testing.T) { + var assert = assert.New(test) + var fml formulae.Formula + + fml = schema.ParseExpr("A7") + assert.True(fml.IsKNF()) + fml = schema.ParseExpr("! A7") + assert.True(fml.IsKNF()) + fml = schema.ParseExpr("!! A7") + assert.False(fml.IsKNF()) + + fml = schema.ParseExpr("(A0 || ! A1 || A7)") + assert.True(fml.IsKNF()) + fml = schema.ParseExpr("(A0 && ! A1 && A7)") + assert.True(fml.IsKNF()) + fml = schema.ParseExpr("(A0 && !! A1 && A7)") + assert.False(fml.IsKNF()) + + fml = schema.ParseExpr("(A0 || ! A1 || A7) && (A4 || ! A5) && A1") + assert.True(fml.IsKNF()) + fml = schema.ParseExpr("(A0 && ! A1 && A7) || (A4 && ! A5) || A1") + assert.False(fml.IsKNF()) + fml = schema.ParseExpr("((A0 || ! A1 || A7) && (A4 || ! A5)) || A8") + assert.False(fml.IsKNF()) +} + +func TestRecogniseDNF(test *testing.T) { + var assert = assert.New(test) + var fml formulae.Formula + + fml = schema.ParseExpr("A7") + assert.True(fml.IsDNF()) + fml = schema.ParseExpr("! A7") + assert.True(fml.IsDNF()) + fml = schema.ParseExpr("!! A7") + assert.False(fml.IsDNF()) + + fml = schema.ParseExpr("(A0 && ! A1 && A7)") + assert.True(fml.IsDNF()) + fml = schema.ParseExpr("(A0 || ! A1 || A7)") + assert.True(fml.IsDNF()) + fml = schema.ParseExpr("(A0 || !! A1 || A7)") + assert.False(fml.IsDNF()) + + fml = schema.ParseExpr("(A0 && ! A1 && A7) || (A4 && ! A5) || A1") + assert.True(fml.IsDNF()) + fml = schema.ParseExpr("(A0 || ! A1 || A7) && (A4 || ! A5) && A1") + assert.False(fml.IsDNF()) + fml = schema.ParseExpr("((A0 && ! A1 && A7) || (A4 && ! A5)) && A8") + assert.False(fml.IsDNF()) +} + +/* ---------------------------------------------------------------- * + * TESTCASE Horn + * ---------------------------------------------------------------- */ + +func TestRecogniseHorn(test *testing.T) { + var assert = assert.New(test) + var fml formulae.Formula + + fml = schema.ParseExpr("A7") + assert.True(fml.IsHornFml()) + fml = schema.ParseExpr("! A7") + assert.True(fml.IsHornFml()) + fml = schema.ParseExpr("!! A7") + assert.False(fml.IsHornFml()) + + fml = schema.ParseExpr("(! A0 || ! A1 || A7)") + assert.True(fml.IsHornFml()) + fml = schema.ParseExpr("(A0 && ! A1 && A7)") + assert.True(fml.IsHornFml()) + fml = schema.ParseExpr("(A0 && !! A1 && A7)") + assert.False(fml.IsHornFml()) + + fml = schema.ParseExpr("(A0 && ! A1 && ! A7) || (A4 && ! A5) || (! A1 && ! A8)") + assert.False(fml.IsHornFml()) + fml = schema.ParseExpr("(A0 && ! A1 && ! A7) || (A4 && ! A5) || (! A1 && ! A8)") + assert.False(fml.IsHornFml()) + fml = schema.ParseExpr("(A0 || ! A1 || ! A7) && (A4 || ! A5) && (! A1 || ! A8)") + assert.True(fml.IsHornFml()) + fml = schema.ParseExpr("((A0 || ! A1 || A7) && (A4 || ! A5)) || A8") + assert.False(fml.IsHornFml()) +} + +func TestTransformHornToFormula(test *testing.T) { + var assert = assert.New(test) + var fml formulae.Formula + var horn formulae.FormulaHorn + var hornClauses []formulae.FormulaHornClause + + fml = schema.ParseExpr("A8") + assert.True(fml.IsHornFml()) + horn = fml.GetHornParts() + hornClauses = horn + assert.Equal(1, len(hornClauses)) + assert.ElementsMatch([]string{"A8"}, hornClauses[0].Pos.GetAtoms()) + assert.ElementsMatch([]string{}, hornClauses[0].Neg.GetAtoms()) + assert.Equal("(1 -> A8)", horn.ToFormula().GetExpr()) + + fml = schema.ParseExpr("!A8") + assert.True(fml.IsHornFml()) + horn = fml.GetHornParts() + hornClauses = horn + assert.Equal(1, len(hornClauses)) + assert.ElementsMatch([]string{}, hornClauses[0].Pos.GetAtoms()) + assert.ElementsMatch([]string{"A8"}, hornClauses[0].Neg.GetAtoms()) + assert.Equal("(A8 -> 0)", horn.ToFormula().GetExpr()) + + fml = schema.ParseExpr("!A3 || A2 || !A7 || !A9") + assert.True(fml.IsHornFml()) + horn = fml.GetHornParts() + hornClauses = horn + assert.Equal(1, len(hornClauses)) + assert.ElementsMatch([]string{"A2"}, hornClauses[0].Pos.GetAtoms()) + assert.ElementsMatch([]string{"A3", "A7", "A9"}, hornClauses[0].Neg.GetAtoms()) + assert.Equal("((A3 && A7 && A9) -> A2)", horn.ToFormula().GetExpr()) + + fml = schema.ParseExpr("!A3 || !A2 || !A7 || !A9") + assert.True(fml.IsHornFml()) + horn = fml.GetHornParts() + hornClauses = horn + assert.Equal(1, len(hornClauses)) + assert.ElementsMatch([]string{}, hornClauses[0].Pos.GetAtoms()) + assert.ElementsMatch([]string{"A2", "A3", "A7", "A9"}, hornClauses[0].Neg.GetAtoms()) + assert.Equal("((A3 && A2 && A7 && A9) -> 0)", horn.ToFormula().GetExpr()) + + fml = schema.ParseExpr("!A3 && A2 && !A7 && A9 && A7") + assert.True(fml.IsHornFml()) + horn = fml.GetHornParts() + hornClauses = horn + assert.Equal(5, len(hornClauses)) + assert.Equal("((A3 -> 0) && (1 -> A2) && (A7 -> 0) && (1 -> A9) && (1 -> A7))", horn.ToFormula().GetExpr()) + + fml = schema.ParseExpr("(A0 || ! A1 || ! A7) && (A4 || ! A5) && (! A1 || ! A8)") + assert.True(fml.IsHornFml()) + horn = fml.GetHornParts() + hornClauses = horn + assert.Equal(3, len(hornClauses)) + assert.Equal("(((A1 && A7) -> A0) && (A5 -> A4) && ((A1 && A8) -> 0))", horn.ToFormula().GetExpr()) +}