/// <summary> /// Reduce a profit matrix by eliminating and forcing certain edges. /// </summary> /// <param name="full">Original complete profit. Its default value /// must be -Inf for the output to be valid (although it is possible /// to extend it to non-inf matrices, it becomes inefficient, so won't be done).</param> /// <param name="reducer">Descriptor of the changes that should be done.</param> private static SparseMatrix reduceprofit(SparseMatrix full, MurtyNode reducer) { SparseMatrix reduced = new SparseMatrix(full, double.NegativeInfinity); int[] removerows = new int[reducer.Forced.Length]; int[] removecols = new int[reducer.Forced.Length]; int h = 0; foreach (MatrixKey force in reducer.Forced) { removerows[h] = force.I; removecols[h] = force.K; h++; } reduced.RemoveRows(removerows); reduced.RemoveColumns(removecols); foreach (MatrixKey force in reducer.Forced) { reduced[force.I, force.K] = 1; // always bigger than the removed edges, hence will always be picked } foreach (MatrixKey eliminate in reducer.Eliminated) { reduced.RemoveAt(eliminate.I, eliminate.K); //reduced[eliminate.I, eliminate.K] = double.NegativeInfinity; } return(reduced); }
/// <summary> /// Efficient equality comparer with other MurtyNode. /// </summary> /// <param name="that">Compared node.</param> /// <returns>True if both nodes are structurally identical. /// This implies having the same field values and the same defined order for each field.</returns> public bool Equals(MurtyNode that) { if (this.Eliminated.Length != that.Eliminated.Length || this.Forced.Length != that.Forced.Length) { return(false); } for (int i = 0; i < this.Eliminated.Length; i++) { if (this.Eliminated[i] != that.Eliminated[i]) { return(false); } } for (int i = 0; i < this.Forced.Length; i++) { if (this.Forced[i] != that.Forced[i]) { return(false); } } if (this.Assignment == null) { return(that.Assignment == null); } else { if (that.Assignment == null) { return(false); } for (int i = 0; i < this.Assignment.Length; i++) { if (this.Assignment[i] != that.Assignment[i]) { return(false); } } } return(true); }
/// <summary> /// Enumerate all possible pairings using a Murty's algorithm. /// </summary> /// <param name="profit">Profit matrix to be maximized.</param> /// <returns>Enumeration of most likely assignments pairing permutations (and their profit assignments).</returns> public static IEnumerable <Tuple <int[], double> > MurtyPairing(SparseMatrix profit) { var frontier = new PriorityQueue <MurtyNode>(); MurtyNode first = new MurtyNode(); first.Assignment = LinearAssignment(profit); //Console.WriteLine(profit.ToStringFull()); frontier.Add(AssignmentValue(profit, first.Assignment), first); while (frontier.Count > 0) { //Console.WriteLine(frontier.Count); double value; MurtyNode best = frontier.Pop(out value); //Console.WriteLine(frontier.Count); //Console.WriteLine(best); yield return(Tuple.Create(best.Assignment, value)); //Console.WriteLine("children___"); foreach (MurtyNode child in best.Children) { child.Assignment = LinearAssignment(reduceprofit(profit, child)); //Console.WriteLine(child); //Console.WriteLine(reduceprofit(profit, child).ToStringFull()); //Console.WriteLine(AssignmentValue(reduceprofit(profit, child), child.Assignment)); if (child.Assignment != null) { frontier.Add(AssignmentValue(profit, child.Assignment), child); } } } }