1 { Version 050625. Copyright © Alexey A.Chernobaev, 1996-2005 }
2
3 unit Graphs;
4 {
5 Объектно-ориентированная библиотека для работы с атрибутированными графами.
6
7 Object-oriented library for processing graphs with attributes.
8 }
9
10 interface
11
12 {$I VCheck.inc}
13
14 uses
15 SysUtils, ExtType, ExtSys, Vectors, AttrType, AttrMap, AttrSet, Aliasv, Aliasm,
16 Boolv, Boolm, Int8v, Int16v, Int16g, Int16m, UInt16v, Int32v, Int64v, F32v, F64v,
17 F80v, F32m, F64m, F80m, Pointerv, MultiLst, IStack, PStack, PQueue, F_PQueue,
18 VStream, VectErr, AttrErr, GraphErr;
19
20 type
21 TGraphObjectState = (gsDestroying, gsValidConnected, gsValidSeparates,
22 gsValidRingEdges);
23 { gsDestroying: объект находится в состоянии уничтожения (выполняется его
24 метод Destroy);
25 gsValidConnected: информация о связности (TGraph.FConnected) верна
26 (состояние определено только для графов);
27 gsValidSeparates: информация о компонентах связности (TVertex.SeparateIndex
28 и TGraph.SeparateCount) верна (состояние определено только для графов);
29 gsValidRingEdges: информация о типа ребра (кольцевое / ациклическое) верна;
30 (определено только для графов; имеет смысл только при gsValidConnected) }
31
32 TGraphObjectStates = set of TGraphObjectState;
33
34 TTempVar = packed record
35 case Byte of
36 0: (AsPtrInt: PtrInt);
37 1: (AsPointer: Pointer);
38 end;
39
40 TGraph = class;
41
42 TGraphObject = class(TAttrSet)
43 protected
44 FIndex: Integer;
45 FStates: TGraphObjectStates;
46 FTemp: TTempVar; { используется различными алгоритмами }
47 public
48 procedure WriteToStream(VStream: TVStream); override;
49 procedure ReadFromStream(VStream: TVStream); override;
50 procedure Assign(Source: TVector); override;
51
52 property Temp: TTempVar read FTemp;
53 end;
54
55 TGraphElement = class(TGraphObject)
56 protected
57 FLocal: TAutoAttrSet;
58 FGraph: TGraph;
59 public
60 destructor Destroy; override;
61
Comparenull62 class function Compare(Element1, Element2: Pointer): Integer;
63 { сравнивает глобальные атрибуты элементов графа, и, если глобальные
64 атрибуты равны, сравнивает локальные атрибуты (атрибуты, начинающиеся
65 с символов, меньших либо равных '.', не участвуют в сравнении) }
66
67 procedure WriteToStream(VStream: TVStream); override;
68 procedure ReadFromStream(VStream: TVStream); override;
69 procedure Assign(Source: TVector); override;
70 procedure Pack; override;
71
HasLocalnull72 function HasLocal: Bool;
Localnull73 function Local: TAttrSet;
74 { набор локальных атрибутов элемента }
75
76 property Graph: TGraph read FGraph;
77 { граф, которому принадлежит данный элемент }
78 end;
79
80 TEdge = class;
81 TVertex = class;
82
83 TVertex = class(TGraphElement)
84 protected
85 NeighbEdges: TClassList;
GetNeighbournull86 function GetNeighbour(I: Integer): TVertex;
GetIncidentEdgenull87 function GetIncidentEdge(I: Integer): TEdge; {$IFDEF V_INLINE}inline;{$ENDIF}
88
89 { *** орграфы (directed graphs) }
90
GetInNeighbournull91 function GetInNeighbour(I: Integer): TVertex;
GetOutNeighbournull92 function GetOutNeighbour(I: Integer): TVertex;
GetInArcnull93 function GetInArc(I: Integer): TEdge;
GetOutArcnull94 function GetOutArc(I: Integer): TEdge;
95
96 { *** деревья }
97
GetParentnull98 function GetParent: TVertex;
99 procedure SafeSetParent(Value: TVertex);
100 procedure SetParent(Value: TVertex);
GetChildnull101 function GetChild(I: Integer): TVertex;
GetIsRootnull102 function GetIsRoot: Bool;
103 procedure SetIsRoot(Value: Bool);
104
105 { *** транспортные сети }
106
GetIsSourcenull107 function GetIsSource: Bool;
108 procedure SetIsSource(Value: Bool);
GetIsSinknull109 function GetIsSink: Bool;
110 procedure SetIsSink(Value: Bool);
111
112 { *** геометрические графы }
113
GetXnull114 function GetX: Float; {$IFDEF V_INLINE}inline;{$ENDIF}
115 procedure SetX(Value: Float); {$IFDEF V_INLINE}inline;{$ENDIF}
GetYnull116 function GetY: Float; {$IFDEF V_INLINE}inline;{$ENDIF}
117 procedure SetY(Value: Float); {$IFDEF V_INLINE}inline;{$ENDIF}
GetZnull118 function GetZ: Float; {$IFDEF V_INLINE}inline;{$ENDIF}
119 procedure SetZ(Value: Float); {$IFDEF V_INLINE}inline;{$ENDIF}
120 public
121 constructor Create(AGraph: TGraph);
122 destructor Destroy; override;
123 procedure Pack; override;
124
125 property Index: Integer read FIndex;
126 { номер вершины среди вершин графа (0..Graph.VertexCount-1) }
127 {$IFDEF V_ALLOW_DEPRECATE}
128 property IndexInGraph: Integer read FIndex; { устарело! }
129 {$ENDIF}
Degreenull130 function Degree: Integer; {$IFDEF V_INLINE}inline;{$ENDIF}
131 { степень вершины графа }
132 property Neighbour[I: Integer]: TVertex read GetNeighbour;
133 { соседние для данной вершины графа [0..Degree-1] }
134 property IncidentVertex[I: Integer]: TVertex read GetNeighbour;
135 { синоним Neighbour }
136 {$IFDEF V_ALLOW_DEPRECATE}
137 property Neighbours[I: Integer]: TVertex read GetNeighbour; { устарело! }
138 property IncidentVertices[I: Integer]: TVertex read GetNeighbour; { устарело! }
139 {$ENDIF}
140 property IncidentEdge[I: Integer]: TEdge read GetIncidentEdge;
141 { инцидентные (соседние) для данной вершины ребра [0..Degree-1] }
SeparateIndexnull142 function SeparateIndex: Integer;
143 { номер компоненты связности, которой принадлежит вершина
144 (0..Graph.SeparateCount-1) }
RingVertexnull145 function RingVertex: Bool;
146 { является ли вершина кольцевой, т.е. этой вершине инцидентно хотя бы одно
147 кольцевое ребро (включая петли) }
148 procedure SortIncidentEdges(CompareEdges: TCompareFunc);
149 { упорядочивает инцидентные ребра графа по возрастанию согласно CompareEdges }
150 procedure SortIncidentEdgesByObject(CompareEdges: TCompareEvent);
151 { упорядочивает инцидентные ребра графа по возрастанию согласно CompareEdges }
152 property TimeMark: PtrInt read FTemp.AsPtrInt;
153 { временн'ая метка вершины; значение определено только непосредственно после
154 вызова метода DFSFromVertex или методов семейства BFSFromVertexXXXX;
155 другие методы могут изменить это значение произвольным образом }
156
157 { *** орграфы }
158
InDegreenull159 function InDegree: Integer;
160 { полустепень захода вершины (количество входящих в вершину дуг) }
OutDegreenull161 function OutDegree: Integer;
162 { полустепень исхода вершины (количество исходящих из вершины дуг) }
163 procedure GetInOutDegree(var VertexInDegree, VertexOutDegree: Integer);
164 { возвращает сразу InDegree и OutDegree }
165 property OutNeighbour[I: Integer]: TVertex read GetOutNeighbour;
166 { вершины графа, в которые из данной вершины исходят дуги [0..OutDegree-1] }
167 property InNeighbour[I: Integer]: TVertex read GetInNeighbour;
168 { вершины графа, из которых в данную вершину входят дуги [0..InDegree-1] }
169 property OutArc[I: Integer]: TEdge read GetOutArc;
170 { исходящие из вершины дуги [0..OutDegree-1] }
171 property InArc[I: Integer]: TEdge read GetInArc;
172 { входящие в вершину дуги [0..InDegree-1] }
173
174 { *** деревья }
175
AddChildnull176 function AddChild: TVertex;
177 { добавляет вершину-потомка }
178 property Parent: TVertex read GetParent write SetParent;
179 { вершина, родительская для данной (nil для корня или изолир. вершины) -
180 всегда совпадает с Neighbour[0], поэтому после изменения Parent индексы
181 соседей могут измениться; кроме того, если вершина не была изолированной,
182 то при изменении Parent связь со старым родителем уничтожается }
ChildCountnull183 function ChildCount: Integer;
184 { возвращает количество потомков; для листьев 0, для изолированных вершин -1 }
185 property Childs[I: Integer]: TVertex read GetChild;
186 { потомки вершины [0..ChildCount-1] }
187 property IsRoot: Bool read GetIsRoot write SetIsRoot;
188 { равняется True, если данная вершина является корнем дерева, иначе - False }
IsAncestorOfnull189 function IsAncestorOf(V: TVertex): Bool;
190 { возвращает True, если данная вершина совпадает с V или является предком
191 вершины V }
192 procedure SortChilds(CompareVertices: TCompareEvent);
193 { упорядочить вершины-потомки в соответствии с CompareVertices }
194
195 { *** транспортные сети }
196
197 property IsNetworkSource: Bool read GetIsSource write SetIsSource;
198 { вершина является истоком }
199 property IsNetworkSink: Bool read GetIsSink write SetIsSink;
200 { вершина является стоком }
201
202 { *** геометрические графы }
203
204 property X: Float read GetX write SetX;
205 { X-координата }
206 property Y: Float read GetY write SetY;
207 { Y-координата }
208 property Z: Float read GetZ write SetZ;
209 { Z-координата }
210 end;
211
212 TEdge = class(TGraphElement)
213 protected
214 FV1, FV2: TVertex;
215 { концы ребра }
RemoveFromNeighbEdgesnull216 function RemoveFromNeighbEdges(V: TVertex): Integer;
217 { используется при удалении / скрытии ребра }
Hiddennull218 function Hidden: Bool;
219 { проверяет, является ли ребро "скрытым" }
220
221 { *** транспортные сети }
222
GetMaxFlownull223 function GetMaxFlow: Float;
224 procedure SetMaxFlow(Value: Float);
GetFlownull225 function GetFlow: Float;
226 procedure SetFlow(Value: Float);
227
228 { *** взвешенные графы (weighted graphs) }
229
GetWeightnull230 function GetWeight: Float; {$IFDEF V_INLINE}inline;{$ENDIF}
231 procedure SetWeight(Value: Float); {$IFDEF V_INLINE}inline;{$ENDIF}
232 public
233 constructor Create(AGraph: TGraph; FromVertex, ToVertex: TVertex);
234 destructor Destroy; override;
235
236 property Index: Integer read FIndex;
237 { номер ребра среди ребер графа (0..Graph.EdgeCount-1) }
238 {$IFDEF V_ALLOW_DEPRECATE}
239 property IndexInGraph: Integer read FIndex; { устарело! }
240 {$ENDIF}
241 property V1: TVertex read FV1;
242 { первый конец ребра (начало дуги в орграфе) }
243 property V2: TVertex read FV2;
244 { второй конец ребра (конец дуги в орграфе) }
EdgeVerticesnull245 function EdgeVertices(Vertex1, Vertex2: TVertex): Bool;
246 { проверяет, являются ли вершины Vertex1 и Vertex2 концами ребра }
IncidentToVertexnull247 function IncidentToVertex(Vertex: TVertex): Bool;
248 { проверяет, инцидентна ли вершина Vertex ребру (т.е. является ли она
249 одним из концов ребра) }
IncidentToEdgeUndirectednull250 function IncidentToEdgeUndirected(Edge: TEdge): Bool;
251 { проверяет, инцидентны ли ребра Self и Edge; граф всегда, независимо от
252 Features, интерпретируется как неориентированный, т.е. True возвращается,
253 если один из концов ребра Self совпадает с одним из концов ребра Edge }
IncidentToEdgeDirectednull254 function IncidentToEdgeDirected(Edge: TEdge): Bool;
255 { проверяет, инцидентны ли ребра Self и Edge; граф всегда, независимо от
256 Features, интерпретируется как ориентированный, т.е. True возвращается,
257 если конец одного из ребер совпадает с началом другого }
IncidentToEdgenull258 function IncidentToEdge(Edge: TEdge): Bool;
259 { проверяет, инцидентны ли ребра Self и Edge; граф интерпретируется
260 как неориентированный или ориентированный в зависимости от Features }
ParallelToEdgeUndirectednull261 function ParallelToEdgeUndirected(Edge: TEdge): Bool;
262 { проверяет, являются ли ребра Self и Edge параллельными; граф всегда,
263 независимо от Features, интерпретируется как неориентированный, т.е.
264 ребра считаются параллельными, если они инцидентны одной и той же
265 неупорядоченной паре вершин }
ParallelToEdgeDirectednull266 function ParallelToEdgeDirected(Edge: TEdge): Bool;
267 { проверяет, являются ли ребра Self и Edge параллельными; граф всегда,
268 независимо от Features, интерпретируется как ориентированный, т.е.
269 ребра считаются параллельными, если они инцидентны одной и той же
270 упорядоченной паре вершин }
ParallelToEdgenull271 function ParallelToEdge(Edge: TEdge): Bool;
272 { проверяет, являются ли ребра Self и Edge параллельными; граф интерпретируется
273 как неориентированный или ориентированный в зависимости от Features }
OtherVertexnull274 function OtherVertex(Vertex: TVertex): TVertex;
275 { если Vertex является одним из концов ребра, то возвращает другой его конец,
276 иначе - nil }
IsLoopnull277 function IsLoop: Bool;
278 { является ли ребро петлей }
RingEdgenull279 function RingEdge: Bool;
280 { является ли ребро кольцевым, т.е. существует ли маршрут (путь в случае
281 орграфа) из V1 в V2, не проходящий через это ребро (дугу); связность
282 графа не требуется; петли считаются кольцевыми ребрами }
283 procedure Hide;
284 { "скрыть" (временно удалить) ребро; изменяет поле Temp; "скрытые" ребра
285 не уничтожаются при уничтожении графа, поэтому их необходимо
286 восстанавливать либо уничтожать вручную перед уничтожением графа; доступ
287 к атрибутам "скрытых" ребер невозможен }
288 procedure Restore;
289 { восстановить ребро, "скрытое" ранее методом Hide; граф не должен
290 подвергаться модификациям после Hide (т.е. в него не должны добавляться
291 и из него не должны удаляться вершины или ребра); ребра необходимо
292 восстанавливать в порядке, обратном "сокрытию" }
293
294 { *** орграфы }
295
296 procedure ChangeDirection;
297 { изменяет направление ребра на противоположное }
298
299 { *** транспортные сети }
300
301 property MaxFlow: Float read GetMaxFlow write SetMaxFlow;
302 { максимальный поток через дугу }
303 property Flow: Float read GetFlow write SetFlow;
304 { поток через дугу }
305
306 { *** взвешенные графы }
307
308 property Weight: Float read GetWeight write SetWeight;
309 { вес ребра (дуги) }
310 end;
311
312 TGraphFeature = (Directed, Tree, Network, Weighted, Geom2D, Geom3D);
313 { свойства графа: направленный граф, дерево, транспортная сеть, взвешенный
314 граф, геометрический граф на плоскости и в трехмерном пространстве;
315 механизм свойств позволяет отслеживать в Run-Time вызовы методов,
316 не предназначенных для графов данного вида и возбуждать при этом исключения
317 (проверка свойств выполняется только при включенном условии компиляции
318 CHECK_GRAPHS); кроме того, использование свойств повышает эффективность -
319 действия, специфичные для графов данного вида, выполняются только тогда,
320 когда явно указано, что граф относится к этому виду }
321
322 TGraphFeatures = set of TGraphFeature;
323
324 TVisitProc = procedure (V: TVertex) of object;
325 TAcceptVertex = function (V: TVertex): Bool of object;
326 TAcceptEdge = function (Edge: TEdge; FromVertex: TVertex): Bool of object;
327
328 TEdgeFilter = class
329 AllowedEdges: TBoolVector;
AcceptEdgenull330 function AcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
331 end;
332
333 TAutoEdgeFilter = class(TEdgeFilter)
334 constructor Create(EdgeCount: Integer);
335 destructor Destroy; override;
336 end;
337
338 TSelectCode = (SelectAll, SelectAny, SelectSpecified, SelectAnyMin, SelectAnyMax,
339 SelectAllMin, SelectAllMax, SelectAllGE, SelectAllLE);
340 { используется в FindMaxIndependentVertexSets для указания, какие максимальные
341 независимые множества вершин и/или сколько множеств следует выдавать:
342 SelectAll: все множества;
343 SelectAny: любое из множеств;
344 SelectSpecified: заданное параметром количество;
345 SelectAnyMin: любое множество минимальной мощности;
346 SelectAnyMax: любое множество максимальной мощности;
347 SelectAllMin: все множества минимальной мощности;
348 SelectAllMax: все множества максимальной мощности;
349 SelectAllGE: мощности, большей либо равной значению параметра;
350 SelectAllLE: мощности, меньшей либо равной значению параметра;
351 }
352
353 TGraph = class(TGraphObject)
354 protected
355 FFeatures: TGraphFeatures;
356 FConnected: Bool;
357 FSeparateCount, FRingEdgeCount: Integer;
358 FVertexAttrMap, FEdgeAttrMap: TAttrMap; { карты глобальных атрибутов вершин и ребер }
359 FVertices, FEdges: TClassList;
360 procedure SetStates(NewStates: TGraphObjectStates);
361 property States: TGraphObjectStates read FStates write SetStates;
362 procedure FreeElements;
GetVertexnull363 function GetVertex(I: Integer): TVertex; {$IFDEF V_INLINE}inline;{$ENDIF}
GetEdgeByIndexnull364 function GetEdgeByIndex(I: Integer): TEdge; {$IFDEF V_INLINE}inline;{$ENDIF}
365 procedure InsertVertex(Vertex: TVertex);
366 { производит необходимые изменения в графе при добавлении вершины; вызывается
367 из TVertex.Create; эта и последующие процедуры введены для того, чтобы
368 сделать граф и элементы графа более "независимыми" (методы элементов графа
369 по возможности не должны менять protected-поля графа) }
370 procedure RemoveVertex(Vertex: TVertex);
371 { производит необходимые изменения в графе при удалении вершины; вызывается
372 из TVertex.Destroy }
373 procedure InsertEdge(Index: Integer; Edge: TEdge);
374 { производит необходимые изменения в графе при добавлении ребра; вызывается
375 из TEdge.Create }
376 procedure RemoveEdge(Edge: TEdge);
377 { производит необходимые изменения в графе при удалении ребра; вызывается
378 из TEdge.Destroy и TEdge.Hide }
379 procedure DetectConnected;
380 { определяет, связен ли граф }
381 procedure DetectSeparates;
382 { находит компоненты связности }
DetectRingsAcceptEdgenull383 function DetectRingsAcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
384 { вспомогательная функция для поиска кольцевых ребер в графе }
DetectRingsAcceptArcnull385 function DetectRingsAcceptArc(Edge: TEdge; FromVertex: TVertex): Bool;
386 { вспомогательная функция для поиска кольцевых ребер в орграфе }
FindMinRingAcceptEdgenull387 function FindMinRingAcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
388 { вспомогательная функция для поиска циклов в графе }
389 procedure DetectRingEdges;
390 { находит кольцевые ребра }
391 procedure CheckValidConnected;
392 { при необходимости определяет, связен ли граф }
393 procedure CheckValidSeparates;
394 { при необходимости находит компоненты связности }
395 procedure CheckValidRingEdges;
396 { при необходимости находит кольцевые ребра и компоненты связности }
397 procedure SetFeatures(Value: TGraphFeatures);
398 { устанавливает свойства графа }
FFindMinPathCondnull399 function FFindMinPathCond(Vertex1, Vertex2: TVertex;
400 AcceptVertex: TAcceptVertex; AcceptEdge: TAcceptEdge;
401 EdgePath: TClassList): Integer;
402 { используется при нахождении минимальных путей (см. FindMinPathCond);
403 внимание! EdgePath должен быть пуст перед вызовом }
FFindMinPathsnull404 function FFindMinPaths(Vertex1, Vertex2: TVertex; SolutionCount: Integer;
405 EdgePaths: TMultiList; DirectedGraph: Bool): Integer;
406 { используется при нахождении заданного количества / всех минимальных путей
407 (см. FindMinPaths) }
FFindMinRingCondnull408 function FFindMinRingCond(Vertex: TVertex; AcceptVertex: TAcceptVertex;
409 AcceptEdge: TAcceptEdge; EdgePath: TClassList): Integer;
410 { используется при нахождении минимальных колец (см. FindMinRingCond) }
411 procedure SetToZero(List: TClassList; Offset: Integer; AType: TAttrType);
412 { используется для обнуления значений вновь созданных атрибутов, когда они
413 создаются на месте "дыр", образующихся после DropAttr }
414 procedure FFindRingsFromEdge(FromEdge: TEdge; Rings: TMultiList;
415 MaxRings: Integer; FindRingFromEdgeHelper: Pointer);
416 { используется при нахождении минимальных колец }
417
418 { *** орграфы }
419
AcceptArcnull420 function AcceptArc(Edge: TEdge; FromVertex: TVertex): Bool;
421 { используется при нахождении минимального пути }
422
423 { *** деревья }
424
GetRootnull425 function GetRoot: TVertex; {$IFDEF V_INLINE}inline;{$ENDIF}
426 procedure SetRoot(Vertex: TVertex);
427
428 { *** транспортные сети }
429
GetNetworkSourcenull430 function GetNetworkSource: TVertex; {$IFDEF V_INLINE}inline;{$ENDIF}
431 procedure SetNetworkSource(Vertex: TVertex); {$IFDEF V_INLINE}inline;{$ENDIF}
GetNetworkSinknull432 function GetNetworkSink: TVertex; {$IFDEF V_INLINE}inline;{$ENDIF}
433 procedure SetNetworkSink(Vertex: TVertex); {$IFDEF V_INLINE}inline;{$ENDIF}
FindMaxFlowAcceptEdgenull434 function FindMaxFlowAcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
435
436 { *** взвешенные графы }
437 procedure Dijkstra(Vertex1, Vertex2: TVertex; AcceptVertex: TAcceptVertex;
438 AcceptEdge: TAcceptEdge; Distances: TFloatVector);
439 public
440 constructor Create;
441 destructor Destroy; override;
442 procedure WriteToStream(VStream: TVStream); override;
443 procedure ReadFromStream(VStream: TVStream); override;
444 procedure Assign(Source: TVector); override;
445 procedure AssignSceleton(Source: TGraph);
446 { копирует в Self "скелет" графа Source (т.е. граф, эквивалентный Source,
447 но без атрибутов) }
448 procedure AssignSimpleSceleton(Source: TGraph);
449 { копирует в Self простой "скелет" графа Source (т.е. граф, эквивалентный
450 Source, но без петель, кратных ребер и атрибутов) }
451 procedure Pack; override;
452 procedure Clear; override;
453 { уничтожает все вершины и ребра графа }
454 procedure ClearEdges;
455 { уничтожает все ребра графа }
456 property Features: TGraphFeatures read FFeatures write SetFeatures;
457 { свойства графа }
VertexCountnull458 function VertexCount: Integer; {$IFDEF V_INLINE}inline;{$ENDIF}
459 { количество вершин графа }
EdgeCountnull460 function EdgeCount: Integer; {$IFDEF V_INLINE}inline;{$ENDIF}
461 { количество ребер графа }
462 property Vertices[I: Integer]: TVertex read GetVertex; default;
463 { вершины графа 0..VertexCount-1 }
464 property Edges[I: Integer]: TEdge read GetEdgeByIndex;
465 { ребра графа 0..EdgeCount-1 }
Connectednull466 function Connected: Bool;
467 { проверяет, является ли граф связным; граф без вершин считается несвязным;
468 граф всегда интерпретируется как неориентированный }
MakeConnectednull469 function MakeConnected(NewEdges: TClassList): Integer;
470 { если количество вершин в графе больше 0, то делает граф связным, добавляя
471 при необходимости новые ребра (одним из концов которых всегда является
472 вершина под номером 0); возвращает количество добавленных ребер; если
473 NewEdges <> nil, то в NewEdges возвращается список новых ребер }
FindArticulationPointsnull474 function FindArticulationPoints(FromVertex: TVertex; Points: TClassList): Bool;
475 { находит точки (узлы) сочленения, принадлежащие той же компоненте связности
476 графа, что и FromVertex (точкой сочленения называется вершина, удаление
477 которой приводит к увеличению числа компонент связности); возвращает True,
478 если точки сочленения существуют, иначе - False; если Points <> nil, то в
479 Points возвращается список точек сочленения }
Biconnectednull480 function Biconnected(ArticulationPoints: TClassList): Bool;
481 { проверяет, является ли граф двусвязным (граф называется двусвязным, если
482 он связен и в нем не существует точек сочленения; граф, состоящий из одной
483 вершины, является двусвязным по определению); возвращает True, если граф
484 является двусвязным, иначе - False; если граф является связным, но
485 не двусвязным, и ArticulationPoints <> nil, то в ArticulationPoints
486 возвращается список точек сочленения графа }
MakeBiconnectednull487 function MakeBiconnected(NewEdges: TClassList): Integer;
488 { делает граф двусвязным и возвращает количество добавленных ребер; если
489 NewEdges <> nil, то в NewEdges возвращается список добавленных ребер }
Bipartitenull490 function Bipartite(A: TBoolVector): Bool;
491 { проверяет, является ли граф двудольным (т.е. его вершины можно разбить на
492 два таких множества A и B, что для каждого ребра графа один из концов
493 лежит в A, а другой - в B); граф может быть несвязным (в таком случае он
494 состоит из некоторого количества связных двудольных компонент и/или
495 нескольких изолированных вершин; если A <> nil, то при положительном
496 результате (граф двудольный) в A возвращается информация о принадлежности
497 вершин к долям: A[I] = True <=> I-ая вершина лежит в A }
IsTreenull498 function IsTree: Bool;
499 { проверяет, является ли граф деревом (связным графом без петель и кратных
500 ребер); не следует путать эту функцию и свойство графа Tree - они никак
501 не связаны }
IsRegularnull502 function IsRegular: Bool;
503 { проверяет, является ли граф регулярным графом (т.е. степени всех его
504 вершин совпадают); граф всегда интерпретируется как неориентированный;
505 граф без вершин считается регулярным }
HasParallelEdgesnull506 function HasParallelEdges: Bool;
507 { проверяет, имеются ли в графе кратные ребра; граф интерпретируется как
508 неориентированный или ориентированный в зависимости от Features }
509 {$IFDEF V_ALLOW_DEPRECATE}
HasDuplicateEdgesnull510 function HasDuplicateEdges: Bool; { устарело! }
511 {$ENDIF}
HasLoopsnull512 function HasLoops: Bool;
513 { проверяет, имеются ли в графе петли }
RemoveParallelEdgesnull514 function RemoveParallelEdges: Bool;
515 { удаляет все кратные ребра (дуги в орграфе) и возвращает True, если в графе
516 существовали кратные ребра (дуги) }
517 {$IFDEF V_ALLOW_DEPRECATE}
RemoveDuplicateEdgesnull518 function RemoveDuplicateEdges: Bool; { устарело! }
519 {$ENDIF}
RemoveLoopsnull520 function RemoveLoops: Bool;
521 { удаляет все петли и возвращает True, если в графе существовали петли }
HideLoopsnull522 function HideLoops(Loops: TClassList): Integer;
523 { "скрывает" (временно удаляет методом Hide) все петли и помещает их в
524 список Loops; "скрытые" петли не уничтожаются при уничтожении графа,
525 поэтому их необходимо восстанавливать либо уничтожать вручную перед
526 уничтожением графа; возвращает количество петель в графе; петли можно
527 восстановить методом RestoreLoops }
528 procedure RestoreLoops(Loops: TClassList);
529 { восстанавливает петли, удаленные методом HideLoops; если граф был изменен
530 (т.е. происходило добавление или уничтожение вершин или ребер), то
531 восстановление невозможно }
ParallelEdgeCountnull532 function ParallelEdgeCount: Integer;
533 { количество кратных ребер в графе }
534 {$IFDEF V_ALLOW_DEPRECATE}
DuplicateEdgeCountnull535 function DuplicateEdgeCount: Integer; { устарело! }
536 {$ENDIF}
LoopCountnull537 function LoopCount: Integer;
538 { количество петель в графе }
SeparateCountnull539 function SeparateCount: Integer;
540 { количество компонент связности в графе }
RingEdgeCountnull541 function RingEdgeCount: Integer;
542 { количество кольцевых ребер, включая петли, в графе }
CyclomaticNumbernull543 function CyclomaticNumber: Integer;
544 { цикломатическое число графа (EdgeCount - VertexCount + SeparateCount) }
CreateVertexAttrnull545 function CreateVertexAttr(const Name: String; AType: TAttrType): Integer;
546 { определяет глобальный (общий для всех вершин) атрибут вершин графа с
547 именем Name и типом AType; начальное значение для числовых атрибутов - 0,
548 для указателей - nil, для строк - ''; возвращает смещение атрибута;
549 если атрибут с таким именем уже был определен, то возбуждается
550 исключительная ситуация }
551 procedure DropVertexAttr(const Name: String);
552 { удаляет глобальный атрибут вершин графа с именем Name; если такой атрибут
553 не был определен, то возбуждается исключительная ситуация }
CreateEdgeAttrnull554 function CreateEdgeAttr(const Name: String; AType: TAttrType): Integer;
555 { определяет глобальный (общий для всех ребер) атрибут ребер графа с
556 именем Name и типом AType; начальное значение для числовых атрибутов - 0,
557 для указателей - nil, для строк - ''; возвращает смещение атрибута;
558 если атрибут с таким именем уже был определен, то возбуждается
559 исключительная ситуация }
560 procedure DropEdgeAttr(const Name: String);
561 { удаляет глобальный атрибут ребер графа с именем Name; если такой атрибут
562 не был определен, то возбуждается исключительная ситуация }
VertexAttrTypenull563 function VertexAttrType(const Name: String): TExtAttrType;
564 { проверяет, определен ли глобальный атрибут вершин графа с именем Name
565 и возвращает его тип, либо AttrNone, если не определен }
SafeCreateVertexAttrnull566 function SafeCreateVertexAttr(const Name: String; AType: TAttrType): Integer;
567 { аналог CreateVertexAttr, но при наличии атрибута с именем Name и типом
568 AType возвращается -1, исключительная ситуация не возбуждается }
569 procedure SafeDropVertexAttr(const Name: String);
570 { аналог DropVertexAttr, но при отсутствии атрибута с именем Name
571 исключительная ситуация не возбуждается }
SafeCreateEdgeAttrnull572 function SafeCreateEdgeAttr(const Name: String; AType: TAttrType): Integer;
573 { аналог CreateEdgeAttr, но при наличии атрибута с именем Name и типом
574 AType возвращается -1, исключительная ситуация не возбуждается }
575 procedure SafeDropEdgeAttr(const Name: String);
576 { аналог DropEdgeAttr, но при отсутствии атрибута с именем Name
577 исключительная ситуация не возбуждается }
EdgeAttrTypenull578 function EdgeAttrType(const Name: String): TExtAttrType;
579 { проверяет, определен ли глобальный атрибут ребер графа с именем Name
580 и возвращает его тип, либо AttrNone, если не определен }
VertexAttrOffsetnull581 function VertexAttrOffset(const Name: String): Integer;
582 { возвращает смещение глобального атрибута вершин графа с заданным именем
583 (атрибут должен быть определен) }
EdgeAttrOffsetnull584 function EdgeAttrOffset(const Name: String): Integer;
585 { возвращает смещение глобального атрибута ребер графа с заданным именем
586 (атрибут должен быть определен) }
587 property VertexAttrMap: TAttrMap read FVertexAttrMap;
588 { карта глобальных атрибутов вершин графа }
589 property EdgeAttrMap: TAttrMap read FEdgeAttrMap;
590 { карта глобальных атрибутов ребер графа }
AddVertexnull591 function AddVertex: TVertex;
592 { создает и добавляет в граф вершину; вершина добавляется в конец
593 списка вершин }
594 procedure AddVertices(ACount: Integer);
595 { создает и добавляет ACount вершин в граф; вершины добавляются в конец
596 списка вершин }
GetEdgenull597 function GetEdge(Vertex1, Vertex2: TVertex): TEdge;
598 { возвращает ребро, инцидентное вершинам Vertex1 и Vertex2, если эти вершины
599 смежны, иначе - nil; при наличии кратных ребер между вершинами может
600 возвращаться любое из них; порядок параметров не важен; любой из параметров
601 может быть равен nil, при этом результат также будет равен nil }
GetEdgeInull602 function GetEdgeI(I1, I2: Integer): TEdge;
603 { возвращает ребро, инцидентное вершинам с индексами I1 и I2, если эти
604 вершины существуют и смежны, иначе - nil; при наличии кратных ребер между
605 вершинами может возвращаться любое из них; порядок параметров не важен }
606 procedure GetEdges(EdgeList: TClassList; Vertex1, Vertex2: TVertex);
607 { возвращает в EdgeList список ребер, инцидентных заданным вершинам, если
608 эти вершины смежны, иначе - пустой список; порядок параметров не важен;
609 и Vertex1, и Vertex2 могут быть равны nil, при этом возвращается пустой
610 список }
611 procedure GetEdgesI(EdgeList: TClassList; I1, I2: Integer);
612 { возвращает в EdgesList список ребер, инцидентных вершинам с индексами I1 и
613 I2, если эти вершины существуют и смежны, иначе - пустой список; порядок
614 параметров не важен }
AddEdgenull615 function AddEdge(Vertex1, Vertex2: TVertex): TEdge;
616 { создает и добавляет в граф ребро между вершинами Vertex1 и Vertex2; ребро
617 добавляется в конец списка ребер }
AddEdgeInull618 function AddEdgeI(I1, I2: Integer): TEdge;
619 { создает и добавляет в граф ребро между вершинами с индексами I1 и I2;
620 ребро добавляется в конец списка ребер }
621 procedure AddEdges(const VertexIndexes: array of Integer);
622 { создает и добавляет в граф ребра между вершинами с индексами VertexIndexes
623 (количество элементов в VertexIndexes должно быть четным):
624 VertexIndexes[0]..VertexIndexes[1],
625 VertexIndexes[2]..VertexIndexes[3]... и т.д. }
626 procedure GetSeparateOf(Source: TGraph; V: TVertex);
627 { делает граф Self равным тому компоненту связности графа Source, которому
628 принадлежит вершина V; соответствие между вершинами графа Self и графа
629 Source устанавливается с помощью поля Temp: после завершения работы
630 процедуры Vertices[I].Temp.AsInt32 = <индекс вершины в графе Source,
631 которая соответствует вершине Vertices[I]>;
632 примечания: атрибуты вершин и ребер не копируются; Source не может
633 совпадать с Self }
634 procedure SetTempForVertices(Value: Int32);
635 { присваивает полям Temp всех вершин графа значение Value }
636 procedure SetTempForEdges(Value: Int32);
637 { присваивает полям Temp всех ребер графа значение Value }
638 procedure SetTempFromVertex(V: TVertex; Value: Int32);
639 { присваивает полям Temp всех вершин графа, находящихся в одной компоненте
640 связности с V, значение Value }
DFSFromVertexnull641 function DFSFromVertex(V: TVertex): Integer;
642 { выполняет разметку вершин графа с помощью поиска в глубину (Depth First
643 Search), исходя из вершины V; полю Temp каждой достигнутой вершины
644 присваивается число, равное "времени" достижения данной вершины (0 для
645 вершины V); возвращается количество достигнутых вершин, равное количеству
646 вершин, принадлежащих той же компоненте связности графа, что и V; полям
647 Temp вершин, принадлежащих другим компонентам связности, присваивается
648 значение -1; граф всегда, независимо от Features, интерпретируется как
649 неориентированный }
BFSFromVertexnull650 function BFSFromVertex(V: TVertex): Integer;
651 { выполняет разметку вершин графа с помощью поиска в ширину (Breadth First
652 Search; другие названия - волновой алгоритм, или алгоритм степного пожара),
653 исходя из вершины V и используя в качестве "временной метки" поле Temp
654 (вершина V получает метку 0); возвращается количество достигнутых вершин,
655 равное количеству вершин, принадлежащих той же компоненте связности графа,
656 что и V; вершины, принадлежащие другим компонентам связности, получают
657 метку -1; граф всегда, независимо от Features, интерпретируется как
658 неориентированный }
BFSTraversalnull659 function BFSTraversal(V: TVertex; VisitProc: TVisitProc): Integer;
660 { аналог BFSFromVertex; если VisitProc <> nil, то при достижении очередной
661 вершины эта вершина передается в call-back процедуру VisitProc (вершина V
662 не передается в VisitProc) }
BFSFromVertexFindMeetingsnull663 function BFSFromVertexFindMeetings(V: TVertex; VertexMeetings,
664 EdgeMeetings: TClassList): Integer;
665 { аналог BFSFromVertex, но встречи "волны" на вершинах и ребрах графа
666 запоминаются в VertexMeetings / EdgeMeetings; на одной вершине или одном
667 ребре может произойти более чем одна встреча, поэтому в списках возможны
668 повторы;
669 примечания:
670 1) если граф связный, то выполняется постусловие:
671 CyclomaticNumber = VertexMeetings.Count + EdgeMeetings.Count + LoopCount;
672 2) допускается VertexMeetings = nil, но тогда и EdgeMeetings считается
673 равным nil }
674 procedure BFSFromVertexDirected(V: TVertex);
675 { аналог BFSFromVertex, но граф всегда, независимо от Features,
676 интерпретируется как ориентированный }
FindMinPathCondnull677 function FindMinPathCond(Vertex1, Vertex2: TVertex; AcceptVertex: TAcceptVertex;
678 AcceptEdge: TAcceptEdge; EdgePath: TClassList): Integer;
679 { находит любой из путей минимальной длины между заданными вершинами,
680 проходящий через вершины, удовлетворяющие условию AcceptVertex и через
681 ребра, удовлетворяющие условию AcceptEdge, и возвращает его длину
682 (-1, если путь не существует, и 0, если Vertex1 = Vertex2); если
683 AcceptVertex = nil, то принимаются все вершины; если AcceptEdge = nil,
684 то принимаются все ребра; если EdgePath <> nil, то в EdgePath помещаются
685 указатели на ребра, по которым проходит путь; граф всегда, независимо от
686 Features, интерпретируется как неориентированный }
FindMinPathUndirectednull687 function FindMinPathUndirected(Vertex1, Vertex2: TVertex;
688 EdgePath: TClassList): Integer;
689 { находит любой из путей минимальной длины между вершинами Vertex1 и Vertex2;
690 граф всегда, независимо от Features, интерпретируется как неориентированный }
FindMinPathDirectednull691 function FindMinPathDirected(Vertex1, Vertex2: TVertex;
692 EdgePath: TClassList): Integer;
693 { находит любой из путей минимальной длины между вершинами Vertex1 и Vertex2;
694 граф всегда, независимо от Features, интерпретируется как ориентированный }
FindMinPathnull695 function FindMinPath(Vertex1, Vertex2: TVertex; EdgePath: TClassList): Integer;
696 { находит любой из путей минимальной длины между вершинами Vertex1 и Vertex2;
697 граф интерпретируется как неориентированный или ориентированный в
698 зависимости от вхождения флага Directed во множество Features }
FindMinPathsUndirectednull699 function FindMinPathsUndirected(Vertex1, Vertex2: TVertex;
700 SolutionCount: Integer; EdgePaths: TMultiList): Integer;
701 { ищет пути между вершинами Vertex1 и Vertex2, длина которых равна длине
702 минимального пути между этими вершинами; если SolutionCount <= 0, то
703 возвращаются все такие пути; если SolutionCount > 0, то возвращаются
704 min(SolutionCount, <количество путей>) путей; функция возвращает
705 количество найденных путей; пути записываются в мультисписок EdgePaths
706 (каждый элемент EdgePaths является списком ребер графа, образующих
707 некоторый путь); граф всегда, независимо от Features, интерпретируется
708 как неориентированный }
FindMinPathsDirectednull709 function FindMinPathsDirected(Vertex1, Vertex2: TVertex;
710 SolutionCount: Integer; EdgePaths: TMultiList): Integer;
711 { аналог FindMinPathsUndirected, но граф всегда интерпретируется как
712 ориентированный }
FindMinPathsnull713 function FindMinPaths(Vertex1, Vertex2: TVertex; SolutionCount: Integer;
714 EdgePaths: TMultiList): Integer;
715 { аналог FindMinPathsUndirected, но граф интерпретируется как
716 ориентированный или неориентированный в зависимости от вхождения флага
717 Directed во множество Features }
FindMinRingCondnull718 function FindMinRingCond(Vertex: TVertex;
719 AcceptVertex: TAcceptVertex; AcceptEdge: TAcceptEdge;
720 EdgePath: TClassList): Integer;
721 { находит любой из циклов минимальной длины, проходящих через вершину Vertex
722 и другие вершины, удовлетворяющие условию AcceptVertex, и по ребрам,
723 удовлетворяющим условию AcceptEdge; возвращается длина цикла (-1, если
724 цикл не существует); если AcceptVertex = nil, то принимаются все вершины;
725 если AcceptEdge = nil, то принимаются все ребра; если EdgePath <> nil,
726 то в EdgePath помещаются указатели на ребра, по которым проходит цикл;
727 граф всегда, независимо от Features, интерпретируется как неориентированный }
FindMinRingnull728 function FindMinRing(Vertex: TVertex; EdgePath: TClassList): Integer;
729 { находит любой из циклов минимальной длины, проходящих через вершину
730 Vertex; граф интерпретируется как неориентированный или ориентированный
731 в зависимости от Features }
CreateRingDegreesVectornull732 function CreateRingDegreesVector: TIntegerVector;
733 { создает вектор кольцевых степеней (без учета петель) вершин графа;
734 Result[I] = <количество кольцевых ребер, инцидентных I-й вершине графа> -
735 <количество петель, инцидентных I-й вершине графа>; граф всегда,
736 независимо от Features, интерпретируется как неориентированный }
FindRingsFromEdgenull737 function FindRingsFromEdge(FromEdge: TEdge; Rings: TMultiList;
738 MaxRings: Integer): Integer;
739 { находит не более, чем MaxRings независимых минимальных колец, проходящих
740 через ребро FromEdge; возвращает количество найденных колец, а также сами
741 кольца в мультисписке Rings (Rings[I] содержит список указателей на ребра,
742 входящие в I-е минимальное кольцо) }
FindMinRingCoveringnull743 function FindMinRingCovering(Rings: TMultiList): Integer;
744 { находит систему независимых минимальных колец графа, покрывающих все
745 кольцевые ребра графа (исключая петли) и возвращает количество колец,
746 а также сами кольца в мультисписке Rings; граф всегда, независимо от
747 Features, интерпретируется как неориентированный;
748 примечания:
749 1) для некоторых графов система независимых минимальных покрывающих колец
750 является также системой независимых минимальных колец, для других -
751 является подмножеством последней, т.е. количество колец в системе
752 покрывающих колец может быть меньше цикломатического числа
753 графа минус количество петель;
754 2) система независимых минимальных покрывающих колец графа в общем случае
755 не единственна }
CompleteRingSystemnull756 function CompleteRingSystem(Rings: TMultiList): Bool;
757 { проверяет, что все кольцевые ребра графа (кроме петель) "покрываются"
758 системой колец Rings, т.е. принадлежат хотя бы одному кольцу }
FindSpanningTreenull759 function FindSpanningTree(EdgeInST: TBoolVector; STEdges: TClassList): Integer;
760 { находит одно из остовных деревьев графа; возвращает количество ребер в
761 остовном дереве; если EdgeInST <> nil, то EdgeInST[I] = True <=> I-е
762 ребро входит в деревов; если STEdges <> nil, то в STEdges возвращается
763 список ребер, входящих в дерево (остовным деревом графа, или остовом,
764 называется любой его подграф, содержащий столько же вершин и компонент
765 связности, что и этот граф, и не содержащий циклов; строго говоря, остов
766 не всегда является деревом - для несвязного графа это лес деревьев) }
FindFundamentalRingsnull767 function FindFundamentalRings(Rings: TMultiList): Integer;
768 { находит некоторую систему фундаментальных циклов графа (исключая петли);
769 возвращает количество циклов; циклы возвращаются в мультисписке Rings
770 (Rings[I] содержит список указателей на ребра, входящие в I-й цикл);
771 фундаментальной системой циклов называется любая система циклов, которые
772 могут быть построены путем добавления к некоторому остову графа его хорд
773 (ребер, не принадлежащих остову); количество циклов в фундаментальной
774 системе равно цикломатическому числу графа минус количество петель }
EdgePathToVertexPathnull775 function EdgePathToVertexPath(FromVertex: TVertex;
776 EdgePath, VertexPath: TClassList): Bool;
777 { преобразует путь, заданный списком ребер и начинающийся с вершины
778 FromVertex, в список вершин; возвращает True при успехе и False при
779 ошибке в EdgePath }
CreateConnectionMatrixnull780 function CreateConnectionMatrix: TBoolMatrix;
781 { создает матрицу связности (aij = True <=> вершины vi и vj соединены ребром
782 либо дугой; aii = True); если граф неориентированный, то создается
783 симметричная матрица }
CreateExtendedConnectionMatrixnull784 function CreateExtendedConnectionMatrix: TIntegerMatrix;
785 { создает обобщенную матрицу связности (aij = <количество ребер (дуг) между
786 вершинами vi и vj>; aii = <количество петель, инцидентных vi>; если граф
787 неориентированный, то создается симметричная матрица }
CreateReachabilityMatrixnull788 function CreateReachabilityMatrix: TBoolMatrix;
789 { создает матрицу достижимости (aij = True <=> вершина vj достижима из vi;
790 aii = True); если граф неориентированный, то создается симметричная матрица }
CreateIncidenceMatrixnull791 function CreateIncidenceMatrix: TBoolMatrix;
792 { создает матрицу инциденций графа (матрицу размерности VertexCount*EdgeCount,
793 где bij = True <=> вершина vi инцидентна ребру ej) }
CreateDistanceMatrixnull794 function CreateDistanceMatrix: TIntegerMatrix;
795 { создает матрицу расстояний (dij = <длина минимального пути из i-й вершины
796 в j-ю>, если путь существует, и -1, если путь не существует; dii = 0);
797 если граф неориентированный, то создается симметричная матрица;
798 вес ребер в случае взвешенных графов не учитывается (т.е. вес любого
799 ребра считается равным единице) }
CreateDegreesVectornull800 function CreateDegreesVector: TIntegerVector;
801 { создает вектор степеней вершин графа }
CreateInt64DegreesVectornull802 function CreateInt64DegreesVector: TInt64Vector;
803 { аналогично, но создает вектор класса TInt64Vector }
UpdateSpectrumnull804 function UpdateSpectrum(Spectrum, SortedSpectrum, TempVector: TInt64Vector): Integer;
805 { выполняет шаг вычисления спектра Де Моргана для вершин графа; в векторе
806 Spectrum должен передаваться предыдущий спектр, начальное значение которого
807 вычисляется с помощью CreateInt64DegreesVector; на выходе вектор Spectrum
808 содержит обновленные значения спектра; если SortedSpectrum <> nil, то в
809 нем возвращаются упорядоченные по возрастанию значения Spectrum; TempVector
810 используется внутри функции и не может быть равен nil; функция возвращает
811 количество различных значений в спектре }
EqualToGraphnull812 function EqualToGraph(G: TGraph; IsomorphousMap: TGenericIntegerVector;
813 CompareVertices, CompareEdges: TCompareFunc): Bool;
814 { определяет, совпадают ли графы Self и G при отображении вершин Self на
815 вершины G, заданном IsomorphousMap (IsomorphousMap[I] = <номер вершины G,
816 соответствующей I-й вершине Self>); для сравнения атрибутов вершин и ребер
817 используются CompareVertices и CompareEdges; графы Self и G должны быть
818 одинаковой размерности и не должны содержать кратных ребер; порядок
819 соответствующих ребер в списках инцидентных ребер (свойство IncidentEdge)
820 должен совпадать в графах для всех вершин! }
821 procedure FindMaxIndependentVertexSets(SelectCode: TSelectCode;
822 SelectParam: Integer; VertexSets: TMultiList);
823 { находит максимальные независимые множества вершин (независимое множество
824 вершин, НМВ - множество вершин графа, таких, что никакие две вершины этого
825 множества не связаны ребром / дугой; максимальное НМВ, МНМВ - такое НМВ,
826 что при добавлении в это множество любой другой вершины графа множество
827 перестает быть независимым) и вернуть их в мультисписке VertexSets;
828 количество возвращаемых множеств определяется значением SelectCode;
829 SelectParam: используется при SelectCode = SelectGE / SelectLE (см.
830 комментарии к типу TSelectCode), при других значениях SelectCode значение
831 SelectParam игнорируется;
832 поскольку существует взаимно-однозначное соответствие между МНМВ графа
833 и кликами (максимальными полными подграфами) дополнительного к нему графа,
834 метод FindMaxIndependentVertexSets позволяет также находить все клики
835 графа; для этого надо построить дополнение графа с помощью метода
836 GetComplementOf и применить к нему данный метод }
837 procedure GetComplementOf(Source: TGraph);
838 { делает граф дополнением графа Source (дополнением некоторого графа
839 называется граф, вершины которого совпадают с вершинами исходного графа,
840 а любые две вершины соединены ребром тогда и только тогда, когда они не
841 соединены ребром в исходном графе);
842 примечания: в ходе преобразования петли уничтожаются; кратность ребер
843 не учитывается; атрибуты вершин и ребер не копируются; Source может
844 совпадать с Self }
845 procedure GetLineGraphOf(Source: TGraph);
846 { делает граф реберным графом графа Source (реберным графом некоторого
847 графа называется граф, вершины которого соответствуют ребрам исходного
848 графа, и две вершины связаны тогда и только тогда, когда соответствующие
849 им ребра смежны в исходном графе, т.е. имеют общий конец);
850 примечания: атрибуты вершин и ребер не копируются; Source не может
851 совпадать с Self }
GetShortestSpanningTreeOfnull852 function GetShortestSpanningTreeOf(Source: TGraph): Float;
853 { делает граф кратчайшим остовным деревом (SST) взвешенного графа Source и
854 возвращает суммарный вес его ребер (если Source несвязен, то создается
855 лес кратчайших остовных деревьев для каждой связной компоненты Source);
856 если граф не был взвешенным, то он становится взвешенным (Weighted in
857 Features = True); соответствие между вершинами графа Self и графа Source
858 порядковое; соответствие между ребрами устанавливается с помощью поля
859 Temp: после завершения работы функции Edges[I].Temp.AsInt32 = <индекс
860 ребра в графе Source, которое соответствует ребру Edges[I]>; если граф
861 Source не является взвешенным, то возбуждается исключительная ситуация;
862 примечания: атрибуты вершин и ребер не копируются; Source не может
863 совпадать с Self }
864 procedure SortVertices(CompareVertices: TCompareFunc);
865 { упорядочивает вершины графа по возрастанию согласно CompareVertices }
866 procedure SortEdges(CompareEdges: TCompareFunc);
867 { упорядочивает ребра графа по возрастанию согласно CompareEdges }
868 procedure SortVerticesByObject(CompareVertices: TCompareEvent);
869 { упорядочивает вершины графа по возрастанию согласно CompareVertices }
870 procedure SortEdgesByObject(CompareEdges: TCompareEvent);
871 { упорядочивает ребра графа по возрастанию согласно CompareEdges }
872 procedure GetVertices(VertexList: TClassList);
873 { возвращает в VertexList список вершин графа }
874
875 { *** деревья }
876
877 { методы SetTempToSubtreeSize и TreeTraversal могут быть применены как к
878 деревьям (IsTree = True), так и к графам, которые могут быть получены из
879 деревьев путем соединения ребрами вершин, принадлежащих одному уровню
880 дерева; для других видов графов результат не определен; метод ArrangeTree
881 должен применяться только к деревьям }
882
883 procedure SetTempToSubtreeSize(FromVertex: TVertex);
884 { устанавливает поля Temp.AsInt32 вершин графа равными количеству вершин
885 во всех поддеревьях вершины FromVertex; для ребер Temp.AsInt32 = 0, если
886 ребро "горизонтальное" (т.е. соединяет вершины, принадлежащие одному
887 уровню дерева), иначе Temp.AsInt32 = -1 }
888 procedure TreeTraversal(FromVertex: TVertex; VertexPath: TClassList);
889 { совершает обход вершин графа, интерпретируемого как дерево с корнем
890 FromVertex, используя порядок обхода сверху вниз / слева направо;
891 указатели на пройденные вершины записываются в список VertexPath }
892 procedure ArrangeTree(FromVertex: TVertex; CompareVertices,
893 CompareEdges: TCompareEvent);
894 { упорядочивает дерево с корнем FromVertex так, чтобы поддеревья каждой
895 вершины располагались слева направо по возрастанию следующих параметров
896 (в порядке уменьшения приоритета):
897 1) количество вершин в поддеревьях;
898 2) степени корней поддеревьев;
899 3) атрибуты корней поддеревьев;
900 4) атрибуты ребер, ведущих к поддеревьям;
901 5) по возрастанию упорядоченных поддеревьев (рекурсивно);
902 для сравнения атрибутов вершин и ребер используются функции
903 CompareVertices и CompareEdges }
904 procedure SortTree(FromVertex: TVertex; CompareVertices: TCompareEvent);
905 { рекурсивно сортирует дерево с корнем FromVertex в соответствии с
906 CompareVertices }
907
908 { *** орграфы }
909
GetArcnull910 function GetArc(FromVertex, ToVertex: TVertex): TEdge;
911 { возвращает дугу от вершины FromVertex к вершине ToVertex, если она
912 существует, иначе - nil; при наличии кратных дуг между вершинами может
913 возвращаться любая из них; любой из параметров может быть равен nil,
914 при этом результат также будет равен nil }
GetArcInull915 function GetArcI(FromIndex, ToIndex: Integer): TEdge;
916 { возвращает дугу от вершины с индексом FromIndex к вершине с индексом
917 ToIndex, если дуга существует, иначе - nil; при наличии кратных дуг между
918 вершинами может возвращаться любая из них }
919 procedure GetArcs(ArcsList: TClassList; FromVertex, ToVertex: TVertex);
920 { возвращает в ArcsList список дуг от вершины FromVertex к вершине ToVertex;
921 и FromVertex, и ToVertex могут быть равны nil, при этом возвращается пустой
922 список }
923 procedure GetArcsI(ArcsList: TClassList; FromIndex, ToIndex: Integer);
924 { возвращает в ArcsList список дуг от вершины с индексом FromIndex к вершине
925 с индексом ToIndex }
926 procedure GetInArcsList(ArcsList: TMultiList);
927 { записывает в I-й элемент мультисписка ArcsList список дуг, входящих
928 в I-ую вершину графа }
929 procedure GetOutArcsList(ArcsList: TMultiList);
930 { записывает в I-й элемент мультисписка ArcsList список дуг, исходящих
931 из I-й вершины графа }
FindStrongComponentsnull932 function FindStrongComponents(ComponentNumbers: TGenericIntegerVector): Integer;
933 { находит сильные компоненты орграфа и возвращает их количество; если
934 ComponentNumbers <> nil, то в ComponentNumbers возвращается информация
935 о принадлежности вершин графа к сильным компонентам: ComponentNumbers[I] =
936 <номер сильной компоненты орграфа (начиная с 0), которой принадлежит I-ая
937 его вершина>; сильная компонента орграфа - один из максимальных сильных
938 подграфов орграфа, т.е. сильный подграф, который не содержится ни в каком
939 другом сильном подграфе; сильный подграф - такой порожденный подграф
940 орграфа, что для любых двух вершин этого подграфа существует соединяющий
941 их путь }
942
943 { *** деревья }
944
945 procedure CorrectTree;
946 { устанавливает правильные значения Parent для вершин дерева; этот метод
947 необходим тогда, когда дерево строилось не только с помощью метода
948 AddChild }
949 property Root: TVertex read GetRoot write SetRoot;
950 { корень дерева }
951
952 { *** транспортные сети }
953
IsNetworkCorrectnull954 function IsNetworkCorrect: Bool;
955 { проверяет корректность транспортной сети:
956 1) граф не тривиален (т.е. в нем более одной вершины);
957 2) граф связен;
958 3) определены вершины истока и стока;
959 4) нет дуг, входящих в исток или выходящих из стока;
960 5) нет кратных дуг }
FindMaxFlowThroughNetworknull961 function FindMaxFlowThroughNetwork: Float;
962 { находит максимальный поток в транспортной сети }
963 property NetworkSource: TVertex read GetNetworkSource write SetNetworkSource;
964 { исток транспортной сети }
965 property NetworkSink: TVertex read GetNetworkSink write SetNetworkSink;
966 { сток транспортной сети }
967
968 { *** взвешенные графы }
969
970 { 1. допускаются только неотрицательные веса ребер (дуг) }
FindMinWeightPathCondnull971 function FindMinWeightPathCond(Vertex1, Vertex2: TVertex;
972 AcceptVertex: TAcceptVertex; AcceptEdge: TAcceptEdge;
973 EdgePath: TClassList): Float;
974 { находит любой из путей минимального суммарного веса между заданными
975 вершинами, проходящий через вершины, удовлетворяющие условию AcceptVertex
976 и через ребра, удовлетворяющие условию AcceptEdge; возвращает суммарный
977 вес найденного пути либо отрицательное число, если путь не существует;
978 если AcceptVertex = nil, то принимаются все вершины; аналогично, если
979 AcceptEdge = nil, то принимаются все ребра; если EdgePath <> nil, то в
980 EdgePath помещаются указатели на ребра, по которым проходит путь; граф
981 всегда интерпретируется как неориентированный }
FindMinWeightPathnull982 function FindMinWeightPath(Vertex1, Vertex2: TVertex; EdgePath: TClassList): Float;
983 { находит любой из путей минимального суммарного веса между заданными
984 вершинами и возвращает его суммарный вес; граф интерпретируется как
985 неориентированный или ориентированный в зависимости от Features }
986 procedure FindDistancesCond(FromVertex: TVertex; AcceptVertex: TAcceptVertex;
987 AcceptEdge: TAcceptEdge; Distances: TFloatVector);
988 { находит длины путей минимального суммарного веса между вершиной FromVertex
989 и всеми другими вершинами графа; пути проходят через вершины,
990 удовлетворяющие условию AcceptVertex и через ребра, удовлетворяющие
991 условию AcceptEdge; если AcceptVertex = nil, то принимаются все вершины;
992 аналогично, если AcceptEdge = nil, то принимаются все ребра; длины путей
993 возвращаются в Distances: Distances[I] = <расстояние между вершинами
994 FromVertex и Vertices[I], если между ними существует путь, удовлетворяющий
995 заданным условиям, либо MaxFloat, если такой путь не существует>; граф
996 всегда, независимо от Features, интерпретируется как неориентированный }
997 procedure FindDistances(FromVertex: TVertex; Distances: TFloatVector);
998 { аналог FindDistancesCond, но граф интерпретируется как неориентированный
999 или ориентированный в зависимости от Features }
1000
1001 { 2. допускаются отрицательные веса ребер (дуг) }
CreateWeightsMatrixnull1002 function CreateWeightsMatrix: TFloatMatrix;
1003 { создает и возвращает матрицу весов ребер (дуг); dij = <длина кратчайшего
1004 пути между вершинами с индексами I и J>, если I <> J и путь существует,
1005 иначе dij = MaxFloat; граф интерпретируется как неориентированный или
1006 ориентированный в зависимости от вхождения флага Directed во множество
1007 Features (для неориентированного графа создается симметричная матрица) }
CreateMinWeightPathsMatrixnull1008 function CreateMinWeightPathsMatrix(var DistancesMatrix: TFloatMatrix;
1009 PathsMatrix: TIntegerMatrix): Bool;
1010 { находит минимальные расстояния между всеми парами вершин взвешенного графа
1011 с использованием алгоритма Флойда; если в графе нет циклов отрицательной
1012 длины, то функция возвращает True, а элемент DistancesMatrix[I, J], где
1013 I <> J, содержит длину кратчайшего пути из Vertices[I] в Vertices[J] (если
1014 путь не существует, то он равен MaxFloat); если DistancesMatrix[I, I] < 0,
1015 то вершина I входит в цикл отрицательной длины; в таком случае функция
1016 завершает работу и возвращает False; если PathsMatrix <> nil, то при
1017 успешном завершении работы она содержит информацию, позволяющую найти
1018 сами пути минимальной длины (с помощью функции DecodeMinWeightPath);
1019 граф интерпретируется как неориентированный или ориентированный в
1020 зависимости от Features;
1021 сложность алгоритма: O(VertexCount^3);
1022 примечание: как при True-, так и False-результате функция возвращает
1023 матрицу WeightMatrix, которую необходимо уничтожить после использования }
DecodeMinWeightPathnull1024 function DecodeMinWeightPath(WeightMatrix: TFloatMatrix;
1025 PathsMatrix: TIntegerMatrix; I, J: Integer;
1026 VertexIndexes: TGenericIntegerVector): Bool;
1027 { находит кратчайший путь между вершинами графа с индексами I и J на основе
1028 матриц WeightMatrix и PathsMatrix, найденных с помощью функции
1029 CreateMinWeightPathsMatrix, если путь между этими вершинами существует;
1030 в этом случае функция возвращает True, а индексы вершин, входящих в
1031 кратчайший путь (включая I и J), записываются в VertexIndexes; иначе
1032 возвращается False }
FindShortestSpanningTreenull1033 function FindShortestSpanningTree(SSTList: TClassList): Float;
1034 { находит кратчайшее остовное дерево (SST) графа (если граф несвязен, то
1035 создается лес кратчайших остовных деревьев) и возвращает суммарный вес
1036 его ребер; если SSTList <> nil, то SSTList[I] = <указатель на I-е ребро,
1037 входящее в SST> }
1038
1039 { *** геометрические графы }
1040
1041 procedure GetExtent2D(var MinX, MaxX, MinY, MaxY: Float);
1042 { возвращает минимальные и максимальные координаты вершин геометрических
1043 2D-графов }
1044 procedure GetExtent3D(var MinX, MaxX, MinY, MaxY, MinZ, MaxZ: Float);
1045 { возвращает минимальные и максимальные координаты вершин геометрических
1046 3D-графов }
1047 procedure AssignCoordinates(Source: TGraph);
1048 { присваивает координатам вершин графа Self координаты вершин графа Source;
1049 графы могут иметь разное количество вершин (в этом случае копируются
1050 координаты первых min(Self.VertexCount, Source.VertexCount) вершин);
1051 если Self является 2D-графом, а Source - 3D, то Z-координаты вершин
1052 графа Source игнорируются; если Self является 3D-графом, а Source - 2D,
1053 то Z-координаты вершин графа Self не меняются }
1054 procedure GetCoords2D(XCoords, YCoords: TFloatVector);
1055 { сохраняет X и Y координаты вершин графа в векторах XCoords и YCoords }
1056 procedure GetCoords3D(XCoords, YCoords, ZCoords: TFloatVector);
1057 { сохраняет X, Y и Z координаты вершин графа в векторах XCoords, YCoords и
1058 ZCoords }
1059 procedure SetCoords2D(XCoords, YCoords: TFloatVector);
1060 { устанавливает X и Y координаты вершин графа из векторов XCoords и YCoords }
1061 procedure SetCoords3D(XCoords, YCoords, ZCoords: TFloatVector);
1062 { устанавливает X, Y и Z координаты вершин графа из векторов XCoords,
1063 YCoords и ZCoords }
1064 end;
1065
1066 const
1067 { внутренние атрибуты (должны начинаться с '.') }
1068 { internal attributes (must begin with '.') }
1069
1070 { Все графы } { All graphs }
1071
1072 { атрибуты вершин } { vertex attributes }
1073 GAttrSeparateIndex = '.Separate';
1074
1075 { атрибуты ребер } { edge attributes }
1076 GAttrRingEdge = '.Ring';
1077
1078 { Деревья } { Trees }
1079
1080 { атрибуты графа } { graph attributes }
1081 GAttrRoot = '.Root';
1082
1083 { атрибуты вершин } { vertex attributes }
1084 GAttrHasParent = '.HasPrnt';
1085 GAttrX = '.X';
1086 GAttrY = '.Y';
1087 GAttrZ = '.Z';
1088
1089 { Сети } { Networks }
1090
1091 { атрибуты графа } { graph attributes }
1092 GAttrNetworkSource = '.NwSrc';
1093 GAttrNetworkSink = '.NwSink';
1094
1095 { атрибуты ребер } { edge attributes }
1096 GAttrMaxFlow = '.MaxFlow';
1097 GAttrFlow = '.Flow';
1098
1099 GAttrWeight = '.Weight';
1100
1101 implementation
1102
1103 { TGraphObject }
1104
1105 procedure TGraphObject.WriteToStream(VStream: TVStream);
1106 begin
1107 inherited WriteToStream(VStream);
1108 VStream.WriteProc(FStates, SizeOf(FStates));
1109 VStream.WriteProc(FTemp, SizeOf(FTemp));
1110 end;
1111
1112 procedure TGraphObject.ReadFromStream(VStream: TVStream);
1113 begin
1114 inherited ReadFromStream(VStream);
1115 VStream.ReadProc(FStates, SizeOf(FStates));
1116 VStream.ReadProc(FTemp, SizeOf(FTemp));
1117 end;
1118
1119 procedure TGraphObject.Assign(Source: TVector);
1120 begin
1121 if Source is TGraphObject then begin
1122 inherited Assign(Source);
1123 FIndex:=TGraphObject(Source).FIndex;
1124 FTemp:=TGraphObject(Source).FTemp;
1125 FStates:=TGraphObject(Source).FStates;
1126 end
1127 else
1128 Error(SIncompatibleClasses);
1129 end;
1130
1131 { TGraphElement }
1132
1133 destructor TGraphElement.Destroy;
1134 begin
1135 FLocal.Free;
1136 inherited Destroy;
1137 end;
1138
1139 procedure TGraphElement.WriteToStream(VStream: TVStream);
1140 begin
1141 inherited WriteToStream(VStream);
1142 if FLocal <> nil then begin
1143 VStream.WriteInt8(1);
1144 FLocal.WriteToStream(VStream);
1145 end
1146 else
1147 VStream.WriteInt8(0);
1148 end;
1149
1150 procedure TGraphElement.ReadFromStream(VStream: TVStream);
1151 begin
1152 inherited ReadFromStream(VStream);
1153 if VStream.ReadInt8 <> 0 then
1154 Local.ReadFromStream(VStream)
1155 else begin
1156 FLocal.Free;
1157 FLocal:=nil;
1158 end;
1159 end;
1160
TGraphElement.Comparenull1161 class function TGraphElement.Compare(Element1, Element2: Pointer): Integer;
1162 var
1163 B1, B2: Bool;
1164 Local1, Local2: TAttrSet;
1165 begin
1166 Result:=CompareUserSets(Element1, Element2);
1167 if Result = 0 then begin
1168 Local1:=TGraphElement(Element1).FLocal;
1169 Local2:=TGraphElement(Element2).FLocal;
1170 B1:=Local1 <> nil;
1171 B2:=Local2 <> nil;
1172 if B1 or B2 then
1173 if B1 = B2 then
1174 Result:=CompareUserSets(Local1, Local2)
1175 else
1176 if B1 then
1177 Result:=1
1178 else
1179 Result:=-1;
1180 end;
1181 end;
1182
1183 procedure TGraphElement.Assign(Source: TVector);
1184 begin
1185 if Source is TGraphElement then begin
1186 inherited Assign(Source);
1187 if TGraphElement(Source).FLocal <> nil then
1188 Local.Assign(TGraphElement(Source).FLocal)
1189 else begin
1190 FLocal.Free;
1191 FLocal:=nil;
1192 end;
1193 end
1194 else
1195 Error(SIncompatibleClasses);
1196 end;
1197
1198 procedure TGraphElement.Pack;
1199 begin
1200 inherited Pack;
1201 if FLocal <> nil then
1202 FLocal.Pack;
1203 end;
1204
HasLocalnull1205 function TGraphElement.HasLocal: Bool;
1206 begin
1207 Result:=FLocal <> nil;
1208 end;
1209
TGraphElement.Localnull1210 function TGraphElement.Local: TAttrSet;
1211 begin
1212 if FLocal = nil then
1213 FLocal:=TAutoAttrSet.Create;
1214 Result:=FLocal;
1215 end;
1216
1217 { TVertex }
1218
1219 constructor TVertex.Create(AGraph: TGraph);
1220 begin
1221 inherited Create(AGraph.FVertexAttrMap);
1222 FGraph:=AGraph;
1223 NeighbEdges:=TClassList.Create;
1224 AGraph.InsertVertex(Self);
1225 end;
1226
1227 destructor TVertex.Destroy;
1228 var
1229 I: Integer;
1230 T: Pointer;
1231 begin
1232 Include(FStates, gsDestroying);
1233 if not (gsDestroying in FGraph.FStates) then begin
1234 if NeighbEdges <> nil then
1235 for I:=0 to NeighbEdges.Count - 1 do begin
1236 T:=NeighbEdges[I];
1237 if T <> nil then begin
1238 if TEdge(T).IsLoop then begin { петля входит дважды! }
1239 NeighbEdges[I]:=nil;
1240 NeighbEdges[NeighbEdges.IndexOf(T)]:=nil;
1241 end;
1242 TObject(T).Free;
1243 end;
1244 end;
1245 FGraph.RemoveVertex(Self);
1246 end;
1247 NeighbEdges.Free;
1248 inherited Destroy;
1249 end;
1250
1251 procedure TVertex.Pack;
1252 begin
1253 inherited Pack;
1254 NeighbEdges.Pack;
1255 end;
1256
Degreenull1257 function TVertex.Degree: Integer;
1258 begin
1259 Result:=NeighbEdges.Count;
1260 end;
1261
GetNeighbournull1262 function TVertex.GetNeighbour(I: Integer): TVertex;
1263 begin
1264 Result:=TEdge(NeighbEdges[I]).OtherVertex(Self);
1265 end;
1266
GetIncidentEdgenull1267 function TVertex.GetIncidentEdge(I: Integer): TEdge;
1268 begin
1269 Result:=NeighbEdges[I];
1270 end;
1271
TVertex.SeparateIndexnull1272 function TVertex.SeparateIndex: Integer;
1273 begin
1274 FGraph.CheckValidSeparates;
1275 Result:=AsInt32[GAttrSeparateIndex];
1276 end;
1277
RingVertexnull1278 function TVertex.RingVertex: Bool;
1279 var
1280 I: Integer;
1281 begin
1282 for I:=0 to NeighbEdges.Count - 1 do
1283 if TEdge(NeighbEdges[I]).RingEdge then begin
1284 Result:=True;
1285 Exit;
1286 end;
1287 Result:=False;
1288 end;
1289
1290 procedure TVertex.SortIncidentEdges(CompareEdges: TCompareFunc);
1291 begin
1292 NeighbEdges.SortBy(CompareEdges);
1293 end;
1294
1295 procedure TVertex.SortIncidentEdgesByObject(CompareEdges: TCompareEvent);
1296 begin
1297 NeighbEdges.SortByObject(CompareEdges);
1298 end;
1299
1300 { *** орграфы }
1301
InDegreenull1302 function TVertex.InDegree: Integer;
1303 var
1304 I: Integer;
1305 begin
1306 {$IFDEF CHECK_GRAPHS}
1307 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1308 {$ENDIF}
1309 Result:=0;
1310 for I:=0 to NeighbEdges.Count - 1 do
1311 if TEdge(NeighbEdges[I]).V2 = Self then
1312 Inc(Result);
1313 end;
1314
TVertex.OutDegreenull1315 function TVertex.OutDegree: Integer;
1316 var
1317 I: Integer;
1318 begin
1319 {$IFDEF CHECK_GRAPHS}
1320 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1321 {$ENDIF}
1322 Result:=0;
1323 for I:=0 to NeighbEdges.Count - 1 do
1324 if TEdge(NeighbEdges[I]).V1 = Self then
1325 Inc(Result);
1326 end;
1327
1328 procedure TVertex.GetInOutDegree(var VertexInDegree, VertexOutDegree: Integer);
1329 var
1330 I: Integer;
1331 begin
1332 {$IFDEF CHECK_GRAPHS}
1333 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1334 {$ENDIF}
1335 VertexInDegree:=0;
1336 VertexOutDegree:=0;
1337 for I:=0 to NeighbEdges.Count - 1 do
1338 if TEdge(NeighbEdges[I]).V1 = Self then
1339 Inc(VertexOutDegree)
1340 else
1341 Inc(VertexInDegree);
1342 end;
1343
1344 {$IFDEF NOWARN}{$WARNINGS OFF}{$ENDIF}
GetInNeighbournull1345 function TVertex.GetInNeighbour(I: Integer): TVertex;
1346 var
1347 J, K: Integer;
1348 begin
1349 {$IFDEF CHECK_GRAPHS}
1350 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1351 {$ENDIF}
1352 K:=0;
1353 for J:=0 to NeighbEdges.Count - 1 do
1354 if TEdge(NeighbEdges[J]).V2 = Self then begin
1355 if K = I then begin
1356 Result:=TEdge(NeighbEdges[J]).V1;
1357 Exit;
1358 end;
1359 Inc(K);
1360 end;
1361 ErrorFmt(SArcNotFound_d, [I]);
1362 end;
1363
GetOutNeighbournull1364 function TVertex.GetOutNeighbour(I: Integer): TVertex;
1365 var
1366 J, K: Integer;
1367 begin
1368 {$IFDEF CHECK_GRAPHS}
1369 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1370 {$ENDIF}
1371 K:=0;
1372 for J:=0 to NeighbEdges.Count - 1 do
1373 if TEdge(NeighbEdges[J]).V1 = Self then begin
1374 if K = I then begin
1375 Result:=TEdge(NeighbEdges[J]).V2;
1376 Exit;
1377 end;
1378 Inc(K);
1379 end;
1380 ErrorFmt(SArcNotFound_d, [I]);
1381 end;
1382
GetInArcnull1383 function TVertex.GetInArc(I: Integer): TEdge;
1384 var
1385 J, K: Integer;
1386 begin
1387 {$IFDEF CHECK_GRAPHS}
1388 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1389 {$ENDIF}
1390 K:=0;
1391 for J:=0 to NeighbEdges.Count - 1 do begin
1392 Result:=NeighbEdges[J];
1393 if Result.V2 = Self then begin
1394 if K = I then
1395 Exit;
1396 Inc(K);
1397 end;
1398 end;
1399 ErrorFmt(SVertexNotFound_d, [I]);
1400 end;
1401
GetOutArcnull1402 function TVertex.GetOutArc(I: Integer): TEdge;
1403 var
1404 J, K: Integer;
1405 begin
1406 {$IFDEF CHECK_GRAPHS}
1407 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1408 {$ENDIF}
1409 K:=0;
1410 for J:=0 to NeighbEdges.Count - 1 do begin
1411 Result:=NeighbEdges[J];
1412 if Result.V1 = Self then begin
1413 if K = I then
1414 Exit;
1415 Inc(K);
1416 end;
1417 end;
1418 ErrorFmt(SVertexNotFound_d, [I]);
1419 end;
1420 {$IFDEF NOWARN}{$WARNINGS ON}{$ENDIF}
1421
1422 { *** деревья }
1423
GetIsRootnull1424 function TVertex.GetIsRoot: Bool;
1425 begin
1426 {$IFDEF CHECK_GRAPHS}
1427 if not (Tree in Graph.Features) then Error(SMethodNotApplicable);
1428 {$ENDIF}
1429 Result:=TVertex(Graph.AsPointer[GAttrRoot]) = Self;
1430 end;
1431
1432 procedure TVertex.SetIsRoot(Value: Bool);
1433 var
1434 I: Integer;
1435 OldRoot: TVertex;
1436 begin
1437 {$IFDEF CHECK_GRAPHS}
1438 if not (Tree in Graph.Features) then Error(SMethodNotApplicable);
1439 {$ENDIF}
1440 OldRoot:=Graph.AsPointer[GAttrRoot];
1441 if Value then begin
1442 Graph.AsPointer[GAttrRoot]:=Self;
1443 AsBool[GAttrHasParent]:=False;
1444 for I:=0 to NeighbEdges.Count - 1 do Neighbour[I].Parent:=Self;
1445 end
1446 else
1447 if OldRoot = Self then
1448 FGraph.AsPointer[GAttrRoot]:=nil;
1449 end;
1450
GetParentnull1451 function TVertex.GetParent: TVertex;
1452 begin
1453 {$IFDEF CHECK_GRAPHS}
1454 if not (Tree in Graph.Features) then Error(SMethodNotApplicable);
1455 {$ENDIF}
1456 if AsBool[GAttrHasParent] and (NeighbEdges.Count > 0) then
1457 Result:=Neighbour[0]
1458 else
1459 Result:=nil;
1460 end;
1461
1462 procedure TVertex.SafeSetParent(Value: TVertex);
1463 var
1464 I: Integer;
1465 E: TEdge;
1466 begin
1467 if Value <> nil then begin
1468 E:=FGraph.GetEdge(Value, Self);
1469 if E = nil then begin
1470 I:=NeighbEdges.Count;
1471 FGraph.AddEdge(Value, Self);
1472 end
1473 else
1474 I:=NeighbEdges.IndexOf(E);
1475 NeighbEdges.Move(I, 0);
1476 AsBool[GAttrHasParent]:=True;
1477 end
1478 else
1479 AsBool[GAttrHasParent]:=False;
1480 end;
1481
1482 procedure TVertex.SetParent(Value: TVertex);
1483 var
1484 V: TVertex;
1485 begin
1486 if not IsRoot then begin
1487 V:=GetParent;
1488 if Value <> V then begin
1489 FGraph.GetEdge(V, Self).Free;
1490 SafeSetParent(Value);
1491 end;
1492 end
1493 else begin
1494 if FGraph.GetEdge(Self, Value) = nil then
1495 Graph.AddEdge(Value, Self);
1496 Value.IsRoot:=True;
1497 end;
1498 end;
1499
AddChildnull1500 function TVertex.AddChild: TVertex;
1501 begin
1502 {$IFDEF CHECK_GRAPHS}
1503 if not (Tree in Graph.Features) then Error(SMethodNotApplicable);
1504 {$ENDIF}
1505 Result:=Graph.AddVertex;
1506 Result.SafeSetParent(Self);
1507 end;
1508
TVertex.ChildCountnull1509 function TVertex.ChildCount: Integer;
1510 begin
1511 {$IFDEF CHECK_GRAPHS}
1512 if not (Tree in Graph.Features) then Error(SMethodNotApplicable);
1513 {$ENDIF}
1514 Result:=NeighbEdges.Count;
1515 if AsBool[GAttrHasParent] then
1516 Dec(Result);
1517 end;
1518
TVertex.GetChildnull1519 function TVertex.GetChild(I: Integer): TVertex;
1520 begin
1521 {$IFDEF CHECK_GRAPHS}
1522 if not (Tree in Graph.Features) then Error(SMethodNotApplicable);
1523 {$ENDIF}
1524 if AsBool[GAttrHasParent] then
1525 Inc(I);
1526 Result:=Neighbour[I];
1527 end;
1528
IsAncestorOfnull1529 function TVertex.IsAncestorOf(V: TVertex): Bool;
1530 begin
1531 if V <> Self then
1532 repeat
1533 V:=V.Parent;
1534 if V = nil then begin
1535 Result:=False;
1536 Exit;
1537 end
1538 until V = Self;
1539 Result:=True;
1540 end;
1541
1542 procedure TVertex.SortChilds(CompareVertices: TCompareEvent);
1543 var
1544 I, J: Integer;
1545 ChildNeighbours, Edges: TClassList;
1546 begin
1547 if ChildCount = 0 then
1548 Exit; { ChildCount проверяет, что граф - дерево }
1549 ChildNeighbours:=TClassList.Create;
1550 Edges:=TClassList.Create;
1551 try
1552 Edges.Assign(NeighbEdges);
1553 J:=0;
1554 if AsBool[GAttrHasParent] then begin
1555 Inc(J);
1556 Edges.Delete(0);
1557 ChildNeighbours.Count:=NeighbEdges.Count - 1;
1558 end
1559 else
1560 ChildNeighbours.Count:=NeighbEdges.Count;
1561 for I:=0 to ChildNeighbours.Count - 1 do begin
1562 ChildNeighbours[I]:=TEdge(NeighbEdges[J]).OtherVertex(Self);
1563 Inc(J);
1564 end;
1565 ChildNeighbours.SortByObjectWith(CompareVertices, Edges);
1566 J:=0;
1567 if AsBool[GAttrHasParent] then
1568 Inc(J);
1569 for I:=0 to Edges.Count - 1 do begin
1570 NeighbEdges[J]:=Edges[I];
1571 Inc(J);
1572 end;
1573 finally
1574 ChildNeighbours.Free;
1575 Edges.Free;
1576 end;
1577 end;
1578
1579 { *** транспортные сети }
1580
GetIsSourcenull1581 function TVertex.GetIsSource: Bool;
1582 begin
1583 {$IFDEF CHECK_GRAPHS}
1584 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1585 {$ENDIF}
1586 Result:=TVertex(Graph.AsPointer[GAttrNetworkSource]) = Self;
1587 end;
1588
1589 procedure TVertex.SetIsSource(Value: Bool);
1590 begin
1591 {$IFDEF CHECK_GRAPHS}
1592 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1593 {$ENDIF}
1594 if Value then
1595 FGraph.AsPointer[GAttrNetworkSource]:=Self
1596 else
1597 if FGraph.AsPointer[GAttrNetworkSource] = Self then
1598 Graph.AsPointer[GAttrNetworkSource]:=nil;
1599 end;
1600
GetIsSinknull1601 function TVertex.GetIsSink: Bool;
1602 begin
1603 {$IFDEF CHECK_GRAPHS}
1604 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1605 {$ENDIF}
1606 Result:=TVertex(Graph.AsPointer[GAttrNetworkSink]) = Self
1607 end;
1608
1609 procedure TVertex.SetIsSink(Value: Bool);
1610 begin
1611 {$IFDEF CHECK_GRAPHS}
1612 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1613 {$ENDIF}
1614 if Value then
1615 FGraph.AsPointer[GAttrNetworkSink]:=Self
1616 else
1617 if Graph.AsPointer[GAttrNetworkSink] = Self then
1618 Graph.AsPointer[GAttrNetworkSink]:=nil;
1619 end;
1620
1621 { *** геометрические графы }
1622
GetXnull1623 function TVertex.GetX: Float;
1624 begin
1625 {$IFDEF CHECK_GRAPHS}
1626 if not (Geom2D in Graph.Features) then Error(SMethodNotApplicable);
1627 {$ENDIF}
1628 Result:=AsFloat[GAttrX];
1629 end;
1630
1631 procedure TVertex.SetX(Value: Float);
1632 begin
1633 {$IFDEF CHECK_GRAPHS}
1634 if not (Geom2D in Graph.Features) then Error(SMethodNotApplicable);
1635 {$ENDIF}
1636 AsFloat[GAttrX]:=Value;
1637 end;
1638
GetYnull1639 function TVertex.GetY: Float;
1640 begin
1641 {$IFDEF CHECK_GRAPHS}
1642 if not (Geom2D in Graph.Features) then Error(SMethodNotApplicable);
1643 {$ENDIF}
1644 Result:=AsFloat[GAttrY];
1645 end;
1646
1647 procedure TVertex.SetY(Value: Float);
1648 begin
1649 {$IFDEF CHECK_GRAPHS}
1650 if not (Geom2D in Graph.Features) then Error(SMethodNotApplicable);
1651 {$ENDIF}
1652 AsFloat[GAttrY]:=Value;
1653 end;
1654
TVertex.GetZnull1655 function TVertex.GetZ: Float;
1656 begin
1657 {$IFDEF CHECK_GRAPHS}
1658 if not (Geom3D in Graph.Features) then Error(SMethodNotApplicable);
1659 {$ENDIF}
1660 Result:=AsFloat[GAttrZ];
1661 end;
1662
1663 procedure TVertex.SetZ(Value: Float);
1664 begin
1665 {$IFDEF CHECK_GRAPHS}
1666 if not (Geom3D in Graph.Features) then Error(SMethodNotApplicable);
1667 {$ENDIF}
1668 AsFloat[GAttrZ]:=Value;
1669 end;
1670
1671 { TEdge }
1672
1673 constructor TEdge.Create(AGraph: TGraph; FromVertex, ToVertex: TVertex);
1674 begin
1675 inherited Create(AGraph.FEdgeAttrMap);
1676 {$IFDEF CHECK_GRAPHS}
1677 if AGraph.FVertices.IndexOf(FromVertex) < 0 then
1678 ErrorFmt(SVertexNotFound_d, [FromVertex]);
1679 if AGraph.FVertices.IndexOf(ToVertex) < 0 then
1680 ErrorFmt(SVertexNotFound_d, [ToVertex]);
1681 {$ENDIF}
1682 FGraph:=AGraph;
1683 FV1:=FromVertex;
1684 FV2:=ToVertex;
1685 V1.NeighbEdges.Add(Self);
1686 V2.NeighbEdges.Add(Self);
1687 AGraph.InsertEdge(AGraph.FEdges.Count, Self);
1688 end;
1689
TEdge.RemoveFromNeighbEdgesnull1690 function TEdge.RemoveFromNeighbEdges(V: TVertex): Integer;
1691 begin
1692 Result:=V.NeighbEdges.IndexOf(Self);
1693 V.NeighbEdges.Delete(Result);
1694 end;
1695
1696 destructor TEdge.Destroy;
1697 begin
1698 if Graph <> nil then begin
1699 Include(FStates, gsDestroying);
1700 if not (gsDestroying in Graph.FStates) then begin
1701 if Tree in Graph.FFeatures then
1702 if V1.AsBool[GAttrHasParent] and (V1.NeighbEdges[0] = Self) then
1703 V1.AsBool[GAttrHasParent]:=False
1704 else
1705 if V2.AsBool[GAttrHasParent] and (V2.NeighbEdges[0] = Self) then
1706 V2.AsBool[GAttrHasParent]:=False;
1707 if (V1 <> nil) and not (gsDestroying in V1.FStates) then
1708 RemoveFromNeighbEdges(V1);
1709 if (V2 <> nil) and not (gsDestroying in V2.FStates) then
1710 RemoveFromNeighbEdges(V2);
1711 Graph.RemoveEdge(Self);
1712 end;
1713 end;
1714 inherited Destroy;
1715 end;
1716
1717 type
1718 PRestoreInfo = ^TRestoreInfo;
1719 TRestoreInfo = record
1720 SaveGraph: TGraph;
1721 V1Index, V2Index: Integer;
1722 end;
1723
TEdge.Hiddennull1724 function TEdge.Hidden: Bool;
1725 begin
1726 Result:=FGraph = nil;
1727 end;
1728
1729 procedure TEdge.Hide;
1730 var
1731 RestoreInfo: PRestoreInfo;
1732 begin
1733 {$IFDEF CHECK_GRAPHS}
1734 if Hidden then Error(SMethodNotApplicable);
1735 {$ENDIF}
1736 New(RestoreInfo);
1737 With RestoreInfo^ do begin
1738 SaveGraph:=FGraph;
1739 V1Index:=RemoveFromNeighbEdges(V1);
1740 V2Index:=RemoveFromNeighbEdges(V2);
1741 end;
1742 FGraph.RemoveEdge(Self);
1743 FGraph:=nil;
1744 FTemp.AsPointer:=RestoreInfo;
1745 end;
1746
1747 procedure TEdge.Restore;
1748 begin
1749 {$IFDEF CHECK_GRAPHS}
1750 if not Hidden then Error(SMethodNotApplicable);
1751 {$ENDIF}
1752 With PRestoreInfo(FTemp.AsPointer)^ do begin
1753 FGraph:=SaveGraph;
1754 FGraph.InsertEdge(Index, Self);
1755 V1.NeighbEdges.Insert(V1Index, Self);
1756 V2.NeighbEdges.Insert(V2Index, Self);
1757 end;
1758 Dispose(PRestoreInfo(FTemp.AsPointer));
1759 end;
1760
EdgeVerticesnull1761 function TEdge.EdgeVertices(Vertex1, Vertex2: TVertex): Bool;
1762 begin
1763 Result:=(V1 = Vertex1) and (V2 = Vertex2) or (V1 = Vertex2) and (V2 = Vertex1);
1764 end;
1765
TEdge.IncidentToVertexnull1766 function TEdge.IncidentToVertex(Vertex: TVertex): Bool;
1767 begin
1768 Result:=(V1 = Vertex) or (V2 = Vertex);
1769 end;
1770
IncidentToEdgeUndirectednull1771 function TEdge.IncidentToEdgeUndirected(Edge: TEdge): Bool;
1772 begin
1773 Result:=(V1 = Edge.V1) or (V2 = Edge.V1) or (V1 = Edge.V2) or (V2 = Edge.V2);
1774 end;
1775
TEdge.IncidentToEdgeDirectednull1776 function TEdge.IncidentToEdgeDirected(Edge: TEdge): Bool;
1777 begin
1778 Result:=(V2 = Edge.V1) or (V1 = Edge.V2);
1779 end;
1780
IncidentToEdgenull1781 function TEdge.IncidentToEdge(Edge: TEdge): Bool;
1782 begin
1783 if Directed in Graph.Features then
1784 Result:=IncidentToEdgeDirected(Edge)
1785 else
1786 Result:=IncidentToEdgeUndirected(Edge);
1787 end;
1788
TEdge.ParallelToEdgeUndirectednull1789 function TEdge.ParallelToEdgeUndirected(Edge: TEdge): Bool;
1790 begin
1791 Result:=(V1 = Edge.V1) and (V2 = Edge.V2) or (V1 = Edge.V2) and (V2 = Edge.V1);
1792 end;
1793
ParallelToEdgeDirectednull1794 function TEdge.ParallelToEdgeDirected(Edge: TEdge): Bool;
1795 begin
1796 Result:=(V1 = Edge.V1) and (V2 = Edge.V2);
1797 end;
1798
ParallelToEdgenull1799 function TEdge.ParallelToEdge(Edge: TEdge): Bool;
1800 begin
1801 Result:=(V1 = Edge.V1) and (V2 = Edge.V2) or
1802 not (Directed in Graph.Features) and (V1 = Edge.V2) and (V2 = Edge.V1);
1803 end;
1804
TEdge.OtherVertexnull1805 function TEdge.OtherVertex(Vertex: TVertex): TVertex;
1806 begin
1807 if Vertex = V1 then
1808 Result:=V2
1809 else
1810 if Vertex = V2 then
1811 Result:=V1
1812 else
1813 Result:=nil;
1814 end;
1815
IsLoopnull1816 function TEdge.IsLoop: Bool;
1817 begin
1818 Result:=V1 = V2;
1819 end;
1820
RingEdgenull1821 function TEdge.RingEdge: Bool;
1822 begin
1823 if (V1.NeighbEdges.Count = 1) or (V2.NeighbEdges.Count = 1) then
1824 Result:=False { рассматриваем особый случай для повышения эффективности }
1825 else begin
1826 Graph.CheckValidRingEdges;
1827 Result:=AsBool[GAttrRingEdge];
1828 end;
1829 end;
1830
1831 { *** транспортные сети }
1832
GetMaxFlownull1833 function TEdge.GetMaxFlow: Float;
1834 begin
1835 {$IFDEF CHECK_GRAPHS}
1836 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1837 {$ENDIF}
1838 Result:=AsFloat[GAttrMaxFlow];
1839 end;
1840
1841 procedure TEdge.SetMaxFlow(Value: Float);
1842 begin
1843 {$IFDEF CHECK_GRAPHS}
1844 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1845 {$ENDIF}
1846 if Value < 0 then
1847 Error(SNegativeNetworkFlow);
1848 AsFloat[GAttrMaxFlow]:=Value;
1849 end;
1850
TEdge.GetFlownull1851 function TEdge.GetFlow: Float;
1852 begin
1853 {$IFDEF CHECK_GRAPHS}
1854 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1855 {$ENDIF}
1856 Result:=AsFloat[GAttrFlow];
1857 end;
1858
1859 procedure TEdge.SetFlow(Value: Float);
1860 begin
1861 {$IFDEF CHECK_GRAPHS}
1862 if not (Network in Graph.Features) then Error(SMethodNotApplicable);
1863 {$ENDIF}
1864 if Value < 0 then
1865 Error(SNegativeNetworkFlow);
1866 AsFloat[GAttrFlow]:=Value;
1867 end;
1868
1869 { *** взвешенные графы }
1870
GetWeightnull1871 function TEdge.GetWeight: Float;
1872 begin
1873 {$IFDEF CHECK_GRAPHS}
1874 if not (Weighted in Graph.Features) then Error(SMethodNotApplicable);
1875 {$ENDIF}
1876 Result:=AsFloat[GAttrWeight];
1877 end;
1878
1879 procedure TEdge.SetWeight(Value: Float);
1880 begin
1881 {$IFDEF CHECK_GRAPHS}
1882 if not (Weighted in Graph.Features) then Error(SMethodNotApplicable);
1883 {$ENDIF}
1884 AsFloat[GAttrWeight]:=Value;
1885 end;
1886
1887 { *** орграфы }
1888
1889 procedure TEdge.ChangeDirection;
1890 var
1891 V: TVertex;
1892 begin
1893 {$IFDEF CHECK_GRAPHS}
1894 if not (Directed in Graph.Features) then Error(SMethodNotApplicable);
1895 {$ENDIF}
1896 V:=FV1; FV1:=FV2; FV2:=V;
1897 end;
1898
1899 { TGraph }
1900
1901 constructor TGraph.Create;
1902 begin
1903 inherited Create(TAttrMap.Create);
1904 FVertices:=TClassList.Create;
1905 FEdges:=TClassList.Create;
1906 FVertexAttrMap:=TAttrMap.Create;
1907 FEdgeAttrMap:=TAttrMap.Create;
1908 end;
1909
1910 procedure TGraph.FreeElements;
1911 var
1912 I: Integer;
1913 begin
1914 Include(FStates, gsDestroying);
1915 for I:=0 to FEdges.Count - 1 do TObject(FEdges[I]).Free;
1916 for I:=0 to FVertices.Count - 1 do TObject(FVertices[I]).Free;
1917 end;
1918
1919 destructor TGraph.Destroy;
1920 var
1921 LocalMap: TAttrMap;
1922 begin
1923 FreeElements;
1924 FEdges.Free;
1925 FVertices.Free;
1926 FVertexAttrMap.Free;
1927 FEdgeAttrMap.Free;
1928 LocalMap:=Map;
1929 inherited Destroy;
1930 LocalMap.Free;
1931 end;
1932
1933 procedure TGraph.SetStates(NewStates: TGraphObjectStates);
1934 var
1935 B: Bool;
1936 begin
1937 B:=gsValidSeparates in FStates;
1938 if B xor (gsValidSeparates in NewStates) then
1939 if B then
1940 SafeDropVertexAttr(GAttrSeparateIndex)
1941 else
1942 SafeCreateVertexAttr(GAttrSeparateIndex, AttrInt32);
1943 B:=gsValidRingEdges in FStates;
1944 if B xor (gsValidRingEdges in NewStates) then
1945 if B then
1946 SafeDropEdgeAttr(GAttrRingEdge)
1947 else
1948 SafeCreateEdgeAttr(GAttrRingEdge, AttrBool);
1949 FStates:=NewStates;
1950 end;
1951
1952 procedure TGraph.WriteToStream(VStream: TVStream);
1953 var
1954 I, N: Integer;
1955 E: TEdge;
1956
1957 procedure WriteIndex(V: TVertex);
1958 var
1959 I: Integer;
1960 begin
1961 if V <> nil then
1962 I:=V.Index
1963 else
1964 I:=-1;
1965 VStream.WriteInt32(I);
1966 end;
1967
1968 begin
1969 FMap.WriteToStream(VStream);
1970 FVertexAttrMap.WriteToStream(VStream);
1971 FEdgeAttrMap.WriteToStream(VStream);
1972 inherited WriteToStream(VStream);
1973 VStream.WriteProc(FFeatures, SizeOf(FFeatures));
1974 VStream.WriteProc(FConnected, SizeOf(FFeatures));
1975 VStream.WriteProc(FSeparateCount, SizeOf(FFeatures));
1976 VStream.WriteProc(FRingEdgeCount, SizeOf(FFeatures));
1977 N:=FVertices.Count;
1978 VStream.WriteInt32(N);
1979 for I:=0 to N - 1 do TVertex(FVertices[I]).WriteToStream(VStream);
1980 N:=FEdges.Count;
1981 VStream.WriteInt32(N);
1982 for I:=0 to N - 1 do begin
1983 E:=FEdges[I];
1984 WriteIndex(E.V1);
1985 WriteIndex(E.V2);
1986 E.WriteToStream(VStream);
1987 end;
1988 if Tree in FFeatures then
1989 WriteIndex(Root);
1990 if Network in FFeatures then begin
1991 WriteIndex(NetworkSource);
1992 WriteIndex(NetworkSink);
1993 end;
1994 end;
1995
1996 procedure TGraph.ReadFromStream(VStream: TVStream);
1997 var
1998 I, N, M: Integer;
1999
ReadVertexnull2000 function ReadVertex: TVertex;
2001 var
2002 K: Integer;
2003 begin
2004 K:=VStream.ReadInt32;
2005 if K <> -1 then
2006 Result:=FVertices[K]
2007 else
2008 Result:=nil;
2009 end;
2010
2011 begin
2012 Clear;
2013 FMap.ReadFromStream(VStream);
2014 FVertexAttrMap.ReadFromStream(VStream);
2015 FEdgeAttrMap.ReadFromStream(VStream);
2016 inherited ReadFromStream(VStream);
2017 VStream.ReadProc(FFeatures, SizeOf(FFeatures));
2018 VStream.ReadProc(FConnected, SizeOf(FFeatures));
2019 VStream.ReadProc(FSeparateCount, SizeOf(FFeatures));
2020 VStream.ReadProc(FRingEdgeCount, SizeOf(FFeatures));
2021 N:=VStream.ReadInt32;
2022 AddVertices(N);
2023 for I:=0 to N - 1 do TVertex(FVertices[I]).ReadFromStream(VStream);
2024 for I:=0 to VStream.ReadInt32 - 1 do begin
2025 N:=VStream.ReadInt32;
2026 M:=VStream.ReadInt32;
2027 AddEdgeI(N, M).ReadFromStream(VStream);
2028 end;
2029 if Tree in FFeatures then
2030 Root:=ReadVertex;
2031 if Network in FFeatures then begin
2032 NetworkSource:=ReadVertex;
2033 NetworkSink:=ReadVertex;
2034 end;
2035 end;
2036
2037 procedure TGraph.Assign(Source: TVector);
2038 var
2039 I: Integer;
2040 V: TVertex;
2041 E: TEdge;
2042 begin
2043 if Source is TGraph then begin
2044 Clear;
2045 FMap.Assign(TGraph(Source).FMap);
2046 FVertexAttrMap.Assign(TGraph(Source).FVertexAttrMap);
2047 FEdgeAttrMap.Assign(TGraph(Source).FEdgeAttrMap);
2048 for I:=0 to TGraph(Source).FVertices.Count - 1 do
2049 AddVertex.Assign(TGraph(Source).FVertices[I]);
2050 for I:=0 to TGraph(Source).FEdges.Count - 1 do begin
2051 E:=TGraph(Source).FEdges[I];
2052 AddEdgeI(E.V1.Index, E.V2.Index).Assign(E);
2053 end;
2054 inherited Assign(Source);
2055 FConnected:=TGraph(Source).FConnected;
2056 FSeparateCount:=TGraph(Source).FSeparateCount;
2057 FRingEdgeCount:=TGraph(Source).FRingEdgeCount;
2058 SetFeatures(TGraph(Source).FFeatures);
2059 if Tree in FFeatures then begin
2060 V:=TGraph(Source).Root;
2061 if V <> nil then
2062 SetRoot(FVertices[V.Index]);
2063 end;
2064 if Network in FFeatures then begin
2065 V:=TGraph(Source).NetworkSource;
2066 if V <> nil then
2067 SetNetworkSource(FVertices[V.Index]);
2068 V:=TGraph(Source).NetworkSink;
2069 if V <> nil then
2070 SetNetworkSink(FVertices[V.Index]);
2071 end;
2072 end
2073 else
2074 Error(SIncompatibleClasses);
2075 end;
2076
2077 procedure TGraph.AssignSceleton(Source: TGraph);
2078 var
2079 I: Integer;
2080 E: TEdge;
2081 begin
2082 Clear;
2083 AddVertices(Source.FVertices.Count);
2084 for I:=0 to TGraph(Source).FEdges.Count - 1 do begin
2085 E:=Source.FEdges[I];
2086 AddEdgeI(E.V1.Index, E.V2.Index);
2087 end;
2088 end;
2089
2090 procedure TGraph.AssignSimpleSceleton(Source: TGraph);
2091 var
2092 I, I1, I2: Integer;
2093 E: TEdge;
2094 begin
2095 Clear;
2096 AddVertices(Source.FVertices.Count);
2097 for I:=0 to TGraph(Source).FEdges.Count - 1 do begin
2098 E:=Source.FEdges[I];
2099 I1:=E.V1.Index;
2100 I2:=E.V2.Index;
2101 if (I1 <> I2) and (GetEdgeI(I1, I2) = nil) then
2102 AddEdgeI(I1, I2);
2103 end;
2104 end;
2105
2106 procedure TGraph.Pack;
2107 var
2108 I: Integer;
2109 begin
2110 inherited Pack;
2111 FVertices.Pack;
2112 FEdges.Pack;
2113 for I:=0 to FVertices.Count - 1 do TVertex(FVertices[I]).Pack;
2114 for I:=0 to FEdges.Count - 1 do TEdge(FEdges[I]).Pack;
2115 end;
2116
2117 procedure TGraph.Clear;
2118 begin
2119 FreeElements;
2120 Exclude(FStates, gsDestroying);
2121 FEdges.Clear;
2122 FVertices.Clear;
2123 States:=[];
2124 end;
2125
2126 procedure TGraph.ClearEdges;
2127 begin
2128 while FEdges.Count > 0 do TEdge(FEdges[0]).Free;
2129 end;
2130
2131 procedure TGraph.InsertVertex(Vertex: TVertex);
2132 begin
2133 Vertex.FIndex:=FVertices.Add(Vertex);
2134 States:=States - [gsValidConnected, gsValidSeparates];
2135 end;
2136
2137 procedure TGraph.RemoveVertex(Vertex: TVertex);
2138
2139 procedure CheckDropAttr(const AttrName: String);
2140 begin
2141 if AsPointer[AttrName] = Vertex then
2142 Map.SafeDropAttr(AttrName);
2143 end;
2144
2145 var
2146 I: Integer;
2147 begin
2148 if Tree in Features then
2149 CheckDropAttr(GAttrRoot);
2150 if Network in Features then begin
2151 CheckDropAttr(GAttrNetworkSource);
2152 CheckDropAttr(GAttrNetworkSink);
2153 end;
2154 FVertices.Delete(Vertex.Index);
2155 if not (gsDestroying in FStates) then begin
2156 for I:=Vertex.Index to FVertices.Count - 1 do
2157 Dec(TVertex(FVertices[I]).FIndex);
2158 States:=States - [gsValidConnected, gsValidSeparates];
2159 end;
2160 end;
2161
2162 procedure TGraph.InsertEdge(Index: Integer; Edge: TEdge);
2163 var
2164 I: Integer;
2165 begin
2166 FEdges.Insert(Index, Edge);
2167 Edge.FIndex:=Index;
2168 for I:=Index + 1 to FEdges.Count - 1 do
2169 Inc(TEdge(FEdges[I]).FIndex);
2170 States:=States - [gsValidConnected, gsValidSeparates, gsValidRingEdges];
2171 end;
2172
2173 procedure TGraph.RemoveEdge(Edge: TEdge);
2174 var
2175 I: Integer;
2176 begin
2177 FEdges.Delete(Edge.Index);
2178 if not (gsDestroying in FStates) then begin
2179 for I:=Edge.Index to FEdges.Count - 1 do
2180 Dec(TEdge(FEdges[I]).FIndex);
2181 States:=States - [gsValidConnected, gsValidSeparates, gsValidRingEdges];
2182 { удаляем кольцевое ребро => другие могут стать некольцевыми;
2183 удаляем некольцевое ребро => граф перестанет быть связным }
2184 end;
2185 end;
2186
2187 procedure TGraph.SetToZero(List: TClassList; Offset: Integer; AType: TAttrType);
2188 var
2189 I: Integer;
2190 ASet: TAttrSet;
2191 begin
2192 for I:=0 to List.Count - 1 do begin
2193 ASet:=TAttrSet(List[I]);
2194 if Offset < ASet.Count then
2195 FillChar(ASet.Memory^.Int8Array[Offset], AttrSizes[AType], 0);
2196 end;
2197 end;
2198
CreateVertexAttrnull2199 function TGraph.CreateVertexAttr(const Name: String; AType: TAttrType): Integer;
2200 begin
2201 {$IFDEF CHECK_GRAPHS}
2202 if (Name <> '') and (Name[1] = '.') then Error(SAttrPrefixReserved);
2203 {$ENDIF}
2204 Result:=FVertexAttrMap.CreateAttr(Name, AType);
2205 SetToZero(FVertices, Result, AType);
2206 end;
2207
CreateEdgeAttrnull2208 function TGraph.CreateEdgeAttr(const Name: String; AType: TAttrType): Integer;
2209 begin
2210 {$IFDEF CHECK_GRAPHS}
2211 if (Name <> '') and (Name[1] = '.') then Error(SAttrPrefixReserved);
2212 {$ENDIF}
2213 Result:=FEdgeAttrMap.CreateAttr(Name, AType);
2214 SetToZero(FEdges, Result, AType);
2215 end;
2216
2217 procedure TGraph.DropVertexAttr(const Name: String);
2218 begin
2219 FVertexAttrMap.DropAttr(Name);
2220 end;
2221
2222 procedure TGraph.DropEdgeAttr(const Name: String);
2223 begin
2224 FEdgeAttrMap.DropAttr(Name);
2225 end;
2226
TGraph.SafeCreateVertexAttrnull2227 function TGraph.SafeCreateVertexAttr(const Name: String; AType: TAttrType): Integer;
2228 begin
2229 Result:=FVertexAttrMap.SafeCreateAttr(Name, AType);
2230 if Result >= 0 then
2231 SetToZero(FVertices, Result, AType);
2232 end;
2233
2234 procedure TGraph.SafeDropVertexAttr(const Name: String);
2235 begin
2236 FVertexAttrMap.SafeDropAttr(Name);
2237 end;
2238
SafeCreateEdgeAttrnull2239 function TGraph.SafeCreateEdgeAttr(const Name: String; AType: TAttrType): Integer;
2240 begin
2241 Result:=FEdgeAttrMap.SafeCreateAttr(Name, AType);
2242 if Result >= 0 then
2243 SetToZero(FEdges, Result, AType);
2244 end;
2245
2246 procedure TGraph.SafeDropEdgeAttr(const Name: String);
2247 begin
2248 FEdgeAttrMap.SafeDropAttr(Name);
2249 end;
2250
VertexAttrTypenull2251 function TGraph.VertexAttrType(const Name: String): TExtAttrType;
2252 begin
2253 Result:=FVertexAttrMap.GetType(Name);
2254 end;
2255
TGraph.EdgeAttrTypenull2256 function TGraph.EdgeAttrType(const Name: String): TExtAttrType;
2257 begin
2258 Result:=FEdgeAttrMap.GetType(Name);
2259 end;
2260
VertexAttrOffsetnull2261 function TGraph.VertexAttrOffset(const Name: String): Integer;
2262 begin
2263 Result:=FVertexAttrMap.Offset(Name);
2264 end;
2265
TGraph.EdgeAttrOffsetnull2266 function TGraph.EdgeAttrOffset(const Name: String): Integer;
2267 begin
2268 Result:=FEdgeAttrMap.Offset(Name);
2269 end;
2270
VertexCountnull2271 function TGraph.VertexCount: Integer;
2272 begin
2273 Result:=FVertices.Count;
2274 end;
2275
TGraph.EdgeCountnull2276 function TGraph.EdgeCount: Integer;
2277 begin
2278 Result:=FEdges.Count;
2279 end;
2280
GetVertexnull2281 function TGraph.GetVertex(I: Integer): TVertex;
2282 begin
2283 Result:=TVertex(FVertices[I]);
2284 end;
2285
TGraph.GetEdgeByIndexnull2286 function TGraph.GetEdgeByIndex(I: Integer): TEdge;
2287 begin
2288 Result:=FEdges[I];
2289 end;
2290
AddVertexnull2291 function TGraph.AddVertex: TVertex;
2292 begin
2293 Result:=TVertex.Create(Self);
2294 end;
2295
2296 procedure TGraph.AddVertices(ACount: Integer);
2297 var
2298 I: Integer;
2299 begin
2300 FVertices.Capacity:=FVertices.Count + ACount;
2301 for I:=1 to ACount do TVertex.Create(Self);
2302 end;
2303
AddEdgenull2304 function TGraph.AddEdge(Vertex1, Vertex2: TVertex): TEdge;
2305 begin
2306 Result:=TEdge.Create(Self, Vertex1, Vertex2);
2307 end;
2308
AddEdgeInull2309 function TGraph.AddEdgeI(I1, I2: Integer): TEdge;
2310 begin
2311 Result:=TEdge.Create(Self, Vertices[I1], Vertices[I2]);
2312 end;
2313
2314 procedure TGraph.AddEdges(const VertexIndexes: array of Integer);
2315 var
2316 I: Integer;
2317 begin
2318 I:=0;
2319 repeat
2320 TEdge.Create(Self,
2321 FVertices[VertexIndexes[I]],
2322 FVertices[VertexIndexes[I + 1]]);
2323 Inc(I, 2);
2324 until I > High(VertexIndexes);
2325 end;
2326
2327 procedure TGraph.GetSeparateOf(Source: TGraph; V: TVertex);
2328 var
2329 I: Integer;
2330 U: TVertex;
2331 E: TEdge;
2332 begin
2333 {$IFDEF CHECK_GRAPHS}
2334 if Source = Self then Error(SErrorInParameters);
2335 {$ENDIF}
2336 Clear;
2337 Source.BFSFromVertex(V);
2338 for I:=0 to Source.VertexCount - 1 do begin
2339 V:=Source.FVertices[I];
2340 if V.FTemp.AsPtrInt >= 0 then begin
2341 U:=AddVertex;
2342 U.FTemp.AsPtrInt:=V.Index;
2343 V.FTemp.AsPtrInt:=U.Index;
2344 end;
2345 end;
2346 for I:=0 to Source.EdgeCount - 1 do begin
2347 E:=Source.FEdges[I];
2348 if E.V1.FTemp.AsPtrInt >= 0 then
2349 AddEdgeI(E.V1.FTemp.AsPtrInt, E.V2.FTemp.AsPtrInt);
2350 end;
2351 end;
2352
2353 {$IFDEF NOWARN}{$WARNINGS OFF}{$ENDIF}
FFindMinPathCondnull2354 function TGraph.FFindMinPathCond(Vertex1, Vertex2: TVertex;
2355 AcceptVertex: TAcceptVertex; AcceptEdge: TAcceptEdge;
2356 EdgePath: TClassList): Integer;
2357 { "волновой" алгоритм поиска пути минимальной длины }
2358 var
2359 I: Integer;
2360 Found: Bool;
2361 V: TVertex;
2362 E: TEdge;
2363 Front, OldFront, T: TClassList;
2364
2365 procedure AddToFront(AVertex: TVertex);
2366 var
2367 I: Integer;
2368 V: TVertex;
2369 E: TEdge;
2370 begin
2371 for I:=0 to AVertex.NeighbEdges.Count - 1 do begin
2372 E:=AVertex.NeighbEdges[I];
2373 if not Assigned(AcceptEdge) or AcceptEdge(E, AVertex) then begin
2374 V:=E.OtherVertex(AVertex);
2375 if V <> Vertex2 then begin
2376 { вершина на другом конце разрешена и не пройдена => проходим }
2377 if (V.FTemp.AsPointer = nil) and
2378 (not Assigned(AcceptVertex) or AcceptVertex(V))
2379 then
2380 Front.Add(E);
2381 end
2382 else begin
2383 Front.Clear;
2384 V.FTemp.AsPointer:=E;
2385 Found:=True;
2386 Exit;
2387 end;
2388 end;
2389 end;
2390 end;
2391
2392 begin
2393 if not (gsValidSeparates in FStates) or
2394 (Vertex1.SeparateIndex = Vertex2.SeparateIndex) then
2395 begin
2396 SetTempForVertices(Int32(nil));
2397 Front:=TClassList.Create;
2398 OldFront:=TClassList.Create;
2399 try
2400 Vertex1.FTemp.AsPointer:=Vertex1; { любой не-nil указатель }
2401 Result:=1;
2402 Found:=False;
2403 AddToFront(Vertex1);
2404 if not Found then
2405 while Front.Count > 0 do begin
2406 Inc(Result);
2407 T:=OldFront;
2408 OldFront:=Front;
2409 Front:=T;
2410 Front.Clear;
2411 { шаг волнового алгоритма }
2412 for I:=0 to OldFront.Count - 1 do begin
2413 E:=OldFront[I];
2414 { помечаем второй конец ребра (дуги) как достигнутый }
2415 if E.V1.FTemp.AsPointer = nil then
2416 V:=E.V1
2417 else
2418 if E.V2.FTemp.AsPointer = nil then
2419 V:=E.V2
2420 else
2421 Continue; { уже достигли эту вершину ранее }
2422 V.FTemp.AsPointer:=E;
2423 AddToFront(V);
2424 if Found then { нашли }
2425 Break;
2426 end;
2427 end;
2428 if Found then begin { обратный ход }
2429 if EdgePath <> nil then begin
2430 for I:=0 to Result - 1 do begin
2431 E:=Vertex2.FTemp.AsPointer;
2432 EdgePath.Add(E);
2433 Vertex2:=E.OtherVertex(Vertex2);
2434 end;
2435 EdgePath.Pack;
2436 EdgePath.Reverse;
2437 end;
2438 end
2439 else
2440 Result:=-1;
2441 finally
2442 Front.Free;
2443 OldFront.Free;
2444 end;
2445 end
2446 else
2447 Result:=-1;
2448 end;
2449
2450 procedure TGraph.SetTempForVertices(Value: Int32);
2451 var
2452 I: Integer;
2453 begin
2454 for I:=0 to FVertices.Count - 1 do
2455 TVertex(FVertices[I]).FTemp.AsPtrInt:=Value;
2456 end;
2457
2458 procedure TGraph.SetTempForEdges(Value: Int32);
2459 var
2460 I: Integer;
2461 begin
2462 for I:=0 to FEdges.Count - 1 do
2463 TEdge(FEdges[I]).FTemp.AsPtrInt:=Value;
2464 end;
2465
2466 procedure TGraph.SetTempFromVertex(V: TVertex; Value: Int32);
2467 var
2468 I, J: Integer;
2469 V1, V2: TVertex;
2470 E: TEdge;
2471 Front, OldFront, T: TClassList;
2472 begin
2473 SetTempForEdges(-1);
2474 Front:=TClassList.Create;
2475 OldFront:=TClassList.Create;
2476 try
2477 V.FTemp.AsPtrInt:=Value;
2478 OldFront.Add(V);
2479 repeat
2480 for I:=0 to OldFront.Count - 1 do begin
2481 V1:=OldFront[I];
2482 for J:=0 to V1.NeighbEdges.Count - 1 do begin
2483 E:=V1.NeighbEdges[J];
2484 if E.FTemp.AsPtrInt <> 0 then begin
2485 V2:=E.OtherVertex(V1);
2486 V2.FTemp.AsPtrInt:=Value;
2487 Front.Add(V2);
2488 E.FTemp.AsPtrInt:=0;
2489 end;
2490 end;
2491 end;
2492 T:=OldFront;
2493 OldFront:=Front;
2494 Front:=T;
2495 Front.Clear;
2496 until OldFront.Count = 0;
2497 finally
2498 Front.Free;
2499 OldFront.Free;
2500 end;
2501 end;
2502
TGraph.DFSFromVertexnull2503 function TGraph.DFSFromVertex(V: TVertex): Integer;
2504 label L1, L2;
2505 var
2506 I: Integer;
2507 Neighbour: TVertex;
2508 S1: TPointerStack;
2509 S2: TIntegerStack;
2510 begin
2511 SetTempForVertices(-1);
2512 Result:=0;
2513 S1:=TPointerStack.Create;
2514 S2:=TIntegerStack.Create;
2515 try
2516 L1:
2517 V.FTemp.AsPtrInt:=Result;
2518 Inc(Result);
2519 I:=0;
2520 L2:
2521 while I < V.NeighbEdges.Count do begin
2522 Neighbour:=V.Neighbour[I];
2523 Inc(I);
2524 if Neighbour.FTemp.AsPtrInt < 0 then begin
2525 S1.Push(V);
2526 S2.Push(I);
2527 V:=Neighbour;
2528 goto L1;
2529 end;
2530 end;
2531 if S1.Count > 0 then begin
2532 V:=S1.Pop;
2533 I:=S2.Pop;
2534 goto L2;
2535 end;
2536 finally
2537 S1.Free;
2538 S2.Free;
2539 end;
2540 end;
2541
BFSFromVertexnull2542 function TGraph.BFSFromVertex(V: TVertex): Integer;
2543 begin
2544 Result:=BFSTraversal(V, nil);
2545 end;
2546
BFSTraversalnull2547 function TGraph.BFSTraversal(V: TVertex; VisitProc: TVisitProc): Integer;
2548 var
2549 I, J, Time: Integer;
2550 V1, V2: TVertex;
2551 Front, OldFront, T: TClassList;
2552 begin
2553 SetTempForVertices(-1);
2554 Result:=1;
2555 Front:=TClassList.Create;
2556 OldFront:=TClassList.Create;
2557 try
2558 V.FTemp.AsPtrInt:=0;
2559 OldFront.Add(V);
2560 Time:=1;
2561 repeat
2562 for I:=0 to OldFront.Count - 1 do begin
2563 V1:=OldFront[I];
2564 for J:=0 to V1.NeighbEdges.Count - 1 do begin
2565 V2:=TEdge(V1.NeighbEdges[J]).OtherVertex(V1);
2566 if V2.FTemp.AsPtrInt = -1 then begin
2567 V2.FTemp.AsPtrInt:=Time;
2568 Inc(Result);
2569 Front.Add(V2);
2570 if Assigned(VisitProc) then
2571 VisitProc(V2);
2572 end;
2573 end; {for}
2574 end; {for}
2575 Inc(Time);
2576 T:=OldFront;
2577 OldFront:=Front;
2578 Front:=T;
2579 Front.Clear;
2580 until OldFront.Count = 0;
2581 finally
2582 Front.Free;
2583 OldFront.Free;
2584 end;
2585 end;
2586
BFSFromVertexFindMeetingsnull2587 function TGraph.BFSFromVertexFindMeetings(V: TVertex; VertexMeetings,
2588 EdgeMeetings: TClassList): Integer;
2589 var
2590 I, J, Time: Integer;
2591 V1, V2: TVertex;
2592 Front, OldFront, T: TClassList;
2593 begin
2594 if Assigned(VertexMeetings) then
2595 VertexMeetings.Clear;
2596 if Assigned(EdgeMeetings) then
2597 EdgeMeetings.Clear;
2598 SetTempForVertices(-1);
2599 Result:=1;
2600 Front:=TClassList.Create;
2601 OldFront:=TClassList.Create;
2602 try
2603 V.FTemp.AsPtrInt:=0;
2604 OldFront.Add(V);
2605 Time:=1;
2606 repeat
2607 for I:=0 to OldFront.Count - 1 do begin
2608 V1:=OldFront[I];
2609 for J:=0 to V1.NeighbEdges.Count - 1 do begin
2610 V2:=TEdge(V1.NeighbEdges[J]).OtherVertex(V1);
2611 if V2.FTemp.AsPtrInt = -1 then begin
2612 V2.FTemp.AsPtrInt:=Time;
2613 Inc(Result);
2614 Front.Add(V2);
2615 end
2616 else { запоминаем места встреч на вершинах / ребрах }
2617 if Assigned(VertexMeetings) then
2618 if V2.FTemp.AsPtrInt = Time then
2619 VertexMeetings.Add(V2)
2620 else
2621 if Assigned(EdgeMeetings) then
2622 if (V2.FTemp.AsPtrInt = Time - 1) and (V1.Index < V2.Index) then
2623 EdgeMeetings.Add(V1.NeighbEdges[J]);
2624 end; {for}
2625 end; {for}
2626 Inc(Time);
2627 T:=OldFront;
2628 OldFront:=Front;
2629 Front:=T;
2630 Front.Clear;
2631 until OldFront.Count = 0;
2632 finally
2633 Front.Free;
2634 OldFront.Free;
2635 end;
2636 if Assigned(VertexMeetings) then
2637 VertexMeetings.Pack;
2638 if Assigned(EdgeMeetings) then
2639 EdgeMeetings.Pack;
2640 {$IFDEF CHECK_GRAPHS} { постусловие }
2641 if Assigned(VertexMeetings) and Assigned(EdgeMeetings) and Connected and
2642 (CyclomaticNumber <> VertexMeetings.Count + EdgeMeetings.Count + LoopCount)
2643 then
2644 Error(SAlgorithmFailure);
2645 {$ENDIF}
2646 end;
2647
2648 procedure TGraph.BFSFromVertexDirected(V: TVertex);
2649 var
2650 I, J, Time: Integer;
2651 V1, V2: TVertex;
2652 E: TEdge;
2653 Front, OldFront, T: TClassList;
2654 begin
2655 SetTempForVertices(-1);
2656 Front:=TClassList.Create;
2657 OldFront:=TClassList.Create;
2658 try
2659 V.FTemp.AsPtrInt:=0;
2660 OldFront.Add(V);
2661 Time:=1;
2662 repeat
2663 for I:=0 to OldFront.Count - 1 do begin
2664 V1:=OldFront[I];
2665 for J:=0 to V1.NeighbEdges.Count - 1 do begin
2666 E:=V1.NeighbEdges[J];
2667 if E.V1 = V1 then begin
2668 V2:=E.V2;
2669 if V2.FTemp.AsPtrInt = -1 then begin
2670 V2.FTemp.AsPtrInt:=Time;
2671 Front.Add(V2);
2672 end;
2673 end;
2674 end;
2675 end;
2676 Inc(Time);
2677 T:=OldFront;
2678 OldFront:=Front;
2679 Front:=T;
2680 Front.Clear;
2681 until OldFront.Count = 0;
2682 finally
2683 Front.Free;
2684 OldFront.Free;
2685 end;
2686 end;
2687
TGraph.FindMinPathCondnull2688 function TGraph.FindMinPathCond(Vertex1, Vertex2: TVertex;
2689 AcceptVertex: TAcceptVertex; AcceptEdge: TAcceptEdge;
2690 EdgePath: TClassList): Integer;
2691 begin
2692 if EdgePath <> nil then
2693 EdgePath.Clear;
2694 if Vertex1 <> Vertex2 then
2695 Result:=FFindMinPathCond(Vertex1, Vertex2, AcceptVertex, AcceptEdge, EdgePath)
2696 else
2697 Result:=0;
2698 end;
2699
FindMinPathUndirectednull2700 function TGraph.FindMinPathUndirected(Vertex1, Vertex2: TVertex;
2701 EdgePath: TClassList): Integer;
2702 begin
2703 Result:=FindMinPathCond(Vertex1, Vertex2, nil, nil, EdgePath);
2704 end;
2705
AcceptArcnull2706 function TGraph.AcceptArc(Edge: TEdge; FromVertex: TVertex): Bool;
2707 begin
2708 Result:=Edge.V1 = FromVertex;
2709 end;
2710
TGraph.FindMinPathDirectednull2711 function TGraph.FindMinPathDirected(Vertex1, Vertex2: TVertex;
2712 EdgePath: TClassList): Integer;
2713 begin
2714 Result:=FindMinPathCond(Vertex1, Vertex2, nil, AcceptArc, EdgePath)
2715 end;
2716
FindMinPathnull2717 function TGraph.FindMinPath(Vertex1, Vertex2: TVertex;
2718 EdgePath: TClassList): Integer;
2719 begin
2720 if Directed in Features then
2721 Result:=FindMinPathCond(Vertex1, Vertex2, nil, AcceptArc, EdgePath)
2722 else
2723 Result:=FindMinPathCond(Vertex1, Vertex2, nil, nil, EdgePath);
2724 end;
2725
TGraph.FFindMinPathsnull2726 function TGraph.FFindMinPaths(Vertex1, Vertex2: TVertex; SolutionCount: Integer;
2727 EdgePaths: TMultiList; DirectedGraph: Bool): Integer;
2728 Label Next;
2729 var
2730 I, J, K, Time: Integer;
2731 P: Pointer;
2732 V, Neighbour: TVertex;
2733 E: TEdge;
2734 Front, OldFront, T: TClassList;
2735 NewEdgePaths, NewEdgePathsRef, OldEdgePaths: TMultiList;
2736 begin
2737 Result:=0;
2738 EdgePaths.Clear;
2739 if not (gsValidSeparates in FStates) or
2740 (Vertex1.SeparateIndex = Vertex2.SeparateIndex) then
2741 begin
2742 Vertex2.FTemp.AsPtrInt:=-1;
2743 if DirectedGraph then
2744 BFSFromVertexDirected(Vertex1)
2745 else
2746 BFSFromVertex(Vertex1);
2747 Time:=Vertex2.FTemp.AsPtrInt;
2748 if Time > 0 then begin
2749 EdgePaths.Grow(1);
2750 OldEdgePaths:=EdgePaths;
2751 Front:=TClassList.Create;
2752 OldFront:=TClassList.Create;
2753 NewEdgePaths:=TMultiList.Create(TClassList);
2754 NewEdgePathsRef:=NewEdgePaths;
2755 try
2756 OldFront.Add(Vertex2);
2757 repeat
2758 Dec(Time);
2759 for I:=0 to OldFront.Count - 1 do begin
2760 V:=OldFront[I];
2761 for J:=0 to V.NeighbEdges.Count - 1 do begin
2762 E:=V.NeighbEdges[J];
2763 if DirectedGraph then
2764 if E.V2 = V then
2765 Neighbour:=E.V1
2766 else
2767 Continue
2768 else
2769 Neighbour:=E.OtherVertex(V);
2770 if Neighbour.FTemp.AsPtrInt = Time then begin
2771 if Front.IndexOf(Neighbour) < 0 then
2772 Front.Add(Neighbour);
2773 for K:=0 to OldEdgePaths.Count - 1 do begin
2774 T:=OldEdgePaths[K];
2775 if (T.Count = 0) or TEdge(T.Last).IncidentToEdgeUndirected(E) then begin
2776 NewEdgePaths.AddAssign(T);
2777 NewEdgePaths.Last.Add(E);
2778 if NewEdgePaths.Count = SolutionCount then
2779 goto Next;
2780 end;
2781 end; {for K}
2782 end;
2783 end; {for J}
2784 end; {for I}
2785 Next:
2786 P:=OldEdgePaths;
2787 OldEdgePaths:=NewEdgePaths;
2788 NewEdgePaths:=TMultiList(P);
2789 NewEdgePaths.Clear;
2790 T:=OldFront;
2791 OldFront:=Front;
2792 Front:=T;
2793 Front.Clear;
2794 until Time = 0;
2795 if OldEdgePaths <> EdgePaths then
2796 EdgePaths.Assign(OldEdgePaths);
2797 Result:=EdgePaths.Count;
2798 for I:=0 to Result - 1 do With EdgePaths[I] do begin
2799 Pack;
2800 Reverse;
2801 end;
2802 finally
2803 Front.Free;
2804 OldFront.Free;
2805 NewEdgePathsRef.Free;
2806 end;
2807 end;
2808 end;
2809 end;
2810
FindMinPathsUndirectednull2811 function TGraph.FindMinPathsUndirected(Vertex1, Vertex2: TVertex;
2812 SolutionCount: Integer; EdgePaths: TMultiList): Integer;
2813 begin
2814 Result:=FFindMinPaths(Vertex1, Vertex2, SolutionCount, EdgePaths, False);
2815 end;
2816
FindMinPathsDirectednull2817 function TGraph.FindMinPathsDirected(Vertex1, Vertex2: TVertex;
2818 SolutionCount: Integer; EdgePaths: TMultiList): Integer;
2819 begin
2820 Result:=FFindMinPaths(Vertex1, Vertex2, SolutionCount, EdgePaths, True);
2821 end;
2822
TGraph.FindMinPathsnull2823 function TGraph.FindMinPaths(Vertex1, Vertex2: TVertex; SolutionCount: Integer;
2824 EdgePaths: TMultiList): Integer;
2825 begin
2826 Result:=FFindMinPaths(Vertex1, Vertex2, SolutionCount, EdgePaths,
2827 Directed in Features);
2828 end;
2829
2830 type
2831 PRingData = ^TRingData;
2832 TRingData = record
2833 Prohibited: TEdge;
2834 UserAcceptEdge: TAcceptEdge;
2835 end;
2836
TGraph.FindMinRingAcceptEdgenull2837 function TGraph.FindMinRingAcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
2838 begin
2839 With PRingData(FTemp.AsPointer)^ do
2840 Result:=(Edge <> Prohibited) and
2841 (not Assigned(UserAcceptEdge) or UserAcceptEdge(Edge, FromVertex));
2842 end;
2843
TGraph.FFindMinRingCondnull2844 function TGraph.FFindMinRingCond(Vertex: TVertex; AcceptVertex: TAcceptVertex;
2845 AcceptEdge: TAcceptEdge; EdgePath: TClassList): Integer;
2846 var
2847 I, PathLength: Integer;
2848 RingFound: Bool;
2849 V: TVertex;
2850 E: TEdge;
2851 T: TClassList;
2852 RingData: TRingData;
2853 begin
2854 if EdgePath <> nil then
2855 T:=TClassList.Create
2856 else
2857 T:=nil;
2858 try
2859 RingData.UserAcceptEdge:=AcceptEdge;
2860 FTemp.AsPointer:=@RingData;
2861 RingFound:=False;
2862 Result:=MaxInt;
2863 for I:=0 to Vertex.NeighbEdges.Count - 1 do begin
2864 { запрещаем одну из дуг }
2865 E:=Vertex.NeighbEdges[I];
2866 if not Assigned(AcceptEdge) or AcceptEdge(E, Vertex) then begin
2867 V:=E.OtherVertex(Vertex);
2868 if V = Vertex then begin { петля }
2869 if EdgePath <> nil then begin
2870 EdgePath.Count:=1;
2871 EdgePath[0]:=E;
2872 end;
2873 Result:=1;
2874 Exit;
2875 end;
2876 RingData.Prohibited:=E;
2877 PathLength:=FFindMinPathCond(Vertex, V, AcceptVertex,
2878 FindMinRingAcceptEdge, T);
2879 if (PathLength > 0) and (PathLength < Result) then begin
2880 RingFound:=True;
2881 Result:=PathLength;
2882 if EdgePath <> nil then begin
2883 EdgePath.Assign(T);
2884 EdgePath.Add(E);
2885 EdgePath.Pack;
2886 end;
2887 end;
2888 if T <> nil then
2889 T.Clear;
2890 end;
2891 end;
2892 if RingFound then
2893 Inc(Result)
2894 else
2895 Result:=-1;
2896 finally
2897 T.Free;
2898 end;
2899 end;
2900
FindMinRingCondnull2901 function TGraph.FindMinRingCond(Vertex: TVertex;
2902 AcceptVertex: TAcceptVertex; AcceptEdge: TAcceptEdge;
2903 EdgePath: TClassList): Integer;
2904 begin
2905 if EdgePath <> nil then
2906 EdgePath.Clear;
2907 if Directed in Features then
2908 Result:=FFindMinPathCond(Vertex, Vertex, AcceptVertex, AcceptEdge, EdgePath)
2909 else
2910 Result:=FFindMinRingCond(Vertex, AcceptVertex, AcceptEdge, EdgePath);
2911 end;
2912
TGraph.FindMinRingnull2913 function TGraph.FindMinRing(Vertex: TVertex; EdgePath: TClassList): Integer;
2914 begin
2915 if Directed in Features then
2916 Result:=FindMinRingCond(Vertex, nil, AcceptArc, EdgePath)
2917 else
2918 Result:=FindMinRingCond(Vertex, nil, nil, EdgePath);
2919 end;
2920 {$IFDEF NOWARN}{$WARNINGS ON}{$ENDIF}
2921
TGraph.CreateRingDegreesVectornull2922 function TGraph.CreateRingDegreesVector: TIntegerVector;
2923 var
2924 I, J, Counter: Integer;
2925 E: TEdge;
2926 NeighbEdges: TClassList;
2927 OldFeatures: TGraphFeatures;
2928 begin
2929 Result:=TIntegerVector.Create(FVertices.Count, 0);
2930 try
2931 OldFeatures:=Features;
2932 try
2933 Features:=OldFeatures - [Directed];
2934 for I:=0 to FVertices.Count - 1 do begin
2935 Counter:=0;
2936 NeighbEdges:=TVertex(FVertices[I]).NeighbEdges;
2937 for J:=0 to NeighbEdges.Count - 1 do begin
2938 E:=NeighbEdges[J];
2939 if E.V1 <> E.V2 then
2940 Inc(Counter, Ord(E.RingEdge)); { петли не считаются }
2941 end;
2942 Result[I]:=Counter;
2943 end;
2944 finally
2945 Features:=OldFeatures;
2946 end;
2947 except
2948 Result.Free;
2949 raise;
2950 end;
2951 end;
2952
2953 { вспомогательный класс для поиска колец (введен из соображений эффективности:
2954 чтобы не создавать большие вектора при каждом вызове FFindRingsFromEdge из
2955 FindMinRingCovering) }
2956 type
2957 TFindRingFromEdgeHelper = class
2958 Graph: TGraph;
2959 SingleTrueIndexes: TIntegerVector;
2960 EdgePath, NewRing, CorrectedRings: TClassList;
2961 NewRings: TMultiList;
2962 NewRingCode, Sum, ProhibitedColumns: TBoolVector;
2963 constructor Create(AGraph: TGraph);
2964 destructor Destroy; override;
2965 procedure CheckRing(Rings: TMultiList);
2966 end;
2967
2968 constructor TFindRingFromEdgeHelper.Create(AGraph: TGraph);
2969 begin
2970 inherited Create;
2971 Graph:=AGraph;
2972 SingleTrueIndexes:=TIntegerVector.Create(0, 0);
2973 EdgePath:=TClassList.Create;
2974 NewRing:=TClassList.Create;
2975 CorrectedRings:=TClassList.Create;
2976 NewRings:=TMultiList.Create(TClassList);
2977 NewRingCode:=TPackedBoolVector.Create(AGraph.FEdges.Count, False);
2978 Sum:=TPackedBoolVector.Create(AGraph.FEdges.Count, False);
2979 ProhibitedColumns:=TBoolVector.Create(AGraph.FEdges.Count, False);
2980 end;
2981
2982 destructor TFindRingFromEdgeHelper.Destroy;
2983 begin
2984 SingleTrueIndexes.Free;
2985 EdgePath.Free;
2986 NewRing.Free;
2987 CorrectedRings.FreeItems;
2988 CorrectedRings.Free;
2989 NewRings.Free;
2990 NewRingCode.Free;
2991 Sum.Free;
2992 ProhibitedColumns.Free;
2993 inherited Destroy;
2994 end;
2995
2996 {$IFDEF NOWARN}{$WARNINGS OFF}{$ENDIF}
2997 procedure TFindRingFromEdgeHelper.CheckRing(Rings: TMultiList);
2998 { проверяет, что найденное кольцо EdgePath не зависит относительно уже
2999 найденных минимальных колец Rings и, если да, то добавляет EdgePath
3000 к Rings; возвращает True, если найдено MaxRings ребер, иначе False }
3001
3002 procedure StandardizeRing;
3003 { приводит кольцо EdgePath к кольцу стандартного вида NewRing }
3004 var
3005 RingStart: Integer;
3006
NextRingIndexnull3007 function NextRingIndex(ADir: Integer): Integer;
3008 begin
3009 Result:=RingStart + ADir;
3010 if Result >= EdgePath.Count then
3011 Result:=0
3012 else
3013 if Result < 0 then
3014 Result:=EdgePath.Count - 1;
3015 end;
3016
3017 var
3018 I, N, MinIndex, Dir: Integer;
3019 E1, E2: TEdge;
3020 begin {StandardizeRing}
3021 { начальным ребром будем считать ребро с минимальным индексом }
3022 MinIndex:=MaxInt;
3023 N:=EdgePath.Count;
3024 for I:=0 to N - 1 do begin
3025 E1:=EdgePath[I];
3026 if E1.Index < MinIndex then begin
3027 RingStart:=I;
3028 MinIndex:=E1.Index;
3029 end;
3030 end;
3031 { определяем направление обхода по возрастанию индекса }
3032 E1:=EdgePath[NextRingIndex(1)];
3033 E2:=EdgePath[NextRingIndex(-1)];
3034 if (E1.Index < E2.Index) or (E1.Index = E2.Index) and (E1.Index < E2.Index)
3035 then
3036 Dir:=1
3037 else
3038 Dir:=-1;
3039 { обходим EdgePath и "собираем" NewRing }
3040 NewRing.Count:=N;
3041 for I:=0 to N - 1 do begin
3042 NewRing[I]:=EdgePath[RingStart];
3043 RingStart:=NextRingIndex(Dir);
3044 end;
3045 EdgePath.Clear;
3046 end; {StandardizeRing}
3047
IndependentRingnull3048 function IndependentRing: Bool;
3049 { возвращает True, если кольцо NewRing не зависит от колец Rings, и
3050 False - иначе }
3051 var
3052 I, J: Integer;
3053 T: TBoolVector;
3054 begin
3055 { представляем NewRing в виде двоичного вектора }
3056 for I:=0 to NewRing.Count - 1 do
3057 NewRingCode[TEdge(NewRing[I]).Index]:=True;
3058 { проверяем независимость }
3059 Sum.SetToDefault;
3060 for I:=0 to SingleTrueIndexes.Count - 1 do
3061 if NewRingCode[SingleTrueIndexes[I]] then
3062 Sum.XorVector(TBoolVector(CorrectedRings[I]));
3063 if Sum.EqualTo(NewRingCode) then begin
3064 NewRingCode.SetToDefault;
3065 Result:=False;
3066 Exit;
3067 end;
3068 { обновляем CorrectedRings, SingleTrueIndexes и ProhibitedColumns }
3069 NewRingCode.XorVector(Sum);
3070 for I:=0 to NewRingCode.Count - 1 do
3071 if not ProhibitedColumns[I] and NewRingCode[I] then begin
3072 for J:=0 to CorrectedRings.Count - 1 do begin
3073 T:=TBoolVector(CorrectedRings[J]);
3074 if T[I] then
3075 T.XorVector(NewRingCode);
3076 end;
3077 SingleTrueIndexes.Add(I);
3078 ProhibitedColumns[I]:=True;
3079 Break;
3080 end;
3081 CorrectedRings.Add(NewRingCode);
3082 NewRingCode:=TPackedBoolVector.Create(Graph.FEdges.Count, False);
3083 Result:=True;
3084 end; {IndependentRing}
3085
3086 var
3087 I: Integer;
3088 begin {CheckRing}
3089 { приводим кольцо к стандартному виду }
3090 StandardizeRing;
3091 { если кольцо было найдено ранее, то выходим }
3092 for I:=0 to Rings.Count - 1 do
3093 if Rings[I].EqualTo(NewRing) then
3094 Exit;
3095 { если кольцо зависит от найденных ранее, то выходим }
3096 if not IndependentRing then
3097 Exit;
3098 { добавляем кольцо в список найденных минимальных колец }
3099 Rings.AddAssign(NewRing);
3100 end; {CheckRing}
3101 {$IFDEF NOWARN}{$WARNINGS ON}{$ENDIF}
3102
3103 procedure TGraph.FFindRingsFromEdge(FromEdge: TEdge; Rings: TMultiList;
3104 MaxRings: Integer; FindRingFromEdgeHelper: Pointer);
3105 var
3106 I: Integer;
3107 begin
3108 With TFindRingFromEdgeHelper(FindRingFromEdgeHelper) do begin
3109 FromEdge.Hide;
3110 try
3111 FindMinPathsUndirected(FromEdge.V1, FromEdge.V2, -1, NewRings);
3112 finally
3113 FromEdge.Restore;
3114 end;
3115 for I:=0 to NewRings.Count - 1 do begin
3116 EdgePath.Assign(NewRings[I]);
3117 NewRings[I]:=nil;
3118 EdgePath.Add(FromEdge);
3119 CheckRing(Rings);
3120 { проверяем количество найденных колец }
3121 if Rings.Count >= MaxRings then
3122 Exit;
3123 end;
3124 end;
3125 end;
3126
TGraph.FindRingsFromEdgenull3127 function TGraph.FindRingsFromEdge(FromEdge: TEdge; Rings: TMultiList;
3128 MaxRings: Integer): Integer;
3129 var
3130 FindRingFromEdgeHelper: TFindRingFromEdgeHelper;
3131 begin
3132 Rings.Clear;
3133 FindRingFromEdgeHelper:=TFindRingFromEdgeHelper.Create(Self);
3134 try
3135 FFindRingsFromEdge(FromEdge, Rings, MaxRings, FindRingFromEdgeHelper);
3136 finally
3137 FindRingFromEdgeHelper.Free;
3138 end;
3139 Result:=Rings.Count;
3140 end;
3141
TGraph.FindMinRingCoveringnull3142 function TGraph.FindMinRingCovering(Rings: TMultiList): Integer;
3143 var
3144 I, CyclesNumber: Integer;
3145 RingEdges: TBoolVector;
3146 FindRingFromEdgeHelper: TFindRingFromEdgeHelper;
3147 OldFeatures: TGraphFeatures;
3148 begin
3149 Rings.Clear;
3150 CyclesNumber:=CyclomaticNumber - LoopCount;
3151 if CyclesNumber > 0 then begin
3152 FindRingFromEdgeHelper:=TFindRingFromEdgeHelper.Create(Self);
3153 RingEdges:=nil;
3154 OldFeatures:=Features;
3155 try
3156 Features:=OldFeatures - [Directed];
3157 { при работе FFindRingsFromEdge используются методы TEdge.Hide /
3158 TEdge.Restore, которые сбрасывают информацию о принадлежности ребра к
3159 кольцам, поэтому для повышения эффективности запоминаем эту информацию }
3160 RingEdges:=TBoolVector.Create(FEdges.Count, False);
3161 for I:=0 to FEdges.Count - 1 do
3162 if TEdge(FEdges[I]).RingEdge then
3163 RingEdges[I]:=True;
3164 { основной цикл }
3165 for I:=0 to FEdges.Count - 1 do
3166 if RingEdges[I] then begin
3167 FFindRingsFromEdge(TEdge(FEdges[I]), Rings, CyclesNumber,
3168 FindRingFromEdgeHelper);
3169 if Rings.Count >= CyclesNumber then
3170 Break;
3171 end;
3172 {$IFDEF CHECK_GRAPHS} { постусловие }
3173 if not CompleteRingSystem(Rings) then
3174 Error(SAlgorithmFailure);
3175 {$ENDIF}
3176 finally
3177 FindRingFromEdgeHelper.Free;
3178 RingEdges.Free;
3179 Features:=OldFeatures;
3180 end;
3181 end;
3182 Result:=Rings.Count;
3183 end;
3184
TGraph.CompleteRingSystemnull3185 function TGraph.CompleteRingSystem(Rings: TMultiList): Bool;
3186 var
3187 I, J: Integer;
3188 E: TEdge;
3189 T: TBoolVector;
3190 Ring: TClassList;
3191 begin
3192 T:=TBoolVector.Create(FEdges.Count, False);
3193 try
3194 for I:=0 to Rings.Count - 1 do begin
3195 Ring:=Rings[I];
3196 for J:=0 to Ring.Count - 1 do
3197 T[TEdge(Ring[J]).Index]:=True;
3198 end;
3199 for I:=0 to FEdges.Count - 1 do begin
3200 E:=FEdges[I];
3201 if (E.V1 <> E.V2) and E.RingEdge and not T[E.Index] then begin
3202 Result:=False;
3203 Exit;
3204 end;
3205 end;
3206 Result:=True;
3207 finally
3208 T.Free;
3209 end;
3210 end;
3211
TEdgeFilter.AcceptEdgenull3212 function TEdgeFilter.AcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
3213 begin
3214 Result:=AllowedEdges[Edge.Index];
3215 end;
3216
3217 constructor TAutoEdgeFilter.Create(EdgeCount: Integer);
3218 begin
3219 inherited Create;
3220 AllowedEdges:=TBoolVector.Create(EdgeCount, True);
3221 end;
3222
3223 destructor TAutoEdgeFilter.Destroy;
3224 begin
3225 AllowedEdges.Free;
3226 inherited Destroy;
3227 end;
3228
FindSpanningTreenull3229 function TGraph.FindSpanningTree(EdgeInST: TBoolVector; STEdges: TClassList): Integer;
3230 var
3231 I: Integer;
3232 E: TEdge;
3233 EdgeFilter: TEdgeFilter;
3234 begin
3235 Result:=0;
3236 EdgeFilter:=TEdgeFilter.Create;
3237 if EdgeInST <> nil then begin
3238 EdgeInST.Count:=FEdges.Count;
3239 EdgeInST.FillValue(False);
3240 EdgeFilter.AllowedEdges:=EdgeInST;
3241 end
3242 else
3243 EdgeFilter.AllowedEdges:=TBoolVector.Create(FEdges.Count, False);
3244 try
3245 if STEdges <> nil then
3246 STEdges.Count:=FEdges.Count;
3247 for I:=0 to FEdges.Count - 1 do begin
3248 E:=FEdges[I];
3249 if FindMinPathCond(E.V1, E.V2, nil, EdgeFilter.AcceptEdge, nil) < 0 then begin
3250 EdgeFilter.AllowedEdges[I]:=True;
3251 if STEdges <> nil then
3252 STEdges[Result]:=E;
3253 Inc(Result);
3254 end;
3255 end;
3256 finally
3257 if EdgeInST = nil then
3258 EdgeFilter.AllowedEdges.Free;
3259 EdgeFilter.Free;
3260 end;
3261 if STEdges <> nil then
3262 STEdges.Count:=Result;
3263 end;
3264
FindFundamentalRingsnull3265 function TGraph.FindFundamentalRings(Rings: TMultiList): Integer;
3266 var
3267 I: Integer;
3268 E: TEdge;
3269 Ring: TClassList;
3270 EdgeFilter: TEdgeFilter;
3271 begin
3272 Rings.Clear;
3273 EdgeFilter:=TAutoEdgeFilter.Create(0);
3274 try
3275 FindSpanningTree(EdgeFilter.AllowedEdges, nil);
3276 for I:=0 to FEdges.Count - 1 do
3277 if not EdgeFilter.AllowedEdges[I] then begin
3278 E:=FEdges[I];
3279 if not E.IsLoop then begin
3280 Rings.Grow(1);
3281 Ring:=Rings.Last;
3282 FindMinPathCond(E.V1, E.V2, nil, EdgeFilter.AcceptEdge, Ring);
3283 Ring.Add(E);
3284 end;
3285 end;
3286 finally
3287 EdgeFilter.Free;
3288 end;
3289 Result:=Rings.Count;
3290 {$IFDEF CHECK_GRAPHS} { постусловие }
3291 if not CompleteRingSystem(Rings) then
3292 Error(SAlgorithmFailure);
3293 {$ENDIF}
3294 end;
3295
3296 {$IFDEF NOWARN}{$WARNINGS OFF}{$ENDIF}
EdgePathToVertexPathnull3297 function TGraph.EdgePathToVertexPath(FromVertex: TVertex;
3298 EdgePath, VertexPath: TClassList): Bool;
3299 var
3300 I: Integer;
3301 V: TVertex;
3302 E: TEdge;
3303 begin
3304 VertexPath.Clear;
3305 if EdgePath.Count > 0 then begin
3306 for I:=0 to EdgePath.Count - 1 do begin
3307 E:=EdgePath[I];
3308 if E.V1 = FromVertex then
3309 V:=E.V2
3310 else
3311 if E.V2 = FromVertex then
3312 V:=E.V1
3313 else begin
3314 VertexPath.Clear;
3315 Result:=False;
3316 Exit;
3317 end;
3318 VertexPath.Add(FromVertex);
3319 FromVertex:=V;
3320 end;
3321 VertexPath.Add(FromVertex);
3322 VertexPath.Pack;
3323 end;
3324 Result:=True;
3325 end;
3326 {$IFDEF NOWARN}{$WARNINGS ON}{$ENDIF}
3327
3328 procedure TGraph.DetectConnected;
3329 { определение связности графа с помощью волнового алгоритма }
3330 var
3331 I, J, NumFired: Integer;
3332 NoProgress: Bool;
3333 V1, V2: TVertex;
3334 OldFront, NewFront, T: TClassList;
3335 begin
3336 if FVertices.Count > 1 then begin
3337 if FEdges.Count >= FVertices.Count - 1 then begin
3338 { выполняется необходимое условие связности: |E|>=|V2|-1 }
3339 SetTempForVertices(-1);
3340 OldFront:=TClassList.Create;
3341 NewFront:=TClassList.Create;
3342 try
3343 NumFired:=1;
3344 TVertex(FVertices[0]).FTemp.AsPtrInt:=0;
3345 OldFront.Add(FVertices[0]);
3346 repeat
3347 NoProgress:=True;
3348 for I:=0 to OldFront.Count - 1 do begin
3349 V1:=OldFront[I];
3350 for J:=0 to V1.NeighbEdges.Count - 1 do begin
3351 V2:=V1.Neighbour[J];
3352 if V2.FTemp.AsPtrInt = -1 then begin
3353 Inc(NumFired);
3354 V2.FTemp.AsPtrInt:=0;
3355 NewFront.Add(V2);
3356 NoProgress:=False;
3357 end;
3358 end;
3359 end;
3360 if NoProgress then begin
3361 FConnected:=False;
3362 Break;
3363 end;
3364 if NumFired = FVertices.Count then begin
3365 FConnected:=True;
3366 Break;
3367 end;
3368 T:=OldFront;
3369 OldFront:=NewFront;
3370 NewFront:=T;
3371 NewFront.Clear;
3372 until False;
3373 finally
3374 OldFront.Free;
3375 NewFront.Free;
3376 end;
3377 end
3378 else
3379 FConnected:=False;
3380 end
3381 else
3382 FConnected:=FVertices.Count = 1;
3383 Include(FStates, gsValidConnected);
3384 end;
3385
3386 procedure TGraph.DetectSeparates;
3387 { определение компонент связности графа с помощью волнового алгоритма }
3388 var
3389 I, J, K, SeparateOffset: Integer;
3390 NoProgress: Bool;
3391 V1, V2: TVertex;
3392 OldFront, NewFront, T: TClassList;
3393 OldStates: TGraphObjectStates;
3394 begin
3395 OldStates:=States;
3396 States:=States + [gsValidSeparates]; { побочный эффект - создание атрибута }
3397 try
3398 if (gsValidConnected in FStates) and FConnected then
3399 FSeparateCount:=1
3400 else begin
3401 FSeparateCount:=0;
3402 SetTempForVertices(-1);
3403 OldFront:=TClassList.Create;
3404 NewFront:=TClassList.Create;
3405 try
3406 for I:=0 to FVertices.Count - 1 do begin
3407 V1:=FVertices[I];
3408 if V1.FTemp.AsPtrInt = -1 then begin
3409 V1.FTemp.AsPtrInt:=FSeparateCount;
3410 OldFront.Clear;
3411 OldFront.Add(V1);
3412 repeat
3413 NoProgress:=True;
3414 for J:=0 to OldFront.Count - 1 do begin
3415 V1:=OldFront[J];
3416 for K:=0 to V1.NeighbEdges.Count - 1 do begin
3417 V2:=V1.Neighbour[K];
3418 if V2.FTemp.AsPtrInt = -1 then begin
3419 V2.FTemp.AsPtrInt:=FSeparateCount;
3420 NewFront.Add(V2);
3421 NoProgress:=False;
3422 end;
3423 end;
3424 end;
3425 if NoProgress then
3426 Break;
3427 T:=OldFront;
3428 OldFront:=NewFront;
3429 NewFront:=T;
3430 NewFront.Clear;
3431 until False;
3432 Inc(FSeparateCount);
3433 end;
3434 end;
3435 FConnected:=FSeparateCount = 1;
3436 Include(FStates, gsValidConnected);
3437 SeparateOffset:=FVertexAttrMap.Offset(GAttrSeparateIndex);
3438 for I:=0 to FVertices.Count - 1 do begin
3439 V1:=FVertices[I];
3440 V1.AsInt32ByOfs[SeparateOffset]:=V1.FTemp.AsPtrInt;
3441 end;
3442 finally
3443 OldFront.Free;
3444 NewFront.Free;
3445 end;
3446 end;
3447 except
3448 States:=OldStates;
3449 raise;
3450 end;
3451 end;
3452
DetectRingsAcceptEdgenull3453 function TGraph.DetectRingsAcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
3454 begin
3455 Result:=Edge <> FTemp.AsPointer;
3456 end;
3457
DetectRingsAcceptArcnull3458 function TGraph.DetectRingsAcceptArc(Edge: TEdge; FromVertex: TVertex): Bool;
3459 begin
3460 Result:=(Edge <> FTemp.AsPointer) and (Edge.V1 = FromVertex);
3461 end;
3462
3463 procedure TGraph.DetectRingEdges;
3464 var
3465 I, J, RingOffset, PathLength: Integer;
3466 B: Bool;
3467 V: TVertex;
3468 E, SaveOne: TEdge;
3469 begin
3470 States:=States + [gsValidRingEdges]; { побочный эффект - создание атрибута }
3471 try
3472 FRingEdgeCount:=0;
3473 if FVertices.Count = 0 then
3474 Exit;
3475 if not (Directed in Features) then begin
3476 { пытаемся определить кольцевые ребра с помощью волнового алгоритма;
3477 результат определяется полем Temp ребер: 0 => неизвестно, 1 => кольцевое }
3478 BFSFromVertex(FVertices[0]);
3479 { если временн'ые метки концов совпадают, то ребро является кольцевым
3480 ("встреча волны на ребре") }
3481 for I:=0 to FEdges.Count - 1 do With TEdge(FEdges[I]) do
3482 FTemp.AsPtrInt:=Ord(V1.TimeMark = V2.TimeMark);
3483 { если противоположные концы более чем двух инцидентных ребер вершины
3484 имеют меньшие временн'ые метки, чем эта вершина, то ребра - кольцевые
3485 ("встреча волны на вершине") }
3486 for I:=0 to FVertices.Count - 1 do begin
3487 V:=FVertices[I];
3488 SaveOne:=nil;
3489 for J:=0 to V.NeighbEdges.Count - 1 do begin
3490 E:=V.NeighbEdges[J];
3491 if E.OtherVertex(V).TimeMark < V.TimeMark then
3492 if SaveOne = nil then
3493 SaveOne:=E
3494 else begin
3495 SaveOne.FTemp.AsPtrInt:=1;
3496 E.FTemp.AsPtrInt:=1;
3497 end;
3498 end;
3499 end;
3500 end
3501 else
3502 SetTempForEdges(0);
3503 { обрабатываем остальные ребра }
3504 RingOffset:=FEdgeAttrMap.Offset(GAttrRingEdge);
3505 for I:=0 to FEdges.Count - 1 do begin
3506 E:=FEdges[I];
3507 if E.Temp.AsPtrInt = 1 then
3508 B:=True
3509 { степень одного из концов равна единице => заведомо некольцевое }
3510 else if (E.V1.NeighbEdges.Count = 1) or (E.V2.NeighbEdges.Count = 1) then
3511 B:=False
3512 else begin
3513 FTemp.AsPointer:=E;
3514 if Directed in Features then
3515 PathLength:=FindMinPathCond(E.V2, E.V1, nil, DetectRingsAcceptArc, nil)
3516 else
3517 PathLength:=FindMinPathCond(E.V1, E.V2, nil, DetectRingsAcceptEdge, nil);
3518 B:=PathLength >= 0;
3519 end;
3520 E.AsBoolByOfs[RingOffset]:=B;
3521 if B then
3522 Inc(FRingEdgeCount);
3523 end;
3524 except
3525 Exclude(FStates, gsValidRingEdges);
3526 raise;
3527 end;
3528 end;
3529
3530 procedure TGraph.CheckValidConnected;
3531 begin
3532 if not (gsValidConnected in FStates) then
3533 DetectConnected;
3534 end;
3535
3536 procedure TGraph.CheckValidSeparates;
3537 begin
3538 if not (gsValidSeparates in FStates) then
3539 DetectSeparates;
3540 end;
3541
3542 procedure TGraph.CheckValidRingEdges;
3543 begin
3544 if not (gsValidRingEdges in FStates) then
3545 DetectRingEdges;
3546 end;
3547
Connectednull3548 function TGraph.Connected: Bool;
3549 begin
3550 CheckValidConnected;
3551 Result:=FConnected;
3552 end;
3553
TGraph.MakeConnectednull3554 function TGraph.MakeConnected(NewEdges: TClassList): Integer;
3555 var
3556 I: Integer;
3557 V1, V2: TVertex;
3558 E: TEdge;
3559 begin
3560 if NewEdges <> nil then
3561 NewEdges.Clear;
3562 Result:=0;
3563 if FVertices.Count > 0 then begin
3564 SetTempForVertices(-1);
3565 V1:=FVertices[0];
3566 SetTempFromVertex(V1, 0);
3567 for I:=1 to FVertices.Count - 1 do begin
3568 V2:=FVertices[I];
3569 if V2.FTemp.AsPtrInt < 0 then begin
3570 SetTempFromVertex(V2, 0);
3571 E:=AddEdge(V1, V2);
3572 Inc(Result);
3573 if NewEdges <> nil then
3574 NewEdges.Add(E);
3575 end;
3576 end;
3577 FConnected:=True;
3578 Include(FStates, gsValidConnected);
3579 end;
3580 end;
3581
TGraph.FindArticulationPointsnull3582 function TGraph.FindArticulationPoints(FromVertex: TVertex; Points: TClassList): Bool;
3583 var
3584 Counter: Integer;
3585 LowPt: TIntegerVector;
3586 Parents: TClassList;
3587
FindFromnull3588 function FindFrom(V: TVertex): Bool;
3589 var
3590 I: Integer;
3591 U, Neighbour: TVertex;
3592 begin
3593 Result:=False;
3594 V.FTemp.AsPtrInt:=Counter;
3595 LowPt[V.Index]:=Counter;
3596 Inc(Counter);
3597 U:=nil;
3598 for I:=0 to V.NeighbEdges.Count - 1 do begin
3599 Neighbour:=V.Neighbour[I];
3600 if Neighbour <> V then begin
3601 if U = nil then
3602 U:=Neighbour;
3603 if Neighbour.FTemp.AsPtrInt < 0 then begin
3604 Parents[Neighbour.Index]:=V;
3605 if FindFrom(Neighbour) then begin
3606 Result:=True;
3607 if Points = nil then
3608 Exit;
3609 end;
3610 if (LowPt[Neighbour.Index] = V.FTemp.AsPtrInt) and
3611 ((Neighbour <> U) or (Parents[V.Index] <> nil)) then
3612 begin
3613 { V - узел сочленения (удаление V приведет к потере связности) }
3614 Result:=True;
3615 if Points = nil then
3616 Exit;
3617 Points.Add(V)
3618 end;
3619 LowPt[V.Index]:=IntMin(LowPt[V.Index], LowPt[Neighbour.Index]);
3620 end
3621 else
3622 LowPt[V.Index]:=IntMin(LowPt[V.Index], Neighbour.FTemp.AsPtrInt);
3623 end;
3624 end;
3625 end;
3626
3627 begin
3628 if Points <> nil then
3629 Points.Clear;
3630 SetTempForVertices(-1);
3631 LowPt:=TIntegerVector.Create(FVertices.Count, -1);
3632 Parents:=TClassList.Create;
3633 try
3634 Parents.Count:=FVertices.Count;
3635 Counter:=0;
3636 Result:=FindFrom(FromVertex);
3637 finally
3638 LowPt.Free;
3639 Parents.Free;
3640 end;
3641 end;
3642
Biconnectednull3643 function TGraph.Biconnected(ArticulationPoints: TClassList): Bool;
3644 begin
3645 if Connected then
3646 Result:=not FindArticulationPoints(FVertices[0], ArticulationPoints)
3647 else
3648 Result:=False;
3649 end;
3650
MakeBiconnectednull3651 function TGraph.MakeBiconnected(NewEdges: TClassList): Integer;
3652 var
3653 Counter: Integer;
3654 LowPt: TIntegerVector;
3655 Parents: TClassList;
3656
3657 procedure MakeFrom(V: TVertex);
3658 var
3659 I: Integer;
3660 U, Neighbour: TVertex;
3661 E: TEdge;
3662 begin
3663 V.FTemp.AsPtrInt:=Counter;
3664 LowPt[V.Index]:=Counter;
3665 Inc(Counter);
3666 U:=nil;
3667 for I:=0 to V.NeighbEdges.Count - 1 do begin
3668 Neighbour:=V.Neighbour[I];
3669 if Neighbour <> V then begin
3670 if U = nil then
3671 U:=Neighbour;
3672 if Neighbour.FTemp.AsPtrInt < 0 then begin
3673 Parents[Neighbour.Index]:=V;
3674 MakeFrom(Neighbour);
3675 if LowPt[Neighbour.Index] = V.FTemp.AsPtrInt then
3676 if Neighbour = U then
3677 if Parents[V.Index] <> nil then begin
3678 { V - узел сочленения }
3679 E:=AddEdge(Parents[V.Index], Neighbour);
3680 Inc(Result);
3681 if NewEdges <> nil then
3682 NewEdges.Add(E);
3683 end
3684 else
3685 else begin
3686 { V - узел сочленения }
3687 E:=AddEdge(U, Neighbour);
3688 Inc(Result);
3689 if NewEdges <> nil then
3690 NewEdges.Add(E);
3691 end;
3692 LowPt[V.Index]:=IntMin(LowPt[V.Index], LowPt[Neighbour.Index]);
3693 end
3694 else
3695 LowPt[V.Index]:=IntMin(LowPt[V.Index], Neighbour.FTemp.AsPtrInt);
3696 end;
3697 end;
3698 end;
3699
3700 var
3701 N: Integer;
3702 begin
3703 N:=FVertices.Count;
3704 if N > 0 then begin
3705 if NewEdges <> nil then
3706 NewEdges.Clear;
3707 Result:=MakeConnected(NewEdges);
3708 SetTempForVertices(-1);
3709 LowPt:=TIntegerVector.Create(N, -1);
3710 Parents:=TClassList.Create;
3711 try
3712 Parents.Count:=N;
3713 Counter:=0;
3714 MakeFrom(FVertices[0]);
3715 finally
3716 LowPt.Free;
3717 Parents.Free;
3718 end;
3719 FConnected:=True;
3720 Include(FStates, gsValidConnected);
3721 end
3722 else
3723 Result:=0;
3724 end;
3725
Bipartitenull3726 function TGraph.Bipartite(A: TBoolVector): Bool;
3727
BipartiteDFSnull3728 function BipartiteDFS(FromVertex: TVertex): Bool;
3729 var
3730 I: Integer;
3731 V, Neighbour: TVertex;
3732 Q: TPointerQueue;
3733 begin
3734 FromVertex.FTemp.AsPtrInt:=0;
3735 Q:=TPointerQueue.Create;
3736 try
3737 Q.AddAfter(FromVertex);
3738 repeat
3739 V:=Q.Head;
3740 for I:=0 to V.NeighbEdges.Count - 1 do begin
3741 Neighbour:=V.Neighbour[I];
3742 if Neighbour.FTemp.AsPtrInt = -1 then begin
3743 Q.AddAfter(Neighbour);
3744 Neighbour.FTemp.AsPtrInt:=1 - V.FTemp.AsPtrInt;
3745 end
3746 else
3747 if Neighbour.FTemp.AsPtrInt = V.FTemp.AsPtrInt then begin
3748 Result:=False;
3749 Exit;
3750 end;
3751 end;
3752 Q.DeleteHead;
3753 until Q.IsEmpty;
3754 Result:=True;
3755 finally
3756 Q.Free;
3757 end;
3758 end;
3759
3760 var
3761 I: Integer;
3762 V: TVertex;
3763 begin
3764 SetTempForVertices(-1);
3765 for I:=0 to FVertices.Count - 1 do begin
3766 V:=FVertices[I];
3767 if (V.FTemp.AsPtrInt = -1) and not BipartiteDFS(V) then begin
3768 Result:=False;
3769 Exit;
3770 end;
3771 end;
3772 if A <> nil then begin
3773 A.Count:=FVertices.Count;
3774 for I:=0 to FVertices.Count - 1 do
3775 A[I]:=TVertex(FVertices[I]).FTemp.AsPtrInt <> 0;
3776 end;
3777 Result:=True;
3778 end;
3779
IsTreenull3780 function TGraph.IsTree: Bool;
3781 begin
3782 Result:=(FEdges.Count = FVertices.Count - 1) and Connected;
3783 end;
3784
IsRegularnull3785 function TGraph.IsRegular: Bool;
3786 var
3787 I, OldDegree: Integer;
3788 begin
3789 if FVertices.Count > 0 then begin
3790 OldDegree:=TVertex(FVertices[0]).NeighbEdges.Count;
3791 for I:=1 to FVertices.Count - 1 do
3792 if TVertex(FVertices[I]).NeighbEdges.Count <> OldDegree then begin
3793 Result:=False;
3794 Exit;
3795 end;
3796 end;
3797 Result:=True;
3798 end;
3799
HasParallelEdgesnull3800 function TGraph.HasParallelEdges: Bool;
3801 var
3802 I, J: Integer;
3803 E1, E2: TEdge;
3804 NeighbEdges: TClassList;
3805 begin
3806 for I:=0 to FEdges.Count - 1 do begin
3807 E1:=FEdges[I];
3808 NeighbEdges:=E1.V1.NeighbEdges;
3809 if E1.V2.NeighbEdges.Count < NeighbEdges.Count then
3810 NeighbEdges:=E1.V2.NeighbEdges;
3811 for J:=0 to NeighbEdges.Count - 1 do begin
3812 E2:=NeighbEdges[J];
3813 if (E2 <> E1) and E2.ParallelToEdge(E1) then begin
3814 Result:=True;
3815 Exit;
3816 end;
3817 end;
3818 end;
3819 Result:=False;
3820 end;
3821
3822 {$IFDEF V_ALLOW_DEPRECATE}
HasDuplicateEdgesnull3823 function TGraph.HasDuplicateEdges: Bool;
3824 begin
3825 Result:=HasParallelEdges;
3826 end;
3827 {$ENDIF}
3828
TGraph.HasLoopsnull3829 function TGraph.HasLoops: Bool;
3830 var
3831 I: Integer;
3832 begin
3833 for I:=0 to FEdges.Count - 1 do
3834 if TEdge(FEdges[I]).IsLoop then begin
3835 Result:=True;
3836 Exit;
3837 end;
3838 Result:=False;
3839 end;
3840
RemoveParallelEdgesnull3841 function TGraph.RemoveParallelEdges: Bool;
3842 var
3843 I, J, K, N: Integer;
3844 M: TIntegerMatrix;
3845 begin
3846 Result:=False;
3847 M:=CreateExtendedConnectionMatrix;
3848 try
3849 N:=FVertices.Count - 1;
3850 if Directed in Features then
3851 for I:=0 to N do
3852 for J:=0 to N do
3853 for K:=2 to M[I, J] do begin
3854 Result:=True;
3855 GetArcI(I, J).Free;
3856 end
3857 else
3858 for I:=0 to N do
3859 for J:=I to N do
3860 for K:=2 to M[I, J] do begin
3861 Result:=True;
3862 GetEdgeI(I, J).Free;
3863 end;
3864 finally
3865 M.Free;
3866 end;
3867 end;
3868
3869 {$IFDEF V_ALLOW_DEPRECATE}
RemoveDuplicateEdgesnull3870 function TGraph.RemoveDuplicateEdges: Bool;
3871 begin
3872 Result:=RemoveParallelEdges;
3873 end;
3874 {$ENDIF}
3875
RemoveLoopsnull3876 function TGraph.RemoveLoops: Bool;
3877 var
3878 I: Integer;
3879 E: TEdge;
3880 begin
3881 Result:=False;
3882 for I:=FEdges.Count - 1 downto 0 do begin
3883 E:=FEdges[I];
3884 if E.IsLoop then begin
3885 E.Free;
3886 Result:=True;
3887 end;
3888 end;
3889 end;
3890
TGraph.HideLoopsnull3891 function TGraph.HideLoops(Loops: TClassList): Integer;
3892 var
3893 I: Integer;
3894 E: TEdge;
3895 begin
3896 Loops.Clear;
3897 for I:=FEdges.Count - 1 downto 0 do begin
3898 E:=FEdges[I];
3899 if E.IsLoop then begin
3900 E.Hide;
3901 Loops.Add(E);
3902 end;
3903 end;
3904 Loops.Pack;
3905 Result:=Loops.Count;
3906 end;
3907
3908 procedure TGraph.RestoreLoops(Loops: TClassList);
3909 var
3910 I: Integer;
3911 begin
3912 for I:=Loops.Count - 1 downto 0 do
3913 TEdge(Loops[I]).Restore;
3914 end;
3915
ParallelEdgeCountnull3916 function TGraph.ParallelEdgeCount: Integer;
3917 var
3918 I, J: Integer;
3919 E1, E2: TEdge;
3920 begin
3921 Result:=0;
3922 for I:=0 to FEdges.Count - 1 do begin
3923 E1:=FEdges[I];
3924 for J:=0 to E1.V1.NeighbEdges.Count - 1 do begin
3925 E2:=E1.V1.NeighbEdges[J];
3926 if (E2 <> E1) and E2.ParallelToEdge(E1) then begin
3927 Inc(Result);
3928 Break;
3929 end;
3930 end;
3931 end;
3932 end;
3933
3934 {$IFDEF V_ALLOW_DEPRECATE}
TGraph.DuplicateEdgeCountnull3935 function TGraph.DuplicateEdgeCount: Integer;
3936 begin
3937 Result:=ParallelEdgeCount;
3938 end;
3939 {$ENDIF}
3940
LoopCountnull3941 function TGraph.LoopCount: Integer;
3942 var
3943 I: Integer;
3944 begin
3945 Result:=0;
3946 for I:=0 to FEdges.Count - 1 do
3947 if TEdge(FEdges[I]).IsLoop then
3948 Inc(Result);
3949 end;
3950
SeparateCountnull3951 function TGraph.SeparateCount: Integer;
3952 begin
3953 CheckValidSeparates;
3954 Result:=FSeparateCount;
3955 end;
3956
TGraph.RingEdgeCountnull3957 function TGraph.RingEdgeCount: Integer;
3958 begin
3959 CheckValidRingEdges;
3960 Result:=FRingEdgeCount;
3961 end;
3962
TGraph.CyclomaticNumbernull3963 function TGraph.CyclomaticNumber: Integer;
3964 begin
3965 Result:=FEdges.Count - FVertices.Count + SeparateCount;
3966 end;
3967
TGraph.GetEdgenull3968 function TGraph.GetEdge(Vertex1, Vertex2: TVertex): TEdge;
3969 var
3970 I: Integer;
3971 begin
3972 Result:=nil;
3973 if Vertex1 <> nil then
3974 for I:=0 to Vertex1.NeighbEdges.Count - 1 do
3975 if Vertex1.Neighbour[I] = Vertex2 then begin
3976 Result:=Vertex1.NeighbEdges[I];
3977 Exit;
3978 end;
3979 end;
3980
GetEdgeInull3981 function TGraph.GetEdgeI(I1, I2: Integer): TEdge;
3982 var
3983 N: Integer;
3984 begin
3985 N:=FVertices.Count;
3986 if (I1 >= 0) and (I1 < N) and (I2 >= 0) and (I2 < N) then
3987 Result:=GetEdge(FVertices[I1], FVertices[I2])
3988 else
3989 Result:=nil;
3990 end;
3991
3992 procedure TGraph.GetEdges(EdgeList: TClassList; Vertex1, Vertex2: TVertex);
3993 var
3994 I: Integer;
3995 begin
3996 EdgeList.Clear;
3997 if Vertex1 <> nil then begin
3998 for I:=0 to Vertex1.NeighbEdges.Count - 1 do
3999 if Vertex1.Neighbour[I] = Vertex2 then
4000 EdgeList.Add(Vertex1.NeighbEdges[I]);
4001 EdgeList.Pack;
4002 end;
4003 end;
4004
4005 procedure TGraph.GetEdgesI(EdgeList: TClassList; I1, I2: Integer);
4006 var
4007 N: Integer;
4008 V1, V2: TVertex;
4009 begin
4010 N:=FVertices.Count;
4011 V1:=nil;
4012 if (I1 >= 0) and (I1 < N) then
4013 V1:=FVertices[I1];
4014 V2:=nil;
4015 if (I2 >= 0) and (I2 < N) then
4016 V2:=FVertices[I2];
4017 GetEdges(EdgeList, V1, V2);
4018 end;
4019
4020 procedure TGraph.SetFeatures(Value: TGraphFeatures);
4021 begin
4022 if Value <> FFeatures then begin
4023 if (Directed in Value) xor (Directed in FFeatures) then
4024 Exclude(FStates, gsValidRingEdges);
4025 if Tree in Value then begin
4026 Map.SafeCreateAttr(GAttrRoot, AttrPointer);
4027 SafeCreateVertexAttr(GAttrHasParent, AttrBool);
4028 end
4029 else begin
4030 Map.SafeDropAttr(GAttrRoot);
4031 SafeDropVertexAttr(GAttrHasParent);
4032 end;
4033 if Network in Value then begin
4034 Include(Value, Directed); { сеть - всегда орграф }
4035 Map.SafeCreateAttr(GAttrNetworkSource, AttrPointer);
4036 Map.SafeCreateAttr(GAttrNetworkSink, AttrPointer);
4037 SafeCreateEdgeAttr(GAttrMaxFlow, AttrFloat);
4038 SafeCreateEdgeAttr(GAttrFlow, AttrFloat);
4039 end
4040 else begin
4041 Map.SafeDropAttr(GAttrNetworkSource);
4042 Map.SafeDropAttr(GAttrNetworkSink);
4043 SafeDropEdgeAttr(GAttrMaxFlow);
4044 SafeDropEdgeAttr(GAttrFlow);
4045 end;
4046 if Weighted in Value then
4047 SafeCreateEdgeAttr(GAttrWeight, AttrFloat)
4048 else
4049 SafeDropEdgeAttr(GAttrWeight);
4050 if Geom3D in Value then
4051 Include(Value, Geom2D);
4052 if Geom2D in Value then begin
4053 SafeCreateVertexAttr(GAttrX, AttrFloat);
4054 SafeCreateVertexAttr(GAttrY, AttrFloat);
4055 end
4056 else begin
4057 SafeDropVertexAttr(GAttrX);
4058 SafeDropVertexAttr(GAttrY);
4059 end;
4060 if Geom3D in Value then
4061 SafeCreateVertexAttr(GAttrZ, AttrFloat)
4062 else
4063 SafeDropVertexAttr(GAttrZ);
4064 FFeatures:=Value;
4065 end;
4066 end;
4067
4068 procedure TGraph.SetTempToSubtreeSize(FromVertex: TVertex);
4069 var
4070 I: Integer;
4071 E: TEdge;
4072
CountSubTreesnull4073 function CountSubTrees(V: TVertex): Integer;
4074 var
4075 I: Integer;
4076 E: TEdge;
4077 begin
4078 Result:=0;
4079 for I:=0 to V.NeighbEdges.Count - 1 do begin
4080 E:=V.NeighbEdges[I];
4081 if E.FTemp.AsPtrInt = -2 then begin
4082 E.FTemp.AsPtrInt:=-1;
4083 Inc(Result, CountSubTrees(E.OtherVertex(V)) + 1);
4084 end;
4085 end;
4086 V.FTemp.AsPtrInt:=Result;
4087 end;
4088
4089 begin
4090 BFSFromVertex(FromVertex);
4091 for I:=0 to FEdges.Count - 1 do begin
4092 E:=FEdges[I];
4093 { исключаем петли и "горизонтальные" ребра }
4094 if E.V1.FTemp.AsPtrInt <> E.V2.FTemp.AsPtrInt then
4095 E.FTemp.AsPtrInt:=-2
4096 else
4097 E.FTemp.AsPtrInt:=0;
4098 end;
4099 CountSubTrees(FromVertex);
4100 end;
4101
4102 procedure TGraph.TreeTraversal(FromVertex: TVertex; VertexPath: TClassList);
4103
4104 procedure DoTraversal(V: TVertex);
4105 var
4106 I: Integer;
4107 VTemp: Int32;
4108 Neighbour: TVertex;
4109 begin
4110 VertexPath.Add(V);
4111 VTemp:=V.FTemp.AsPtrInt;
4112 for I:=0 to V.NeighbEdges.Count - 1 do begin
4113 Neighbour:=V.Neighbour[I];
4114 if Neighbour.FTemp.AsPtrInt > VTemp then
4115 DoTraversal(Neighbour);
4116 end;
4117 end;
4118
4119 begin
4120 VertexPath.Clear;
4121 BFSFromVertex(FromVertex);
4122 DoTraversal(FromVertex);
4123 VertexPath.Pack;
4124 end;
4125
4126 type
4127 { используется для сортировки поддеревьев }
4128 TArrangeHelper = class
4129 Limit: Int32;
4130 CurrentVertex: TVertex;
4131 FCompareVertices, FCompareEdges: TCompareEvent;
4132 constructor Create(ACompareVertices, ACompareEdges: TCompareEvent);
CompareEdgesnull4133 function CompareEdges(Edge1, Edge2: Pointer): Integer;
4134 end;
4135
4136 constructor TArrangeHelper.Create(ACompareVertices, ACompareEdges: TCompareEvent);
4137 begin
4138 inherited Create;
4139 FCompareVertices:=ACompareVertices;
4140 FCompareEdges:=ACompareEdges;
4141 end;
4142
TArrangeHelper.CompareEdgesnull4143 function TArrangeHelper.CompareEdges(Edge1, Edge2: Pointer): Integer;
4144 var
4145 B: Bool;
4146 V1, V2: TVertex;
4147
CompareSubtreesnull4148 function CompareSubtrees(From1, From2: TVertex): Integer;
4149 { сравнивает поддеревья графа с корнями From1 и From2 }
4150 var
4151 I: Integer;
4152 DownEdges1, DownEdges2: TClassList;
4153
4154 procedure GetDownEdges(From: TVertex; DownEdges: TClassList);
4155 { определить ребра, ведущие к дочерним вершинам }
4156 var
4157 I: Integer;
4158 VTemp: Int32;
4159 E: TEdge;
4160 begin
4161 DownEdges.Clear;
4162 VTemp:=From.FTemp.AsPtrInt;
4163 for I:=0 to From.NeighbEdges.Count - 1 do begin
4164 E:=From.NeighbEdges[I];
4165 if (E.FTemp.AsPtrInt = -1) and (E.OtherVertex(From).FTemp.AsPtrInt < VTemp) then
4166 DownEdges.Add(E);
4167 end;
4168 end;
4169
4170 begin
4171 { сравнить количество вершин в поддеревьях }
4172 Result:=From1.FTemp.AsPtrInt - From2.FTemp.AsPtrInt;
4173 if Result = 0 then begin
4174 { сравнить степени корней }
4175 Result:=From1.NeighbEdges.Count - From2.NeighbEdges.Count;
4176 if Result = 0 then begin
4177 { сравнить атрибуты корней }
4178 Result:=FCompareVertices(From1, From2);
4179 if Result = 0 then begin
4180 { определить ребра, ведущие к дочерним вершинам }
4181 DownEdges1:=TClassList.Create;
4182 DownEdges2:=TClassList.Create;
4183 try
4184 GetDownEdges(From1, DownEdges1);
4185 GetDownEdges(From2, DownEdges2);
4186 Result:=DownEdges1.Count - DownEdges2.Count;
4187 if Result = 0 then begin
4188 { сравнить атрибуты ребер, ведущих к дочерним вершинам }
4189 for I:=0 to DownEdges1.Count - 1 do begin
4190 Result:=FCompareEdges(DownEdges1[I], DownEdges2[I]);
4191 if Result <> 0 then
4192 Exit;
4193 end;
4194 { сравнить поддеревья }
4195 for I:=0 to DownEdges1.Count - 1 do begin
4196 Result:=CompareSubtrees(TEdge(DownEdges1[I]).OtherVertex(From1),
4197 TEdge(DownEdges2[I]).OtherVertex(From2));
4198 if Result <> 0 then
4199 Exit;
4200 end;
4201 end;
4202 finally
4203 DownEdges1.Free;
4204 DownEdges2.Free;
4205 end;
4206 end; {if}
4207 end; {if}
4208 end; {if}
4209 end;
4210
4211 begin
4212 if Edge1 <> Edge2 then begin
4213 V1:=TEdge(Edge1).OtherVertex(CurrentVertex);
4214 V2:=TEdge(Edge2).OtherVertex(CurrentVertex);
4215 B:=V1.FTemp.AsPtrInt < Limit;
4216 if B and (V2.FTemp.AsPtrInt < Limit) then
4217 Result:=CompareSubtrees(V1, V2)
4218 else { одно из ребер - ссылка "вверх" }
4219 if B then
4220 Result:=-1
4221 else
4222 Result:=1;
4223 end
4224 else
4225 Result:=0;
4226 end;
4227
4228 procedure TGraph.ArrangeTree(FromVertex: TVertex; CompareVertices,
4229 CompareEdges: TCompareEvent);
4230 var
4231 ArrangeHelper: TArrangeHelper;
4232
4233 procedure DoArrange(V: TVertex);
4234 var
4235 I: Integer;
4236 E: TEdge;
4237 begin
4238 for I:=0 to V.NeighbEdges.Count - 1 do begin
4239 E:=V.NeighbEdges[I];
4240 if E.FTemp.AsPtrInt = -1 then begin
4241 E.FTemp.AsPtrInt:=-2;
4242 DoArrange(E.OtherVertex(V));
4243 end;
4244 end;
4245 ArrangeHelper.Limit:=V.FTemp.AsPtrInt;
4246 ArrangeHelper.CurrentVertex:=V;
4247 V.NeighbEdges.ConservativeSortByObject(ArrangeHelper.CompareEdges);
4248 end;
4249
4250 begin
4251 if not IsTree then
4252 Error(SMethodNotApplicable);
4253 SetTempToSubtreeSize(FromVertex);
4254 ArrangeHelper:=TArrangeHelper.Create(CompareVertices, CompareEdges);
4255 try
4256 DoArrange(FromVertex);
4257 finally
4258 ArrangeHelper.Free;
4259 end;
4260 end;
4261
4262 procedure TGraph.SortTree(FromVertex: TVertex; CompareVertices: TCompareEvent);
4263
4264 procedure DoSort(V: TVertex);
4265 var
4266 I: Integer;
4267 begin
4268 for I:=0 to V.ChildCount - 1 do
4269 DoSort(V.Childs[I]);
4270 V.SortChilds(CompareVertices);
4271 end;
4272
4273 begin
4274 DoSort(FromVertex);
4275 end;
4276
CreateConnectionMatrixnull4277 function TGraph.CreateConnectionMatrix: TBoolMatrix;
4278 var
4279 I: Integer;
4280 E: TEdge;
4281 begin
4282 I:=FVertices.Count;
4283 if Directed in Features then
4284 Result:=TBoolMatrix.Create(I, I, False)
4285 else
4286 Result:=TSimBoolMatrix.Create(I, False);
4287 try
4288 Result.SetDiagonal(True);
4289 for I:=0 to FEdges.Count - 1 do begin
4290 E:=FEdges[I];
4291 Result[E.V1.Index, E.V2.Index]:=True;
4292 end;
4293 except
4294 Result.Free;
4295 raise;
4296 end;
4297 end;
4298
CreateExtendedConnectionMatrixnull4299 function TGraph.CreateExtendedConnectionMatrix: TIntegerMatrix;
4300 var
4301 I: Integer;
4302 E: TEdge;
4303 begin
4304 I:=FVertices.Count;
4305 if Directed in Features then
4306 Result:=TIntegerMatrix.Create(I, I, 0)
4307 else
4308 Result:=TSimIntegerMatrix.Create(I, 0);
4309 try
4310 for I:=0 to FEdges.Count - 1 do begin
4311 E:=FEdges[I];
4312 Result.IncItem(E.V1.Index, E.V2.Index, 1);
4313 end;
4314 except
4315 Result.Free;
4316 raise;
4317 end;
4318 end;
4319
CreateReachabilityMatrixnull4320 function TGraph.CreateReachabilityMatrix: TBoolMatrix;
4321 var
4322 I, J, K, N: Integer;
4323 Changed: Bool;
4324 begin
4325 N:=FVertices.Count;
4326 if not (Directed in Features) then begin
4327 Result:=TSimBoolMatrix.Create(N, False);
4328 if SeparateCount = 1 then
4329 Result.Vector.FillValue(True)
4330 else begin
4331 for I:=0 to N - 1 do begin
4332 K:=TVertex(FVertices[I]).SeparateIndex;
4333 for J:=I to N - 1 do
4334 if TVertex(FVertices[J]).SeparateIndex = K then
4335 Result[I, J]:=True;
4336 end;
4337 end;
4338 end
4339 else begin
4340 Result:=CreateConnectionMatrix;
4341 try
4342 repeat
4343 Changed:=False;
4344 for I:=0 to N - 1 do
4345 for J:=0 to N - 1 do
4346 if (I <> J) and Result[I, J] then begin
4347 for K:=0 to N - 1 do
4348 if Result[J, K] and not Result[I, K] then begin
4349 Result[I, K]:=True;
4350 Changed:=True;
4351 end;
4352 for K:=0 to N - 1 do
4353 if Result[K, I] and not Result[K, J] then begin
4354 Result[K, J]:=True;
4355 Changed:=True;
4356 end;
4357 end;
4358 until not Changed;
4359 except
4360 Result.Free;
4361 raise;
4362 end;
4363 end;
4364 end;
4365
CreateIncidenceMatrixnull4366 function TGraph.CreateIncidenceMatrix: TBoolMatrix;
4367 var
4368 I: Integer;
4369 begin
4370 Result:=TBoolMatrix.Create(FVertices.Count, FEdges.Count, False);
4371 try
4372 for I:=0 to FEdges.Count - 1 do With TEdge(FEdges[I]) do begin
4373 Result[V1.Index, I]:=True;
4374 Result[V2.Index, I]:=True;
4375 end;
4376 except
4377 Result.Free;
4378 raise;
4379 end;
4380 end;
4381
CreateDistanceMatrixnull4382 function TGraph.CreateDistanceMatrix: TIntegerMatrix;
4383 var
4384 I, J, N: Integer;
4385 begin
4386 N:=FVertices.Count;
4387 Result:=nil;
4388 try
4389 if Directed in Features then begin
4390 Result:=TIntegerMatrix.Create(N, N, 0);
4391 for I:=0 to N - 1 do begin
4392 BFSFromVertexDirected(FVertices[I]);
4393 for J:=0 to N - 1 do
4394 Result[I, J]:=TVertex(FVertices[J]).FTemp.AsPtrInt;
4395 end;
4396 end
4397 else begin
4398 Result:=TSimIntegerMatrix.Create(N, 0);
4399 for I:=0 to N - 1 do begin
4400 BFSFromVertex(FVertices[I]);
4401 for J:=I + 1 to N - 1 do
4402 Result[I, J]:=TVertex(FVertices[J]).FTemp.AsPtrInt;
4403 end;
4404 end;
4405 except
4406 Result.Free;
4407 raise;
4408 end;
4409 end;
4410
TGraph.CreateDegreesVectornull4411 function TGraph.CreateDegreesVector: TIntegerVector;
4412 var
4413 I, N: Integer;
4414 begin
4415 N:=FVertices.Count;
4416 Result:=TIntegerVector.Create(N, 0);
4417 try
4418 for I:=0 to N - 1 do
4419 Result[I]:=TVertex(FVertices[I]).NeighbEdges.Count;
4420 except
4421 Result.Free;
4422 raise;
4423 end;
4424 end;
4425
CreateInt64DegreesVectornull4426 function TGraph.CreateInt64DegreesVector: TInt64Vector;
4427 var
4428 I, N: Integer;
4429 begin
4430 N:=FVertices.Count;
4431 Result:=TInt64Vector.Create(N, 0);
4432 try
4433 for I:=0 to N - 1 do
4434 Result[I]:=TVertex(FVertices[I]).NeighbEdges.Count;
4435 except
4436 Result.Free;
4437 raise;
4438 end;
4439 end;
4440
UpdateSpectrumnull4441 function TGraph.UpdateSpectrum(Spectrum, SortedSpectrum, TempVector: TInt64Vector): Integer;
4442 var
4443 I, J, N: Integer;
4444 OldValue: Int64;
4445 V: TVertex;
4446 begin
4447 Result:=0;
4448 N:=FVertices.Count;
4449 if N > 0 then begin
4450 TempVector.Assign(Spectrum);
4451 for I:=0 to N - 1 do begin
4452 V:=FVertices[I];
4453 for J:=0 to V.NeighbEdges.Count - 1 do
4454 Spectrum.IncItem(I, TempVector[TEdge(V.NeighbEdges[J]).OtherVertex(V).Index]);
4455 end;
4456 if SortedSpectrum = nil then
4457 SortedSpectrum:=TempVector;
4458 SortedSpectrum.Assign(Spectrum);
4459 SortedSpectrum.Sort;
4460 OldValue:=SortedSpectrum[0];
4461 Inc(Result);
4462 for I:=1 to N - 1 do
4463 if SortedSpectrum[I] <> OldValue then begin
4464 Inc(Result);
4465 OldValue:=SortedSpectrum[I];
4466 end;
4467 end;
4468 end;
4469
4470 {$IFDEF NOWARN}{$WARNINGS OFF}{$ENDIF}
TGraph.EqualToGraphnull4471 function TGraph.EqualToGraph(G: TGraph; IsomorphousMap: TGenericIntegerVector;
4472 CompareVertices, CompareEdges: TCompareFunc): Bool;
4473
CompareNeighbIndexesnull4474 function CompareNeighbIndexes(NeighbIndexes1, NeighbIndexes2: TIntegerVector;
4475 NeighbEdges1, NeighbEdges2: TClassList): Bool;
4476 begin
4477 if Assigned(CompareEdges) then begin
4478 NeighbIndexes1.SortWith(NeighbEdges1);
4479 NeighbIndexes2.SortWith(NeighbEdges2);
4480 end
4481 else begin
4482 NeighbIndexes1.Sort;
4483 NeighbIndexes2.Sort;
4484 end;
4485 Result:=NeighbIndexes1.EqualTo(NeighbIndexes2);
4486 end;
4487
CompareNeighbEdgesnull4488 function CompareNeighbEdges(NeighbIndexes: TIntegerVector;
4489 NeighbEdges1, NeighbEdges2: TClassList): Bool;
4490 var
4491 RangeBegin, RangeEnd: Integer;
4492
CompareRangenull4493 function CompareRange: Bool;
4494 var
4495 K, L: Integer;
4496 Found: Bool;
4497 E: TEdge;
4498 begin
4499 Result:=False;
4500 if RangeEnd > RangeBegin then
4501 for K:=RangeBegin to RangeEnd do begin
4502 Found:=False;
4503 E:=NeighbEdges1[K];
4504 for L:=RangeBegin to RangeEnd do
4505 if (NeighbEdges2[L] <> nil) and
4506 (CompareEdges(E, NeighbEdges2[L]) = 0) then
4507 begin
4508 Found:=True;
4509 NeighbEdges2[L]:=nil;
4510 Break;
4511 end;
4512 if not Found then
4513 Exit;
4514 end
4515 else
4516 if CompareEdges(NeighbEdges1[RangeBegin], NeighbEdges2[RangeBegin]) <> 0 then
4517 Exit;
4518 Result:=True;
4519 end;
4520
4521 var
4522 I, N, LastNeighbour: Integer;
4523 begin
4524 N:=NeighbIndexes.Count;
4525 if N > 0 then begin
4526 Result:=False;
4527 LastNeighbour:=NeighbIndexes[0];
4528 RangeBegin:=0;
4529 RangeEnd:=0;
4530 for I:=1 to N - 1 do begin
4531 if NeighbIndexes[I] <> LastNeighbour then begin
4532 if not CompareRange then
4533 Exit;
4534 RangeBegin:=I;
4535 end;
4536 Inc(RangeEnd);
4537 end;
4538 if not CompareRange then
4539 Exit;
4540 end;
4541 Result:=True;
4542 end;
4543
4544 var
4545 I, J, N: Integer;
4546 IsDirected: Bool;
4547 V1, V2: TVertex;
4548 E: TEdge;
4549 InNeighbIndexes1, InNeighbIndexes2, OutNeighbIndexes1, OutNeighbIndexes2: TIntegerVector;
4550 InNeighbEdges1, InNeighbEdges2, OutNeighbEdges1, OutNeighbEdges2: TClassList;
4551 begin
4552 Result:=False;
4553 if (FVertices.Count = G.FVertices.Count) and (FEdges.Count = G.FEdges.Count) and
4554 ((Directed in Features) = (Directed in G.Features)) then
4555 begin
4556 for I:=0 to FVertices.Count - 1 do
4557 TVertex(FVertices[I]).FTemp.AsPtrInt:=IsomorphousMap[I];
4558 InNeighbIndexes1:=TIntegerVector.Create(0, 0);
4559 InNeighbIndexes2:=TIntegerVector.Create(0, 0);
4560 IsDirected:=Directed in Features;
4561 if IsDirected then begin
4562 OutNeighbIndexes1:=TIntegerVector.Create(0, 0);
4563 OutNeighbIndexes2:=TIntegerVector.Create(0, 0);
4564 end;
4565 if Assigned(CompareEdges) or IsDirected then begin
4566 InNeighbEdges1:=TClassList.Create;
4567 InNeighbEdges2:=TClassList.Create;
4568 if IsDirected then begin
4569 OutNeighbEdges1:=TClassList.Create;
4570 OutNeighbEdges2:=TClassList.Create;
4571 end;
4572 end;
4573 try
4574 for I:=0 to FVertices.Count - 1 do begin
4575 V1:=FVertices[I];
4576 V2:=G.FVertices[IsomorphousMap[I]];
4577 N:=V1.NeighbEdges.Count;
4578 { проверяем совпадение степеней вершин, а также их атрибутов }
4579 if (N <> V2.NeighbEdges.Count) or
4580 Assigned(CompareVertices) and (CompareVertices(V1, V2) <> 0) then
4581 Exit;
4582 if N > 0 then begin
4583 { проверяем совпадение "окружения" }
4584 if IsDirected then begin
4585 InNeighbIndexes1.Clear;
4586 InNeighbEdges1.Clear;
4587 OutNeighbIndexes1.Clear;
4588 OutNeighbEdges1.Clear;
4589 for J:=0 to V1.NeighbEdges.Count - 1 do begin
4590 E:=V1.NeighbEdges[J];
4591 if E.V1 = V1 then begin
4592 OutNeighbEdges1.Add(E);
4593 OutNeighbIndexes1.Add(E.V2.FTemp.AsPtrInt);
4594 end
4595 else begin
4596 InNeighbEdges1.Add(E);
4597 InNeighbIndexes1.Add(E.V1.FTemp.AsPtrInt);
4598 end;
4599 end;
4600 InNeighbIndexes2.Clear;
4601 InNeighbEdges2.Clear;
4602 OutNeighbIndexes2.Clear;
4603 OutNeighbEdges2.Clear;
4604 for J:=0 to V2.NeighbEdges.Count - 1 do begin
4605 E:=V2.NeighbEdges[J];
4606 if E.V1 = V2 then begin
4607 OutNeighbEdges2.Add(E);
4608 OutNeighbIndexes2.Add(E.V2.Index);
4609 end
4610 else begin
4611 InNeighbEdges2.Add(E);
4612 InNeighbIndexes2.Add(E.V1.Index);
4613 end;
4614 end;
4615 if not CompareNeighbIndexes(OutNeighbIndexes1, OutNeighbIndexes2,
4616 OutNeighbEdges1, OutNeighbEdges2)
4617 then
4618 Exit;
4619 end
4620 else begin
4621 InNeighbIndexes1.Count:=N;
4622 InNeighbIndexes2.Count:=N;
4623 for J:=0 to N - 1 do begin
4624 InNeighbIndexes1[J]:=V1.Neighbour[J].FTemp.AsPtrInt;
4625 InNeighbIndexes2[J]:=V2.Neighbour[J].Index;
4626 end;
4627 if Assigned(CompareEdges) then begin
4628 InNeighbEdges1.Assign(V1.NeighbEdges);
4629 InNeighbEdges2.Assign(V2.NeighbEdges);
4630 end;
4631 end;
4632 if not CompareNeighbIndexes(InNeighbIndexes1, InNeighbIndexes2,
4633 InNeighbEdges1, InNeighbEdges2)
4634 then
4635 Exit;
4636 { проверяем совпадение атрибутов ребер; петли и кратные ребра требуют
4637 специальной обработки }
4638 if Assigned(CompareEdges) then begin
4639 if not CompareNeighbEdges(InNeighbIndexes1, InNeighbEdges1,
4640 InNeighbEdges2)
4641 then
4642 Exit;
4643 if IsDirected and not CompareNeighbEdges(OutNeighbIndexes1,
4644 OutNeighbEdges1, OutNeighbEdges2)
4645 then
4646 Exit;
4647 end;
4648 end;
4649 end;
4650 finally
4651 InNeighbIndexes1.Free;
4652 InNeighbIndexes2.Free;
4653 if IsDirected then begin
4654 OutNeighbIndexes1.Free;
4655 OutNeighbIndexes2.Free;
4656 end;
4657 if Assigned(CompareEdges) or IsDirected then begin
4658 InNeighbEdges1.Free;
4659 InNeighbEdges2.Free;
4660 if IsDirected then begin
4661 OutNeighbEdges1.Free;
4662 OutNeighbEdges2.Free;
4663 end;
4664 end;
4665 end;
4666 Result:=True;
4667 end;
4668 end;
4669 {$IFDEF NOWARN}{$WARNINGS ON}{$ENDIF}
4670
4671 {$IFDEF NOWARN}{$WARNINGS OFF}{$ENDIF}
4672 procedure TGraph.FindMaxIndependentVertexSets(SelectCode: TSelectCode;
4673 SelectParam: Integer; VertexSets: TMultiList);
4674 { реализован алгоритм систематического перебора Брона и Кэрбоша, описанный в:
4675 "Н.Кристофидес. Теория графов. Алгоритмический подход. М., Мир, 1978 г." }
4676 Label
4677 Label2, Label3, Label5;
4678 var
4679 I, J, ExtremumSize: Integer;
4680 GoodVertex, B1, B2{$IFDEF CHECK_GRAPHS}, B{$ENDIF}: Bool;
4681 V: TVertex;
4682 CurrentSet{S}, ExtremumSet, ActiveList, BackList: TClassList;
4683 SelectedVertices{Xik}: TPointerStack;
4684 ActiveLists{Q+}, BackLists{Q-}, ExtremumSets: TMultiList;
4685
4686 procedure ExcludeNeighbours(AMultiList: TMultiList);
4687 var
4688 I: Integer;
4689 AList: TClassList;
4690 begin
4691 AList:=AMultiList.Last;
4692 AMultiList.AddAssign(AList);
4693 if AList.Count > 0 then
4694 for I:=0 to V.NeighbEdges.Count - 1 do
4695 AMultiList.Last.Remove(V.Neighbour[I]);
4696 end;
4697
4698 begin
4699 VertexSets.Clear;
4700 if FVertices.Count > 0 then begin
4701 CurrentSet:=TClassList.Create;
4702 SelectedVertices:=TPointerStack.Create;
4703 ActiveLists:=TMultiList.Create(TClassList);
4704 BackLists:=TMultiList.Create(TClassList);
4705 ExtremumSets:=nil;
4706 if SelectCode in [SelectAnyMin, SelectAnyMax] then begin
4707 ExtremumSet:=TClassList.Create;
4708 if SelectCode = SelectAnyMin then
4709 ExtremumSize:=MaxInt
4710 else
4711 ExtremumSize:=0;
4712 end
4713 else
4714 if SelectCode in [SelectAllMin, SelectAllMax] then begin
4715 ExtremumSets:=TMultiList.Create(TClassList);
4716 if SelectCode = SelectAllMin then
4717 ExtremumSize:=MaxInt
4718 else
4719 ExtremumSize:=0;
4720 end;
4721 try
4722 ActiveLists.Count:=1;
4723 ActiveLists[0].Assign(FVertices); { Q+(0) = V }
4724 BackLists.Count:=1;
4725 { находим вершину V из Q+ такую, что при добавлении ее в S последнеее
4726 остается независимым }
4727 Label2:
4728 ActiveList:=ActiveLists.Last;
4729 if CurrentSet.Count > 0 then begin
4730 {$IFDEF CHECK_GRAPHS}
4731 B:=False;
4732 {$ENDIF}
4733 for I:=0 to ActiveList.Count - 1 do begin
4734 V:=ActiveList[I];
4735 GoodVertex:=True;
4736 for J:=0 to V.NeighbEdges.Count - 1 do
4737 if CurrentSet.IndexOf(V.Neighbour[J]) >= 0 then begin
4738 GoodVertex:=False;
4739 Break;
4740 end;
4741 if GoodVertex then begin
4742 {$IFDEF CHECK_GRAPHS}
4743 B:=True;
4744 {$ENDIF}
4745 Break;
4746 end;
4747 end;
4748 {$IFDEF CHECK_GRAPHS}
4749 if not B then
4750 Error(SAlgorithmFailure);
4751 {$ENDIF}
4752 end
4753 else
4754 V:=ActiveList[0];
4755 ExcludeNeighbours(ActiveLists); { Q+(k+1) = Q+(k) - [<соседи V>] - [V] }
4756 ActiveLists.Last.Remove(V);
4757 ExcludeNeighbours(BackLists); { Q-(k+1) = Q-(k+1) - [<соседи V>] }
4758 CurrentSet.Add(V);
4759 SelectedVertices.Push(V);
4760 { Inc(k) }
4761 Label3:
4762 { если существует вершина, принадлежащая Q-(k), такая, что ни одна ее
4763 вершина-сосед не входит в Q+(k), то goto Label5, иначе goto Label4 }
4764 ActiveList:=ActiveLists.Last;
4765 BackList:=BackLists.Last;
4766 for I:=0 to BackList.Count - 1 do begin
4767 V:=BackList[I];
4768 GoodVertex:=True;
4769 if ActiveList.Count > 0 then
4770 for J:=0 to V.NeighbEdges.Count - 1 do
4771 if ActiveList.IndexOf(V.Neighbour[J]) >= 0 then begin
4772 GoodVertex:=False;
4773 Break;
4774 end;
4775 if GoodVertex then
4776 goto Label5;
4777 end;
4778 {Label4:}
4779 B1:=ActiveList.Count = 0;
4780 B2:=BackList.Count = 0;
4781 if B1 and B2 then begin
4782 { S является максимальным независимым множеством }
4783 Case SelectCode of
4784 SelectAnyMin:
4785 begin
4786 B1:=False;
4787 if CurrentSet.Count < ExtremumSize then begin
4788 ExtremumSize:=CurrentSet.Count;
4789 ExtremumSet.Assign(CurrentSet);
4790 end;
4791 end;
4792 SelectAnyMax:
4793 begin
4794 B1:=False;
4795 if CurrentSet.Count > ExtremumSize then begin
4796 ExtremumSize:=CurrentSet.Count;
4797 ExtremumSet.Assign(CurrentSet);
4798 end;
4799 end;
4800 SelectAllMin:
4801 begin
4802 B1:=False;
4803 if CurrentSet.Count <= ExtremumSize then begin
4804 if CurrentSet.Count < ExtremumSize then begin
4805 ExtremumSize:=CurrentSet.Count;
4806 ExtremumSets.Clear;
4807 end;
4808 ExtremumSets.AddAssign(CurrentSet);
4809 end;
4810 end;
4811 SelectAllMax:
4812 begin
4813 B1:=False;
4814 if CurrentSet.Count >= ExtremumSize then begin
4815 if CurrentSet.Count > ExtremumSize then begin
4816 ExtremumSize:=CurrentSet.Count;
4817 ExtremumSets.Clear;
4818 end;
4819 ExtremumSets.AddAssign(CurrentSet);
4820 end;
4821 end;
4822 SelectAllGE:
4823 B1:=CurrentSet.Count >= SelectParam;
4824 SelectAllLE:
4825 B1:=CurrentSet.Count <= SelectParam;
4826 Else
4827 B1:=True;
4828 End;
4829 if B1 then
4830 VertexSets.AddAssign(CurrentSet);
4831 if (SelectCode = SelectAny) or (SelectCode = SelectSpecified) and
4832 (VertexSets.Count >= SelectParam)
4833 then
4834 Exit;
4835 end
4836 else
4837 goto Label2;
4838 Label5:
4839 { Dec(k) }
4840 ActiveLists.Grow(-1);
4841 if (CurrentSet.Count > 0) or (ActiveLists.Count > 0) then begin
4842 BackLists.Grow(-1);
4843 V:=SelectedVertices.Pop;
4844 CurrentSet.Remove(V);
4845 ActiveLists.Last.Remove(V);
4846 BackLists.Last.Add(V);
4847 goto Label3;
4848 end
4849 else { конец }
4850 if SelectCode in [SelectAnyMin, SelectAnyMax] then
4851 VertexSets.Add(ExtremumSet)
4852 else
4853 if SelectCode in [SelectAllMin, SelectAllMax] then
4854 VertexSets.Assign(ExtremumSets);
4855 finally
4856 CurrentSet.Free;
4857 ActiveLists.Free;
4858 BackLists.Free;
4859 SelectedVertices.Free;
4860 ExtremumSets.Free;
4861 end;
4862 end;
4863 end;
4864 {$IFDEF NOWARN}{$WARNINGS ON}{$ENDIF}
4865
4866 procedure TGraph.GetComplementOf(Source: TGraph);
4867 var
4868 I, J: Integer;
4869 M: TBoolMatrix;
4870 begin
4871 M:=Source.CreateConnectionMatrix;
4872 try
4873 if Source <> Self then begin
4874 Clear;
4875 AddVertices(Source.VertexCount);
4876 end
4877 else
4878 ClearEdges;
4879 for I:=0 to M.RowCount - 1 do
4880 for J:=M.StartOfRow(I) to M.ColCount - 1 do
4881 if not M[I, J] then
4882 AddEdgeI(I, J);
4883 finally
4884 M.Free;
4885 end;
4886 end;
4887
4888 procedure TGraph.GetLineGraphOf(Source: TGraph);
4889 var
4890 I, J, K, N, T1, T2: Integer;
4891 V: TVertex;
4892 B: TBoolMatrix;
4893 begin
4894 {$IFDEF CHECK_GRAPHS}
4895 if Source = Self then Error(SErrorInParameters);
4896 {$ENDIF}
4897 Clear;
4898 N:=Source.EdgeCount;
4899 AddVertices(N);
4900 B:=TBoolMatrix.Create(N, N, False);
4901 try
4902 for I:=0 to Source.FVertices.Count - 1 do begin
4903 V:=Source.FVertices[I];
4904 N:=V.NeighbEdges.Count - 1;
4905 for J:=0 to N do begin
4906 T1:=TEdge(V.NeighbEdges[J]).Index;
4907 for K:=0 to N do
4908 if K <> J then begin
4909 T2:=TEdge(V.NeighbEdges[K]).Index;
4910 if not B[T1, T2] then begin
4911 AddEdgeI(T1, T2);
4912 B[T1, T2]:=True;
4913 end;
4914 end;
4915 end;
4916 end;
4917 finally
4918 B.Free;
4919 end;
4920 end;
4921
TGraph.GetShortestSpanningTreeOfnull4922 function TGraph.GetShortestSpanningTreeOf(Source: TGraph): Float;
4923 var
4924 I: Integer;
4925 E1, E2: TEdge;
4926 SSTList: TClassList;
4927 begin
4928 Clear;
4929 SSTList:=TClassList.Create;
4930 try
4931 Result:=Source.FindShortestSpanningTree(SSTList);
4932 AddVertices(Source.FVertices.Count);
4933 Features:=Features + [Weighted];
4934 for I:=0 to SSTList.Count - 1 do begin
4935 E1:=SSTList[I];
4936 E2:=AddEdgeI(E1.V1.Index, E1.V2.Index);
4937 E2.Weight:=E1.Weight;
4938 E2.FTemp.AsPtrInt:=E1.Index;
4939 end;
4940 finally
4941 SSTList.Free;
4942 end;
4943 end;
4944
4945 procedure TGraph.SortVertices(CompareVertices: TCompareFunc);
4946 var
4947 I: Integer;
4948 begin
4949 FVertices.SortBy(CompareVertices);
4950 for I:=0 to FVertices.Count - 1 do TVertex(FVertices[I]).FIndex:=I;
4951 end;
4952
4953 procedure TGraph.SortEdges(CompareEdges: TCompareFunc);
4954 var
4955 I: Integer;
4956 begin
4957 FEdges.SortBy(CompareEdges);
4958 for I:=0 to FEdges.Count - 1 do TEdge(FEdges[I]).FIndex:=I;
4959 end;
4960
4961 procedure TGraph.SortVerticesByObject(CompareVertices: TCompareEvent);
4962 var
4963 I: Integer;
4964 begin
4965 FVertices.SortByObject(CompareVertices);
4966 for I:=0 to FVertices.Count - 1 do TVertex(FVertices[I]).FIndex:=I;
4967 end;
4968
4969 procedure TGraph.SortEdgesByObject(CompareEdges: TCompareEvent);
4970 var
4971 I: Integer;
4972 begin
4973 FEdges.SortByObject(CompareEdges);
4974 for I:=0 to FEdges.Count - 1 do TEdge(FEdges[I]).FIndex:=I;
4975 end;
4976
4977 procedure TGraph.GetVertices(VertexList: TClassList);
4978 begin
4979 VertexList.Assign(FVertices);
4980 end;
4981
4982 { *** орграфы }
4983
GetArcnull4984 function TGraph.GetArc(FromVertex, ToVertex: TVertex): TEdge;
4985 var
4986 I: Integer;
4987 begin
4988 {$IFDEF CHECK_GRAPHS}
4989 if not (Directed in Features) then Error(SMethodNotApplicable);
4990 {$ENDIF}
4991 if FromVertex <> nil then
4992 for I:=0 to FromVertex.NeighbEdges.Count - 1 do begin
4993 Result:=FromVertex.NeighbEdges[I];
4994 if (Result.V1 = FromVertex) and (Result.V2 = ToVertex) then
4995 Exit;
4996 end;
4997 Result:=nil;
4998 end;
4999
TGraph.GetArcInull5000 function TGraph.GetArcI(FromIndex, ToIndex: Integer): TEdge;
5001 var
5002 N: Integer;
5003 begin
5004 {$IFDEF CHECK_GRAPHS}
5005 if not (Directed in Features) then Error(SMethodNotApplicable);
5006 {$ENDIF}
5007 N:=FVertices.Count;
5008 if (FromIndex >= 0) and (FromIndex < N) and (ToIndex >= 0) and (ToIndex < N) then
5009 Result:=GetArc(FVertices[FromIndex], FVertices[ToIndex])
5010 else
5011 Result:=nil;
5012 end;
5013
5014 procedure TGraph.GetArcs(ArcsList: TClassList; FromVertex, ToVertex: TVertex);
5015 var
5016 I: Integer;
5017 E: TEdge;
5018 begin
5019 {$IFDEF CHECK_GRAPHS}
5020 if not (Directed in Features) then Error(SMethodNotApplicable);
5021 {$ENDIF}
5022 ArcsList.Clear;
5023 if FromVertex <> nil then begin
5024 for I:=0 to FromVertex.NeighbEdges.Count - 1 do begin
5025 E:=FromVertex.NeighbEdges[I];
5026 if (E.V1 = FromVertex) and (E.V2 = ToVertex) then
5027 ArcsList.Add(E);
5028 end;
5029 ArcsList.Pack;
5030 end;
5031 end;
5032
5033 procedure TGraph.GetArcsI(ArcsList: TClassList; FromIndex, ToIndex: Integer);
5034 var
5035 N: Integer;
5036 FromVertex, ToVertex: TVertex;
5037 begin
5038 {$IFDEF CHECK_GRAPHS}
5039 if not (Directed in Features) then Error(SMethodNotApplicable);
5040 {$ENDIF}
5041 N:=FVertices.Count;
5042 if (FromIndex >= 0) and (FromIndex < N) then
5043 FromVertex:=FVertices[FromIndex]
5044 else
5045 FromVertex:=nil;
5046 if (ToIndex >= 0) and (ToIndex < N) then
5047 ToVertex:=FVertices[ToIndex]
5048 else
5049 ToVertex:=nil;
5050 GetArcs(ArcsList, FromVertex, ToVertex);
5051 end;
5052
5053 procedure TGraph.GetInArcsList(ArcsList: TMultiList);
5054 var
5055 I, J, N: Integer;
5056 V: TVertex;
5057 E: TEdge;
5058 AList: TClassList;
5059 begin
5060 {$IFDEF CHECK_GRAPHS}
5061 if not (Directed in Features) then Error(SMethodNotApplicable);
5062 {$ENDIF}
5063 N:=FVertices.Count;
5064 ArcsList.Count:=N;
5065 for I:=0 to N - 1 do begin
5066 AList:=ArcsList[I];
5067 AList.Clear;
5068 V:=FVertices[I];
5069 for J:=0 to V.NeighbEdges.Count - 1 do begin
5070 E:=V.NeighbEdges[J];
5071 if E.V2 = V then
5072 AList.Add(E);
5073 end;
5074 AList.Pack;
5075 end;
5076 end;
5077
5078 procedure TGraph.GetOutArcsList(ArcsList: TMultiList);
5079 var
5080 I, J, N: Integer;
5081 V: TVertex;
5082 E: TEdge;
5083 AList: TClassList;
5084 begin
5085 {$IFDEF CHECK_GRAPHS}
5086 if not (Directed in Features) then Error(SMethodNotApplicable);
5087 {$ENDIF}
5088 N:=FVertices.Count;
5089 ArcsList.Count:=N;
5090 for I:=0 to N - 1 do begin
5091 AList:=ArcsList[I];
5092 AList.Clear;
5093 V:=FVertices[I];
5094 for J:=0 to V.NeighbEdges.Count - 1 do begin
5095 E:=V.NeighbEdges[J];
5096 if E.V1 = V then
5097 AList.Add(E);
5098 end;
5099 AList.Pack;
5100 end;
5101 end;
5102
FindStrongComponentsnull5103 function TGraph.FindStrongComponents(ComponentNumbers: TGenericIntegerVector): Integer;
5104 var
5105 Counter1, Counter2: Integer;
5106 SearchNumbers: TIntegerVector;
5107 Roots: TClassList;
5108 Unfinished: TPointerStack;
5109
5110 procedure Search(FromVertex: TVertex);
5111 var
5112 I, SearchNumber: Integer;
5113 V: TVertex;
5114 E: TEdge;
5115 begin
5116 Inc(Counter1);
5117 SearchNumbers.IncItem(FromVertex.Index, Counter1);
5118 Unfinished.Push(FromVertex);
5119 FromVertex.FTemp.AsPtrInt:=0;
5120 Roots.Add(FromVertex);
5121 for I:=0 to FromVertex.NeighbEdges.Count - 1 do begin
5122 E:=FromVertex.NeighbEdges[I];
5123 if E.V1 = FromVertex then begin
5124 V:=E.OtherVertex(FromVertex);
5125 SearchNumber:=SearchNumbers[V.Index];
5126 if SearchNumber = -1 then
5127 Search(V)
5128 else
5129 if V.FTemp.AsPtrInt = 0 then { <=> Unfinished.IndexOf(V) >= 0 }
5130 while SearchNumbers[TVertex(Roots.Last).Index] > SearchNumber do
5131 Roots.Pop;
5132 end;
5133 end; {for}
5134 if FromVertex = Roots.Last then begin
5135 repeat
5136 V:=Unfinished.Pop;
5137 V.FTemp.AsPtrInt:=-1;
5138 if ComponentNumbers <> nil then
5139 ComponentNumbers[V.Index]:=Counter2;
5140 until FromVertex = V;
5141 Inc(Counter2);
5142 Roots.Pop;
5143 end;
5144 end;
5145
5146 var
5147 I: Integer;
5148 begin
5149 {$IFDEF CHECK_GRAPHS}
5150 if not (Directed in Features) then Error(SMethodNotApplicable);
5151 {$ENDIF}
5152 Counter1:=0;
5153 Counter2:=0;
5154 SearchNumbers:=TIntegerVector.Create(FVertices.Count, -1);
5155 Roots:=TClassList.Create;
5156 Unfinished:=TPointerStack.Create;
5157 try
5158 if ComponentNumbers <> nil then
5159 ComponentNumbers.Count:=FVertices.Count;
5160 SetTempForVertices(-1);
5161 for I:=0 to FVertices.Count - 1 do
5162 if SearchNumbers[I] = -1 then
5163 Search(FVertices[I]);
5164 finally
5165 SearchNumbers.Free;
5166 Roots.Free;
5167 Unfinished.Free;
5168 end;
5169 Result:=Counter2;
5170 end;
5171
5172 { *** деревья }
5173
GetRootnull5174 function TGraph.GetRoot: TVertex;
5175 begin
5176 {$IFDEF CHECK_GRAPHS}
5177 if not (Tree in Features) then Error(SMethodNotApplicable);
5178 {$ENDIF}
5179 Result:=AsPointer[GAttrRoot];
5180 end;
5181
5182 procedure TGraph.SetRoot(Vertex: TVertex);
5183 begin
5184 if Vertex <> nil then
5185 Vertex.IsRoot:=True
5186 else
5187 AsPointer[GAttrRoot]:=nil;
5188 end;
5189
5190 procedure TGraph.CorrectTree;
5191
5192 procedure DoCorrect(V: TVertex);
5193 var
5194 I: Integer;
5195 VTemp: Int32;
5196 Neighbour: TVertex;
5197 begin
5198 VTemp:=V.FTemp.AsPtrInt;
5199 for I:=0 to V.NeighbEdges.Count - 1 do begin
5200 Neighbour:=V.Neighbour[I];
5201 if Neighbour.FTemp.AsPtrInt > VTemp then begin
5202 Neighbour.SafeSetParent(V);
5203 DoCorrect(Neighbour);
5204 end;
5205 end;
5206 end;
5207
5208 var
5209 V: TVertex;
5210 begin
5211 {$IFDEF CHECK_GRAPHS}
5212 if not (Tree in Features) then Error(SMethodNotApplicable);
5213 {$ENDIF}
5214 if IsTree then begin
5215 V:=Root;
5216 if V <> nil then begin
5217 BFSFromVertex(V);
5218 DoCorrect(V);
5219 end
5220 else
5221 Error(STreeHasNoRoot);
5222 end
5223 else
5224 Error(SMethodNotApplicable);
5225 end;
5226
5227 { *** транспортные сети }
5228
TGraph.GetNetworkSourcenull5229 function TGraph.GetNetworkSource: TVertex;
5230 begin
5231 {$IFDEF CHECK_GRAPHS}
5232 if not (Network in Features) then Error(SMethodNotApplicable);
5233 {$ENDIF}
5234 Result:=AsPointer[GAttrNetworkSource];
5235 end;
5236
5237 procedure TGraph.SetNetworkSource(Vertex: TVertex);
5238 begin
5239 Vertex.IsNetworkSource:=True;
5240 end;
5241
TGraph.GetNetworkSinknull5242 function TGraph.GetNetworkSink: TVertex;
5243 begin
5244 {$IFDEF CHECK_GRAPHS}
5245 if not (Network in Features) then Error(SMethodNotApplicable);
5246 {$ENDIF}
5247 Result:=AsPointer[GAttrNetworkSink];
5248 end;
5249
5250 procedure TGraph.SetNetworkSink(Vertex: TVertex);
5251 begin
5252 Vertex.IsNetworkSink:=True;
5253 end;
5254
IsNetworkCorrectnull5255 function TGraph.IsNetworkCorrect: Bool;
5256 var
5257 NwSrc, NwSink: TVertex;
5258 begin
5259 NwSrc:=NetworkSource;
5260 NwSink:=NetworkSink;
5261 Result:=(NwSrc <> nil) and (NwSink <> nil) and (NwSrc <> NwSink) and
5262 (NwSrc.InDegree = 0) and (NwSink.OutDegree = 0) and Connected and
5263 not HasParallelEdges;
5264 end;
5265
5266 type
5267 PFlowData = ^TFlowData;
5268 TFlowData = record
5269 TempFlow, TempMaxFlow: Float;
5270 { теоретически в логических переменных нет необходимости, но их
5271 использование несколько повышает производительность, а главное -
5272 предупреждает возможное зацикливание из-за ошибок округления }
5273 AllowForward, AllowBack: Bool;
5274 end;
5275
5276 { для повышения эффективности в методе FindMaxFlowThroughNetwork вместо
5277 атрибутов используются динамические переменные }
5278
TGraph.FindMaxFlowAcceptEdgenull5279 function TGraph.FindMaxFlowAcceptEdge(Edge: TEdge; FromVertex: TVertex): Bool;
5280 begin
5281 With PFlowData(Edge.FTemp.AsPointer)^ do
5282 if Edge.V1 = FromVertex then
5283 Result:=AllowForward{TempFlow < TempMaxFlow}
5284 else
5285 Result:=AllowBack{TempFlow > 0};
5286 end;
5287
FindMaxFlowThroughNetworknull5288 function TGraph.FindMaxFlowThroughNetwork: Float;
5289 var
5290 I, IMaxIncrease: Integer;
5291 F, MaxIncrease: Float;
5292 P: PFlowData;
5293 NwSrc, NwSink, V: TVertex;
5294 E: TEdge;
5295 EdgePath: TClassList;
5296 begin
5297 if not IsNetworkCorrect then
5298 Error(SMethodNotApplicable);
5299 NwSrc:=NetworkSource;
5300 NwSink:=NetworkSink;
5301 for I:=0 to FEdges.Count - 1 do begin
5302 E:=FEdges[I];
5303 New(P);
5304 With P^ do begin
5305 TempFlow:=0;
5306 TempMaxFlow:=E.AsFloat[GAttrMaxFlow];
5307 AllowForward:=0 < TempMaxFlow;
5308 AllowBack:=False;
5309 end;
5310 E.FTemp.AsPointer:=P;
5311 end;
5312 EdgePath:=TClassList.Create;
5313 try
5314 while FindMinPathCond(NwSrc, NwSink, nil, FindMaxFlowAcceptEdge,
5315 EdgePath) >= 0 do { в орграфе приращений найден конечный путь }
5316 begin
5317 { увеличиваем поток вдоль найденного пути, насколько возможно, уменьшая
5318 поток вдоль ребер, пройденных в обратном направлении, и увеличивая -
5319 в прямом }
5320 MaxIncrease:=MaxFloat;
5321 IMaxIncrease:=0;
5322 V:=NwSrc;
5323 for I:=0 to EdgePath.Count - 1 do begin
5324 E:=EdgePath[I];
5325 With PFlowData(E.FTemp.AsPointer)^ do
5326 if V = E.V1 then begin { ребро пройдено в прямом направлении }
5327 F:=TempMaxFlow - TempFlow;
5328 if F < MaxIncrease then begin
5329 MaxIncrease:=F;
5330 IMaxIncrease:=I;
5331 end;
5332 end
5333 else { ребро пройдено в обратном направлении }
5334 if TempFlow < MaxIncrease then begin
5335 MaxIncrease:=TempFlow;
5336 IMaxIncrease:=I;
5337 end;
5338 V:=E.OtherVertex(V);
5339 end; {for}
5340 V:=NwSrc;
5341 for I:=0 to EdgePath.Count - 1 do begin
5342 E:=EdgePath[I];
5343 With PFlowData(E.FTemp.AsPointer)^ do begin
5344 if V = E.V1 then
5345 TempFlow:=TempFlow + MaxIncrease
5346 else
5347 TempFlow:=TempFlow - MaxIncrease;
5348 if I <> IMaxIncrease then begin
5349 AllowForward:=TempFlow < TempMaxFlow;
5350 AllowBack:=TempFlow > 0;
5351 end
5352 else { страхуемся от зацикливания }
5353 if V = E.V1 then
5354 AllowForward:=False
5355 else
5356 AllowBack:=False;
5357 end;
5358 V:=E.OtherVertex(V);
5359 end; {for}
5360 end;
5361 finally
5362 Result:=0;
5363 for I:=0 to NwSink.NeighbEdges.Count - 1 do
5364 Result:=Result + PFlowData(TEdge(NwSink.NeighbEdges[I]).FTemp.AsPointer)^.TempFlow;
5365 for I:=0 to FEdges.Count - 1 do begin
5366 E:=FEdges[I];
5367 E.AsFloat[GAttrFlow]:=PFlowData(E.FTemp.AsPointer)^.TempFlow;
5368 Dispose(PFlowData(E.FTemp.AsPointer));
5369 end;
5370 EdgePath.Free;
5371 end;
5372 end;
5373
5374 { *** взвешенные графы }
5375
5376 procedure TGraph.Dijkstra(Vertex1, Vertex2: TVertex; AcceptVertex: TAcceptVertex;
5377 AcceptEdge: TAcceptEdge; Distances: TFloatVector);
5378 var
5379 I, WeightOffset, NeighbIndex: Integer;
5380 VDistance, T: Float;
5381 V, Neighbour: TVertex;
5382 E: TEdge;
5383 NodeList: TClassList;
5384 PriorityQueue: TFloatPriorityQueue;
5385 Allowed: TBoolVector;
5386 { использование Allowed повышает скорость работы и, кроме того, при наличии в
5387 графе ребер с отрицательными весами и выключенной проверке CHECK_GRAPHS
5388 предохраняет от Access Violation (но не гарантирует правильной работы!) }
5389 begin
5390 {$IFDEF CHECK_GRAPHS}
5391 for I:=0 to FEdges.Count - 1 do
5392 if TEdge(FEdges[I]).Weight < 0 then
5393 Error(SMethodNotApplicable);
5394 {$ENDIF}
5395 WeightOffset:=FEdgeAttrMap.Offset(GAttrWeight);
5396 SetTempForVertices(Int32(nil));
5397 PriorityQueue:=TFloatPriorityQueue.Create;
5398 NodeList:=TClassList.Create;
5399 Allowed:=nil;
5400 try
5401 NodeList.Count:=FVertices.Count;
5402 Allowed:=TBoolVector.Create(FVertices.Count, True);
5403 Distances[Vertex1.Index]:=0;
5404 V:=Vertex1;
5405 repeat
5406 VDistance:=Distances[V.Index];
5407 Allowed[V.Index]:=False;
5408 for I:=0 to V.NeighbEdges.Count - 1 do begin
5409 E:=V.NeighbEdges[I];
5410 if not Assigned(AcceptEdge) or AcceptEdge(E, V) then begin
5411 Neighbour:=E.OtherVertex(V);
5412 NeighbIndex:=Neighbour.Index;
5413 if Allowed[NeighbIndex] and
5414 (not Assigned(AcceptVertex) or AcceptVertex(Neighbour)) then
5415 begin
5416 T:=VDistance + E.AsFloatByOfs[WeightOffset]; { E.Weight }
5417 if T < Distances[NeighbIndex] then begin
5418 Neighbour.FTemp.AsPointer:=E;
5419 Distances[NeighbIndex]:=T;
5420 NodeList[NeighbIndex]:=PriorityQueue.ChangeNodePriority(
5421 NodeList[NeighbIndex], Neighbour, T);
5422 end;
5423 end;
5424 end;
5425 end; {for}
5426 if PriorityQueue.IsEmpty then
5427 Break;
5428 V:=PriorityQueue.DeleteMin;
5429 until V = Vertex2;
5430 finally
5431 PriorityQueue.Free;
5432 NodeList.Free;
5433 Allowed.Free;
5434 end;
5435 end;
5436
FindMinWeightPathCondnull5437 function TGraph.FindMinWeightPathCond(Vertex1, Vertex2: TVertex;
5438 AcceptVertex: TAcceptVertex; AcceptEdge: TAcceptEdge;
5439 EdgePath: TClassList): Float;
5440 var
5441 E: TEdge;
5442 Distances: TFloatVector;
5443 begin
5444 if EdgePath <> nil then
5445 EdgePath.Clear;
5446 if Vertex1 <> Vertex2 then begin
5447 Result:=-1;
5448 if not (gsValidSeparates in FStates) or
5449 (Vertex1.SeparateIndex = Vertex2.SeparateIndex) then
5450 begin { используется классический алгоритм Дейкстры }
5451 Distances:=TFloatVector.Create(FVertices.Count, MaxFloat);
5452 try
5453 Dijkstra(Vertex1, Vertex2, AcceptVertex, AcceptEdge, Distances);
5454 if Distances[Vertex2.Index] < MaxFloat then begin
5455 Result:=Distances[Vertex2.Index];
5456 if EdgePath <> nil then begin
5457 repeat
5458 E:=Vertex2.FTemp.AsPointer;
5459 EdgePath.Add(E);
5460 Vertex2:=E.OtherVertex(Vertex2);
5461 until Vertex2 = Vertex1;
5462 EdgePath.Pack;
5463 EdgePath.Reverse;
5464 end;
5465 end;
5466 finally
5467 Distances.Free;
5468 end;
5469 end;
5470 end
5471 else
5472 Result:=0;
5473 end;
5474
TGraph.FindMinWeightPathnull5475 function TGraph.FindMinWeightPath(Vertex1, Vertex2: TVertex;
5476 EdgePath: TClassList): Float;
5477 begin
5478 if Directed in Features then
5479 Result:=FindMinWeightPathCond(Vertex1, Vertex2, nil, AcceptArc, EdgePath)
5480 else
5481 Result:=FindMinWeightPathCond(Vertex1, Vertex2, nil, nil, EdgePath);
5482 end;
5483
5484 procedure TGraph.FindDistancesCond(FromVertex: TVertex; AcceptVertex: TAcceptVertex;
5485 AcceptEdge: TAcceptEdge; Distances: TFloatVector);
5486 begin
5487 Distances.Count:=FVertices.Count;
5488 Distances.FillValue(MaxFloat);
5489 Dijkstra(FromVertex, nil, AcceptVertex, AcceptEdge, Distances);
5490 end;
5491
5492 procedure TGraph.FindDistances(FromVertex: TVertex; Distances: TFloatVector);
5493 begin
5494 if Directed in Features then
5495 FindDistancesCond(FromVertex, nil, AcceptArc, Distances)
5496 else
5497 FindDistancesCond(FromVertex, nil, nil, Distances);
5498 end;
5499
CreateWeightsMatrixnull5500 function TGraph.CreateWeightsMatrix: TFloatMatrix;
5501 var
5502 I, Index1, Index2, WeightOffset: Integer;
5503 T: Float;
5504 E: TEdge;
5505 begin
5506 {$IFDEF CHECK_GRAPHS}
5507 if not (Weighted in Features) then Error(SMethodNotApplicable);
5508 {$ENDIF}
5509 WeightOffset:=FEdgeAttrMap.Offset(GAttrWeight);
5510 I:=FVertices.Count;
5511 if Directed in Features then
5512 Result:=TFloatMatrix.Create(I, I, MaxFloat)
5513 else
5514 Result:=TSimFloatMatrix.Create(I, MaxFloat);
5515 try
5516 for I:=0 to FEdges.Count - 1 do begin
5517 { если вершины соединены более чем одним ребром (дугой), то
5518 выбираем ребро (дугу) с минимальным весом }
5519 E:=FEdges[I];
5520 Index1:=E.V1.Index;
5521 Index2:=E.V2.Index;
5522 T:=E.AsFloatByOfs[WeightOffset]; { E.Weight }
5523 if T < Result[Index1, Index2] then
5524 Result[Index1, Index2]:=T;
5525 end;
5526 except
5527 Result.Free;
5528 raise;
5529 end;
5530 end;
5531
TGraph.CreateMinWeightPathsMatrixnull5532 function TGraph.CreateMinWeightPathsMatrix(var DistancesMatrix: TFloatMatrix;
5533 PathsMatrix: TIntegerMatrix): Bool;
5534
StartOfRownull5535 function StartOfRow(Row: Integer): Integer;
5536 begin
5537 if PathsMatrix <> nil then
5538 Result:=0
5539 else
5540 Result:=DistancesMatrix.StartOfRow(Row);
5541 end;
5542
5543 var
5544 I, J, K, N: Integer;
5545 R, S, T: Float;
5546 NewMatrix: TFloatMatrix;
5547 begin
5548 {$IFDEF CHECK_GRAPHS}
5549 if not (Weighted in Features) then Error(SMethodNotApplicable);
5550 {$ENDIF}
5551 { создаем матрицу весов ребер (дуг) }
5552 N:=FVertices.Count;
5553 if PathsMatrix <> nil then begin
5554 PathsMatrix.SetSize(N, N);
5555 for I:=0 to N - 1 do
5556 for J:=0 to N - 1 do
5557 PathsMatrix[I, J]:=I;
5558 end;
5559 DistancesMatrix:=CreateWeightsMatrix;
5560 try
5561 if Directed in Features then
5562 NewMatrix:=TFloatMatrix.Create(N, N, MaxFloat)
5563 else
5564 NewMatrix:=TSimFloatMatrix.Create(N, MaxFloat);
5565 try
5566 { основной цикл }
5567 Dec(N);
5568 for K:=0 to N do begin
5569 for I:=0 to N do
5570 if I <> K then
5571 for J:=StartOfRow(I) to N do
5572 if J <> K then begin
5573 R:=DistancesMatrix[I, K];
5574 S:=DistancesMatrix[K, J];
5575 T:=DistancesMatrix[I, J];
5576 if (R < MaxFloat) and (S < MaxFloat) then begin
5577 R:=R + S;
5578 if R < T then
5579 if I <> J then begin
5580 NewMatrix[I, J]:=R;
5581 if PathsMatrix <> nil then
5582 PathsMatrix[I, J]:=PathsMatrix[K, J];
5583 end
5584 else
5585 if R < 0 then begin
5586 DistancesMatrix[I, J]:=R;
5587 Result:=False;
5588 Exit;
5589 end
5590 else
5591 else
5592 NewMatrix[I, J]:=T;
5593 end
5594 else
5595 NewMatrix[I, J]:=T;
5596 end
5597 else
5598 NewMatrix[I, J]:=DistancesMatrix[I, J]
5599 else
5600 for J:=DistancesMatrix.StartOfRow(I) to N do
5601 NewMatrix[I, J]:=DistancesMatrix[I, J];
5602 DistancesMatrix.Assign(NewMatrix);
5603 end; {for K}
5604 Result:=True;
5605 finally
5606 NewMatrix.Free;
5607 end;
5608 except
5609 DistancesMatrix.Free;
5610 DistancesMatrix:=nil;
5611 raise;
5612 end;
5613 end;
5614
DecodeMinWeightPathnull5615 function TGraph.DecodeMinWeightPath(WeightMatrix: TFloatMatrix;
5616 PathsMatrix: TIntegerMatrix; I, J: Integer;
5617 VertexIndexes: TGenericIntegerVector): Bool;
5618 begin
5619 VertexIndexes.Clear;
5620 if WeightMatrix[I, J] < MaxFloat then begin
5621 repeat
5622 VertexIndexes.Add(J);
5623 J:=PathsMatrix[I, J];
5624 until I = J;
5625 VertexIndexes.Add(I);
5626 VertexIndexes.Pack;
5627 VertexIndexes.Reverse;
5628 Result:=True;
5629 end
5630 else
5631 Result:=False;
5632 end;
5633
TGraph.FindShortestSpanningTreenull5634 function TGraph.FindShortestSpanningTree(SSTList: TClassList): Float;
5635 var
5636 I, N, NeighbIndex: Integer;
5637 T: Float;
5638 V, Neighbour: TVertex;
5639 E: TEdge;
5640 PriorityQueue: TFloatPriorityQueue;
5641 Distances: TFloatVector;
5642 NodeList: TClassList;
5643 begin
5644 {$IFDEF CHECK_GRAPHS}
5645 if not (Weighted in Features) then Error(SMethodNotApplicable);
5646 {$ENDIF}
5647 Result:=0;
5648 if SSTList <> nil then
5649 SSTList.Clear;
5650 N:=FVertices.Count;
5651 if N > 1 then begin
5652 PriorityQueue:=TFloatPriorityQueue.Create;
5653 Distances:=nil;
5654 NodeList:=nil;
5655 try
5656 Distances:=TFloatVector.Create(N, MaxFloat);
5657 NodeList:=TClassList.Create;
5658 NodeList.Count:=N;
5659 for I:=0 to N - 1 do
5660 NodeList[I]:=PriorityQueue.Add(FVertices[I], MaxFloat);
5661 if SSTList <> nil then
5662 SSTList.Capacity:=N - 1;
5663 SetTempForVertices(Int32(nil));
5664 while not PriorityQueue.IsEmpty do begin
5665 V:=PriorityQueue.DeleteMin;
5666 if Distances[V.Index] <> MaxFloat then begin
5667 E:=V.FTemp.AsPointer;
5668 if SSTList <> nil then
5669 SSTList.Add(E);
5670 Result:=Result + E.Weight;
5671 end;
5672 Distances[V.Index]:=-MaxFloat;
5673 for I:=0 to V.NeighbEdges.Count - 1 do begin
5674 E:=V.NeighbEdges[I];
5675 Neighbour:=E.OtherVertex(V);
5676 NeighbIndex:=Neighbour.Index;
5677 T:=E.Weight;
5678 if T < Distances[NeighbIndex] then begin
5679 NodeList[NeighbIndex]:=PriorityQueue.ChangeNodePriority(
5680 NodeList[NeighbIndex], Neighbour, T);
5681 Distances[NeighbIndex]:=T;
5682 Neighbour.FTemp.AsPointer:=E;
5683 end;
5684 end;
5685 end;
5686 finally
5687 PriorityQueue.Free;
5688 Distances.Free;
5689 NodeList.Free;
5690 end;
5691 if SSTList <> nil then
5692 SSTList.Pack;
5693 end;
5694 end;
5695
5696 { *** геометрические графы }
5697
5698 procedure TGraph.GetExtent2D(var MinX, MaxX, MinY, MaxY: Float);
5699 var
5700 I, XOffset, YOffset: Integer;
5701 X1, Y1: Float;
5702 V: TVertex;
5703 begin
5704 {$IFDEF CHECK_GRAPHS}
5705 if not (Geom2D in Features) then Error(SMethodNotApplicable);
5706 {$ENDIF}
5707 XOffset:=FVertexAttrMap.Offset(GAttrX);
5708 YOffset:=FVertexAttrMap.Offset(GAttrY);
5709 MinX:=MaxFloat;
5710 MaxX:=-MaxFloat;
5711 MinY:=MaxFloat;
5712 MaxY:=-MaxFloat;
5713 for I:=0 to FVertices.Count - 1 do begin
5714 V:=FVertices[I];
5715 X1:=V.AsFloatByOfs[XOffset];
5716 if X1 < MinX then
5717 MinX:=X1;
5718 if X1 > MaxX then
5719 MaxX:=X1;
5720 Y1:=V.AsFloatByOfs[YOffset];
5721 if Y1 < MinY then
5722 MinY:=Y1;
5723 if Y1 > MaxY then
5724 MaxY:=Y1;
5725 end;
5726 end;
5727
5728 procedure TGraph.GetExtent3D(var MinX, MaxX, MinY, MaxY, MinZ, MaxZ: Float);
5729 var
5730 I, XOffset, YOffset, ZOffset: Integer;
5731 X1, Y1, Z1: Float;
5732 V: TVertex;
5733 begin
5734 {$IFDEF CHECK_GRAPHS}
5735 if not (Geom3D in Features) then Error(SMethodNotApplicable);
5736 {$ENDIF}
5737 XOffset:=FVertexAttrMap.Offset(GAttrX);
5738 YOffset:=FVertexAttrMap.Offset(GAttrY);
5739 ZOffset:=FVertexAttrMap.Offset(GAttrZ);
5740 MinX:=MaxFloat;
5741 MaxX:=-MaxFloat;
5742 MinY:=MaxFloat;
5743 MaxY:=-MaxFloat;
5744 MinZ:=MaxFloat;
5745 MaxZ:=-MaxFloat;
5746 for I:=0 to FVertices.Count - 1 do begin
5747 V:=FVertices[I];
5748 X1:=V.AsFloatByOfs[XOffset];
5749 if X1 < MinX then
5750 MinX:=X1;
5751 if X1 > MaxX then
5752 MaxX:=X1;
5753 Y1:=V.AsFloatByOfs[YOffset];
5754 if Y1 < MinY then
5755 MinY:=Y1;
5756 if Y1 > MaxY then
5757 MaxY:=Y1;
5758 Z1:=V.AsFloatByOfs[ZOffset];
5759 if Z1 < MinZ then
5760 MinZ:=Z1;
5761 if Z1 > MaxZ then
5762 MaxZ:=Z1;
5763 end;
5764 end;
5765
5766 {$IFDEF NOWARN}{$WARNINGS OFF}{$ENDIF}
5767 procedure TGraph.AssignCoordinates(Source: TGraph);
5768 var
5769 I, XOffset, YOffset, ZOffset, SrcXOffset, SrcYOffset, SrcZOffset, Min: Integer;
5770 D3: Bool;
5771 V, SrcV: TVertex;
5772 begin
5773 {$IFDEF CHECK_GRAPHS}
5774 if not (Geom2D in Features) and (Geom2D in Source.Features) then
5775 Error(SMethodNotApplicable);
5776 {$ENDIF}
5777 XOffset:=FVertexAttrMap.Offset(GAttrX);
5778 YOffset:=FVertexAttrMap.Offset(GAttrY);
5779 SrcXOffset:=Source.FVertexAttrMap.Offset(GAttrX);
5780 SrcYOffset:=Source.FVertexAttrMap.Offset(GAttrY);
5781 D3:=(Geom3D in Features) and (Geom3D in Source.Features);
5782 if D3 then begin
5783 ZOffset:=FVertexAttrMap.Offset(GAttrZ);
5784 SrcZOffset:=Source.FVertexAttrMap.Offset(GAttrZ);
5785 end;
5786 Min:=Source.FVertices.Count;
5787 if FVertices.Count < Min then
5788 Min:=FVertices.Count;
5789 for I:=0 to Min - 1 do begin
5790 V:=FVertices[I];
5791 SrcV:=Source.FVertices[I];
5792 V.AsFloatByOfs[XOffset]:=SrcV.AsFloatByOfs[SrcXOffset];
5793 V.AsFloatByOfs[YOffset]:=SrcV.AsFloatByOfs[SrcYOffset];
5794 if D3 then
5795 V.AsFloatByOfs[ZOffset]:=SrcV.AsFloatByOfs[SrcZOffset];
5796 end;
5797 end;
5798 {$IFDEF NOWARN}{$WARNINGS ON}{$ENDIF}
5799
5800 procedure TGraph.GetCoords2D(XCoords, YCoords: TFloatVector);
5801 var
5802 I, N, XOffset, YOffset: Integer;
5803 begin
5804 {$IFDEF CHECK_GRAPHS}
5805 if not (Geom2D in Features) then Error(SMethodNotApplicable);
5806 {$ENDIF}
5807 N:=FVertices.Count;
5808 XCoords.Count:=N;
5809 YCoords.Count:=N;
5810 XOffset:=FVertexAttrMap.Offset(GAttrX);
5811 YOffset:=FVertexAttrMap.Offset(GAttrY);
5812 for I:=0 to N - 1 do With TVertex(FVertices[I]) do begin
5813 XCoords[I]:=AsFloatByOfs[XOffset];
5814 YCoords[I]:=AsFloatByOfs[YOffset];
5815 end;
5816 end;
5817
5818 procedure TGraph.GetCoords3D(XCoords, YCoords, ZCoords: TFloatVector);
5819 var
5820 I, N, ZOffset: Integer;
5821 begin
5822 {$IFDEF CHECK_GRAPHS}
5823 if not (Geom3D in Features) then Error(SMethodNotApplicable);
5824 {$ENDIF}
5825 GetCoords2D(XCoords, YCoords);
5826 N:=FVertices.Count;
5827 ZCoords.Count:=N;
5828 ZOffset:=FVertexAttrMap.Offset(GAttrZ);
5829 for I:=0 to N - 1 do
5830 ZCoords[I]:=TVertex(FVertices[I]).AsFloatByOfs[ZOffset];
5831 end;
5832
5833 procedure TGraph.SetCoords2D(XCoords, YCoords: TFloatVector);
5834 var
5835 I, XOffset, YOffset: Integer;
5836 begin
5837 {$IFDEF CHECK_GRAPHS}
5838 if not (Geom2D in Features) then Error(SMethodNotApplicable);
5839 {$ENDIF}
5840 XOffset:=FVertexAttrMap.Offset(GAttrX);
5841 YOffset:=FVertexAttrMap.Offset(GAttrY);
5842 for I:=0 to FVertices.Count - 1 do With TVertex(FVertices[I]) do begin
5843 AsFloatByOfs[XOffset]:=XCoords[I];
5844 AsFloatByOfs[YOffset]:=YCoords[I];
5845 end;
5846 end;
5847
5848 procedure TGraph.SetCoords3D(XCoords, YCoords, ZCoords: TFloatVector);
5849 var
5850 I, ZOffset: Integer;
5851 begin
5852 {$IFDEF CHECK_GRAPHS}
5853 if not (Geom3D in Features) then Error(SMethodNotApplicable);
5854 {$ENDIF}
5855 SetCoords2D(XCoords, YCoords);
5856 ZOffset:=FVertexAttrMap.Offset(GAttrZ);
5857 for I:=0 to FVertices.Count - 1 do
5858 TVertex(FVertices[I]).AsFloatByOfs[ZOffset]:=ZCoords[I];
5859 end;
5860
5861 end.
5862