Adventskalender 21. Dezember 2023 - Logische Programmierung
- heisenberg
- Beiträge: 3692
- Registriert: 04.06.2015 01:17:27
- Lizenz eigener Beiträge: MIT Lizenz
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Ich habe mir diese Webseite als Prolog Grundlagenkurs etwas angeschaut. Das scheint mir im Vergleich zu ein paar anderen das Beste zu sein, was ich gefunden habe:
https://user.phil.hhu.de/~petersen/WiSe ... rolog.html
https://user.phil.hhu.de/~petersen/WiSe ... rolog.html
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Hallo @Heisenberg,
der Link ist wirklich gut. Das erste Kapitel hat ja schon Dinge erklärt, die mir unklar waren und Du auch schon erklärt hast. Mit deklarativen Programmiersprachen hatte ich bisher nichts zu tun. Ich freue mich auch, durch diesen Adventskalender einen Anlass zu haben, mich damit zu beschäftigen. Wir müssen ja nicht schon morgen den Guru Status erreichen. Übermorgen reicht vollkommen aus .
Viele Grüße, Christoph
der Link ist wirklich gut. Das erste Kapitel hat ja schon Dinge erklärt, die mir unklar waren und Du auch schon erklärt hast. Mit deklarativen Programmiersprachen hatte ich bisher nichts zu tun. Ich freue mich auch, durch diesen Adventskalender einen Anlass zu haben, mich damit zu beschäftigen. Wir müssen ja nicht schon morgen den Guru Status erreichen. Übermorgen reicht vollkommen aus .
Viele Grüße, Christoph
- heisenberg
- Beiträge: 3692
- Registriert: 04.06.2015 01:17:27
- Lizenz eigener Beiträge: MIT Lizenz
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Ich habe auch nochmal im SWI-Prolog-Forum eine Frage gestellt. Aber mit der Antwort kann ich (noch) nix anfangen...
https://swi-prolog.discourse.group/t/cr ... nts/7101/1
https://swi-prolog.discourse.group/t/cr ... nts/7101/1
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
So fühlt es sich an, wenn einer aus nem Windows-Forum hierherkommt und ne Frage zu seinem Pi stellt
Jesus saves. Buddha does incremental backups.
Windows ist doof, Linux funktioniert nicht • Don't break debian! • Wie man widerspricht
Windows ist doof, Linux funktioniert nicht • Don't break debian! • Wie man widerspricht
- heisenberg
- Beiträge: 3692
- Registriert: 04.06.2015 01:17:27
- Lizenz eigener Beiträge: MIT Lizenz
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Inzwischen hat jemand im Prolog-Forum einen Fix für die Unique-Klausel gepostet:
Das funktioniert jetzt mit der Testfunktion auch so wie es soll. Erklärung im verlinkten Forenthread.
Code: Alles auswählen
unique([]).
unique([_]).
unique([H|T]) :- T\=[],
\+ contains(T, H),
unique(T).
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
@Heisenberg: Vielen Dank für Deine Frage im Forum. Es ist wohl wirklich angebracht, den Debugger auszuprobieren. Normalerweise ist das aber nicht mein Ding. Bisher habe ich zum Probieren oder zur Fehlersuche in anderen Programmiersprachen Ausgaben auf dem Terminal ausgegeben.
Eine klitzekleine Kleinigkeit habe ich auch. In "rule4" kann man statt
auch gleich
schreiben. Das "\=" wird im unique Fix benutzt, aber auch in dem von Dir empfohlenen Skript vorgestellt.
Eine klitzekleine Kleinigkeit habe ich auch. In "rule4" kann man statt
Code: Alles auswählen
PA = 768358;
PB = 768358;
PD = 768358
Code: Alles auswählen
PC \= 768358
- heisenberg
- Beiträge: 3692
- Registriert: 04.06.2015 01:17:27
- Lizenz eigener Beiträge: MIT Lizenz
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Hallo zusammen,
vielleicht gibt's ja nach Weihnachten noch ein paar hilfreiche Tips vom Content-Creator hier.
Ich habe hier auch nochmal eine einfache Einführung zu Prolog gesehen und mal reingelesen. Die finde ich ganz gelungen:
https://www.swisseduc.ch/informatik/pro ... folien.pdf
Ansonsten stelle ich hier noch mal meinen MYSQL-Ansatz vor, der natürlich bei Weitem nicht so logisch elegant ist, wie Prolog:
1. Grundlegende Datentabellen
Es gibt zunächst mal 3 Grundtabellen: city, population und station
2. Einfache Regelumsetzungen
Die einfachen Regeln kann man in einer Verknüpfungstabelle der obigen 3 Tabellen umsetzen.
Regel #1
Die Regel #1 "Krasnojarsk" hat nicht die höchste Bevölkerungszahl. Damit man auf der Basis weiterarbeiten kann, speichere ich das gleich als SQL-View ab:
Regel #3
Regel 3 ist auch einfach. Hier verknüpfe ich Station und Stadt und schmeisse alle Kombinationen raus, in denen Omsk nicht Station B ist.
Regel #2 und Regel #4
Regeln #2 und #4 sind auch noch einfach und deswegen reicht auch hier eine Verknüpfungstabelle zwischen station und population.
Regel #2: Alle Datensätze, in denen die Station anders als D ist und die Bewohnerzahl 1090811 hat aussortieren
Regel #4: alle Datensätze, bei denen Station C weniger als 1000000 Einwohner hat aussortieren
Komplexe Regel #5 - Teil 1
Jetzt wird es schwieriger. Regel 5 benötigt die Verknüpfung aller 3 Tabellen. Dazu baue ich auf den bereits vorhandenen Verknüpfungstabellen, die die vorhandenen Regeln abbilden eine zusammengesetzte Tabelle. Dazu benötige ich grundsätzlich eine Verknüpfung der gemeinsamen Felder (Schlüsselfelder) der Tabellen:
D. h. wenn ich city_population und city_station verknüpfe, muss ich das mit dem gemeinsamen Schlüssel city_name tun. Das gleiche gilt für die Tabelle city_station und station_population, wobei hier der gemeinsame Schlüssel station_name ist. Zum Dritten noch das gleiche mit station_population und city_population mit dem Schüssel population.
Damit ich einzelne Datensätze aussortieren kann muss ich deswegen wieder mit einem negierten JOIN arbeiten; denn würde ich mit einem WHERE arbeiten, würde ich nur die Menge erhalten, die ich ja nicht will.
Zur Erklärung der übrigen Regeln: Die logischen Folgen aus Regel 5, dass eine Station mit der Bevölkerungszahl 1172070 der Station in der Stadt Tjumen folgt, ist, dass Tjumen nicht die letzte Station sein kann und die Stadt mit der Bevölkerungszahl 1172070 nicht die erste sein kann. Diese beiden Elemente werden mit dem negierten INNER JOIN aussortiert.
Damit ist jetzt in der VIEW csp eine Liste von Möglichkeiten, welche Wegpunkte in welcher Stadt mit welcher Bevölkerungszahl noch in Frage kommt. Das sind gar nicht mehr so viele.
Zwei SQL-Funktionen
Jetzt brauchen wir noch 2 SQL-Funktionen, die abbilden, dass jede Stadt nur einmal Wegpunkt sein darf. Ich nenne das gleich wie in der Prolog-Variante "UNIQUE". Da MySQL aber typisierte Variablen hat, braucht es dafür 2 Funktionen, eine für Strings und eine für Zahlen:
Finale: Regel #5 - Teil 2
Jetzt kommt das grosse Finale. Hier wird die Tabelle der einzelnen Wegpunkte (Station, Stadt, Bevölkerungszahl, ...) in den Weg tranponiert, also von dem Zustand ...
... in diesen ...
... wobei dann am Schluss nur noch ein Datensatz übrig bleiben sollte: Die Lösung.
Dazu spanne ich den Select über die gleiche Tabelle mit mehren Aliasen, wähle für die jeweilige Station den entsprechenden Stationsnamen aus und filtere das ganze durch die beiden Uniquefunktionen, damit sowohl Bevölkerungszahl als auch Stadtname nur jeweils einmal vorkommen:
Jetzt muss noch der 2. Teil der 5. Regel erfüllt werden. Die Stadt, die Tjumen folgt, hat 1172070 Einwohner. Hier gibt es drei mögliche Konstellationen, die ich selektiere:
Das wäre dann die Bedingung dazu:
Als komplette Abfrage ergibt sich dann:
Dieser Select gibt jetzt die Lösung aus.
Als Verbesserungsmöglichkeit könnte man die Station noch numerisch setzen und dann hat man statt 3 Einzelabfragen bzgl. Regel #5-Teil2 nur noch eine einzelne komplexe Abfrage, was dann mehr eine klare logisch strukturierte Lösung wäre.
Hier ist noch der Datenbankdump der MariaDB dazu: 42056
Ich glaube im Vergleich sieht man, dass es bestimmt sehr lohnenswert ist, zu verstehen, wie das mit Prolog geht, weil das viel weniger Code ist.
vielleicht gibt's ja nach Weihnachten noch ein paar hilfreiche Tips vom Content-Creator hier.
Ich habe hier auch nochmal eine einfache Einführung zu Prolog gesehen und mal reingelesen. Die finde ich ganz gelungen:
https://www.swisseduc.ch/informatik/pro ... folien.pdf
Ansonsten stelle ich hier noch mal meinen MYSQL-Ansatz vor, der natürlich bei Weitem nicht so logisch elegant ist, wie Prolog:
1. Grundlegende Datentabellen
Es gibt zunächst mal 3 Grundtabellen: city, population und station
Code: Alles auswählen
MariaDB [raetsel]> select * from city;
+-------------+
| name |
+-------------+
| Krasnojarsk |
| Omsk |
| Tjumen |
| Novosibirsk |
+-------------+
4 rows in set (0,001 sec)
MariaDB [raetsel]> select * from station;
+------+
| name |
+------+
| A |
| B |
| C |
| D |
+------+
4 rows in set (0,001 sec)
MariaDB [raetsel]> select * from population;
+---------+
| count |
+---------+
| 768358 |
| 1090811 |
| 1172070 |
| 1612833 |
+---------+
4 rows in set (0,001 sec)
Die einfachen Regeln kann man in einer Verknüpfungstabelle der obigen 3 Tabellen umsetzen.
Regel #1
Die Regel #1 "Krasnojarsk" hat nicht die höchste Bevölkerungszahl. Damit man auf der Basis weiterarbeiten kann, speichere ich das gleich als SQL-View ab:
Code: Alles auswählen
CREATE VIEW city_population AS
SELECT name,count
FROM city, population
WHERE NOT (name="Krasnojarsk" and count = 1612833);
Regel 3 ist auch einfach. Hier verknüpfe ich Station und Stadt und schmeisse alle Kombinationen raus, in denen Omsk nicht Station B ist.
Code: Alles auswählen
CREATE VIEW city_station AS
SELECT station.name AS station_name, city.name AS city_name
FROM station
LEFT JOIN city ON
NOT (
station.name = "A" and city.name="Omsk"
or station.name = "C" and city.name="Omsk"
or station.name = "D" and city.name="Omsk"
) ;
Regel #2 und Regel #4
Regeln #2 und #4 sind auch noch einfach und deswegen reicht auch hier eine Verknüpfungstabelle zwischen station und population.
Code: Alles auswählen
CREATE VIEW station_population AS
SELECT station.name, population.count
FROM station
LEFT JOIN population ON NOT (
name="A" AND count = 1090811
OR name="B" AND count = 1090811
OR name="C" AND count = 1090811
OR name="C" AND count < 1000000
);
Regel #4: alle Datensätze, bei denen Station C weniger als 1000000 Einwohner hat aussortieren
Komplexe Regel #5 - Teil 1
Jetzt wird es schwieriger. Regel 5 benötigt die Verknüpfung aller 3 Tabellen. Dazu baue ich auf den bereits vorhandenen Verknüpfungstabellen, die die vorhandenen Regeln abbilden eine zusammengesetzte Tabelle. Dazu benötige ich grundsätzlich eine Verknüpfung der gemeinsamen Felder (Schlüsselfelder) der Tabellen:
D. h. wenn ich city_population und city_station verknüpfe, muss ich das mit dem gemeinsamen Schlüssel city_name tun. Das gleiche gilt für die Tabelle city_station und station_population, wobei hier der gemeinsame Schlüssel station_name ist. Zum Dritten noch das gleiche mit station_population und city_population mit dem Schüssel population.
Damit ich einzelne Datensätze aussortieren kann muss ich deswegen wieder mit einem negierten JOIN arbeiten; denn würde ich mit einem WHERE arbeiten, würde ich nur die Menge erhalten, die ich ja nicht will.
Code: Alles auswählen
CREATE VIEW csp AS
SELECT city_station.station_name, city_station.city_name, station_population.count
FROM city_population, city_station
INNER JOIN station_population ON
city_station.station_name = station_population.name
AND NOT ( city_name = "Tjumen" AND station_name = "D")
AND NOT ( station_name = "A" AND count = 1172070 )
WHERE city_population.name = city_station.city_name
AND city_population.count = station_population.count ;
Damit ist jetzt in der VIEW csp eine Liste von Möglichkeiten, welche Wegpunkte in welcher Stadt mit welcher Bevölkerungszahl noch in Frage kommt. Das sind gar nicht mehr so viele.
Zwei SQL-Funktionen
Jetzt brauchen wir noch 2 SQL-Funktionen, die abbilden, dass jede Stadt nur einmal Wegpunkt sein darf. Ich nenne das gleich wie in der Prolog-Variante "UNIQUE". Da MySQL aber typisierte Variablen hat, braucht es dafür 2 Funktionen, eine für Strings und eine für Zahlen:
Code: Alles auswählen
DELIMITER $$
CREATE FUNCTION unique_str(IN a VARCHAR(30), IN b VARCHAR(30), IN c VARCHAR(30), IN d VARCHAR(30)) RETURNS INT
BEGIN
IF (a!=b AND a!=c AND a!=d AND b!=c AND b!=d AND c!=d) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
$$
DELIMITER $$
CREATE FUNCTION unique_int(IN a INT, IN b INT, IN c INT, IN d INT) RETURNS INT
BEGIN
IF (a!=b AND a!=c AND a!=d AND b!=c AND b!=d AND c!=d) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
$$
Jetzt kommt das grosse Finale. Hier wird die Tabelle der einzelnen Wegpunkte (Station, Stadt, Bevölkerungszahl, ...) in den Weg tranponiert, also von dem Zustand ...
Code: Alles auswählen
A, Krasnojarsk, 1172070
A, Tjumen, 1090811
...
D, Novosivirsk, 1612833
Code: Alles auswählen
Krasnojarsk, 1172070, Omsk, 1234567, Tjumen, 1090811, Novosivirsk, 1612833
...
Tjumen, 1234567, Omsk ,1172070, Tjumen, 1090811, Novosivirsk, 1612833
Dazu spanne ich den Select über die gleiche Tabelle mit mehren Aliasen, wähle für die jeweilige Station den entsprechenden Stationsnamen aus und filtere das ganze durch die beiden Uniquefunktionen, damit sowohl Bevölkerungszahl als auch Stadtname nur jeweils einmal vorkommen:
Code: Alles auswählen
SELECT csp_a.city_name, csp_a.count,
csp_b.city_name, csp_b.count,
csp_c.city_name, csp_c.count,
csp_d.city_name, csp_d.count
FROM csp AS csp_a
LEFT JOIN csp AS csp_b ON csp_b.station_name = "B"
LEFT JOIN csp AS csp_c ON csp_c.station_name = "C"
LEFT JOIN csp AS csp_d ON csp_d.station_name = "D"
WHERE csp_a.station_name = "A"
AND unique_str(csp_a.city_name,csp_b.city_name,csp_c.city_name,csp_d.city_name)
AND unique_int(csp_a.count, csp_b.count,csp_c.count,csp_d.count);
Das wäre dann die Bedingung dazu:
Code: Alles auswählen
csp_a.city_name = "Tjumen" AND csp_b.count=1172070
OR csp_b.city_name = "Tjumen" AND csp_c.count=1172070
OR csp_c.city_name = "Tjumen" AND csp_d.count=1172070
Code: Alles auswählen
SELECT csp_a.city_name, csp_a.count,
csp_b.city_name, csp_b.count,
csp_c.city_name, csp_c.count,
csp_d.city_name, csp_d.count
FROM csp AS csp_a
LEFT JOIN csp AS csp_b ON csp_b.station_name = "B"
LEFT JOIN csp AS csp_c ON csp_c.station_name = "C"
LEFT JOIN csp AS csp_d ON csp_d.station_name = "D"
WHERE csp_a.station_name = "A"
AND unique_str(csp_a.city_name,csp_b.city_name,csp_c.city_name,csp_d.city_name)
AND unique_int(csp_a.count, csp_b.count,csp_c.count,csp_d.count)
and (
csp_a.city_name = "Tjumen" AND csp_b.count=1172070
OR csp_b.city_name = "Tjumen" AND csp_c.count=1172070
OR csp_c.city_name = "Tjumen" AND csp_d.count=1172070
);
Als Verbesserungsmöglichkeit könnte man die Station noch numerisch setzen und dann hat man statt 3 Einzelabfragen bzgl. Regel #5-Teil2 nur noch eine einzelne komplexe Abfrage, was dann mehr eine klare logisch strukturierte Lösung wäre.
Hier ist noch der Datenbankdump der MariaDB dazu: 42056
Ich glaube im Vergleich sieht man, dass es bestimmt sehr lohnenswert ist, zu verstehen, wie das mit Prolog geht, weil das viel weniger Code ist.
- paedubucher
- Beiträge: 858
- Registriert: 22.02.2009 16:19:02
- Lizenz eigener Beiträge: GNU Free Documentation License
- Wohnort: Schweiz
-
Kontaktdaten:
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Ich war gestern noch sehr beschäftigt und heute war ich vorübergehend ausser Kraft gesetzt, aber ich werde mich noch einmal tiefer in die Materie einarbeiten und kann dann hoffentlich noch etwas dazu beitragen.Meillo hat geschrieben:22.12.2023 16:32:26TRex ist traumatisiert und paedubucher scheint sich entspannt zurueckzulehnen ... Wir stuempern mit unserem Halbwissen rum, dabei ist es bei einer so indirekten/high-level Sprache wie Prolog besonders wichtig, zu *wissen* was man tut und Trial'n'Error kaum hilfreich.
Dazu etwas Hintergrund: Ich habe Prolog etwa vor 5 Jahren im Studium für 3-4 Wochen behandelt und hatte damals seine Funktionsweise recht gut verstanden. Für dieses Türchen wollte ich mich wieder in die Materie einarbeiten und habe es gerade soweit gebracht, dass das Logical eine Lösung ausspuckt, und ich den Text hierzu schrieb. Erst am Abend vor der Veröffentlichung des Beitrags habe ich anhand einer geografischen Karte versucht meine Lösung du verifizieren, bin dann aber erschrocken, dass etwas nicht stimmt. Und da ich auf die Schnelle nicht auf die Lösung kam, habe ich dieses Problem als Übung zum Türchen formuliert.
So tappe ich auch noch im Dämmerlicht, krame aber jetzt einmal meine alten Notizen zur Vorlesung hervor.
Nachtrag: Das Rätselbuch gibt die Lösungen an, so können wir ein paar Sachen schon einmal verifizieren:
- Tjumen (768.358): A ist falsch, PA ist korrekt
- Omsk (1.172.070): B ist korrekt (da gegeben), PB ist falsch
- Novosibirsk (1.612.833): C ist falsch, PC ist falsch
- Krasnojarsk (1.090.811): D ist falsch, PD ist falsch
Nach-Nachtrag: In der swipl-Konsole kann man mit einem Punkt abbrechen und mit einem Semikolon weitere Lösungen anzeigen lassen. Offenbar ist die erste Lösung nicht die einzige.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Meine unelegante Lösung in Python ist dort: 42057. Die Ergebnisse decken sich mit Einwohnerzahlen gemäß Wikipedia. Aber das nur als Referenz. Mit Prolog bin ich noch nicht so weit.
- paedubucher
- Beiträge: 858
- Registriert: 22.02.2009 16:19:02
- Lizenz eigener Beiträge: GNU Free Documentation License
- Wohnort: Schweiz
-
Kontaktdaten:
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Der Kater vom Vorabend und der Nebel, der sich nach fünf Jahre Prolog-Abstinenz vor meinen Augen gebildet hat, lichten sich. Ich habe euch und mich selbst mit dem Prädikat namens has_population/2 wohl etwas an der Nase herumgeführt. Dieses sagt bloss aus, dass das erste Argument eine Stadt und das zweite eine Bevölkrungszahl sein muss. Eine Zuordnung der beiden Variablen findet aber nicht statt.
So kann has_population/2 gebraucht werden, um die ersten paar Regeln etwas kompakter zu formulieren. Statt:
schreibt man:
Das ist eine kleine Vereinfachung. Die Konsequenz daraus ist aber, dass wir die Zuordnungen von Städten zu Bevölkerungen per Regeln ausdrücken müssen, etwa so:
Also überall, wo wir einen Oder-Block mit runden Klammern mit has_population/2-Verwendungen hatten, muss nun der Block umformuliert werden. Die Variablen X und PX im obigen Beispiel matchen auf city(X) und population(PX). Damit sollte sich das Rätsel wohl lösen lassen!
So kann has_population/2 gebraucht werden, um die ersten paar Regeln etwas kompakter zu formulieren. Statt:
Code: Alles auswählen
city(A),
population(PA),
Code: Alles auswählen
has_population(A, PA),
Code: Alles auswählen
A = X, PA = PX;
B = X, PB = PX;
C = X, PC = PX;
D = X, PD = PX
Zuletzt geändert von paedubucher am 23.12.2023 17:56:37, insgesamt 3-mal geändert.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
- paedubucher
- Beiträge: 858
- Registriert: 22.02.2009 16:19:02
- Lizenz eigener Beiträge: GNU Free Documentation License
- Wohnort: Schweiz
-
Kontaktdaten:
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Das ist in ungefähr das, was Prolog im Hinergrund macht
Bei Prolog sieht es bloss eleganter aus
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
- heisenberg
- Beiträge: 3692
- Registriert: 04.06.2015 01:17:27
- Lizenz eigener Beiträge: MIT Lizenz
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Das verstehe ich.paedubucher hat geschrieben:23.12.2023 17:43:43So kann has_population/2 gebraucht werden, um die ersten paar Regeln etwas kompakter zu formulieren. Statt:
schreibt man:Code: Alles auswählen
city(A), population(PA),
Das ist eine kleine Vereinfachung.Code: Alles auswählen
has_population(A, PA),
Das verstehe ich überhaupt nicht. Kannst Du das nochmal anders und mit konkreten Code-Beispielen des vorliegenden Codes erläutern?Die Konsequenz daraus ist aber, dass wir die Zuordnungen von Städten zu Bevölkerungen per Regeln ausdrücken müssen, etwa so:
Also überall, wo wir einen Oder-Block mit runden Klammern mit has_population/2-Verwendungen hatten, muss nun der Block umformuliert werden. Die Variablen X und PX im obigen Beispiel matchen auf city(X) und population(PX). Damit sollte sich das Rätsel wohl lösen lassen!Code: Alles auswählen
A = X, PA = PX; B = X, PB = PX; C = X, PC = PX; D = X, PD = PX
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Ich habe jetzt eine korrekte Lösung in Prolog, bei der ich allerdings has_population und comes_right_after_in zu Fuß mit "Oder" Verknüpfungen erledigt habe. Das sind etwas längere verschachtelte Klammerausdrücke. Die Erklärung bzw der Umbau von has_population ist mir noch nicht klar. Das schaue ich mir noch an. Das temporäre "Machwerk" ist wie das Python Skript 3 Monate verfügbar. Die Prolog Datei ist dort: 42058
- paedubucher
- Beiträge: 858
- Registriert: 22.02.2009 16:19:02
- Lizenz eigener Beiträge: GNU Free Documentation License
- Wohnort: Schweiz
-
Kontaktdaten:
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Folgendes bedeutet:heisenberg hat geschrieben:23.12.2023 19:16:22Das verstehe ich überhaupt nicht. Kannst Du das nochmal anders und mit konkreten Code-Beispielen des vorliegenden Codes erläutern?paedubucher hat geschrieben:23.12.2023 17:43:43Die Konsequenz daraus ist aber, dass wir die Zuordnungen von Städten zu Bevölkerungen per Regeln ausdrücken müssen, etwa so:Also überall, wo wir einen Oder-Block mit runden Klammern mit has_population/2-Verwendungen hatten, muss nun der Block umformuliert werden. Die Variablen X und PX im obigen Beispiel matchen auf city(X) und population(PX). Damit sollte sich das Rätsel wohl lösen lassen!Code: Alles auswählen
A = X, PA = PX; B = X, PB = PX; C = X, PC = PX; D = X, PD = PX
Code: Alles auswählen
has_population(A, PA)
Wenn jetzt X eine gesuchte Stadt mit der Bevölkerung PX ist (siehe Ende der stations/8-Regel), dann muss man A und PA noch auf X und PX matchen, oder B und PB auf X und PX usw. Dieser Und-Zusammenhang hat noch gefehlt.
Edit: Ich löse mal die erste Regel. Die fünfte Regel sollte sich dann mit comes_right_after_in/3 analog dazu lösen lassen.
Code: Alles auswählen
% K wie "Krasnojansk"
population(PK),
PK \= 1612833,
(
PA = PK, A = krasnojarsk;
PB = PK, B = krasnojarsk;
PC = PK, C = krasnojarsk;
PD = PK, D = krasnojarsk
),
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Ist der Code Block für Regel 1 dann äquivalent zu dem Block unten? Das würde ja bedeuten, dass einige Klammern überflüssig sind.
Code: Alles auswählen
% rule 1
(
(
A = krasnnojarsk,
PA \= 1612833
);
(
B = krasnnojarsk,
PB \= 1612833
);
(
C = krasnnojarsk,
PC \= 1612833
);
(
D = krasnnojarsk,
PD \= 1612833
)
- paedubucher
- Beiträge: 858
- Registriert: 22.02.2009 16:19:02
- Lizenz eigener Beiträge: GNU Free Documentation License
- Wohnort: Schweiz
-
Kontaktdaten:
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Ja, da Und stärker bindet als Oder.chrbr hat geschrieben:23.12.2023 20:06:59Ist der Code Block für Regel 1 dann äquivalent zu dem Block unten? Das würde ja bedeuten, dass einige Klammern überflüssig sind.Code: Alles auswählen
% rule 1 ( ( A = krasnnojarsk, PA \= 1612833 ); ( B = krasnnojarsk, PB \= 1612833 ); ( C = krasnnojarsk, PC \= 1612833 ); ( D = krasnnojarsk, PD \= 1612833 )
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
- paedubucher
- Beiträge: 858
- Registriert: 22.02.2009 16:19:02
- Lizenz eigener Beiträge: GNU Free Documentation License
- Wohnort: Schweiz
-
Kontaktdaten:
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Hier ist nun meine funktionierende Lösung: 42060
Ein paar Anmerkungen: mit maplist/2 kann man ein Prädikat auf eine Liste von Variablen anwenden:
Die erste Regel:
Und die fünfte Regel:
Komischerweise wird die gleiche Lösung mehrmals gefunden, d.h. wohl auf verschiedenen Pfaden im Regelbaum. Mithilfe von distinct/1 kann man aber mehrdeutige Lösungen ignorieren:
Nach der erste Lösung habe ich ";" eingetippt, um eine weitere anzeigen zu lassen. Die Antwort darauf lautet "false", da es keine weiteren Lösungen mehr gibt.
Ein paar Anmerkungen: mit maplist/2 kann man ein Prädikat auf eine Liste von Variablen anwenden:
Code: Alles auswählen
maplist(city, [A, B, C, D]),
maplist(population, [PA, PB, PC, PD]),
Code: Alles auswählen
population(PK),
PK \= 1612833,
(
PA = PK, A = krasnojarsk;
PB = PK, B = krasnojarsk;
PC = PK, C = krasnojarsk;
PD = PK, D = krasnojarsk
),
Code: Alles auswählen
comes_right_after_in(X, tjumen, [A, B, C, D]),
(
PA = 1172070, A = X;
PB = 1172070, B = X;
PC = 1172070, C = X;
PD = 1172070, D = X
).
Code: Alles auswählen
$ swipl transsib.pl
?- distinct(stations(A, PA, B, PB, C, PC, D, PD)).
A = tjumen,
PA = 768358,
B = omsk,
PB = 1172070,
C = novosibirsk,
PC = 1612833,
D = krasnojarsk,
PD = 1090811 ;
false.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Da sollte der Fix in unique helfen, den Heisenberg gepostet hat. Ich habe is_set() statt unique verwendet. Damit wird nur eine Lösung gefunden. Das comes_right_after_in(X, tjumen, [A, B, C, D]) muss ich mir auch genauer anschauen und verstehen.paedubucher hat geschrieben:23.12.2023 22:40:47Komischerweise wird die gleiche Lösung mehrmals gefunden, d.h. wohl auf verschiedenen Pfaden im Regelbaum. Mithilfe von distinct/1 kann man aber mehrdeutige Lösungen ignorieren:
Es war wirklich gut, dass das Beispiel nicht auf Anhieb funktioniert hat. Dann hätte ich es vielleicht damit abgetan, dass es wie nicht anders zu erwarten auch mit irgendeiner anderen Sprache funktioniert. So hat es den Buddler geweckt .
- paedubucher
- Beiträge: 858
- Registriert: 22.02.2009 16:19:02
- Lizenz eigener Beiträge: GNU Free Documentation License
- Wohnort: Schweiz
-
Kontaktdaten:
Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
Das is_set/1 kannte ich gar nicht (mehr?), Danke für den Hinweis!chrbr hat geschrieben:23.12.2023 22:58:10Da sollte der Fix in unique helfen, den Heisenberg gepostet hat. Ich habe is_set() statt unique verwendet. Damit wird nur eine Lösung gefunden. Das comes_right_after_in(X, tjumen, [A, B, C, D]) muss ich mir auch genauer anschauen und verstehen.paedubucher hat geschrieben:23.12.2023 22:40:47Komischerweise wird die gleiche Lösung mehrmals gefunden, d.h. wohl auf verschiedenen Pfaden im Regelbaum. Mithilfe von distinct/1 kann man aber mehrdeutige Lösungen ignorieren:
Es war wirklich gut, dass das Beispiel nicht auf Anhieb funktioniert hat. Dann hätte ich es vielleicht damit abgetan, dass es wie nicht anders zu erwarten auch mit irgendeiner anderen Sprache funktioniert. So hat es den Buddler geweckt .
Ja, es lag wirklich an dieser Klausel, dass mehrere Lösungen gefunden worden sind. Aber die Lösung ist noch einfacher:heisenberg hat geschrieben:22.12.2023 21:19:39Inzwischen hat jemand im Prolog-Forum einen Fix für die Unique-Klausel gepostet:
Das funktioniert jetzt mit der Testfunktion auch so wie es soll. Erklärung im verlinkten Forenthread.Code: Alles auswählen
unique([]). unique([_]). unique([H|T]) :- T\=[], \+ contains(T, H), unique(T).
Code: Alles auswählen
unique([]).
unique([H|T]) :-
not(contains(T, H)),
unique(T).
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.