lemon/min_mean_cycle.h
changeset 2483 bf6d7b624d5c
parent 2413 21eb3ccdc3df
child 2509 a8081c9cd96a
equal deleted inserted replaced
1:fd4d28f40a3b 2:8a33f22b8580
    19 #ifndef LEMON_MIN_MEAN_CYCLE_H
    19 #ifndef LEMON_MIN_MEAN_CYCLE_H
    20 #define LEMON_MIN_MEAN_CYCLE_H
    20 #define LEMON_MIN_MEAN_CYCLE_H
    21 
    21 
    22 /// \ingroup min_cost_flow
    22 /// \ingroup min_cost_flow
    23 ///
    23 ///
    24 /// \file 
    24 /// \file
    25 /// \brief Karp algorithm for finding a minimum mean cycle.
    25 /// \brief Karp algorithm for finding a minimum mean cycle.
    26 
    26 
    27 #include <lemon/graph_utils.h>
    27 #include <lemon/graph_utils.h>
    28 #include <lemon/topology.h>
    28 #include <lemon/topology.h>
    29 #include <lemon/path.h>
    29 #include <lemon/path.h>
    42   /// \param Graph The directed graph type the algorithm runs on.
    42   /// \param Graph The directed graph type the algorithm runs on.
    43   /// \param LengthMap The type of the length (cost) map.
    43   /// \param LengthMap The type of the length (cost) map.
    44   ///
    44   ///
    45   /// \author Peter Kovacs
    45   /// \author Peter Kovacs
    46 
    46 
    47 #ifdef DOXYGEN
       
    48   template <typename Graph, typename LengthMap>
       
    49 #else
       
    50   template <typename Graph,
    47   template <typename Graph,
    51     typename LengthMap = typename Graph::template EdgeMap<int> >
    48     typename LengthMap = typename Graph::template EdgeMap<int> >
    52 #endif
       
    53 
       
    54   class MinMeanCycle
    49   class MinMeanCycle
    55   {
    50   {
    56     typedef typename Graph::Node Node;
    51     typedef typename Graph::Node Node;
    57     typedef typename Graph::NodeIt NodeIt;
    52     typedef typename Graph::NodeIt NodeIt;
    58     typedef typename Graph::Edge Edge;
    53     typedef typename Graph::Edge Edge;
    63 
    58 
    64     typedef typename Graph::template NodeMap<int> IntNodeMap;
    59     typedef typename Graph::template NodeMap<int> IntNodeMap;
    65     typedef typename Graph::template NodeMap<Edge> PredNodeMap;
    60     typedef typename Graph::template NodeMap<Edge> PredNodeMap;
    66     typedef Path<Graph> Path;
    61     typedef Path<Graph> Path;
    67     typedef std::vector<Node> NodeVector;
    62     typedef std::vector<Node> NodeVector;
    68     typedef typename NodeVector::iterator NodeVectorIt;
       
    69 
    63 
    70   protected:
    64   protected:
    71 
    65 
    72     /// \brief Data sturcture for path data.
    66     /// \brief Data sturcture for path data.
    73     struct PathData
    67     struct PathData
    87       PathDataNodeMap;
    81       PathDataNodeMap;
    88 
    82 
    89   protected:
    83   protected:
    90 
    84 
    91     /// \brief Node map for storing path data.
    85     /// \brief Node map for storing path data.
    92     /// 
    86     ///
    93     /// Node map for storing path data of all nodes in the current
    87     /// Node map for storing path data of all nodes in the current
    94     /// component. dmap[v][k] is the length of a shortest directed walk 
    88     /// component. dmap[v][k] is the length of a shortest directed walk
    95     /// to node v from the starting node containing exactly k edges.
    89     /// to node v from the starting node containing exactly k edges.
    96     PathDataNodeMap dmap;
    90     PathDataNodeMap dmap;
    97     
    91 
    98     /// \brief The directed graph the algorithm runs on.
    92     /// \brief The directed graph the algorithm runs on.
    99     const Graph& graph;
    93     const Graph &graph;
   100     /// \brief The length of the edges.
    94     /// \brief The length of the edges.
   101     const LengthMap& length;
    95     const LengthMap &length;
   102     
    96 
   103     /// \brief The total length of the found cycle.
    97     /// \brief The total length of the found cycle.
   104     Length cycle_length;
    98     Length cycle_length;
   105     /// \brief The number of edges in the found cycle.
    99     /// \brief The number of edges in the found cycle.
   106     int cycle_size;
   100     int cycle_size;
   107     /// \brief A node for obtaining a minimum mean cycle. 
   101     /// \brief A node for obtaining a minimum mean cycle.
   108     Node cycle_node;
   102     Node cycle_node;
   109 
   103 
   110     /// \brief The found cycle.
   104     /// \brief The found cycle.
   111     Path *cycle_path;
   105     Path *cycle_path;
   112     /// \brief The algorithm uses local \ref lemon::Path "Path" 
   106     /// \brief The algorithm uses local \ref lemon::Path "Path"
   113     /// structure to store the found cycle.
   107     /// structure to store the found cycle.
   114     bool local_path;
   108     bool local_path;
   115     
   109 
   116     /// \brief Node map for identifying strongly connected components.
   110     /// \brief Node map for identifying strongly connected components.
   117     IntNodeMap comp;
   111     IntNodeMap comp;
   118     /// \brief The number of strongly connected components.
   112     /// \brief The number of strongly connected components.
   119     int comp_num;
   113     int comp_num;
   120     /// \brief Counter for identifying the current component.
   114     /// \brief Counter for identifying the current component.
   121     int comp_cnt;
   115     int comp_cnt;
   122     /// \brief Nodes of the current component.
   116     /// \brief Nodes of the current component.
   123     NodeVector nodes;
   117     NodeVector nodes;
   124     /// \brief The processed nodes in the last round.
   118     /// \brief The processed nodes in the last round.
   125     NodeVector process;
   119     NodeVector process;
   126     
   120 
   127   public :
   121   public :
   128 
   122 
   129     /// \brief The constructor of the class.
   123     /// \brief The constructor of the class.
   130     ///
   124     ///
   131     /// The constructor of the class.
   125     /// The constructor of the class.
   132     ///
   126     ///
   133     /// \param _graph The directed graph the algorithm runs on.
   127     /// \param _graph The directed graph the algorithm runs on.
   134     /// \param _length The length (cost) of the edges.
   128     /// \param _length The length (cost) of the edges.
   135     MinMeanCycle( const Graph& _graph,
   129     MinMeanCycle( const Graph &_graph,
   136 		  const LengthMap& _length ) :
   130 		  const LengthMap &_length ) :
   137       graph(_graph), length(_length), dmap(_graph), comp(_graph),
   131       graph(_graph), length(_length), dmap(_graph), comp(_graph),
   138       cycle_length(0), cycle_size(-1), cycle_node(INVALID),
   132       cycle_length(0), cycle_size(-1), cycle_node(INVALID),
   139       cycle_path(NULL), local_path(false)
   133       cycle_path(NULL), local_path(false)
   140     { }
   134     { }
   141 
   135 
   142     /// \brief The destructor of the class.
   136     /// \brief The destructor of the class.
   143     ~MinMeanCycle() { 
   137     ~MinMeanCycle() {
   144       if (local_path) delete cycle_path;
   138       if (local_path) delete cycle_path;
   145     }
   139     }
   146 
   140 
   147   protected:
   141   protected:
   148 
   142 
   154       for (NodeIt v(graph); v != INVALID; ++v) {
   148       for (NodeIt v(graph); v != INVALID; ++v) {
   155 	if (comp[v] == comp_cnt) nodes.push_back(v);
   149 	if (comp[v] == comp_cnt) nodes.push_back(v);
   156       }
   150       }
   157       // Creating vectors for all nodes
   151       // Creating vectors for all nodes
   158       int n = nodes.size();
   152       int n = nodes.size();
   159       for (NodeVectorIt vi = nodes.begin(); vi != nodes.end(); ++vi) {
   153       for (int i = 0; i < nodes.size(); ++i) {
   160 	dmap[*vi].resize(n + 1);
   154 	dmap[nodes[i]].resize(n + 1);
   161       }
   155       }
   162     }
   156     }
   163     
   157 
   164     /// \brief Processes all rounds of computing required path data for 
   158     /// \brief Processes all rounds of computing required path data for
   165     /// the current component.
   159     /// the current component.
   166     void processRounds() {
   160     void processRounds() {
   167       dmap[nodes[0]][0] = PathData(true, 0);
   161       dmap[nodes[0]][0] = PathData(true, 0);
   168       process.clear();
   162       process.clear();
   169       // Processing the first round
   163       // Processing the first round
   171 	Node v = graph.target(e);
   165 	Node v = graph.target(e);
   172 	if (comp[v] != comp_cnt || v == nodes[0]) continue;
   166 	if (comp[v] != comp_cnt || v == nodes[0]) continue;
   173 	dmap[v][1] = PathData(true, length[e], e);
   167 	dmap[v][1] = PathData(true, length[e], e);
   174 	process.push_back(v);
   168 	process.push_back(v);
   175       }
   169       }
   176       // Processing other rounds 
   170       // Processing other rounds
   177       int n = nodes.size(), k;
   171       int n = nodes.size(), k;
   178       for (k = 2; k <= n && process.size() < n; ++k) {
   172       for (k = 2; k <= n && process.size() < n; ++k)
   179 	processNextBuildRound(k);
   173 	processNextBuildRound(k);
   180       }
   174       for ( ; k <= n; ++k)
   181       for ( ; k <= n; ++k) {
       
   182 	processNextFullRound(k);
   175 	processNextFullRound(k);
   183       }
   176     }
   184     }
   177 
   185     
       
   186     /// \brief Processes one round of computing required path data and
   178     /// \brief Processes one round of computing required path data and
   187     /// rebuilds \ref process vector.
   179     /// rebuilds \ref process vector.
   188     void processNextBuildRound(int k) {
   180     void processNextBuildRound(int k) {
   189       NodeVector next;
   181       NodeVector next;
   190       for (NodeVectorIt ui = process.begin(); ui != process.end(); ++ui) {
   182       for (int i = 0; i < process.size(); ++i) {
   191 	for (OutEdgeIt e(graph, *ui); e != INVALID; ++e) {
   183 	for (OutEdgeIt e(graph, process[i]); e != INVALID; ++e) {
   192 	  Node v = graph.target(e);
   184 	  Node v = graph.target(e);
   193 	  if (comp[v] != comp_cnt) continue;
   185 	  if (comp[v] != comp_cnt) continue;
   194 	  if (!dmap[v][k].found) {
   186 	  if (!dmap[v][k].found) {
   195 	    next.push_back(v);
   187 	    next.push_back(v);
   196 	    dmap[v][k] = PathData(true, dmap[*ui][k-1].dist + length[e], e);
   188 	    dmap[v][k] = PathData(true, dmap[process[i]][k-1].dist + length[e], e);
   197 	  }
   189 	  }
   198 	  else if (dmap[*ui][k-1].dist + length[e] < dmap[v][k].dist) {
   190 	  else if (dmap[process[i]][k-1].dist + length[e] < dmap[v][k].dist) {
   199 	    dmap[v][k] = PathData(true, dmap[*ui][k-1].dist + length[e], e);
   191 	    dmap[v][k] = PathData(true, dmap[process[i]][k-1].dist + length[e], e);
   200 	  }
   192 	  }
   201 	}
   193 	}
   202       }
   194       }
   203       process.swap(next);
   195       process.swap(next);
   204     }
   196     }
   205 
   197 
   206     /// \brief Processes one round of computing required path data
   198     /// \brief Processes one round of computing required path data
   207     /// using \ref nodes vector instead of \ref process vector.
   199     /// using \ref nodes vector instead of \ref process vector.
   208     void processNextFullRound(int k) {
   200     void processNextFullRound(int k) {
   209       for (NodeVectorIt ui = nodes.begin(); ui != nodes.end(); ++ui) {
   201       for (int i = 0; i < nodes.size(); ++i) {
   210 	for (OutEdgeIt e(graph, *ui); e != INVALID; ++e) {
   202 	for (OutEdgeIt e(graph, nodes[i]); e != INVALID; ++e) {
   211 	  Node v = graph.target(e);
   203 	  Node v = graph.target(e);
   212 	  if (comp[v] != comp_cnt) continue;
   204 	  if (comp[v] != comp_cnt) continue;
   213 	  if ( !dmap[v][k].found || 
   205 	  if ( !dmap[v][k].found ||
   214 	       dmap[*ui][k-1].dist + length[e] < dmap[v][k].dist ) {
   206 	       dmap[nodes[i]][k-1].dist + length[e] < dmap[v][k].dist ) {
   215 	    dmap[v][k] = PathData(true, dmap[*ui][k-1].dist + length[e], e);
   207 	    dmap[v][k] = PathData(true, dmap[nodes[i]][k-1].dist + length[e], e);
   216 	  }
   208 	  }
   217 	}
   209 	}
   218       }
   210       }
   219     }
   211     }
   220     
   212 
   221     /// \brief Finds the minimum cycle mean value in the current 
   213     /// \brief Finds the minimum cycle mean value in the current
   222     /// component.
   214     /// component.
   223     bool findCurrentMin(Length &min_length, int &min_size, Node &min_node) {
   215     bool findCurrentMin(Length &min_length, int &min_size, Node &min_node) {
   224       bool found_min = false;
   216       bool found_min = false;
   225       for (NodeVectorIt vi = nodes.begin(); vi != nodes.end(); ++vi) {
   217       for (int i = 0; i < nodes.size(); ++i) {
   226 	int n = nodes.size();
   218 	int n = nodes.size();
   227 	if (!dmap[*vi][n].found) continue;
   219 	if (!dmap[nodes[i]][n].found) continue;
   228 	Length len;
   220 	Length len;
   229 	int size;
   221 	int size;
   230 	bool found_one = false;
   222 	bool found_one = false;
   231 	for (int k = 0; k < n; ++k) {
   223 	for (int k = 0; k < n; ++k) {
   232 	  if (!dmap[*vi][k].found) continue;
   224 	  if (!dmap[nodes[i]][k].found) continue;
   233 	  Length _len = dmap[*vi][n].dist - dmap[*vi][k].dist;
   225 	  Length _len = dmap[nodes[i]][n].dist - dmap[nodes[i]][k].dist;
   234 	  int _size = n - k; 
   226 	  int _size = n - k;
   235 	  if (!found_one || len * _size < _len * size) {
   227 	  if (!found_one || len * _size < _len * size) {
   236 	    found_one = true;
   228 	    found_one = true;
   237 	    len = _len;
   229 	    len = _len;
   238 	    size = _size;
   230 	    size = _size;
   239 	  }
   231 	  }
   240 	}
   232 	}
   241 	if ( found_one && 
   233 	if ( found_one &&
   242 	     (!found_min || len * min_size < min_length * size) ) {
   234 	     (!found_min || len * min_size < min_length * size) ) {
   243 	  found_min = true;
   235 	  found_min = true;
   244 	  min_length = len;
   236 	  min_length = len;
   245 	  min_size = size;
   237 	  min_size = size;
   246 	  min_node = *vi;
   238 	  min_node = nodes[i];
   247 	}
   239 	}
   248       }
   240       }
   249       return found_min;
   241       return found_min;
   250     }
   242     }
   251     
   243 
   252   public:  
   244   public:
   253     
   245 
   254     /// \brief Runs the algorithm.
   246     /// \brief Runs the algorithm.
   255     ///
   247     ///
   256     /// Runs the algorithm.
   248     /// Runs the algorithm.
   257     ///
   249     ///
   258     /// \return \c true if a cycle exists in the graph.
   250     /// \return \c true if a cycle exists in the graph.
   259     ///
   251     ///
   260     /// \note Apart from the return value, m.run() is just a shortcut 
   252     /// \note Apart from the return value, m.run() is just a shortcut
   261     /// of the following code.
   253     /// of the following code.
   262     /// \code
   254     /// \code
   263     ///   m.init();
   255     ///   m.init();
   264     ///   m.findMinMean();
   256     ///   m.findMinMean();
   265     ///   m.findCycle();
   257     ///   m.findCycle();
   267     bool run() {
   259     bool run() {
   268       init();
   260       init();
   269       findMinMean();
   261       findMinMean();
   270       return findCycle();
   262       return findCycle();
   271     }
   263     }
   272     
   264 
   273     /// \brief Initializes the internal data structures.
   265     /// \brief Initializes the internal data structures.
   274     void init() {
   266     void init() {
   275       comp_num = stronglyConnectedComponents(graph, comp);
   267       comp_num = stronglyConnectedComponents(graph, comp);
   276       if (!cycle_path) {
   268       if (!cycle_path) {
   277 	local_path = true;
   269 	local_path = true;
   283     ///
   275     ///
   284     /// Computes all the required path data and finds the minimum cycle
   276     /// Computes all the required path data and finds the minimum cycle
   285     /// mean value in the graph.
   277     /// mean value in the graph.
   286     ///
   278     ///
   287     /// \return \c true if a cycle exists in the graph.
   279     /// \return \c true if a cycle exists in the graph.
   288     /// 
   280     ///
   289     /// \pre \ref init() must be called before using this function.
   281     /// \pre \ref init() must be called before using this function.
   290     bool findMinMean() {
   282     bool findMinMean() {
   291       cycle_node = INVALID;
   283       cycle_node = INVALID;
   292       for (comp_cnt = 0; comp_cnt < comp_num; ++comp_cnt) {
   284       for (comp_cnt = 0; comp_cnt < comp_num; ++comp_cnt) {
   293 	initCurrent();
   285 	initCurrent();
   294 	processRounds();
   286 	processRounds();
   295 	
   287 
   296 	Length min_length;
   288 	Length min_length;
   297 	int min_size;
   289 	int min_size;
   298 	Node min_node;
   290 	Node min_node;
   299 	bool found_min = findCurrentMin(min_length, min_size, min_node);
   291 	bool found_min = findCurrentMin(min_length, min_size, min_node);
   300 	
   292 
   301 	if ( found_min && (cycle_node == INVALID || 
   293 	if ( found_min && (cycle_node == INVALID ||
   302 	     min_length * cycle_size < cycle_length * min_size) ) {
   294 	     min_length * cycle_size < cycle_length * min_size) ) {
   303 	  cycle_length = min_length;
   295 	  cycle_length = min_length;
   304 	  cycle_size = min_size;
   296 	  cycle_size = min_size;
   305 	  cycle_node = min_node;
   297 	  cycle_node = min_node;
   306 	}
   298 	}
   307       }
   299       }
   308       return (cycle_node != INVALID);
   300       return (cycle_node != INVALID);
   309     }
   301     }
   310     
   302 
   311     /// \brief Finds a critical (minimum mean) cycle.
   303     /// \brief Finds a critical (minimum mean) cycle.
   312     ///
   304     ///
   313     /// Finds a critical (minimum mean) cycle using the path data
   305     /// Finds a critical (minimum mean) cycle using the path data
   314     /// stored in \ref dmap.
   306     /// stored in \ref dmap.
   315     ///
   307     ///
   316     /// \return \c true if a cycle exists in the graph.
   308     /// \return \c true if a cycle exists in the graph.
   317     /// 
   309     ///
   318     /// \pre \ref init() and \ref findMinMean() must be called before 
   310     /// \pre \ref init() and \ref findMinMean() must be called before
   319     /// using this function.
   311     /// using this function.
   320     bool findCycle() {
   312     bool findCycle() {
   321       if (cycle_node == INVALID) return false;
   313       if (cycle_node == INVALID) return false;
   322       cycle_length = 0;
   314       cycle_length = 0;
   323       cycle_size = 0;
   315       cycle_size = 0;
   343       return true;
   335       return true;
   344     }
   336     }
   345 
   337 
   346     /// \brief Resets the internal data structures.
   338     /// \brief Resets the internal data structures.
   347     ///
   339     ///
   348     /// Resets the internal data structures so that \ref findMinMean() 
   340     /// Resets the internal data structures so that \ref findMinMean()
   349     /// and \ref findCycle() can be called again (e.g. when the 
   341     /// and \ref findCycle() can be called again (e.g. when the
   350     /// underlaying graph has been modified).
   342     /// underlaying graph has been modified).
   351     void reset() {
   343     void reset() {
   352       for (NodeIt u(graph); u != INVALID; ++u)
   344       for (NodeIt u(graph); u != INVALID; ++u)
   353 	dmap[u].clear();
   345 	dmap[u].clear();
   354       cycle_node = INVALID;
   346       cycle_node = INVALID;
   355       if (cycle_path) cycle_path->clear();
   347       if (cycle_path) cycle_path->clear();
   356       comp_num = stronglyConnectedComponents(graph, comp);
   348       comp_num = stronglyConnectedComponents(graph, comp);
   357     }
   349     }
   358     
   350 
   359     /// \brief Returns the total length of the found cycle.
   351     /// \brief Returns the total length of the found cycle.
   360     ///
   352     ///
   361     /// Returns the total length of the found cycle.
   353     /// Returns the total length of the found cycle.
   362     ///
   354     ///
   363     /// \pre \ref run() must be called before using this function.
   355     /// \pre \ref run() must be called before using this function.
   364     Length cycleLength() const { 
   356     Length cycleLength() const {
   365       return cycle_length;
   357       return cycle_length;
   366     }
   358     }
   367     
   359 
   368     /// \brief Returns the number of edges in the found cycle.
   360     /// \brief Returns the number of edges in the found cycle.
   369     ///
   361     ///
   370     /// Returns the number of edges in the found cycle.
   362     /// Returns the number of edges in the found cycle.
   371     ///
   363     ///
   372     /// \pre \ref run() must be called before using this function.
   364     /// \pre \ref run() must be called before using this function.
   373     int cycleEdgeNum() const { 
   365     int cycleEdgeNum() const {
   374       return cycle_size;
   366       return cycle_size;
   375     }
   367     }
   376     
   368 
   377     /// \brief Returns the mean length of the found cycle.
   369     /// \brief Returns the mean length of the found cycle.
   378     ///
   370     ///
   379     /// Returns the mean length of the found cycle.
   371     /// Returns the mean length of the found cycle.
   380     ///
   372     ///
   381     /// \pre \ref run() must be called before using this function.
   373     /// \pre \ref run() must be called before using this function.
   384     ///
   376     ///
   385     /// \note m.minMean() is just a shortcut of the following code.
   377     /// \note m.minMean() is just a shortcut of the following code.
   386     /// \code
   378     /// \code
   387     ///   return m.cycleEdgeNum() / double(m.cycleLength());
   379     ///   return m.cycleEdgeNum() / double(m.cycleLength());
   388     /// \endcode
   380     /// \endcode
   389     double minMean() const { 
   381     double minMean() const {
   390       return cycle_length / (double)cycle_size;
   382       return cycle_length / (double)cycle_size;
   391     }
   383     }
   392 
   384 
   393     /// \brief Returns a const reference to the \ref lemon::Path "Path"
   385     /// \brief Returns a const reference to the \ref lemon::Path "Path"
   394     /// structure of the found cycle.
   386     /// structure of the found cycle.
   397     /// structure of the found cycle.
   389     /// structure of the found cycle.
   398     ///
   390     ///
   399     /// \pre \ref run() must be called before using this function.
   391     /// \pre \ref run() must be called before using this function.
   400     ///
   392     ///
   401     /// \sa \ref cyclePath()
   393     /// \sa \ref cyclePath()
   402     const Path &cycle() const {
   394     const Path& cycle() const {
   403       return *cycle_path;
   395       return *cycle_path;
   404     }
   396     }
   405     
   397 
   406     /// \brief Sets the \ref lemon::Path "Path" structure storing the 
   398     /// \brief Sets the \ref lemon::Path "Path" structure storing the
   407     /// found cycle.
   399     /// found cycle.
   408     /// 
   400     ///
   409     /// Sets the \ref lemon::Path "Path" structure storing the found 
   401     /// Sets the \ref lemon::Path "Path" structure storing the found
   410     /// cycle. If you don't use this function before calling 
   402     /// cycle. If you don't use this function before calling
   411     /// \ref run(), it will allocate one. The destuctor deallocates 
   403     /// \ref run(), it will allocate one. The destuctor deallocates
   412     /// this automatically allocated map, of course.
   404     /// this automatically allocated map, of course.
   413     ///
   405     ///
   414     /// \note The algorithm calls only the \ref lemon::Path::addFront()
   406     /// \note The algorithm calls only the \ref lemon::Path::addFront()
   415     /// "addFront()" method of the given \ref lemon::Path "Path" 
   407     /// "addFront()" method of the given \ref lemon::Path "Path"
   416     /// structure.
   408     /// structure.
   417     /// 
   409     ///
   418     /// \return \c (*this)
   410     /// \return \c (*this)
   419     MinMeanCycle &cyclePath(Path& path) {
   411     MinMeanCycle& cyclePath(Path &path) {
   420       if (local_path) {
   412       if (local_path) {
   421 	delete cycle_path;
   413 	delete cycle_path;
   422 	local_path = false;
   414 	local_path = false;
   423       }
   415       }
   424       cycle_path = &path;
   416       cycle_path = &path;