function MatrixFitRoute($route) { require_once 'matrix.php'; $this->refreshPosibleTruck(); $route_possible_trucks = $this->getPossibleTrucks($route); $copy_possible_trucks = $this->truck_possible; $list_all_possible_trucks = array(); foreach ($copy_possible_trucks as $value) { $list_all_possible_trucks = array_merge($list_all_possible_trucks, $value); } $list_all_possible_trucks = array_unique(array_merge($list_all_possible_trucks, $route_possible_trucks)); $pending_routes = array_keys($this->routes); array_push($pending_routes, "new"); $assigned_trucks = array(); //create white_matrix $white_matrix = array(); foreach ($list_all_possible_trucks as $truck_id) { $white_matrix[$truck_id] = array(); foreach ($pending_routes as $route_id) { if ($route_id == "new") { $white_matrix[$truck_id][$route_id] = in_array($truck_id, $route_possible_trucks) ? 1 : 0; } else { $white_matrix[$truck_id][$route_id] = in_array($truck_id, $copy_possible_trucks[$route_id]) ? 1 : 0; } } } $grey_matrix = new Matrix($white_matrix); //basic required condition for solution if (!$grey_matrix->possible()) { return false; } //cardinality==1 check for $route. this means that the route has only one truck that it can use. foreach ($grey_matrix->getColumnKeys() as $route_id) { if ($grey_matrix->getColumnCardinal($route_id) == 1) { $truck_id = $grey_matrix->getFirstPositiveRow($route_id); if ($truck_id === false) { trigger_error("Looked for positive row but found none", E_USER_ERROR); } else { $assigned_trucks[$truck_id] = $route_id; $grey_matrix->deleteRow($truck_id); $grey_matrix->deleteColumn($route_id); } } } //cardinality==1 check for $truck. this means that there is only one route that can use this truck foreach ($grey_matrix->getRowKeys() as $truck_id) { if ($grey_matrix->getRowCardinal($truck_id) == 1) { $route_id = $grey_matrix->getFirstPositiveColumn($truck_id); if ($route_id === false) { trigger_error("Looked for positive col but found none", E_USER_ERROR); } else { $assigned_trucks[$truck_id] = $route_id; $grey_matrix->deleteRow($truck_id); $grey_matrix->deleteColumn($route_id); } } } //trivial solution found if (count($grey_matrix->getColumnKeys()) < 1) { return $assigned_trucks; } //check again for basic condition before continuing if (!$grey_matrix->possible()) { return false; } //iterate while there are still routes to be fit, we will include exit statments under certain conditions inside the loop $black_matrix = new Matrix($grey_matrix->getMatrix()); $ignores = array(); $routes_ids = $black_matrix->getColumnKeys(); $last_route_id = end($routes_ids); $first_route_id = reset($routes_ids); $max_loop = $black_matrix->maximumIterations(); $loop_count = 0; while (true) { if ($loop_count >= $max_loop) { trigger_error("loops count exceeded logical max loop, please check the code for errors", E_USER_ERROR); } $black_matrix = new Matrix($grey_matrix->getMatrix()); //recreate for loop $routes_ids = $black_matrix->getColumnKeys(); //recreate for loop $assignments = array(); // list of assignments for solution $previous_route_id = false; $previous_route_value = false; $n = 1; //for slice porpuses foreach ($routes_ids as $route_id) { if ($black_matrix->possible() === false) { return false; } if (count($black_matrix->getColumnKeys()) == 0 || count($black_matrix->getRowKeys()) == 0) { return false; } if (!isset($ignores[$route_id])) { $ignores[$route_id] = array(); } $fix_truck = $black_matrix->getFirstPositiveRow($route_id, $ignores[$route_id]); //there are no more positive values availables if ($fix_truck === false) { //no more subsitituions left if ($route_id == $first_route_id) { return false; } else { $previous_step = $previous_route_value; if ($previous_step === false) { trigger_error("something went wrong while searching for the previous positive of {$previous_route_id}", E_USER_ERROR); } else { array_push($ignores[$previous_route_id], $previous_step); } $ignores = array_slice($ignores, 0, $n, TRUE); break; //restart loop } } else { $n += 1; $assignments[$fix_truck] = $route_id; $black_matrix->deleteRow($fix_truck); $black_matrix->deleteColumn($route_id); $previous_route_id = $route_id; $previous_route_value = $fix_truck; //A solution was found, hurray! if ($route_id == $last_route_id) { return array_merge($assigned_trucks, $assignments); } } } } }