/// <summary> /// Initializes the solver so that the optimization can be run. /// </summary> /// <exception cref="GraphNotConnectedException"> /// If not all target nodes are connected to the start node. /// </exception> public virtual void Initialize() { BuildSearchGraph(); // Use SteinerPreprocessor for search space reduction. SearchSpace = AllNodes.ToList(); var variableTargetNodes = SearchSpace.Where(IsVariableTargetNode); var preProc = new SteinerPreprocessor(SearchSpace, TargetNodes, StartNode, variableTargetNodes); var result = preProc.ReduceSearchSpace(); TargetNodes = result.FixedTargetNodes; var remainingNodes = result.RemainingNodes; SearchSpace = remainingNodes.Except(TargetNodes).ToList(); Distances = result.DistanceLookup; ShortestPaths = result.ShortestPathLookup; StartNode = result.StartNode; // SkillNode-Ids of the remaining search space may represent more than one node. This // information needs to be saved. var expansionDict = new IReadOnlyCollection <ushort> [ushort.MaxValue]; foreach (var node in remainingNodes) { expansionDict[node.Id] = node.Nodes; } var inExpansion = new HashSet <ushort>(remainingNodes.SelectMany(n => n.Nodes)); // Add the remaining nodes as single (unmerged) ones. foreach (var node in AllNodes) { if (!inExpansion.Contains(node.Id)) { expansionDict[node.Id] = new[] { node.Id }; } } NodeExpansionDictionary = expansionDict; // The hidden root node and ascendancy nodes do not count for the total node count. UncountedNodes = 1 + StartNode.Nodes.Count(n => SkillTree.Skillnodes[n].IsAscendancyNode); Debug.WriteLine("Search space dimension: " + SearchSpace.Count); Debug.WriteLine("Target node count: " + TargetNodes.Count); IsInitialized = true; }