Esempio n. 1
0
 def test_random(self, _, seed):
     'Test method = "random" for a range of seeds'
     alg = BiDirectional(self.G, self.max_res, self.min_res, seed=seed)
     # Run and test results
     alg.run()
     self.assertEqual(alg.path, self.result_path)
     self.assertEqual(alg.total_cost, self.total_cost)
     self.assertTrue(all(alg.consumed_resources == self.consumed_resources))
Esempio n. 2
0
 def test_backward(self):
     alg = BiDirectional(self.G,
                         self.max_res,
                         self.min_res,
                         direction='backward')
     alg.run()
     self.assertEqual(alg.path, self.result_path)
     self.assertEqual(alg.total_cost, self.total_cost)
     self.assertTrue(alg.consumed_resources == self.consumed_resources)
Esempio n. 3
0
 def test_bidirectional(self):
     """
     Test BiDirectional with randomly chosen sequence of directions
     for a range of seeds.
     """
     alg = BiDirectional(self.G, self.max_res, self.min_res)
     alg.run()
     self.assertEqual(alg.path, self.result_path)
     self.assertEqual(alg.total_cost, self.total_cost)
     self.assertEqual(alg.consumed_resources, self.consumed_resources)
Esempio n. 4
0
 def test_unprocessed(self):
     'Test method = "unprocessed"'
     alg = BiDirectional(self.G,
                         self.max_res,
                         self.min_res,
                         method="unprocessed")
     alg.run()
     self.assertEqual(alg.path, self.result_path)
     self.assertEqual(alg.total_cost, self.total_cost)
     self.assertTrue(alg.consumed_resources == self.consumed_resources)
Esempio n. 5
0
 def test_bidirectional_forward(self):
     """Test BiDirectional with custom callback."""
     alg = BiDirectional(self.G,
                         self.max_res,
                         self.min_res,
                         direction="forward",
                         REF_callback=self.my_callback)
     alg.run()
     self.assertEqual(alg.path, self.result_path)
     self.assertEqual(alg.total_cost, self.total_cost)
     self.assertEqual(alg.consumed_resources, self.consumed_resources)
Esempio n. 6
0
 def test_bidirectional(self):
     """Test BiDirectional with custom callback."""
     alg = BiDirectional(self.G,
                         self.max_res,
                         self.min_res,
                         method="unprocessed",
                         REF_callback=self.my_callback)
     # Overwrite graph as original labelling won't match
     self.my_callback.G = alg.G
     alg.run()
     self.assertEqual(alg.path, self.result_path)
     self.assertEqual(alg.total_cost, self.total_cost)
     self.assertEqual(alg.consumed_resources, self.consumed_resources)
Esempio n. 7
0
 def test_unprocessed_time_limit(self):
     'Test time_limit parameter'
     alg = BiDirectional(self.G,
                         self.max_res,
                         self.min_res,
                         method="unprocessed",
                         time_limit=0.001)
     start = time()
     alg.run()
     self.assertTrue(time() - start <= 0.001 + 1e-3)
     self.assertEqual(alg.path, self.result_path)
     self.assertEqual(alg.total_cost, self.total_cost)
     self.assertTrue(alg.consumed_resources == self.consumed_resources)
Esempio n. 8
0
    def solve(self, time_limit):
        """
        Solves the subproblem with cspy.
        Time limit is reduced by 0.5 seconds as a safety window.

        Resolves at most twice:
        1. using elementary = False,
        2. using elementary = True, and threshold, if a route has already been
        found previously.
        """
        if not self.run_subsolve:
            return self.routes, False

        self.formulate()
        logger.debug("resources = {}".format(self.resources))
        logger.debug("min res = {}".format(self.min_res))
        logger.debug("max res = {}".format(self.max_res))

        more_routes = False

        my_callback = self.get_REF()
        direction = ("forward" if
                     (self.time_windows or self.pickup_delivery
                      or self.distribution_collection) else "both")
        # Run only twice: Once with `elementary=False` check if route already
        # exists.

        s = ([False, True] if (not self.distribution_collection
                               and not self.elementary) else [True])
        for elementary in s:
            if elementary:
                # Use threshold if non-elementary (safe-guard against large
                # instances)
                thr = self._avg_path_len * min(self.G.edges[i, j]["weight"]
                                               for (i, j) in self.G.edges())
            else:
                thr = None
            logger.debug(
                f"Solving subproblem using elementary={elementary}, threshold={thr}, direction={direction}"
            )
            alg = BiDirectional(
                self.sub_G,
                self.max_res,
                self.min_res,
                threshold=thr,
                direction=direction,
                time_limit=time_limit - 0.5 if time_limit else None,
                elementary=elementary,
                REF_callback=my_callback,
                # pickup_delivery_pairs=self.pickup_delivery_pairs,
            )

            # Pass processed graph
            if my_callback is not None:
                my_callback._sub_G = alg.G
                my_callback._source_id = alg._source_id
                my_callback._sink_id = alg._sink_id
            alg.run()
            logger.debug("subproblem")
            logger.debug("cost = %s", alg.total_cost)
            logger.debug("resources = %s", alg.consumed_resources)

            if alg.total_cost is not None and alg.total_cost < -(1e-3):
                new_route = self.create_new_route(alg.path)
                logger.debug(alg.path)
                path_len = len(alg.path)
                if not any(
                        list(new_route.edges()) == list(r.edges())
                        for r in self.routes):
                    more_routes = True
                    self.routes.append(new_route)
                    self.total_cost = new_route.graph["cost"]
                    logger.debug("reduced cost = %s", alg.total_cost)
                    logger.debug("real cost = %s", self.total_cost)
                    if path_len > 2:
                        self._avg_path_len += (
                            path_len - self._avg_path_len) / self._iters
                        self._iters += 1
                    break
                else:
                    logger.info("Route already found, finding elementary one")
            else:
                break
        return self.routes, more_routes
Esempio n. 9
0
    def solve(self, time_limit):
        """
        Solves the subproblem with cspy.

        Resolves until:
        1. heuristic algorithm gives a new route (column with -ve reduced cost);
        2. exact algorithm gives a new route;
        3. neither heuristic nor exact give a new route.

        Note : time_limit has no effect for the moment
        """
        if not self.run_subsolve:
            return self.routes, False

        self.formulate()
        logger.debug("resources = {}".format(self.resources))
        logger.debug("min res = {}".format(self.min_res))
        logger.debug("max res = {}".format(self.max_res))

        more_routes = False

        while True:
            if self.exact:
                logger.debug("solving with bidirectional")
                self.alg = BiDirectional(
                    self.sub_G,
                    self.max_res,
                    self.min_res,
                    direction="both",
                    method="generated",
                    REF_forward=self.get_REF("forward"),
                    REF_backward=self.get_REF("backward"),
                    REF_join=self.get_REF("join"),
                )
            else:
                logger.debug("solving with greedyelim")
                self.alg = GreedyElim(
                    self.sub_G,
                    self.max_res,
                    self.min_res,
                    REF=self.get_REF("forward"),
                    max_depth=40,
                )
            self.alg.run()
            logger.debug("subproblem")
            logger.debug("cost = %s" % self.alg.total_cost)
            logger.debug("resources = %s" % self.alg.consumed_resources)
            if self.alg.total_cost < -(10**-3):
                more_routes = True
                self.add_new_route()
                logger.debug("new route %s" % self.alg.path)
                logger.debug("reduced cost = %s" % self.alg.total_cost)
                logger.debug("real cost = %s" % self.total_cost)
                break
            # If not already solved exactly
            elif not self.exact:
                # Solve exactly from here on
                self.exact = True
            # Solved heuristically and exactly and no more routes
            else:
                break
        return self.routes, more_routes
Esempio n. 10
0
 def test_time_limit_raises(self):
     'Time limit of 0 raises an exception'
     alg = BiDirectional(self.G, self.max_res, self.min_res, time_limit=0)
     alg.run()
     with self.assertRaises(Exception) as context:
         alg.path