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