/**
  * @param $rideNodes
  * @param $emptyRideNodes
  * @param $drivingPools
  * @return RideConfiguration[]
  */
 public function buildConfigurations($rideNodes, $drivingPools, $emptyRideNodes)
 {
     $this->rideNodes = $rideNodes;
     $this->drivingPools = $drivingPools;
     $this->emptyRides = $emptyRideNodes;
     $workNodes = $this->rideNodes;
     ConfigurationBuilder::sortNodesByStartMinute($workNodes);
     $this->adjacenceMatrix = ConfigurationBuilder::buildAdjacenceMatrixFromNodes($workNodes, $emptyRideNodes);
     //build some different configurations
     $rideConfigurations = array();
     $diversity = count($this->drivingPools);
     $factor = $diversity * 2;
     // take for each driving pool another start node,
     // and then shuffle the whole node array some times
     // to create another start set to begin with
     for ($i = 0; $i < $factor; $i++) {
         $workRideNodes = $workNodes;
         if ($i > $diversity) {
             shuffle($workRideNodes);
         } else {
             $switch = $workRideNodes[0];
             $workRideNodes[0] = $workRideNodes[$i];
             $workRideNodes[$i] = $switch;
         }
         $rideConfigurations[] = $this->buildGenericLeastDurationConfiguration($workRideNodes);
     }
     return $rideConfigurations;
 }
 /**
  * @param $rideNodes
  * @param $emptyRideNodes
  * @param $drivingPools
  * @return RideConfiguration[]
  */
 public function buildConfigurations($rideNodes, $drivingPools, $emptyRideNodes)
 {
     $this->rideNodes = $rideNodes;
     $this->drivingPools = $drivingPools;
     $this->emptyRideNodes = $emptyRideNodes;
     $workNodes = $this->rideNodes;
     ConfigurationBuilder::sortNodesByStartMinute($workNodes);
     $this->adjacenceMatrix = ConfigurationBuilder::buildAdjacenceMatrixFromNodes($workNodes, $emptyRideNodes);
     //Initial Config by LeastDistance Strategy
     $s = microtime(true);
     //        $initConfig = $this->buildFeasibleConfiguration();
     $initConfig = $this->buildFeasibleConfigFromStrategy(new RideStrategyLeastDuration());
     $e = microtime(true);
     $this->logWithParameters('ride.log.ridenodes', array(count($this->rideNodes), round($e - $s, 3)));
     if ($initConfig) {
         $configurations = $this->annealConfigurations($initConfig);
         return $configurations;
     }
     return null;
 }
 /**
  * Production code:
  * runs routing algorithm to set optimized missions and orders for a shift
  *
  * @param Shift $shift
  * @param boolean $verbose
  * @return array containing information for user
  */
 public function buildRidePlanForShift(Shift $shift, $verbose = true)
 {
     $day = $shift->getDate();
     $tr = $this->container->get('translator');
     $infos = array();
     if ($verbose) {
         $infos[] = $tr->trans('ride.info.shift') . ' ' . $day->format('d.m.Y') . ', ' . $tr->trans(DateTimeService::getDayOfWeek($day)) . ' ' . $shift->getShiftType()->getName() . '.';
     }
     //set php execution timeout for big calculations
     ini_set('max_execution_time', 300);
     $em = $this->container->get('entity_manager');
     $em->beginTransaction();
     //set STRATEGY for RideOptimization
     $rideStrategy = new RideStrategyAnnealing();
     $rideStrategy->setContainer($this->container);
     //set Shift
     $shift->setManuallyEdited(false);
     // optimization resets manual attribute
     // set DrivingPools
     $drivingPools = $shift->getDrivingPoolsAsArray();
     if (count($drivingPools) < 1) {
         $em->rollback();
         $infos[] = $tr->trans('ride.error.noPools') . ' ' . $shift->getShiftType()->getName() . '.';
         return $infos;
     }
     // set DrivingMissions
     $dispoManagement = $this->container->get('tixi_app.dispomanagement');
     $drivingMissions = $dispoManagement->getDrivingMissionsInShift($shift);
     if (count($drivingMissions) < 1) {
         $em->rollback();
         $infos[] = $tr->trans('ride.error.noMissions') . ' ' . $shift->getShiftType()->getName() . '.';
         return $infos;
     }
     //clean drivingPools for new optimization
     foreach ($drivingPools as $pool) {
         $pool->removeDrivingMissions();
     }
     $configurationBuilder = new ConfigurationBuilder($drivingMissions, $drivingPools, $rideStrategy);
     $this->logger($tr->trans('ride.log.dayAndShift'), array($day->format('d.m.Y'), $shift->getShiftType()->getName()));
     //get all empty Rides
     $emptyRides = $configurationBuilder->buildAllPossibleEmptyRides();
     //get routing information from routing machine and fill node objects
     $s = microtime(true);
     $routeManagement = $this->container->get('tixi_app.routemanagement');
     $emptyRides = $routeManagement->fillRoutesForMultipleRideNodes($emptyRides);
     $e = microtime(true);
     $this->logger($tr->trans('ride.log.routingTime'), array(count($emptyRides), round($e - $s, 3)));
     //create ride configurations with strategy
     $s = microtime(true);
     $rideConfigurations = $configurationBuilder->buildConfigurations();
     if ($rideConfigurations === null) {
         $em->rollback();
         $infos[] = $tr->trans('ride.error.noConfiguration');
         return $infos;
     }
     $e = microtime(true);
     $nodes = count($rideConfigurations);
     $this->logger($tr->trans('ride.log.buildTime'), array($nodes, round($e - $s, 3)));
     // get the best feasible configuration
     $rideConfiguration = $this->getBestConfiguration($rideConfigurations);
     $configurationAnalyzer = new ConfigurationAnalyzer($rideConfiguration);
     $configurationAnalyzer->assignMissionsAndVehiclesToPool();
     $booked = $rideConfiguration->countNodes();
     $overbooked = count($rideConfiguration->getNotFeasibleNodes());
     if ($verbose) {
         $infos[] = $tr->trans('ride.info.nodes') . ' ' . $booked . ', ' . $tr->trans('ride.info.overbooked') . ' ' . $overbooked . '.';
     }
     $this->logger($tr->trans('ride.log.success'), array($nodes, $overbooked));
     // if everything worked, return successfully
     $em->commit();
     $em->flush();
     return $infos;
 }
 /**
  * this adds all missions to existing configuration with compare to a time slice window,
  * no exact routing informations given
  * @param $rideNodes
  * @param $drivingPools
  * @param $emptyRideNodes
  * @param \Tixi\App\AppBundle\Ride\RideConfiguration $existingConfiguration
  * @return RideConfiguration
  */
 public function buildConfiguration($rideNodes, $drivingPools, $emptyRideNodes, RideConfiguration $existingConfiguration = null)
 {
     $this->rideNodes = $rideNodes;
     $this->drivingPools = $drivingPools;
     /**@var $workRideNodes RideNode[] */
     $workRideNodes = $this->rideNodes;
     $addTimePickup = DispositionVariables::ARRIVAL_BEFORE_PICKUP;
     //remove existing nodes from workSet
     if ($existingConfiguration) {
         $rideConfiguration = $existingConfiguration;
         foreach ($rideConfiguration->getRideNodeLists() as $list) {
             foreach ($list->getRideNodes() as $key => $node) {
                 unset($workRideNodes[$key]);
             }
         }
     } else {
         $rideConfiguration = new RideConfiguration($this->drivingPools);
     }
     ConfigurationBuilder::sortNodesByStartMinute($workRideNodes);
     $workRideNodeLists = $rideConfiguration->getRideNodeLists();
     //always loop all available pools - but stop when no missions are left so it is
     //possible to have empty pools (no driver/vehicle needed for these missions)
     foreach ($drivingPools as $drivingPool) {
         if (count($workRideNodes) < 1) {
             break;
         }
         if (count($workRideNodeLists) > 0) {
             $rideNodeList = array_shift($workRideNodeLists);
         } else {
             $rideNodeList = new RideNodeList();
             $rideConfiguration->addRideNodeList($rideNodeList);
         }
         // no existing list with nodes,
         // so we add rideNodes normally with time constraint
         if ($rideNodeList->isEmpty()) {
             $rideNodeList->addRideNode(array_shift($workRideNodes));
             $actualNode = $rideNodeList->getActualRideNode();
             foreach ($workRideNodes as $nodeKey => $node) {
                 if ($node->startMinute > $actualNode->endMinute + $addTimePickup) {
                     $actualNode = $node;
                     $rideNodeList->addRideNode($node);
                     unset($workRideNodes[$nodeKey]);
                 }
             }
         } else {
             // existing list with nodes,
             // add rideNodes with time constraint between existing nodes
             foreach ($rideNodeList->getRideNodes() as $listNode) {
                 foreach ($workRideNodes as $nodeKey => $node) {
                     if (!$listNode->previousNode) {
                         if ($node->endMinute + $addTimePickup < $listNode->startMinute) {
                             $rideNodeList->addRideNodeBeforeRideNode($node, $listNode);
                             unset($workRideNodes[$nodeKey]);
                             continue;
                         }
                     } else {
                         if ($node->endMinute + $addTimePickup < $listNode->startMinute && $node->startMinute > $listNode->previousNode->endMinute + $addTimePickup) {
                             $rideNodeList->addRideNodeBeforeRideNode($node, $listNode);
                             unset($workRideNodes[$nodeKey]);
                             continue;
                         }
                     }
                     if (!$listNode->nextNode) {
                         if ($node->startMinute > $listNode->endMinute + $addTimePickup) {
                             $rideNodeList->addRideNodeAfterRideNode($node, $listNode);
                             unset($workRideNodes[$nodeKey]);
                             continue;
                         }
                     } else {
                         if ($node->startMinute > $listNode->endMinute + $addTimePickup && $node->endMinute + $addTimePickup < $listNode->nextNode->startMinute) {
                             $rideNodeList->addRideNodeAfterRideNode($node, $listNode);
                             unset($workRideNodes[$nodeKey]);
                             continue;
                         }
                     }
                 }
             }
         }
     }
     //left Nodes are not feasible
     if (count($workRideNodes) > 1) {
         $rideConfiguration->setNotFeasibleNodes($workRideNodes);
     }
     return $rideConfiguration;
 }