/// <summary> /// Solves the given problem. /// </summary> /// <returns></returns> public sealed override Tour Solve(TSPTWProblem problem, TObjective objective, out float fitness) { // generate random solution. var customers = new List <int>(); for (var customer = 0; customer < problem.Times.Length; customer++) { if (customer != problem.First && customer != problem.Last) { customers.Add(customer); } } customers.Shuffle <int>(); customers.Insert(0, problem.First); if (problem.Last.HasValue && problem.First != problem.Last) { // the special case of a fixed last customer. customers.Add(problem.Last.Value); } var route = new Tour(customers, problem.Last); // calculate fitness. fitness = objective.Calculate(problem, route); return(route); }
/// <summary> /// Solves the given problem. /// </summary> /// <returns></returns> public sealed override Tour Solve(TSPTWProblem problem, TObjective objective, out float fitness) { // generate random order for unplaced customers. var customers = new List <int>(); for (var customer = 0; customer < problem.Times.Length / 2; customer++) { if (customer != problem.First && customer != problem.Last) { customers.Add(customer); } } customers.Shuffle <int>(); // generate empty route based on problem definition. var route = problem.CreateEmptyTour(); // add all customers by using cheapest insertion. for (var i = 0; i < customers.Count; i++) { CheapestInsertionDirectedHelper.InsertCheapestDirected(route, problem.Times, problem.TurnPenalties, customers[i], float.MaxValue); } // calculate fitness. fitness = objective.Calculate(problem, route); return(route); }
/// <summary> /// Returns true if there was an improvement, false otherwise. /// </summary> /// <returns></returns> public bool Apply(TSPTWProblem problem, TObjective objective, Tour tour, int level, out float difference) { var original = objective.Calculate(problem, tour); if (problem.Times.Length == 1) { difference = 0; return(false); } difference = 0; while (level > 0) { // remove random customer after another random customer. var customer = _random.Generate(problem.Times.Length); var insert = _random.Generate(problem.Times.Length - 1); if (insert >= customer) { // customer is the same of after. insert++; } // shift after the next customer. tour.ShiftAfter(customer, insert); var afterShift = objective.Calculate(problem, tour); var shiftDiff = afterShift - original; difference += shiftDiff; // decrease level. level--; } return(difference < 0); }
/// <summary> /// Returns true if there was an improvement, false otherwise. /// </summary> /// <returns></returns> public bool Apply(TSPTWProblem problem, TObjective objective, Tour solution, out float delta) { var before = float.MaxValue; if (objective.IsNonContinuous) { before = objective.Calculate(problem, solution); } // STRATEGY: // 1: try to move a violated customer backwards. // 2: try to move a non-violated customer forward. // 3: try to move a non-violated customer backward. // 4: try to move a violated customer forward. if (!_assumeFeasible) { if (this.MoveViolatedBackward(problem, objective, solution, out delta)) { // success already, don't try anything else. if (objective.IsNonContinuous) { delta = before - objective.Calculate(problem, solution); } return(delta > 0); } } if (this.MoveNonViolatedForward(problem, objective, solution, out delta)) { // success already, don't try anything else. if (objective.IsNonContinuous) { delta = before - objective.Calculate(problem, solution); } return(delta > 0); } if (this.MoveNonViolatedBackward(problem, objective, solution, out delta)) { // success already, don't try anything else. if (objective.IsNonContinuous) { delta = before - objective.Calculate(problem, solution); } return(delta > 0); } if (!_assumeFeasible) { if (this.MoveViolatedForward(problem, objective, solution, out delta)) { // success already, don't try anything else. if (objective.IsNonContinuous) { delta = before - objective.Calculate(problem, solution); } return(delta > 0); } } return(false); }
/// <summary> /// Returns true if there was an improvement, false otherwise. /// </summary> /// <returns></returns> public bool Apply(TSPTWProblem problem, TObjective objective, Tour tour, int level, out float difference) { var original = objective.Calculate(problem, tour); if (problem.Times.Length / 2 == 1) { difference = 0; return(false); } difference = 0; while (level > 0) { // remove random customer after another random customer. var customer = _random.Generate(problem.Times.Length / 2); if (customer == problem.First || customer == problem.Last) { // don't move unmovable customers. continue; } var before = _random.Generate((problem.Times.Length / 2) - 1); if (before >= customer) { // customer is the same of after. before++; } if (problem.First != problem.Last && problem.Last.HasValue && problem.Last == before) { // don't move after a fixed last customer. continue; } // get the actual id's of the customers. var directedCustomer = tour.GetDirectedId(customer); var directedBefore = tour.GetDirectedId(before); // do the best possible shift after. tour.ShiftAfterBestTurns(problem.Times, problem.TurnPenalties, directedCustomer, directedBefore); // calculate new fitness. var afterShift = objective.Calculate(problem, tour); var shiftDiff = afterShift - original; difference += shiftDiff; // decrease level. level--; } return(difference < 0); }
/// <summary> /// Returns true if there was an improvement, false otherwise. /// </summary> /// <returns></returns> public bool Apply(TSPTWProblem problem, TObjective objective, Tour solution, out float delta) { if (_validFlags == null) { _validFlags = new bool[problem.Times.Length / 2]; } // STRATEGY: // 1: try to move a violated customer backwards. // 2: try to move a non-violated customer forward. // 3: try to move a non-violated customer backward. // 4: try to move a violated customer forward. if (!_assumeFeasible) { if (this.MoveViolatedBackward(problem, objective, solution, out delta)) { // success already, don't try anything else. return(delta > 0); } } if (this.MoveNonViolatedForward(problem, objective, solution, out delta)) { // success already, don't try anything else. return(delta > 0); } if (this.MoveNonViolatedBackward(problem, objective, solution, out delta)) { // success already, don't try anything else. return(delta > 0); } if (!_assumeFeasible) { if (this.MoveViolatedForward(problem, objective, solution, out delta)) { // success already, don't try anything else. return(delta > 0); } } return(false); }
/// <summary> /// Returns true if there was an improvement, false otherwise. /// </summary> /// <returns></returns> public bool MoveViolatedForward(TSPTWProblem problem, TObjective objective, Tour solution, out float delta) { // search for invalid customers. var enumerator = solution.GetEnumerator(); var time = 0f; var fitness = 0f; var position = 0; var invalids = new List <Tuple <int, int> >(); // al list of customer-position pairs. var previous = Constants.NOT_SET; while (enumerator.MoveNext()) { var current = enumerator.Current; if (previous != Constants.NOT_SET) { // keep track of time. time += problem.Times[previous][current]; } var window = problem.Windows[enumerator.Current]; if (window.Max < time && position > 0 && position < problem.Times.Length - 1) { // ok, unfeasible and customer is not the first 'moveable' customer. fitness += time - window.Max; if (enumerator.Current != problem.Last) { // when the last customer is fixed, don't try to relocate. invalids.Add(new Tuple <int, int>(enumerator.Current, position)); } } if (window.Min > time) { // wait here! time = window.Min; } // increase position. position++; previous = enumerator.Current; } // ... ok, if a customer was found, try to move it. foreach (var invalid in invalids) { // ok try the new position. for (var newPosition = invalid.Item2 + 1; newPosition < problem.Times.Length; newPosition++) { var before = solution.GetCustomerAt(newPosition); if (before == problem.Last) { // cannot move a customer after a fixed last customer. continue; } // calculate new total min diff. var newFitness = 0.0f; previous = Constants.NOT_SET; time = 0; enumerator = solution.GetEnumerator(); while (enumerator.MoveNext()) { var current = enumerator.Current; if (current != invalid.Item1) { // ignore invalid, add it after 'before'. if (previous != Constants.NOT_SET) { // keep track if time. time += problem.Times[previous][current]; } var window = problem.Windows[enumerator.Current]; if (window.Max < time) { // ok, unfeasible and customer is not the first 'moveable' customer. newFitness += time - window.Max; } if (window.Min > time) { // wait here! time = window.Min; } previous = current; if (current == before) { // also add the before->invalid. time += problem.Times[current][invalid.Item1]; window = problem.Windows[invalid.Item1]; if (window.Max < time) { // ok, unfeasible and customer is not the first 'moveable' customer. newFitness += time - window.Max; } if (window.Min > time) { // wait here! time = window.Min; } previous = invalid.Item1; } } } if (newFitness < fitness) { // there is improvement! delta = fitness - newFitness; solution.ShiftAfter(invalid.Item1, before); return(true); } } } delta = 0; return(false); }
/// <summary> /// Returns true if there was an improvement, false otherwise. /// </summary> /// <returns></returns> public bool Apply(TSPTWProblem problem, TObjective objective, Tour tour, out float difference) { return(this.Apply(problem, objective, tour, 1, out difference)); }
/// <summary> /// Returns true if there was an improvement, false otherwise. /// </summary> /// <returns></returns> public bool MoveViolatedForward(TSPTWProblem problem, TObjective objective, Tour solution, out float delta) { if (_validFlags == null) { _validFlags = new bool[problem.Times.Length / 2]; } float time, waitTime, violatedTime; int violated; var fitness = objective.Calculate(problem, solution, out violated, out violatedTime, out waitTime, out time, ref _validFlags); // if no violated customer found return false. if (violated == 0) { delta = 0; return(false); } // loop over all customers. var enumerator = solution.GetEnumerator(); var position = 0; while (enumerator.MoveNext()) { if (position == 0) { // don't move the first customer. position++; continue; } // get the id of the current customer. var current = enumerator.Current; var id = DirectedHelper.ExtractId(current); if (problem.Last == id) { // don't place a fixed last customer. position++; continue; } // is this customer violated. if (_validFlags[id]) { // no it's not, move on. position++; continue; } // move over all customers before the current position. var enumerator2 = solution.GetEnumerator(); var position2 = 0; while (enumerator2.MoveNext()) { if (position2 <= position) { // only consider placement after. position2++; continue; } var current2 = enumerator2.Current; var id2 = DirectedHelper.ExtractId(current2); if (problem.Last == id2 && problem.Last != problem.First) { // don't place a fixed last customer. position2++; continue; } // test and check fitness. // TODO: do best-placement? check best turn at 'current'. var shiftedTour = solution.GetShiftedAfter(current, current2); // generates a tour as if current was placed right after current2. var newFitness = objective.Calculate(problem, shiftedTour); if (newFitness < fitness) { // there is improvement! delta = fitness - newFitness; solution.ShiftAfter(current, current2); return(true); } position2++; } position++; } delta = 0; return(false); }