Skip to content

Commit 98aeb9c

Browse files
committed
week3 materjalid
1 parent 3f7ac80 commit 98aeb9c

37 files changed

Lines changed: 2690 additions & 0 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ gen
1414
*.dot
1515
*.swp
1616
*.class
17+
18+
# week3
19+
graphs

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ repositories {
1616
}
1717

1818
dependencies {
19+
// week3
20+
implementation 'com.google.guava:guava:33.5.0-jre'
21+
implementation 'guru.nidi:graphviz-java-all-j2v8:0.18.1'
22+
implementation 'ch.qos.logback:logback-classic:1.5.32'
23+
1924
// initial
2025
testImplementation 'junit:junit:4.13.2'
2126
// week2
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package week3;
2+
3+
import java.io.IOException;
4+
import java.nio.file.Path;
5+
import java.util.Set;
6+
7+
/**
8+
* Abstraktne klass FiniteAutomaton implementeerimiseks.
9+
* Võimaldab automaadi joonistamist.
10+
*/
11+
public abstract class AbstractAutomaton {
12+
/**
13+
* Selle meetodiga annab automaadi koostaja teada, millised olekud automaadis
14+
* esinevad.
15+
*/
16+
public abstract void addState(int state);
17+
18+
/**
19+
* Kasulik abimeetod Grep kodutööks, mis loob uue seisundi ja tagastab selle ID.
20+
*/
21+
public int addState() {
22+
Set<Integer> states = getStates();
23+
for (int i = 0; i < Integer.MAX_VALUE; i++) {
24+
if (!states.contains(i)) {
25+
addState(i);
26+
return i;
27+
}
28+
}
29+
throw new RuntimeException("Too many states");
30+
}
31+
32+
/**
33+
* Selle meetodiga määratakse algolek. Võib eeldada, et eelnevalt on see olek
34+
* automaati lisatud.
35+
*/
36+
public abstract void setStartState(int state);
37+
38+
/**
39+
* Selle meetodiga märgitakse olek lõppolekuks.
40+
*/
41+
public abstract void addAcceptingState(int state);
42+
43+
/**
44+
* Selle meetodiga lisatakse uus üleminek. Epsilon-ülemineku korral on label==null.
45+
* Võib eeldada, et olekud fromState ja toState on juba eelnevalt lisatud.
46+
*/
47+
public abstract void addTransition(int fromState, Character label, int toState);
48+
49+
/**
50+
* Tagastab kõigi lisatud olekute hulga.
51+
*/
52+
public abstract Set<Integer> getStates();
53+
54+
/**
55+
* Tagastab algoleku.
56+
*/
57+
public abstract Integer getStartState();
58+
59+
/**
60+
* Tagastab lõppolekud.
61+
*/
62+
public abstract Set<Integer> getAcceptingStates();
63+
64+
/**
65+
* Tagastab, millised üleminekud antud olekust väljuvad.
66+
*/
67+
public abstract Set<Character> getOutgoingLabels(int state);
68+
69+
/**
70+
* Tagastab, millistesse olekutesse antud olekust antud sümboliga saab.
71+
*/
72+
public abstract Set<Integer> getDestinations(int state, Character label);
73+
74+
/**
75+
* See meetod peab ütlema, kas automaat tunneb ära näidatud sisendi.
76+
*/
77+
public abstract boolean accepts(String input);
78+
79+
public void renderPngFile(Path path) throws IOException {
80+
AbstractAutomatonVisualizer.renderPngFile(this, path);
81+
}
82+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package week3;
2+
3+
import guru.nidi.graphviz.attribute.Label;
4+
import guru.nidi.graphviz.attribute.Rank;
5+
import guru.nidi.graphviz.attribute.Rank.RankDir;
6+
import guru.nidi.graphviz.attribute.Shape;
7+
import guru.nidi.graphviz.engine.Format;
8+
import guru.nidi.graphviz.engine.Graphviz;
9+
import guru.nidi.graphviz.model.Graph;
10+
import guru.nidi.graphviz.model.Link;
11+
import guru.nidi.graphviz.model.Node;
12+
13+
import java.io.IOException;
14+
import java.nio.file.Path;
15+
import java.util.List;
16+
17+
import static guru.nidi.graphviz.attribute.Attributes.attr;
18+
import static guru.nidi.graphviz.model.Factory.*;
19+
20+
public class AbstractAutomatonVisualizer {
21+
22+
private final AbstractAutomaton automaton;
23+
24+
public AbstractAutomatonVisualizer(AbstractAutomaton automaton) {
25+
this.automaton = automaton;
26+
}
27+
28+
private Node makeNode(Integer state) {
29+
return node(Integer.toString(state));
30+
}
31+
32+
private Shape getStateShape(Integer state) {
33+
return automaton.getAcceptingStates().contains(state) ? Shape.DOUBLE_CIRCLE : Shape.CIRCLE;
34+
}
35+
36+
private Label getLabelLabel(Character label) {
37+
if (label != null && label == 'ε') return Label.of("RTFM!");
38+
return Label.of(Character.toString(label == null ? 'ε' : label));
39+
}
40+
41+
private List<Link> getStateLinks(Integer state) {
42+
return automaton.getOutgoingLabels(state).stream()
43+
.flatMap(label ->
44+
automaton.getDestinations(state, label).stream()
45+
.map(toState ->
46+
to(makeNode(toState))
47+
.with(getLabelLabel(label))
48+
)
49+
)
50+
.toList();
51+
}
52+
53+
private Graph getGraph() {
54+
List<Node> stateNodes = automaton.getStates().stream()
55+
.map(state ->
56+
makeNode(state)
57+
.with(getStateShape(state))
58+
.link(getStateLinks(state))
59+
)
60+
.toList();
61+
62+
Node nullNode = node("null")
63+
.with(Label.of(""), Shape.NONE, attr("width", 0), attr("height", 0))
64+
.link(to(makeNode(automaton.getStartState())));
65+
66+
return graph("automaton")
67+
.directed()
68+
.with(stateNodes)
69+
.with(nullNode)
70+
.graphAttr()
71+
.with(Rank.dir(RankDir.LEFT_TO_RIGHT));
72+
}
73+
74+
public static void renderPngFile(AbstractAutomaton automaton, Path path) throws IOException {
75+
Graph graph = new AbstractAutomatonVisualizer(automaton).getGraph();
76+
//System.out.println(Graphviz.fromGraph(graph).render(Format.DOT).toString());
77+
Graphviz.fromGraph(graph).scale(2).render(Format.PNG).toFile(path.toFile().getCanonicalFile());
78+
}
79+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package week3;
2+
3+
import java.io.IOException;
4+
import java.nio.file.Paths;
5+
import java.util.*;
6+
7+
public class FiniteAutomaton extends AbstractAutomaton {
8+
9+
@Override
10+
public void addState(int state) {
11+
throw new UnsupportedOperationException();
12+
}
13+
14+
@Override
15+
public void setStartState(int state) {
16+
throw new UnsupportedOperationException();
17+
}
18+
19+
@Override
20+
public void addAcceptingState(int state) {
21+
throw new UnsupportedOperationException();
22+
}
23+
24+
@Override
25+
public void addTransition(int fromState, Character label, int toState) {
26+
throw new UnsupportedOperationException();
27+
}
28+
29+
@Override
30+
public Set<Integer> getStates() {
31+
throw new UnsupportedOperationException();
32+
}
33+
34+
@Override
35+
public Integer getStartState() {
36+
throw new UnsupportedOperationException();
37+
}
38+
39+
@Override
40+
public Set<Integer> getAcceptingStates() {
41+
throw new UnsupportedOperationException();
42+
}
43+
44+
@Override
45+
public Set<Character> getOutgoingLabels(int state) {
46+
throw new UnsupportedOperationException();
47+
}
48+
49+
@Override
50+
public Set<Integer> getDestinations(int state, Character label) {
51+
throw new UnsupportedOperationException();
52+
}
53+
54+
@Override
55+
public boolean accepts(String input) {
56+
throw new UnsupportedOperationException();
57+
}
58+
59+
/**
60+
* Seda meetodit ei hinnata ja seda ei pea muutma, aga läbikukkunud testide korral
61+
* antakse sulle automaadi kirjelduseks just selle meetodi tagastusväärtus.
62+
*/
63+
@Override
64+
public String toString() {
65+
return super.toString();
66+
}
67+
68+
static void main() throws IOException {
69+
FiniteAutomaton fa = new FiniteAutomaton();
70+
71+
fa.addState(0);
72+
fa.addState(1);
73+
fa.addState(2);
74+
75+
fa.addTransition(0, 'b', 0);
76+
fa.addTransition(0, 'c', 2);
77+
fa.addTransition(2, 'a', 1);
78+
fa.addTransition(1, 'd', 0);
79+
fa.addTransition(0, null, 1);
80+
81+
fa.setStartState(0);
82+
fa.addAcceptingState(1);
83+
84+
System.out.println(fa.accepts("cadbbbca")); // true
85+
System.out.println(fa.accepts("abc")); // false
86+
System.out.println(fa.accepts("")); // true
87+
88+
// Pead ise veenduda, et toString töötab...
89+
System.out.println(fa);
90+
fa.renderPngFile(Paths.get("graphs", "auto.png"));
91+
}
92+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package week3.buildingblocks;
2+
3+
import com.google.common.collect.HashMultimap;
4+
import com.google.common.collect.Multimap;
5+
6+
import java.util.HashMap;
7+
import java.util.HashSet;
8+
import java.util.Map;
9+
import java.util.Set;
10+
11+
public record Person(String name, int age) {
12+
13+
public static Map<String, Integer> makeAgeMap(Set<Person> people) {
14+
Map<String, Integer> map = new HashMap<>();
15+
// Lisada kõik inimesed siia map'ile, et nende nimele vastaks nende vanus.
16+
return map;
17+
}
18+
19+
public static Map<String, Set<Integer>> makeAgeMultimap(Set<Person> people) {
20+
Map<String, Set<Integer>> map = new HashMap<>();
21+
// Sama asi on nüüd vaja teha. Kui on aga mitut sama nimega inimest erinevate vanustega,
22+
// siis tahame koguda kõik vastavad vanused hulka, näiteks sisendi
23+
// { (Anna, 13), (Jüri, 10), (Anna, 15) }
24+
// ootame tulemusena
25+
// { Anna -> {13,15}, Jüri -> {10} }
26+
// Peamine tüütus on siin see, et neid hulkasid peab ise looma!
27+
return map;
28+
}
29+
30+
public static Multimap<String, Integer> makeAgeGuavaMultimap(Set<Person> people) {
31+
Multimap<String, Integer> map = HashMultimap.create();
32+
// Mmm vihje: saad copy-paste'iga lahendada!
33+
return map;
34+
}
35+
36+
37+
static void main() {
38+
39+
// Esimeses klassis on kõik hästi...
40+
Set<Person> esimeneKlass = new HashSet<>();
41+
esimeneKlass.add(new Person("Mari", 9));
42+
esimeneKlass.add(new Person("Juhan", 8));
43+
System.out.println(makeAgeMap(esimeneKlass));
44+
45+
// Aga siin on kaks sama nimega inimest ja tahaks, et jääks mõlemad vanused meelde:
46+
Set<Person> teineKlass = new HashSet<>();
47+
teineKlass.add(new Person("Mari", 18));
48+
teineKlass.add(new Person("Juhan", 12));
49+
teineKlass.add(new Person("Mari", 19));
50+
51+
System.out.println(makeAgeMap(teineKlass));
52+
System.out.println(makeAgeMultimap(teineKlass));
53+
System.out.println(makeAgeGuavaMultimap(teineKlass));
54+
55+
}
56+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package week3.buildingblocks;
2+
3+
import java.util.*;
4+
5+
public record Transition(int source, String label, int target) {
6+
7+
public static Map<Integer, Map<String, Integer>> makeTransitionMap(Set<Transition> transitions) {
8+
Map<Integer, Map<String, Integer>> map = new HashMap<>();
9+
// Siin on peamine mure, et mapi sees on omakorda vaja neid mapikesed luua!
10+
return map;
11+
}
12+
13+
static void main() {
14+
Set<Transition> transitions = new HashSet<>();
15+
transitions.add(new Transition(1, "a", 2));
16+
transitions.add(new Transition(1, "b", 3));
17+
transitions.add(new Transition(2, "c", 3));
18+
System.out.println(makeTransitionMap(transitions)); // {1={a=2, b=3}, 2={c=3}}
19+
}
20+
21+
@Override
22+
public String toString() {
23+
return "(%d,%s,%d)".formatted(source, label, target);
24+
}
25+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package week3.buildingblocks;
2+
3+
import java.util.HashSet;
4+
import java.util.Set;
5+
6+
public class TransitionUtils {
7+
8+
public static Set<Transition> compose(Set<Transition> rel1, Set<Transition> rel2) {
9+
Set<Transition> result = new HashSet<>();
10+
for (Transition t1 : rel1) {
11+
for (Transition t2 : rel2) {
12+
if (t1.target() == t2.source()) {
13+
String label = t1.label() + t2.label();
14+
result.add(new Transition(t1.source(), label, t2.target()));
15+
}
16+
}
17+
}
18+
return result;
19+
}
20+
21+
// Arvutame nüüd transitiivse sulundi relatsiooni astendamise teel:
22+
public static Set<Transition> transitiveClosure(Set<Transition> rel) {
23+
Set<Transition> closure = new HashSet<>();
24+
Set<Transition> relPowers = new HashSet<>(rel);
25+
// Peab lisama sulundite hulka kõik uued üleminekud, kuni asi enam ei muutu.
26+
// Vaja arvutada R^i = compose(R^{i-1},R) ehk tsüklis astendamist korrata:
27+
return closure;
28+
}
29+
30+
static void main() {
31+
Set<Transition> rel = new HashSet<>();
32+
rel.add(new Transition(0, "a", 1));
33+
rel.add(new Transition(1, "b", 2));
34+
rel.add(new Transition(1, "c", 3));
35+
System.out.println(transitiveClosure(rel)); // [(0,a,1), (0,ab,2), (0,ac,3), (1,b,2), (1,c,3)]
36+
}
37+
}

0 commit comments

Comments
 (0)