Re: Adventskalender 21. Dezember 2023 - Logische Programmierung
https://user.phil.hhu.de/~petersen/WiSe ... rolog.html
die deutschsprachige Supportwebseite rund um das Debian-Projekt
https://debianforum.de/forum/
Code: Alles auswählen
unique([]).
unique([_]).
unique([H|T]) :- T\=[],
\+ contains(T, H),
unique(T).
Code: Alles auswählen
PA = 768358;
PB = 768358;
PD = 768358
Code: Alles auswählen
PC \= 768358
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)
Code: Alles auswählen
CREATE VIEW city_population AS
SELECT name,count
FROM city, population
WHERE NOT (name="Krasnojarsk" and count = 1612833);
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"
) ;
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
);
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 ;
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;
$$
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
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);
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
);
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.
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
Das ist in ungefähr das, was Prolog im Hinergrund macht
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
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)
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
),
Code: Alles auswählen
% rule 1
(
(
A = krasnnojarsk,
PA \= 1612833
);
(
B = krasnnojarsk,
PB \= 1612833
);
(
C = krasnnojarsk,
PC \= 1612833
);
(
D = krasnnojarsk,
PD \= 1612833
)
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 )
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.
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:
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).