Esempio n. 1
0
        public void AssignmentValue1()
        {
            int[] matches = new int[6];
            AE.Fill(matches, i => i);

            Assert.AreEqual(6, GC.AssignmentValue(threecomp, matches));
        }
Esempio n. 2
0
        public void LinearAssignmentUnique()
        {
            SparseMatrix profit = new SparseMatrix(4, 4);

            for (int i = 0; i < 10; i++)
            {
                profit[i, i] = (i + 1) / 2.0;
            }

            int[] best     = GC.LinearAssignment(profit);
            int[] expected = new int[10];
            AE.Fill(expected, i => i);

            Assert.IsTrue(expected.SequenceEqual(best));
        }
Esempio n. 3
0
        /// <summary>
        /// Solve the linear assignment problem with the hungarian algorithm proposed by Kuhn.
        /// </summary>
        /// <param name="matrix">Utility matrix, where each row represent a worker and each column, a work.
        /// It is represented sparsely, but every index should have at least one entry (the return is a non-sparse list).
        /// This is for efficiency reasons, as the problem at hand doesn't require sparsity in the output.</param>
        /// <returns>Dense assignment list.</returns>
        private static int[] Hungarian(SparseMatrix matrix)
        {
            // initial feasible labeling
            var rowmax = matrix.FoldRows(Math.Max, 0);

            double[] labelx = new double[matrix.Width];
            double[] labely = new double[matrix.Height];

            int   [] matchx = new int   [labelx.Length];
            int   [] matchy = new int   [labelx.Length];

            bool  [] visitx = new bool  [labelx.Length];      // set represented by its indicator function
            bool  [] visity = new bool  [labely.Length];      // idem

            double[] slack  = new double[labely.Length];
            int   [] parent = new int   [labely.Length];
            int      root   = -1;

            int    iminslack = int.MaxValue;
            double delta     = double.PositiveInfinity;

            foreach (var item in rowmax)
            {
                labelx[item.Key] = item.Value;
            }

            AE.Fill(matchx, -1);
            AE.Fill(matchy, -1);

            // find an unmatched worker to start building a tree
            while ((root = Array.IndexOf(matchx, -1)) != -1)
            {
                // annotate all its slacks
                AE.Fill(parent, root);
                AE.Fill(slack, i => labelx[root] + labely[i] - matrix[root, i]);

                Array.Clear(visitx, 0, visitx.Length);
                Array.Clear(visity, 0, visity.Length);
                visitx[root] = true;

                bool found = false;
                while (!found)
                {
                    // find the minimal slack where "y is in T"
                    iminslack = int.MaxValue;
                    delta     = double.PositiveInfinity;

                    for (int i = 0; i < slack.Length; i++)
                    {
                        if (visity[i] == false && slack[i] < delta)
                        {
                            iminslack = i;
                            delta     = slack[i];
                        }
                    }

                    if (double.IsPositiveInfinity(delta))
                    {
                        return(null);                 // there is no solution
                    }

                    // change the labels to tighten the slacks
                    // {
                    for (int i = 0; i < labelx.Length; i++)
                    {
                        if (visitx[i] == true)
                        {
                            labelx[i] -= delta;
                        }
                    }

                    for (int i = 0; i < labely.Length; i++)
                    {
                        if (visity[i] == true)
                        {
                            labely[i] += delta;
                        }
                        else
                        {
                            slack[i] -= delta;
                        }
                    }
                    // }

                    visity[iminslack] = true;

                    // for matched minimal slack, expand tree
                    if (matchy[iminslack] != -1)
                    {
                        int match = matchy[iminslack];
                        visitx[match] = true;

                        for (int i = 0; i < labely.Length; i++)
                        {
                            if (!visity[i])
                            {
                                double mdelta = labelx[match] + labely[i] - matrix[match, i];
                                if (mdelta < slack[i])
                                {
                                    slack [i] = mdelta;
                                    parent[i] = match;
                                }
                            }
                        }
                    }
                    // for unmatched minimal slack, the tree has an augmenting branch,
                    // follow it and invert every edge
                    else
                    {
                        found = true;
                    }
                }

                // invert augmenting branch
                // {
                int px, py, ty;
                for (py = iminslack, px = parent[py]; px != root; py = ty, px = parent[py])
                {
                    ty         = matchx[px];
                    matchx[px] = py;
                    matchy[py] = px;
                }

                matchx[px] = py;
                matchy[py] = px;
                // }
            }

            return(matchx);
        }