/** * build rideConfiguration in this builder and returns it * * @return RideConfiguration */ public function createConfigurationFromExistingMissions() { foreach ($this->drivingPools as $pool) { $rideNodeList = new RideNodeList($pool); if ($pool->hasAssociatedDrivingMissions()) { $nodes = $this->createRideNodesFromDrivingMissions($pool->getDrivingMissions()); $this->sortNodesByStartMinute($nodes); foreach ($nodes as $node) { $rideNodeList->addRideNode($node); } } $this->rideConfiguration->addRideNodeList($rideNodeList); } return $this->rideConfiguration; }
/** * @param $rideNodes RideNode[] * @return RideConfiguration */ private function buildGenericLeastDurationConfiguration($rideNodes) { $rideConfiguration = new RideConfiguration($this->drivingPools); $workRideNodes = $rideNodes; //always loop all available pools - but stop when no missions are left so it is //possible to have empty rideNodeLists (no driver/vehicle needed for these) //the amount of created rideNodeLists will give the amount of used vehicles foreach ($this->drivingPools as $drivingPool) { if (count($workRideNodes) < 1) { break; } $rideNodeList = new RideNodeList($drivingPool); //set first node on start $rideNodeList->addRideNode(array_shift($workRideNodes)); $poolExtraMinutesPerRide = 0; if ($drivingPool->hasAssociatedDriver()) { $poolExtraMinutesPerRide += $drivingPool->getDriver()->getExtraMinutes(); } $stillFeasible = true; while ($stillFeasible) { $actualNode = $rideNodeList->getActualRideNode(); $bestNode = null; $bestNodeKey = null; $bestEmptyRide = null; $actualDuration = -1; //check all nodes in workSet for feasible and best distance foreach ($workRideNodes as $compareNodeKey => $compareNode) { $emptyRide = $this->adjacenceMatrix[$actualNode->getRideNodeHashId()][$compareNode->getRideNodeHashId()]; //not feasible, get next node if ($emptyRide === -1) { continue; } if ($this->isTaboo($rideNodeList, $compareNode)) { continue; } // feasible $feasibleTimeForNextNode = $actualNode->endMinute + $emptyRide->duration + DispositionVariables::ARRIVAL_BEFORE_PICKUP + $poolExtraMinutesPerRide; //feasible time for node + emptyRide -> to next node if ($feasibleTimeForNextNode <= $compareNode->startMinute) { if ($actualDuration === -1) { $bestNode = $compareNode; $bestNodeKey = $compareNodeKey; $bestEmptyRide = $emptyRide; $actualDuration = $emptyRide->duration; } if ($emptyRide->duration < $actualDuration) { $bestNode = $compareNode; $bestNodeKey = $compareNodeKey; $bestEmptyRide = $emptyRide; $actualDuration = $emptyRide->duration; } } } if ($bestNode && $bestEmptyRide) { $rideNodeList->addRideNode($bestNode); $rideNodeList->addRideNode($bestEmptyRide); unset($workRideNodes[$bestNodeKey]); } else { $stillFeasible = false; } } $rideConfiguration->addRideNodeList($rideNodeList); } $rideConfiguration->setNotFeasibleNodes($workRideNodes); $rideConfiguration->removeEmptyRideNodeLists(); return $rideConfiguration; }
/** * 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; }