Commit 1f97991c authored by Max Rapp's avatar Max Rapp

Merge branch 'master' of gl.kwarc.info:teaching/AI

parents f3f4d893 d5d5c12c
Readme
===
AI 1 - 2019/2020
---
* 2019-10-28: `prolog/2019-10-28-tutorial.pl` (simple prolog exercises)
* 2019-10-31 (substition for Katja): `prolog/2019-10-31-tutorial.pl` (simple prolog exercises)
* 2019-11-04: `prolog/2019-11-04-trees.pl` (some simple tree exercises)
* 2019-11-11: `2019-11-11-nary-trees.pl` (tree exercise in preparation for tree-search homework)
% This is the prolog file we created during the tutorial.
%
% Remark: inspired by this problem list: http://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/
% INTRODUCTION
country(germany).
geolocation(X) :- country(X).
bigger(russia, germany).
bigger(germany, belgium).
bigger(A, B) :-
bigger(A, C), bigger(C, B).
% LIST EXERCISES
firstelement([A|_], A).
lastelement([A], A).
lastelement([_|A], B) :-
lastelement(A, B).
secondlast([H,_], H).
secondlast([_|A], B) :-
secondlast(A, B).
second([], []).
second([A], [A]).
second([A,_|B], [A|Restlist]) :-
second(B, Restlist).
prepend(A, B, [A|B]).
duplicate([], []).
duplicate([A], [A,A]).
duplicate([H|T], [H,H|T2]) :-
duplicate(T, T2).
% INSERTION SORT
insert(Element, [], [Element]).
insert(Element, [Hs|Ts], [Element,Hs|Ts]):-
Element =< Hs.
insert(Element, [Hs|Ts], [Hs|Tl]) :-
Element >= Hs,
insert(Element, Ts, Tl).
inssort([], []).
inssort([H|T], Result) :-
inssort(T, X),
insert(H, X, Result).
% INTRODUCTION
animal(elephant).
bigger(elephant, bird).
bigger(elephant, cow).
bigger(cow, mouse).
bigger(X, Y) :-
bigger(X, A), bigger(A, Y).
% Note: The above definition for a transitive relation
% results in loop, which wasn't resolved during the tutorial.
% If you want to know more about it, take a look at this answer:
% https://stackoverflow.com/a/28615704
% SIMPLE LIST TASKS
% inspired from http://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/
getfirst([X|_], X).
getlast([X], X).
getlast([_|R], X) :-
getlast(R, X).
getsecondlast([X,_], X).
getsecondlast([_|R], X) :-
getsecondlast(R, X).
getlength([], 0).
getlength([X|R], L) :-
getlength(R, N), L is N+1.
second([], []).
second([X], [X]).
second([X,Y|R], [X|S]) :-
second(R, S).
fourth(X, Y) :-
second(X, Z), second(Z, Y).
prepend(X,SomeList,[X|SomeList]).
duplicate([], []).
duplicate([X|R], [X,X|S]) :-
duplicate(R, S).
% INSERTION SORT
insert(X, [], [X]).
insert(X, [H|R], [H|S]) :-
X >= H, insert(X, R, S).
insert(X, [H|R], [X,H|R]) :-
X =< H.
inssort([], []).
inssort([H|T], L) :-
inssort(T, TSorted),
write('inserting '),
write(H),
write('\n'),
insert(H, TSorted, L).
% Check that a tree is indeed a binary tree
% (as specified in the homework)
isbinary(nil).
isbinary(tree(N, X, Y)) :-
integer(N),
isbinary(X),
isbinary(Y).
% Helper predicate: get the maximum of two integers
% e.g max(2,7,X) results in X=7.
%
% ! is the cut operator.
% It tells prolog not to backtrack anymore.
% In this case, we want to ignore the second case,
% if the first case is applicable.
max(X,Y,X) :- X >= Y, !.
max(_,Y,Y).
% Get the largest node in a tree
% (assuming it only contains natural numbers)
treemax(nil, 0).
treemax(tree(N, X, Y), Result) :-
treemax(X, XRes),
treemax(Y, YRes),
max(XRes, YRes, XYRes),
max(XYRes, N, Result).
% Get the depth of a tree
treedepth(nil, 0).
treedepth(tree(_, X, Y), Depth) :-
treedepth(X, XDepth),
treedepth(Y, YDepth),
max(XDepth, YDepth, D),
Depth is D + 1.
% helper predicate: concatenate two lists
concatenate([], L, L).
concatenate([H|T], L, [H|TL]) :-
concatenate(T, L, TL).
% get the leaves of a binary tree
leaves(nil, []).
leaves(tree(N, nil, nil), [N]) :- !.
leaves(tree(N, X, Y), Result) :-
leaves(X, XL),
leaves(Y, YL),
concatenate(XL, YL, Result).
% compute the result of a formula (which you can think of as a tree).
% Example tree: plus(times(2,6), 7)
compute(SomeInt, SomeInt) :-
integer(SomeInt).
compute(times(X, Y), R) :-
compute(X, XRes),
compute(Y, YRes),
R is XRes * YRes.
compute(plus(X, Y), R) :-
compute(X, XRes),
compute(Y, YRes),
R is XRes + YRes.
% The tree definition from the homework assignment.
istree(tree(Value,Children)) :-
string(Value),subtrees(Children).
subtrees([]).
subtrees([(Cost,T)|Rest]) :-
number(Cost),istree(T), subtrees(Rest).
% An example tree.
% If you want to call e.g. addweights with this tree, you can do it with the following trick:
% tree1(X), addweights(X, Sum).
tree1(tree("A", [(2, tree("B", [(1, tree("E", [])), (2, tree("F", []))])),
(5, tree("C", [(2, tree("G", []))])),
(2, tree("D", [(1, tree("X", [(1, tree("Y", []))]))]))])).
% Add up all the weights of the edges in the tree.
% (we called it cw in the tutorial)
addweights(tree(_, []), 0).
addweights(tree(_, [(X, T)|Rest]), S) :-
addweights(T, S1),
addweights(tree("asdf", Rest), S2),
S is X + S1 + S2.
% Also adds up all the weights, but in a different way:
% In the previous attempt, we always expected a tree as argument and constructed trees on demand.
% In this approach we'll take a list of (Cost, Tree) pairs instead.
% This is not as pretty, but a useful approach for some tree search algorithms.
addweights2([], 0).
addweights2([(X, tree(_, Children))|Rest], S) :-
addweights2(Rest, S1),
addweights2(Children, S2),
S is S1 + S2 + X.
addweights2(T, S) :-
istree(T),
addweights2([(0, T)], S).
peter.
%?- peter.
likes(peter, mary).
likes(peter, sophie).
cool(X) :- likes(peter,X).
%?- trace, cool(sophie).
%?- trace, cool(X).
has_wheels(mybike, 2).
has_wheels(mytricycle, 3).
has_wheels(mytoycar, 4).
has_wheels(mycar, 4).
has_motor(mybike).
has_motor(mycar).
car(X) :- has_wheels(X, 4), has_motor(X).
%?- trace, car(Y).
% Cool cool cool, but how can we code with this?
% The answers is for the most part...RECURSION!
nat(zero).
nat(s(X)) :- nat(X).
% add(X, Y, Z) -> X + Y = Z
add(X, zero, X).
add(X, s(Y), s(Z)) :- add(X, Y, Z).
% We see, there is no "return" in Prolog, only predicates.
% For every predicate please state in a comment which parameters
% are input and which are output.
%% List comprehension:
% list e.g. [1,2,3] or [jamie,cersei], empty list = []
% pattern matching with lists:
% [Head|Tail], where Head is an element and Tail is a List!
% Also works with first 2 elements [X1, X2 | T]
append([],L2,L2).
append([H|T],L2,[H|Res]):-
append(T,L2,Res).
% A practical example
% Signature for our problem:
% countN(N : int, L : List[int]) -> int
% counts the occurrences of N in L and returns the result.
% With Prolog-like lists: countN(N, [H | T]) -> int
% L = [2, 3, 5, 2, 7, 1, 2, 2, 5, 9]
% countN(3, L) -> 1
% countN(2, L) -> 4
% countN(8, L) -> 0
% countN(5, L) -> 2
% Delcarative Approach
% countN(N, L) -> res
% res = 0
% for e in L:
% if e == N:
% res += 1
% return res
% Functional / Recursive Approach
% Base Cases:
% countN(N, []) -> return 0
% Recursive Case:
% countN(N, [H | T]) ->
% if N == H
% return countN(N, [T]) + 1
% else
% return countN(N, [T])
% ... in prolog we can't "return", so we need another variable in the predicate
% countN(N, L, RES) the number of occurrences of N in list L
% will be "returned/safed" in RES (Will be in relation with RES)
% Base Cases:
countN(_, [], 0).
%?- trace, countN(2, [], X).
% Recursive Case:
countN(N, [N | T], RES) :- countN(N, T, OLDRES), RES is OLDRES + 1.
countN(N, [M | T], RES) :- not(N=M), countN(N, T, RES).
% Point out: "N" in first line list compr. "is" can be very useful
%?- trace, countN(2, [2], X).
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment