Compare commits

...

9 Commits

9 changed files with 230 additions and 50 deletions

View File

@ -0,0 +1,23 @@
package formulae
/* ---------------------------------------------------------------- *
* METHOD Get Atoms
* ---------------------------------------------------------------- */
func schemeGetAtoms(fml Formula, prevValues [](*[]Formula)) *[]Formula {
if fml.IsAtom() {
return &[]Formula{fml.Copy()}
} else {
var results = []Formula{}
for _, prevValue := range prevValues {
results = append(results, *prevValue...)
}
return &results
}
}
var fnGetAtoms = CreateFromSchemeFmlsValued(schemeGetAtoms)
func (fml Formula) GetAtoms() []Formula {
return *fnGetAtoms(fml)
}

View File

@ -11,6 +11,7 @@ import (
type Formula struct { type Formula struct {
kind string kind string
name string
expr string expr string
valence int valence int
subformulae [](*Formula) subformulae [](*Formula)
@ -28,18 +29,38 @@ func (fml *Formula) SetExpr(expr string) { fml.expr = expr }
func (fml Formula) GetExpr() string { return fml.expr } func (fml Formula) GetExpr() string { return fml.expr }
func (fml *Formula) SetSubformulae(children [](*Formula)) { func (fml Formula) GetName() string { return fml.name }
fml.subformulae = children
fml.valence = len(children) func (fml *Formula) SetSubformulae(subfmls [](*Formula)) {
fml.subformulae = subfmls
fml.valence = len(subfmls)
} }
func (fml Formula) GetSubFormulae() []Formula { func (fml Formula) GetSubFormulae() []Formula {
var n int = fml.valence var n int = fml.valence
var children = make([]Formula, n) var subfmls = make([]Formula, n)
for i, subfml := range fml.subformulae { for i, subfml := range fml.subformulae {
children[i] = *subfml subfmls[i] = *subfml
} }
return children return subfmls
}
func (fml Formula) GetAllSubFormulae() []Formula {
var subfml = fml.GetSubFormulae()
var result = []Formula{fml.Copy()}
for _, child := range subfml {
result = append(result, child.GetAllSubFormulae()...)
}
return result
}
func (fml Formula) GetAllSubFormulaeStrict() []Formula {
var subfml = fml.GetSubFormulae()
var result = []Formula{}
for _, child := range subfml {
result = append(result, child.GetAllSubFormulae()...)
}
return result
} }
func (fml Formula) GetChild(indexOpt ...int) Formula { func (fml Formula) GetChild(indexOpt ...int) Formula {
@ -84,17 +105,27 @@ func (fml Formula) pretty(preindent string, tab string, prepend string, depth in
} }
} }
// shallow copy
func (fml Formula) Copy() Formula {
return Formula{
expr: fml.expr,
kind: fml.kind,
valence: fml.valence,
subformulae: fml.subformulae,
}
}
func (fml Formula) Deepcopy() Formula { func (fml Formula) Deepcopy() Formula {
var children = make([](*Formula), len(fml.subformulae)) var subfmls = make([](*Formula), len(fml.subformulae))
for i, child := range fml.subformulae { for i, subfml := range fml.subformulae {
childCopy := child.Deepcopy() subfmlCopy := subfml.Deepcopy()
children[i] = &childCopy subfmls[i] = &subfmlCopy
} }
return Formula{ return Formula{
expr: fml.expr, expr: fml.expr,
kind: fml.kind, kind: fml.kind,
valence: fml.valence, valence: fml.valence,
subformulae: children, subformulae: subfmls,
} }
} }
@ -117,3 +148,4 @@ func (fml Formula) IsConjunction() bool { return fml.kind == "and" || fm
func (fml Formula) IsDisjunction2() bool { return fml.kind == "or2" } func (fml Formula) IsDisjunction2() bool { return fml.kind == "or2" }
func (fml Formula) IsDisjunction() bool { return fml.kind == "or" || fml.kind == "or2" } func (fml Formula) IsDisjunction() bool { return fml.kind == "or" || fml.kind == "or2" }
func (fml Formula) IsImplication() bool { return fml.kind == "implies" } func (fml Formula) IsImplication() bool { return fml.kind == "implies" }
func (fml Formula) IsDoubleImplication() bool { return fml.kind == "iff" }

View File

@ -22,23 +22,25 @@ var Contradiction = Formula{
* METHODS: Constructions * METHODS: Constructions
* ---------------------------------------------------------------- */ * ---------------------------------------------------------------- */
func Atom(expr string) Formula { func Atom(name string) Formula {
return Formula{ return Formula{
kind: "atom", kind: "atom",
expr: expr, name: name,
expr: name,
valence: 0, valence: 0,
subformulae: [](*Formula){}, subformulae: [](*Formula){},
} }
} }
func NegatedAtom(expr string) Formula { func NegatedAtom(name string) Formula {
return Negation(Atom(expr)) return Negation(Atom(name))
} }
func Generic(expr string) Formula { func Generic(name string) Formula {
return Formula{ return Formula{
kind: "generic", kind: "generic",
expr: expr, name: name,
expr: "{" + name + "}",
valence: 0, valence: 0,
subformulae: [](*Formula){}, subformulae: [](*Formula){},
} }
@ -115,3 +117,12 @@ func Implies(fml1 Formula, fml2 Formula) Formula {
subformulae: [](*Formula){&fml1, &fml2}, subformulae: [](*Formula){&fml1, &fml2},
} }
} }
func DoubleImplication(fml1 Formula, fml2 Formula) Formula {
return Formula{
kind: "iff",
expr: "(" + fml1.expr + " <-> " + fml2.expr + ")",
valence: 2,
subformulae: [](*Formula){&fml1, &fml2},
}
}

View File

@ -14,7 +14,7 @@ func Eval(fml formulae.Formula, I []string) int {
var schema = func(_I []string) func(formulae.Formula, []int) int { var schema = func(_I []string) func(formulae.Formula, []int) int {
return func(fml formulae.Formula, prevValues []int) int { return func(fml formulae.Formula, prevValues []int) int {
if fml.IsAtom() || fml.IsGeneric() { if fml.IsAtom() || fml.IsGeneric() {
return utils.BoolToInt(utils.StrListContains(_I, fml.GetExpr())) return utils.BoolToInt(utils.StrListContains(_I, fml.GetName()))
} else if fml.IsTautologySymbol() { } else if fml.IsTautologySymbol() {
return 1 return 1
} else if fml.IsContradictionSymbol() { } else if fml.IsContradictionSymbol() {
@ -31,6 +31,8 @@ func Eval(fml formulae.Formula, I []string) int {
return utils.MaxList(prevValues) return utils.MaxList(prevValues)
} else if fml.IsImplication() { } else if fml.IsImplication() {
return utils.BoolToInt(prevValues[0] <= prevValues[1]) return utils.BoolToInt(prevValues[0] <= prevValues[1])
} else if fml.IsDoubleImplication() {
return utils.BoolToInt(prevValues[0] == prevValues[1])
} else { } else {
panic("Could not evaluate expression!") panic("Could not evaluate expression!")
} }

View File

@ -64,9 +64,20 @@ func NNF(fml formulae.Formula) formulae.Formula {
} }
} else if fml.IsImplication() { } else if fml.IsImplication() {
return formulae.FormulaPair{ return formulae.FormulaPair{
Pos: formulae.Implies(prevPos[0], prevPos[1]), Pos: formulae.Disjunction2(prevNeg[0], prevPos[1]),
Neg: formulae.Conjunction2(prevPos[0], prevNeg[1]), Neg: formulae.Conjunction2(prevPos[0], prevNeg[1]),
} }
} else if fml.IsDoubleImplication() {
return formulae.FormulaPair{
Pos: formulae.Conjunction2(
formulae.Disjunction2(prevNeg[0], prevPos[1]),
formulae.Disjunction2(prevNeg[1], prevPos[0]),
),
Neg: formulae.Disjunction2(
formulae.Conjunction2(prevPos[0], prevNeg[1]),
formulae.Conjunction2(prevPos[1], prevNeg[0]),
),
}
} else { } else {
panic("Could not evaluate expression!") panic("Could not evaluate expression!")
} }

View File

@ -23,25 +23,124 @@ func TestEvalLiteral(test *testing.T) {
var val int var val int
var fml formulae.Formula var fml formulae.Formula
var I []string var I []string
fml = schema.ParseExpr("A0") fml = schema.ParseExpr("A0")
I = []string{"A0"} I = []string{"A0"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(1, val) assert.Equal(1, val)
fml = schema.ParseExpr("A0") fml = schema.ParseExpr("A0")
I = []string{} I = []string{}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(0, val) assert.Equal(0, val)
fml = schema.ParseExpr("! A0") fml = schema.ParseExpr("! A0")
I = []string{"A0"} I = []string{"A0"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(0, val) assert.Equal(0, val)
fml = schema.ParseExpr("! A0") fml = schema.ParseExpr("! A0")
I = []string{} I = []string{}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(1, val) assert.Equal(1, val)
} }
func TestEvalComplex1(test *testing.T) { func TestEvalNegation(test *testing.T) {
var assert = assert.New(test)
var val int
var fml formulae.Formula
var I []string
fml = schema.ParseExpr("A4 || ! A4")
I = []string{}
val = recursion.Eval(fml, I)
assert.Equal(1, val)
fml = schema.ParseExpr("A4 && ! A4")
I = []string{}
val = recursion.Eval(fml, I)
assert.Equal(0, val)
}
func TestEvalConjunction(test *testing.T) {
var assert = assert.New(test)
var val int
var fml formulae.Formula
var I []string
fml = schema.ParseExpr("A0 && A1")
I = []string{"A0"}
val = recursion.Eval(fml, I)
assert.Equal(0, val)
fml = schema.ParseExpr("A0 && A1")
I = []string{"A0", "A1"}
val = recursion.Eval(fml, I)
assert.Equal(1, val)
}
func TestEvalDisjunction(test *testing.T) {
var assert = assert.New(test)
var val int
var fml formulae.Formula
var I []string
fml = schema.ParseExpr("A0 || A1")
I = []string{"A0"}
val = recursion.Eval(fml, I)
assert.Equal(1, val)
fml = schema.ParseExpr("A0 || A1")
I = []string{"A7"}
val = recursion.Eval(fml, I)
assert.Equal(0, val)
}
func TestEvalImplication(test *testing.T) {
var assert = assert.New(test)
var val int
var fml formulae.Formula
var I []string
fml = schema.ParseExpr("A0 -> A1")
I = []string{"A0"}
val = recursion.Eval(fml, I)
assert.Equal(0, val)
fml = schema.ParseExpr("A0 -> A1")
I = []string{"A0", "A1"}
val = recursion.Eval(fml, I)
assert.Equal(1, val)
fml = schema.ParseExpr("A0 -> A1")
I = []string{"A7"}
val = recursion.Eval(fml, I)
assert.Equal(1, val)
}
func TestEvalIff(test *testing.T) {
var assert = assert.New(test)
var val int
var fml formulae.Formula
var I []string
fml = schema.ParseExpr("A0 <-> A1")
I = []string{"A0"}
val = recursion.Eval(fml, I)
assert.Equal(0, val)
fml = schema.ParseExpr("A0 <-> A1")
I = []string{"A0", "A1"}
val = recursion.Eval(fml, I)
assert.Equal(1, val)
fml = schema.ParseExpr("A0 <-> A1")
I = []string{"A7"}
val = recursion.Eval(fml, I)
assert.Equal(1, val)
}
func TestEvalComplex(test *testing.T) {
var assert = assert.New(test) var assert = assert.New(test)
var val int var val int
var fml formulae.Formula var fml formulae.Formula
@ -50,26 +149,24 @@ func TestEvalComplex1(test *testing.T) {
I = []string{"A0", "A2"} I = []string{"A0", "A2"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(1, val) assert.Equal(1, val)
I = []string{"A0", "A3"} I = []string{"A0", "A3"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(1, val) assert.Equal(1, val)
I = []string{"A0"} I = []string{"A0"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(0, val) assert.Equal(0, val)
I = []string{"A4", "A8"} I = []string{"A4", "A8"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(1, val) assert.Equal(1, val)
}
func TestEvalComplex2(test *testing.T) {
var assert = assert.New(test)
var val int
var fml formulae.Formula
var I []string
fml = schema.ParseExpr("( ! A0 || (( A0 && A3 ) || ! A2 ))") fml = schema.ParseExpr("( ! A0 || (( A0 && A3 ) || ! A2 ))")
I = []string{"A0", "A2"} I = []string{"A0", "A2"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(0, val) assert.Equal(0, val)
I = []string{"A0", "A3"} I = []string{"A0", "A3"}
val = recursion.Eval(fml, I) val = recursion.Eval(fml, I)
assert.Equal(1, val) assert.Equal(1, val)
@ -90,9 +187,8 @@ func TestAtomsNoduplicates(test *testing.T) {
assert.Equal(1, n, "Atome dürfen nicht mehrfach vorkommen!") assert.Equal(1, n, "Atome dürfen nicht mehrfach vorkommen!")
} }
func TestAtomsNononatoms(test *testing.T) { func TestAtomsNoNonAtoms(test *testing.T) {
test.Skip("Methode noch nicht implementiert") test.Skip("Methode noch nicht implementiert")
test.Skip("Syntax for generic expressions in ANTLR4 g4 needs to be implemented.")
var assert = assert.New(test) var assert = assert.New(test)
var fml formulae.Formula var fml formulae.Formula
var val []string var val []string
@ -298,12 +394,14 @@ func TestNNFatoms(test *testing.T) {
nnf_expected = formulae.Atom("A7") nnf_expected = formulae.Atom("A7")
fml = schema.ParseExpr("A7") fml = schema.ParseExpr("A7")
assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr()) assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr())
fml = schema.ParseExpr("!! A7") fml = schema.ParseExpr("!! A7")
assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr()) assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr())
nnf_expected = formulae.NegatedAtom("A7") nnf_expected = formulae.NegatedAtom("A7")
fml = schema.ParseExpr("! A7") fml = schema.ParseExpr("! A7")
assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr()) assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr())
fml = schema.ParseExpr("!!! A7") fml = schema.ParseExpr("!!! A7")
assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr()) assert.Equal(nnf_expected.GetExpr(), recursion.NNF(fml).GetExpr())
} }

View File

@ -3,6 +3,7 @@ package schema
import ( import (
"logik/aussagenlogik/formulae" "logik/aussagenlogik/formulae"
parser "logik/grammars/aussagenlogik" parser "logik/grammars/aussagenlogik"
"regexp"
"github.com/antlr/antlr4/runtime/Go/antlr" "github.com/antlr/antlr4/runtime/Go/antlr"
) )
@ -65,22 +66,13 @@ func (ant antlrTree) getLabel() string {
} }
func (ant antlrTree) getTextContent() string { func (ant antlrTree) getTextContent() string {
var expr string = ant.getLabel()
for _, subant := range ant.getChildren() {
expr += subant.getTextContent()
}
return expr
}
func (ant antlrTree) getTextContentLeaves() string {
var expr string = "" var expr string = ""
var subants = ant.getChildren() var subants = ant.getChildren()
if len(subants) == 0 { if len(subants) == 0 {
expr = ant.getLabel() return ant.getLabel()
} else { }
for _, subant := range subants { for _, subant := range subants {
expr += subant.getTextContent() expr += subant.getTextContent()
}
} }
return expr return expr
} }
@ -116,9 +108,12 @@ func (ant antlrTree) toFormula() formulae.Formula {
case "contradiction": case "contradiction":
return formulae.Contradiction return formulae.Contradiction
case "atom": case "atom":
return formulae.Atom(ant.getTextContentLeaves()) name := ant.getTextContent()
return formulae.Atom(name)
case "generic": case "generic":
return formulae.Generic(ant.getTextContentLeaves()) re := regexp.MustCompile(`^{|}$`)
name := string(re.ReplaceAll([]byte(ant.getTextContent()), []byte("")))
return formulae.Generic(name)
case "not": case "not":
// NOTE: expr = ! expr // NOTE: expr = ! expr
if nChildren == 2 { if nChildren == 2 {
@ -139,6 +134,11 @@ func (ant antlrTree) toFormula() formulae.Formula {
if nChildren == 3 { if nChildren == 3 {
return formulae.Implies(subants[0].toFormula(), subants[2].toFormula()) return formulae.Implies(subants[0].toFormula(), subants[2].toFormula())
} }
case "iff":
// NOTE: expr = expr <=> expr
if nChildren == 3 {
return formulae.DoubleImplication(subants[0].toFormula(), subants[2].toFormula())
}
case "and", "or": case "and", "or":
// NOTE: expr = expr op expr op ... op expr // NOTE: expr = expr op expr op ... op expr
var n int = int((len(subants) + 1) / 2) var n int = int((len(subants) + 1) / 2)

View File

@ -7,27 +7,29 @@ LBRACE: '(';
RBRACE: ')'; RBRACE: ')';
LCURLYBRACE: '{'; LCURLYBRACE: '{';
RCURLYBRACE: '}'; RCURLYBRACE: '}';
TEXT: [a-zA-Z0-9\\_];
// Symbole (erlaube mehrere Varianten) // Symbole (erlaube mehrere Varianten)
SYMB_NOT: ('!'|'~'|'not'); SYMB_NOT: ('!'|'~'|'not');
SYMB_AND: ('&'+|'^'|'and'); SYMB_AND: ('&'+|'^'|'and');
SYMB_OR: ('|'+|'v'|'or'); SYMB_OR: ('|'+|'v'|'or');
SYMB_IMPL: ('->'|'=>'); SYMB_IFF: ([<][-]+[>]|[<][=]+[>]|'iff');
SYMB_IMPL: (~[<][-]+[>]|~[<][=]+[>]);
// Rules // Rules
start: open <EOF> | closed <EOF>; start: open <EOF> | closed <EOF>;
closed: atomic | not | LBRACE open RBRACE; closed: atomic | not | LBRACE open RBRACE;
open: and2 | and | or2 | or | implies; open: and2 | and | or2 | or | implies | iff;
// Schemata für atomische Ausdrücke // Schemata für atomische Ausdrücke
atomic: taut | contradiction | atom; //| generic; atomic: taut | contradiction | atom | generic;
taut: ('1'|'true'); taut: ('1'|'true');
contradiction: ('0'|'false'); contradiction: ('0'|'false');
atom: 'A0' | 'A1' | 'A' NUMBER; // muss A0, A1 wegen falsum/verum extra auflisten atom: 'A0' | 'A1' | 'A' NUMBER; // muss A0, A1 wegen falsum/verum extra auflisten
// // als 'generische' Formeln schreibe bspw. {F}, {G}, {F1}, usw. // als 'generische' Formeln schreibe bspw. {F}, {G}, usw.
// // generic: LCURLYBRACE (.*?) RCURLYBRACE; generic: LCURLYBRACE TEXT+ RCURLYBRACE | LCURLYBRACE TEXT* ( generic TEXT* )+ RCURLYBRACE;
// FIXME: dieses Schema führt zu Konflikten // FIXME: liest Zahlen schlecht ein
// Schema für Negation: ¬ F // Schema für Negation: ¬ F
not: symb=SYMB_NOT closed; not: symb=SYMB_NOT closed;
@ -39,3 +41,5 @@ or2: closed symb=SYMB_OR closed;
or: ( closed ( symb=SYMB_OR closed )+ ); or: ( closed ( symb=SYMB_OR closed )+ );
// Schema für Implikation: F1 ⟶ F2 // Schema für Implikation: F1 ⟶ F2
implies: closed symb=SYMB_IMPL closed; implies: closed symb=SYMB_IMPL closed;
// Schema für Implikation: F1 ⟷ F2
iff: closed symb=SYMB_IFF closed;

View File

@ -16,7 +16,6 @@ function call_go() {
} }
function check_requirements() { function check_requirements() {
[ -f "go.sum" ] && rm "go.sum";
call_go get "$( cat scripts/requirements )"; call_go get "$( cat scripts/requirements )";
} }