-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLUEMINUT.txt
200 lines (137 loc) · 5.83 KB
/
LUEMINUT.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
Verkoista ja containereista, lyhyesti.
Alkuun pääsee seuraavilla includeilla:
#include "lcelib/Containers.H"
#include "lcelib/Nets.H"
#include "lcelib/Randgens.H"
Hyvin yksinkertainen verkkoimplementaatio, jolla kelpaa aloittaa,
tuntee nimen SymmNet. Se on templaattiluokka, joka syö parametreinaan
särmiin varastoidun datatyypin sekä tarkan implementaation määrittäviä
templaattiluokkia. Seuraavat lienevät tässä vaiheessa käyttökelpoisia:
SymmNet<bool> net(size); // painottamaton
SymmNet<float> net(size); // painotettu
SymmNet<NDEdgeData> net(size); // jos jotakuta vielä kiinnostaa
Verkon koko pitää siis määrittää luotaessa. Muukin on toki
mahdollista: kertokaa sitten, kun tarvitsette tällaisia
ominaisuuksia.
Jos solmuja halutaan arpoa satunnaisesti painottaen degreellä tai
strengthillä, kannattaa seuraavia käyttää:
SymmNet<*, ExplSumTreeTable>
SymmNet<*, ExplSumTreeTable, WeightSumTable>
Ensimmäinen käyttää painona degreetä, jälkimmäinen strengthiä. Tämä on
vain arvaus siitä, mitä käyttäjä tahtoo: jos solmun paino varastoidaan
eksplisiittisesti (jälkimmäinen) kirjasto olettaa, että sitä halutaan
käyttää painona. Kaikki on kuitenkin kustomoitavissa: painot tuotetaan
viime kädessä käyttäjän määrittelemän policy-luokan perusteella. *
korvataan siis halutulla särmäluokalla.
Verkon solmuihin pääsee käsiksi []-operaattorilla, joka syö ihan
tavallisia etumerkittömiä kokonaislukuja. Siis tyyliin:
net[i]
Varsinainen iteraattori on
olemassa, mutta sille ei kiinteän kokoisilla verkoilla liene
tarvetta. Geneeriset algoritmit (dijkstraattorit tms.) käyttävät toki
iteraattoreita, koska haluavat olla riippumattomia verkon
implementaatiosta.
const-referenssin solmuihin saa käyttämällä ()-operaattoria. Tämä voi
olla ajoittain kätevää; kaiken pitäisi kuitenkin yleisesti toimia
tavanomaisillakin referensseillä. const-referenssi on periaattessa
suora referenssi solmun naapurustoa kuvaavaan tietorakenteeseen.
Särmän i->j saa ulos seuraavalla notaatiolla:
net[i][j]
Tälle voi sitten tehdä mitä lystää: =, +=, metodikutsut "->"-
operaattorin kautta tms. on implementoitu. Verkko pidetään
automaagisesti symmetrisenä ja aputietorakenteet valideina. Nollaksi
(tai yleisemmin, default-konstruoituun arvoon) menevät särmät
poistetaan verkosta automaagisesti. Kun sellaisia kysytään, saavat ne
arvon 0 (tai yleisemmin default).
Const-referenssin särmään saa ulos joko tyyliin:
net(i)[j]
tai
net(i,j)
Sekin palauttaa default-arvon, jos särmää ei löydy verkosta.
Särmäiteraattori toimii seuraavasti:
for (NetType::edge_iterator j=net[i].begin(); !j.finished(); ++j) {
edge_destination=*j;
edge_weight=j.value();
j.value()+=1; // jne;
}
"value()" antaa siis ulos referenssin särmän painoon. *-operaattori
palauttaa ainoastaan const-referenssejä: särmän siirto täytyy siis
tehdä "manuaalisesti" kopioimalla särmä ja asettamalla vanha
0:ksi. Tämä lähinnä turvallisuus- ja
yhteensopivuussyistä. Iteraattoritkin pitävät verkon invarianteista
huolen automaagisesti.
NetType korvataan yllä vaikkapa ilmauksella
SymmNet<bool> tms. Kannattanee sanoa koodin alussa esimerkiksi, jotta:
typedef SymmNet<bool> NetType;
niin ei tarvitse toistaa itseään, ja implementaatiota voi vaihtaa
helposti.
Solmu valitaan painotetun satunnaisesti komennolla
node=net.weighedRandSlot(randgen);
Tästä tulee ulos siis numero: itse solmuun saa referenssin []- tai
()-operaattoreilla kuten edellä.
Sivuvaikutusten kanssa kannattaa olla tarkkana. Kun verkkoon lisätään
särmä, vaikuttaa se heti toisen päänsä solmuun, painorakenteisiin
jne.
Containerit.
Eniten tarvitut container-luokat ovat seuraavat. Esitys on jälleen
yksinkertainen: luokista esitetään ainoastaan vakioversiot:
Set<KeyType>
operaatiot:
bool contains(key);
bool put(key) // true, jos oli ennestääm
bool remove(key) // true, jos oli ja voitiin poistaa
size_t size() // montako elementtiä
SetType::iterator begin(), jolle * palauttaa avaimen, ++ ja finished()
kuten edellä, lisäksi remove() joka poistaa
elementin, johon osoitetaan
Map<KeyType, ValueType>
operaatiot:
contains, remove ja size kuten edellä
ValueType & operator[](KeyType key)
eli siis map[key]=value jne. Standardikirjaston esimerkin mukaisesti
palauttaa default-konstruoidun arvon, jos avain ei ollut
läsnä.
Iteraattorista saa vastaavan referenssin kutsulla i.value(), kuten
verkkojenkin tapuksessa.
AutoMap<KeyType, ValueType>
Kuten Map, mutta nollaan menevät arvot poistetaan automaagisesti.
Ranmarin saa käyttöön julistuksella:
RandNumGen<> rands(int seed (optional));
Select-operaatiot syövät suoraan generaattoreita: näin käyttäjän ei
tarvitse kiinnostua siitä, montako satunnaislukua tarvitaan ja missä
muodossa.
Luvun väliltä [0, x[ saa ulos kutsulla
ResultType rands.next(ResultType x);
Palautusarvo on siis samaa tyyppiä kuin syöte. Tämä on yleensä aika
näppärää. (1.0 on muuten flotari, 1 int).
Työn iloa!
Esimerkkejä (testaamattomia):
Solmun i klusterointikerroin:
size_t sum;
// naapurit:
for (NetType::const_edge_iterator j=net(i).begin();
!j.finished();
++j) {
// niiden naapurit. Huomaa, ettei särmää *j->i tarvitse suodattaa pois.
for (NetType::const_edge_iterator k=net(*j).begin();
!k.finished();
++k) {
if (net(*k)[i] != 0) sum++;
}
result=((float) sum)/net(i).size() / ( net(i).size()-1 );
Huomaa: Kannattaa välttää toistuvia jakolaskuja, koska
niistä saattaa syntyä pyöristysvirhettä. Lasketaan mieluummin
summan osamäärä kuin osamäärien summa.
Jos kyseessä on painottamaton verkko, käy if-lauseen sijasta yksinkertaisesti
sum+=net(*k,i);
koska bool konvertoituu automaagisesti arvoihin 1 ja
0. Harjoitustyöksi jätettäköön, miksi tulosta ei jaeta/kerrota
kahdella.
Solmun i naapureiden average-degree:
size_t sum
for (NetType::const_edge_iterator j=net(i).begin();
!j.finished();
++j) {
sum+=net(*j).size();
}
result=((float) sum)/net(i).size();