/* * Het eigenlijk werk wordt gedaan door drie wederzijds recursieve methodes: * - ParseExpressie, die een complete propositie ontleedt * - ParseTerm, die een formule ontleedt waarin op top-nivo geen of-operatoren worden gebruikt * - ParseFactor, die alleen maar een losse variabele verwerkt, * of een negatie, of een complete propositie, die dan wel tussen haakjes moet staan. * De methodes leveren de herkende deelformule op, * en verplaatsen de cursor naar de positie in de invoer daar net voorbij. */ private IFormule ParseFactor() { SkipSpaces(); if (cursor < lengte && inhoud[cursor] == '(') { cursor++; // passeer het openingshaakje IFormule resultaat = ParseExpressie(); // tussen de haakjes mag een complete propositie staan SkipSpaces(); if (inhoud[cursor] != ')') { throw new Exception("sluithaakje ontbreekt op positie " + cursor); } cursor++; // passeer het sluithaakje return(resultaat); } if (cursor < lengte && (inhoud[cursor] == '-' || inhoud[cursor] == '!' || inhoud[cursor] == '~')) { cursor += 1; // passeer het negatieteken IFormule resultaat = ParseFactor(); return(MaakNegatie(resultaat)); } // geen haakje, geen not-teken, dus dan moeten we een variabele herkennen string variabele = ""; // Controleer alle opvolgende letters en cijfers en maak er een variabele van while (cursor < lengte && Char.IsLetterOrDigit(inhoud[cursor])) { variabele += inhoud[cursor]; cursor += 1; } return(MaakPropositie(variabele)); }
/* * Deze recursieve methode krijgt een Formule, een Set van nog te valueren variabelen, * en een Valuatie voor een deel van de variabelen. * * Deze methode geeft een Valuatie terug die de gegeven formule vervult. * Wanneer zo'n Valuatie niet bestaat geeft hij de waarde null terug. */ private static Valuatie Vervulbaar(IFormule formule, SortedSet <string> variabelen, Valuatie valuatie) { Valuatie resultaat; string var = GetElement(variabelen); if (var == null) { return(valuatie); } // Haal variabele uit lijst van te checken variabelen variabelen.Remove(var); // Controleer of formule vervulbaar is voor de waarde (eerst waar, want als zowel waar als onwaar mogelijk is, wordt waar gekozen) resultaat = VervulbaarVoorWaarde(formule, variabelen, valuatie, var, true); if (resultaat != null) { return(resultaat); } resultaat = VervulbaarVoorWaarde(formule, variabelen, valuatie, var, false); if (resultaat != null) { return(resultaat); } return(null); }
public static void Main() { while (true) { try { String invoer = Console.ReadLine(); IFormule formule = Parser.ParseFormule(invoer); Valuatie valuatie = Solver.Vervulbaar(formule); if (valuatie == null) { Console.WriteLine("UNSAT"); } else { Console.WriteLine("SAT\n" + valuatie); } } catch (Exception exc) { Console.WriteLine("FOUT: " + exc.Message); } break; } }
/* * Deze methode start het recursieve ontleedproces op, * en controleert na afloop of inderdaad de hele invoer is geconsumeerd. */ private IFormule ParseFormule() { IFormule e = ParseExpressie(); SkipSpaces(); if (cursor < lengte) { throw new Exception($"Extra input op positie {cursor} ({inhoud[cursor]})"); } return(e); }
private IFormule ParseExpressie() { IFormule t = ParseTerm(); SkipSpaces(); if (cursor < lengte - 1 && (inhoud[cursor] == '\\' && inhoud[cursor + 1] == '/' || inhoud[cursor] == '|' && inhoud[cursor + 1] == '|')) { cursor += 2; // passeer het voegteken IFormule e = ParseExpressie(); return(MaakDisjunctie(t, e)); } return(t); }
private IFormule ParseTerm() { IFormule f = ParseFactor(); SkipSpaces(); if (cursor < lengte - 1 && (inhoud[cursor] == '/' && inhoud[cursor + 1] == '\\' || inhoud[cursor] == '&' && inhoud[cursor + 1] == '&')) { cursor += 2; // passeer het voegteken IFormule t = ParseTerm(); return(MaakConjunctie(f, t)); } return(f); }
/* * Deze methode geeft een Valuatie terug die de gegeven Formule vervult. * Wanneer zo'n Valuatie niet bestaat geeft hij de waarde null terug. * * Deze methode roept de gelijknamige recursieve methode met 3 parameters aan, met de volgende initiele waarden: * - formule de gegeven Formule, * - variabelen de Set van alle variabelen uit de Formule, verkregen door eerst de methode Verzamel aan te roepen, * - valuatie de lege valuatie. */ public static Valuatie Vervulbaar(IFormule formule) { if (formule == null) { return(null); } SortedSet <string> variabelen = new SortedSet <string>(); formule.Verzamel(variabelen); Valuatie valuatie = new Valuatie(); return(Vervulbaar(formule, variabelen, valuatie)); }
/* * Deze methode controleert de vervulbaarheid van een formule voor een bepaalde waarde voor een enkele variabele */ private static Valuatie VervulbaarVoorWaarde(IFormule formule, SortedSet <string> variabelen, Valuatie valuatie, string var, bool waarde) { // Voeg variabele toe aan valuatie valuatie.VoegToe(var, waarde); // Controleer of formule waar kan zijn if (formule.KanWaar(valuatie)) { // Controleer recursief Valuatie resultaat = Vervulbaar(formule, variabelen, valuatie); // Als er een resultaat is, return deze if (resultaat != null) { return(resultaat); } } // Anders verwijder de variabele weer uit de valuatie en return null valuatie.Verwijder(var); return(null); }
/* * Het eigenlijk werk wordt gedaan door drie wederzijds recursieve methodes: * - ParseExpressie, die een complete propositie ontleedt * - ParseTerm, die een formule ontleedt waarin op top-nivo geen of-operatoren worden gebruikt * - ParseFactor, die alleen maar een losse variabele verwerkt, * of een negatie, of een complete propositie, die dan wel tussen haakjes moet staan. * De methodes leveren de herkende deelformule op, * en verplaatsen de cursor naar de positie in de invoer daar net voorbij. */ private IFormule ParseFactor() { SkipSpaces(); if (cursor < lengte && inhoud[cursor] == '(') { cursor++; // passeer het openingshaakje IFormule resultaat = ParseExpressie(); // tussen de haakjes mag een complete propositie staan SkipSpaces(); if (inhoud[cursor] != ')') { throw new Exception("sluithaakje ontbreekt op positie " + cursor); } cursor++; // passeer het sluithaakje return(resultaat); } else if (cursor < lengte && (inhoud[cursor] == '-' || inhoud[cursor] == '!' || inhoud[cursor] == '~')) { // TODO: zorg dat de parser ook een negatie kan herkennen cursor++; IFormule resultaat = ParseFactor(); SkipSpaces(); return(MaakNegatie(resultaat)); } else { // geen haakje, geen not-teken, dus dan moeten we een variabele herkennen // TODO: zorg dat de parser ook een variabele kan herkennen string resultaat = ""; while (cursor < lengte && char.IsLetterOrDigit(inhoud[cursor])) { resultaat += inhoud[cursor]; cursor++; } return(MaakPropositie(resultaat)); } }
public Negatie(IFormule negatie) { formule = negatie; }
static IFormule MaakNegatie(IFormule formule) { return(new Negatie(formule)); }
static IFormule MaakDisjunctie(IFormule links, IFormule rechts) { return(new Disjunctie(links, rechts)); }
/* * Deze recursieve methode krijgt een Formule, een Set van nog te valueren variabelen, * en een Valuatie voor een deel van de variabelen. * * Deze methode geeft een Valuatie terug die de gegeven formule vervult. * Wanneer zo'n Valuatie niet bestaat geeft hij de waarde null terug. */ private static Valuatie Vervulbaar(IFormule formule, SortedSet <string> variabelen, Valuatie valuatie) { // TODO: schrijf de methode die een Valuatie vindt die een formule vervult return(null); }
/* * Het hoofdprogramma leest een regel van de standaardinvoer, en zet die om naar een formule. * We zoeken een valuatie die de formule vervult. * Als dat lukt, printen we "SAT" op de eerste regel van de standaarduitvoer, en op de tweede regel de valuatie. * Als de formule niet vervulbaar is, printen we alleen "UNSAT" op de eerste regel. */ public static void Main() { while (true) { try { String invoer = Console.ReadLine(); IFormule formule = Parser.ParseFormule(invoer); Console.WriteLine(formule.ToString()); // deze regel kun je gebruiken om de parser te testen DateTime start = DateTime.Now; Valuatie valuatie = Solver.Vervulbaar(formule); DateTime eind = DateTime.Now; invoer = Console.ReadLine(); if (invoer == "p") { Console.WriteLine(formule.ToString()); } else if (invoer == "e") { } else if (invoer == "t") { } else if (invoer == "u") { } else if (invoer == "v") { } else if (invoer == "n") { if (valuatie == null) { Console.Write($"SAT\n{valuatie}"); } } else if (invoer == "y") { if (valuatie == null) { Console.WriteLine("UNSAT"); } else { Console.WriteLine($"SAT\n{valuatie}"); } } Console.WriteLine($"oplostijd: {(eind - start).Ticks / 1E7} seconde"); // deze regel kun je gebruiken om het solve-proces te timen } catch (Exception exc) { // De parser kan exceptions opwerpen als de formule syntaxfouten bevat Console.WriteLine($"FOUT: {exc.Message}"); } break; // in de definitieve versie moet deze break staan, zodat er maar 1 formule wordt verwerkt. // tijdens het testen kun je hem tijdelijk weghalen, zodat je meerdere formules na elkaar kunt proberen. } Console.ReadLine(); // in de definitieve versie moet dit weg, maar tijdens interactief testen voorkomt dit dat het window meteen wegflitst }
static IFormule MaakDisjunctie(IFormule links, IFormule rechts) { // TODO: schrijf de methode die een Disjunctie maakt return(new Disjunctie(links, rechts)); }
static IFormule MaakNegatie(IFormule formule) { // TODO: schrijf de methode die een Negatie maakt return(new Negatie(formule)); }
public Negatie(IFormule formule) { this.formule = formule; }
public Disjunctie(IFormule links, IFormule rechts) { lformule = links; rformule = rechts; }
public Conjunctie(IFormule links, IFormule rechts) { this.links = links; this.rechts = rechts; }