示例#1
0
 public MosekSolver(System.Collections.Generic.IEqualityComparer <object> EqCompare) : base(EqCompare)
 {
     env = new mosek.Env();
     env.set_Stream(mosek.streamtype.log, null);
     env.set_Stream(mosek.streamtype.msg, null);
     env.set_Stream(mosek.streamtype.err, null);
     env.init();
     msgStream = new MosekMsg();
 }
示例#2
0
            public static void Main(string[] args)
            {
                string filename = "../data/25fv47.mps";
                string slvr     = "intpnt";

                if (args.Length < 2)
                {
                    Console.WriteLine("Usage: callback ( psim | dsim | intpnt ) filename");
                }

                if (args.Length >= 1)
                {
                    slvr = args[0];
                }
                if (args.Length >= 2)
                {
                    filename = args[1];
                }

                using (Env env = new mosek.Env())
                {
                    using (Task task = new Task(env, 0, 0))
                    {
                        task.readdata(filename);
                        task.set_Stream(streamtype.log, new myStream());

                        if (slvr == "psim")
                        {
                            task.putintparam(iparam.optimizer, optimizertype.primal_simplex);
                        }
                        else if (slvr == "dsim")
                        {
                            task.putintparam(iparam.optimizer, optimizertype.dual_simplex);
                        }
                        else if (slvr == "intpnt")
                        {
                            task.putintparam(iparam.optimizer, optimizertype.intpnt);
                        }

                        // Turn all MOSEK logging off (note that errors and other messages
                        // are still sent through the log stream)
                        task.putintparam(iparam.log, 0);

                        task.set_Progress(new myCallback(3600));

                        task.optimize();

                        task.solutionsummary(streamtype.msg);
                    }
                }
            }
示例#3
0
        public static void Main(string[] args)
        {
            string filename = "../data/25fv47.mps";
            string slvr     = "intpnt";

            if (args.Length < 2)
            {
                Console.WriteLine("Usage: callback ( psim | dsim | intpnt ) filename");
            }

            if (args.Length >= 1)
            {
                slvr = args[0];
            }
            if (args.Length >= 2)
            {
                filename = args[1];
            }

            using (Env env = new mosek.Env())
            {
                using (Task task = new Task(env, 0, 0))
                {
                    task.readdata(filename);

                    if (slvr == "psim")
                    {
                        task.putintparam(iparam.optimizer, optimizertype.primal_simplex);
                    }
                    else if (slvr == "dsim")
                    {
                        task.putintparam(iparam.optimizer, optimizertype.dual_simplex);
                    }
                    else if (slvr == "intpnt")
                    {
                        task.putintparam(iparam.optimizer, optimizertype.intpnt);
                    }

                    double maxtime = 0.06;
                    task.set_InfoCallback(new myCallback(maxtime));
                    task.optimize();

                    task.solutionsummary(streamtype.msg);
                }
            }
        }
示例#4
0
            public static void Main(string[] args)
            {
                if (args.Length < 3)
                {
                    Console.WriteLine("Too few input arguments. Syntax:");
                    Console.WriteLine("\tcallback.py psim inputfile");
                    Console.WriteLine("\tcallback.py dsim inputfile");
                    Console.WriteLine("\tcallback.py intpnt inputfile");
                }
                else
                {
                    using (Env env = new mosek.Env())
                    {
                        using (Task task = new Task(env, 0, 0))
                        {
                            string filename = args[2];
                            task.readdata(filename);
                            task.set_Stream(streamtype.log, new myStream());

                            if (args[1] == "psim")
                            {
                                task.putintparam(iparam.optimizer, optimizertype.primal_simplex);
                            }
                            else if (args[1] == "dsim")
                            {
                                task.putintparam(iparam.optimizer, optimizertype.dual_simplex);
                            }
                            else if (args[1] == "intpnt")
                            {
                                task.putintparam(iparam.optimizer, optimizertype.intpnt);
                            }

                            // Turn all MOSEK logging off (note that errors and other messages
                            // are still sent through the log stream)
                            task.putintparam(iparam.log, 0);

                            task.ProgressCB = new myCallback(3600);

                            task.optimize();

                            task.solutionsummary(streamtype.msg);
                        }
                    }
                }
            }
示例#5
0
        public virtual void Shutdown()
        {
            /* stop optimize */

            if (progressCB != null)
            {
                progressCB.Abort();
            }

            disposed = true;

            /* This method could be called while we are solving.
             * We must wait until solve has exited and deleted it's resources. */
            lock (classLock)
            {
                if (env != null)
                {
                    env.Dispose();
                    env = null;
                }
            }
        }
示例#6
0
        public PositionTable <double> Optimize(Story story, PositionTable <double> position)
        {
            int           count = -1;
            List <double> X     = new List <double>();

            int[,] index = new int[story.Characters.Count, story.FrameCount];
            for (int i = 0; i < story.Characters.Count; ++i)
            {
                for (int frame = 0; frame < story.FrameCount; ++frame)
                {
                    index[i, frame] = -2;
                }
            }
            for (int i = 0; i < story.Characters.Count; ++i)
            {
                for (int frame = 0; frame < story.FrameCount; ++frame)
                {
                    if (story.SessionTable[i, frame] != -1)
                    {
                        if (frame > 0 && story.SessionTable[i, frame - 1] != -1 && Math.Abs(position[i, frame] - position[i, frame - 1]) < 1e-5)
                        {
                            index[i, frame] = count;
                        }
                        else
                        {
                            index[i, frame] = ++count;
                            X.Add(position[i, frame]);
                        }
                    }
                }
            }

            Dictionary <Tuple <int, int>, double> Q = new Dictionary <Tuple <int, int>, double>();

            for (int i = 0; i < X.Count; ++i)
            {
                Q.Add(new Tuple <int, int>(i, i), 2);
            }



            List <int>    li = new List <int>();
            List <int>    lj = new List <int>();
            List <double> lv = new List <double>();

            foreach (KeyValuePair <Tuple <int, int>, double> pair in Q)
            {
                if (pair.Key.Item1 >= pair.Key.Item2 && pair.Value != 0)
                {
                    li.Add(pair.Key.Item1);
                    lj.Add(pair.Key.Item2);
                    lv.Add((double)pair.Value);
                }
            }

            int[]    qsubi = li.ToArray();
            int[]    qsubj = lj.ToArray();
            double[] qval  = lv.ToArray();


            List <Tuple <int, int> > listInner = new List <Tuple <int, int> >();
            List <Tuple <int, int> > listOuter = new List <Tuple <int, int> >();

            for (int frame = 0; frame < story.FrameCount; ++frame)
            {
                List <Tuple <int, double> > l = new List <Tuple <int, double> >();
                for (int i = 0; i < story.Characters.Count; ++i)
                {
                    if (story.SessionTable[i, frame] != -1)
                    {
                        l.Add(new Tuple <int, double>(i, position[i, frame]));
                    }
                }
                l.Sort((a, b) => a.Item2.CompareTo(b.Item2));
                for (int k = 0; k < l.Count - 1; ++k)
                {
                    int x = l[k].Item1;
                    int y = l[k + 1].Item1;
                    if (story.SessionTable[x, frame] == story.SessionTable[y, frame])
                    {
                        if (!listInner.Contains(new Tuple <int, int>(index[x, frame], index[y, frame])))
                        {
                            listInner.Add(new Tuple <int, int>(index[x, frame], index[y, frame]));
                        }
                    }
                    else
                    {
                        if (!listOuter.Contains(new Tuple <int, int>(index[x, frame], index[y, frame])))
                        {
                            listOuter.Add(new Tuple <int, int>(index[x, frame], index[y, frame]));
                        }
                    }
                }
            }

            const double infinity      = 0;
            int          NumConstraint = listInner.Count + listOuter.Count;
            int          NumVariable   = X.Count;


            double[]         blx = new double[NumVariable];
            double[]         bux = new double[NumVariable];
            mosek.boundkey[] bkx = new mosek.boundkey[NumVariable];

            for (int i = 0; i < NumVariable; ++i)
            {
                bkx[i] = mosek.boundkey.ra;
                blx[i] = -double.MaxValue;
                bux[i] = double.MaxValue;
            }
            bkx[0] = mosek.boundkey.fx;
            bkx[0] = 0;
            bkx[0] = 0;


            int[][]    asub = new int[NumVariable][];
            double[][] aval = new double[NumVariable][];


            List <int>[]    asubList = new List <int> [NumVariable];
            List <double>[] avalList = new List <double> [NumVariable];
            for (int i = 0; i < NumVariable; ++i)
            {
                asubList[i] = new List <int>();
                avalList[i] = new List <double>();
            }
            for (int i = 0; i < listInner.Count; ++i)
            {
                Tuple <int, int> pair = listInner[i];
                int x = pair.Item1;
                int y = pair.Item2;

                asubList[x].Add(i);
                avalList[x].Add(-1);

                asubList[y].Add(i);
                avalList[y].Add(1);
            }
            for (int i = 0; i < listOuter.Count; ++i)
            {
                int j = i + listInner.Count;
                Tuple <int, int> pair = listOuter[i];
                int x = pair.Item1;
                int y = pair.Item2;
                asubList[x].Add(j);
                avalList[x].Add(-1);

                asubList[y].Add(j);
                avalList[y].Add(1);
            }
            for (int i = 0; i < NumVariable; ++i)
            {
                asub[i] = asubList[i].ToArray();
                aval[i] = avalList[i].ToArray();
            }
            mosek.boundkey[] bkc = new mosek.boundkey[NumConstraint];
            double[]         blc = new double[NumConstraint];
            double[]         buc = new double[NumConstraint];
            for (int i = 0; i < listInner.Count; ++i)
            {
                bkc[i] = mosek.boundkey.fx;
                blc[i] = 0;
                buc[i] = 0;
            }
            for (int i = listInner.Count; i < listInner.Count + listOuter.Count; ++i)
            {
                bkc[i] = mosek.boundkey.lo;
                //blc[i] = 84;
                blc[i] = _app.Status.Config.Style.OuterGap;
                buc[i] = 1000;
            }

            mosek.Task task = null;
            mosek.Env  env  = null;
            double[]   xx   = new double[NumVariable];
            try
            {
                env = new mosek.Env();
                env.set_Stream(mosek.streamtype.log, new msgclass(""));
                env.init();

                task = new mosek.Task(env, 0, 0);
                task.set_Stream(mosek.streamtype.log, new msgclass(""));
                task.putmaxnumvar(NumVariable);
                task.putmaxnumcon(NumConstraint);


                task.append(mosek.accmode.con, NumConstraint);
                task.append(mosek.accmode.var, NumVariable);

                task.putcfix(0.0);

                for (int j = 0; j < NumVariable; ++j)
                {
                    task.putcj(j, -2 * X[j]);
                    task.putbound(mosek.accmode.var, j, bkx[j], blx[j], bux[j]);

                    task.putavec(mosek.accmode.var, j, asub[j], aval[j]);
                }

                for (int i = 0; i < NumConstraint; ++i)
                {
                    task.putbound(mosek.accmode.con, i, bkc[i], blc[i], buc[i]);
                }

                task.putobjsense(mosek.objsense.minimize);
                task.putqobj(qsubi, qsubj, qval);

                task.optimize();
                task.solutionsummary(mosek.streamtype.msg);

                mosek.solsta solsta;
                mosek.prosta prosta;

                task.getsolutionstatus(mosek.soltype.itr,
                                       out prosta,
                                       out solsta);
                task.getsolutionslice(mosek.soltype.itr,
                                      mosek.solitem.xx,
                                      0,
                                      NumVariable,
                                      xx);

                switch (solsta)
                {
                case mosek.solsta.optimal:
                case mosek.solsta.near_optimal:
                    Console.WriteLine("Optimal primal solution\n");
                    //for (int j = 0; j < NumVariable; ++j)
                    //    Console.WriteLine("x[{0}]:", xx[j]);
                    break;

                case mosek.solsta.dual_infeas_cer:
                case mosek.solsta.prim_infeas_cer:
                case mosek.solsta.near_dual_infeas_cer:
                case mosek.solsta.near_prim_infeas_cer:
                    Console.WriteLine("Primal or dual infeasibility.\n");
                    break;

                case mosek.solsta.unknown:
                    Console.WriteLine("Unknown solution status.\n");
                    break;

                default:
                    Console.WriteLine("Other solution status");
                    break;
                }
            }
            catch (mosek.Exception e)
            {
                Console.WriteLine(e.Code);
                Console.WriteLine(e);
            }
            finally
            {
                if (task != null)
                {
                    task.Dispose();
                }
                if (env != null)
                {
                    env.Dispose();
                }
            }

            PositionTable <double> result = new PositionTable <double>(story.Characters.Count, story.FrameCount);

            for (int i = 0; i < story.Characters.Count; ++i)
            {
                for (int frame = 0; frame < story.FrameCount; ++frame)
                {
                    if (story.SessionTable[i, frame] != -1)
                    {
                        result[i, frame] = xx[index[i, frame]];
                    }
                }
            }

            return(result);
        }
示例#7
0
        public PersistentOptimizer(StorylineApp app, Story story, PositionTable <int> perm, PositionTable <int> segment, double innerDist, double outerDist)
        {
            // restore data structures
            this._app    = app;
            this.story   = story;
            this.perm    = perm;
            this.segment = segment;

            // initialize
            // index for Q at character i, timeframe j
            index = new int[story.Characters.Count, story.FrameCount];
            for (int i = 0; i < story.Characters.Count; ++i)
            {
                for (int frame = 0; frame < story.FrameCount; ++frame)
                {
                    index[i, frame] = -1; // invalid value
                }
            }
            //
            List <double> X = new List <double>();
            int count       = -1;
            for (int i = 0; i < story.Characters.Count; ++i)
            {
                for (int frame = 0; frame < story.FrameCount; ++frame)
                {
                    if (story.SessionTable[i, frame] != -1)
                    {
                        if (frame > 0 && story.SessionTable[i, frame - 1] != -1 && segment[i, frame] == segment[i, frame - 1])
                        {
                            index[i, frame] = count;
                        }
                        else
                        {
                            index[i, frame] = ++count;
                            X.Add(perm[i, frame]); // assign perm to X
                        }
                    }
                }
            }
            int NumVariable = X.Count;
            xCount = X.Count;

            // calculate sparse objective matrix Q
            #region Matrix
            Dictionary <Tuple <int, int>, double> matrix = new Dictionary <Tuple <int, int>, double>();
            for (int i = 0; i < X.Count; ++i)
            {
                matrix.Add(new Tuple <int, int>(i, i), 0.1);//simon, ctk
            }
            for (int i = 0; i < story.Characters.Count; ++i)
            {
                for (int frame = 0; frame < story.FrameCount - 1; ++frame)
                {
                    int left         = frame;
                    int right        = frame + 1;
                    var leftSession  = story.SessionTable[i, left];
                    var rightSession = story.SessionTable[i, right];

                    var needBreak = false;
                    foreach (var sessionBreak in _app.Status.Config.SessionBreaks)
                    {
                        if (sessionBreak.session1 == leftSession && sessionBreak.session2 == rightSession &&
                            sessionBreak.frame == left)
                        {
                            needBreak = true;
                            break;
                        }
                    }

                    if (leftSession != -1 && rightSession != -1 && segment[i, left] != segment[i, right] && !needBreak)
                    {
                        Tuple <int, int> ll = new Tuple <int, int>(index[i, left], index[i, left]);
                        Tuple <int, int> lr = new Tuple <int, int>(index[i, left], index[i, right]);
                        Tuple <int, int> rl = new Tuple <int, int>(index[i, right], index[i, left]);
                        Tuple <int, int> rr = new Tuple <int, int>(index[i, right], index[i, right]);
                        if (!matrix.ContainsKey(ll))
                        {
                            matrix.Add(ll, 0);
                        }
                        if (!matrix.ContainsKey(lr))
                        {
                            matrix.Add(lr, 0);
                        }
                        if (!matrix.ContainsKey(rl))
                        {
                            matrix.Add(rl, 0);
                        }
                        if (!matrix.ContainsKey(rr))
                        {
                            matrix.Add(rr, 0);
                        }
                        matrix[ll] += 2;
                        matrix[rr] += 2;
                        matrix[lr] -= 2;
                        matrix[rl] -= 2;
                    }
                }
            }

            // sparse representation to matrix Q
            List <int> li    = new List <int>();
            List <int> lj    = new List <int>();
            List <double> lv = new List <double>();
            foreach (KeyValuePair <Tuple <int, int>, double> pair in matrix)
            {
                if (pair.Key.Item1 >= pair.Key.Item2 && Math.Abs(pair.Value) > 0.000001)
                {
                    li.Add(pair.Key.Item1);
                    lj.Add(pair.Key.Item2);
                    lv.Add(pair.Value);
                }
            }
            // input must be array instead of list
            int[] qsubi   = li.ToArray();
            int[] qsubj   = lj.ToArray();
            double[] qval = lv.ToArray();
            #endregion

            // calculate inner and outer constraints
            #region Constraints
            // constraint { <index of k, index of k+1>: bundle}
            Dictionary <Tuple <int, int>, int> constraints = new Dictionary <Tuple <int, int>, int>();

            List <int>[] asubList    = new List <int> [NumVariable];
            List <double>[] avalList = new List <double> [NumVariable];
            for (int i = 0; i < NumVariable; ++i)
            {
                asubList[i] = new List <int>();
                avalList[i] = new List <double>();
            }

            List <mosek.boundkey> bkcList = new List <boundkey>();
            List <double> blcList         = new List <double>();
            List <double> bucList         = new List <double>();

            var sessionInnerGaps = _app.Status.Config.sessionInnerGaps;
            var sessionOuterGaps = _app.Status.Config.sessionOuterGaps;
            // for each time frame
            int constraintCounter = 0;
            for (int frame = 0; frame < story.FrameCount; ++frame)
            {
                // charaters at timeframe
                List <Tuple <int, int> > l = new List <Tuple <int, int> >();
                for (int i = 0; i < story.Characters.Count; ++i)
                {
                    if (story.SessionTable[i, frame] != -1)
                    {
                        l.Add(new Tuple <int, int>(i, perm[i, frame]));
                    }
                }
                // get character order in current frame
                // apply result in location tree sort
                l.Sort((a, b) => a.Item2.CompareTo(b.Item2));

                for (int k = 0; k < l.Count - 1; ++k)
                {
                    int x = l[k].Item1;
                    int y = l[k + 1].Item1;
                    // inner constraints
                    // x is upper character
                    var indexX = index[x, frame];
                    // y is lower character
                    var indexY   = index[y, frame];
                    var sessionX = story.SessionTable[x, frame];
                    var sessionY = story.SessionTable[y, frame];
                    if (sessionX == sessionY)
                    {
                        // lower character index and higher character index
                        Tuple <int, int> tuple = new Tuple <int, int>(indexX, indexY);
                        if (constraints.ContainsKey(tuple))
                        {
                            var i = constraints[tuple];
                            Debug.Assert(i >= 0);
                            // change default gaps with respect to sessionInnerGaps
                            buildInnerGapConstraints(sessionInnerGaps, sessionX, blcList, i, bucList);
                        }
                        else
                        {
                            int i = constraintCounter++;
                            // type ra for range, fx for fixed
                            bkcList.Add(mosek.boundkey.ra);
                            // add contraint of innergap +- 2
                            // lower
                            blcList.Add(Math.Max(innerDist - 2, 2));
                            // upper
                            bucList.Add(innerDist + 2);
                            buildInnerGapConstraints(sessionInnerGaps, sessionX, blcList, i, bucList);

                            // Row index of non - zeros in column i
                            // sparse array for i-th constraint
                            asubList[indexX].Add(i);
                            // Non - zero Values of column i.
                            avalList[indexX].Add(-1);
                            asubList[indexY].Add(i);
                            avalList[indexY].Add(1);
                            // positive for inner gap
                            // store the index for further modification
                            // assigned in sessionInnerGaps
                            constraints.Add(tuple, i);
                        }
                    }
                    else
                    {
                        Tuple <int, int> tuple = new Tuple <int, int>(indexX, indexY);
                        if (constraints.ContainsKey(tuple))
                        {
                            var j = constraints[tuple];
                            Debug.Assert(j <= 0);
                            j *= -1;
                            // change default gaps with respect to sessionOuterGaps
                            buildOuterGapConstraints(sessionOuterGaps, sessionX, sessionY, blcList, j, bucList, bkcList);
                        }
                        else
                        {
                            int j = constraintCounter++;
                            // default setting
                            bkcList.Add(mosek.boundkey.lo);
                            blcList.Add(outerDist);
                            bucList.Add(1000);
                            buildOuterGapConstraints(sessionOuterGaps, sessionX, sessionY, blcList, j, bucList, bkcList);
                            asubList[indexX].Add(j);
                            avalList[indexX].Add(-1);
                            asubList[indexY].Add(j);
                            avalList[indexY].Add(1);
                            // negative for outer gap
                            // store the index for further modification
                            // assigned in sessionInnerGaps
                            constraints.Add(tuple, -j);
                        }
                    }
                }
            }

            foreach (KeyValuePair <Tuple <int, int>, int> pair in constraints)
            {
                if (pair.Value >= 0)
                {
                    innerList.Add(pair.Key);
                }
                else
                {
                    outerList.Add(pair.Key);
                }
            }
            int NumConstraint = innerList.Count + outerList.Count;

            // to array
            int[][] asub    = new int[NumVariable][];
            double[][] aval = new double[NumVariable][];

            for (int i = 0; i < NumVariable; ++i)
            {
                asub[i] = asubList[i].ToArray();
                aval[i] = avalList[i].ToArray();
            }

            mosek.boundkey[] bkc = bkcList.ToArray();
            double[] blc         = blcList.ToArray();
            double[] buc         = bucList.ToArray();
            Debug.Assert(constraintCounter == NumConstraint);
            #endregion

            // calculate variable bound
            double[] blx         = new double[NumVariable];
            double[] bux         = new double[NumVariable];
            mosek.boundkey[] bkx = new mosek.boundkey[NumVariable];
            for (int i = 0; i < NumVariable; ++i)
            {
                bkx[i] = mosek.boundkey.ra;
                blx[i] = -12000;
                bux[i] = 12000;
            }

            // addCharacterYConstraints in a +- 10 range
            foreach (var yConstraint in _app.Status.Config.CharacterYConstraints)
            {
                if (yConstraint.frame < 0 || yConstraint.frame > story.FrameCount)
                {
                    continue;
                }
                var i = index[yConstraint.characterId, yConstraint.frame];
                if (i != -1)
                {
                    blx[i] = yConstraint.lowerY;
                    bux[i] = yConstraint.upperY;
                }
            }

            // setup mosek
            #region Mosek
            try
            {
                env = new mosek.Env();
                env.init();

                task = new mosek.Task(env, 0, 0);
                task.putmaxnumvar(NumVariable);
                task.putmaxnumcon(NumConstraint);

                task.append(mosek.accmode.con, NumConstraint);
                task.append(mosek.accmode.var, NumVariable);

                task.putcfix(0.0);

                for (int j = 0; j < NumVariable; ++j)
                {
                    task.putcj(j, 0);
                    task.putbound(mosek.accmode.var, j, bkx[j], blx[j], bux[j]);
                    task.putavec(mosek.accmode.var, j, asub[j], aval[j]);
                }

                for (int i = 0; i < NumConstraint; ++i)
                {
                    task.putbound(mosek.accmode.con, i, bkc[i], blc[i], buc[i]);
                }

                task.putobjsense(mosek.objsense.minimize);
                task.putqobj(qsubi, qsubj, qval);
            }
            catch (mosek.Exception e)
            {
                Console.WriteLine(e.Code);
                Console.WriteLine(e);
            }
            #endregion
        }
示例#8
0
        public LODOptimizer(StorylineApp app, List <Node>[] _nodePool)
        {
            _app     = app;
            nodePool = _nodePool;
            count    = 0;
            for (int frame = 0; frame < nodePool.Count(); frame++)
            {
                foreach (Node node in nodePool[frame])
                {
                    if (frame > 0 && node.alignPrev != null)
                    {
                        index.Add(node, index[node.alignPrev]);
                    }
                    else
                    {
                        index.Add(node, count++);
                    }
                }
            }
            int NumVariable = index.Count;

            #region Matrix
            var matrix = new Dictionary <Tuple <int, int>, double>();
            for (int i = 0; i < index.Count; ++i)
            {
                matrix.Add(new Tuple <int, int>(i, i), 0.01);//simon
            }
            for (int frame = 0; frame < nodePool.Count() - 1; frame++)
            {
                foreach (Node left in nodePool[frame])
                {
                    foreach (Node right in nodePool[frame + 1])
                    {
                        if (left.alignNext != right)//这样才有可能算进(yi-yj)^2里
                        {
                            int weight          = left.segments.Intersect(right.segments).Count();
                            Tuple <int, int> ll = new Tuple <int, int>(index[left], index[left]);
                            Tuple <int, int> lr = new Tuple <int, int>(index[left], index[right]);
                            Tuple <int, int> rl = new Tuple <int, int>(index[right], index[left]);
                            Tuple <int, int> rr = new Tuple <int, int>(index[right], index[right]);
                            if (!matrix.ContainsKey(ll))
                            {
                                matrix.Add(ll, 0);
                            }
                            if (!matrix.ContainsKey(lr))
                            {
                                matrix.Add(lr, 0);
                            }
                            if (!matrix.ContainsKey(rl))
                            {
                                matrix.Add(rl, 0);
                            }
                            if (!matrix.ContainsKey(rr))
                            {
                                matrix.Add(rr, 0);
                            }
                            matrix[ll] += weight;
                            matrix[rr] += weight;
                            matrix[lr] -= weight;
                            matrix[rl] -= weight;
                        }
                    }
                }
            }
            List <int>    li = new List <int>();
            List <int>    lj = new List <int>();
            List <double> lv = new List <double>();
            foreach (KeyValuePair <Tuple <int, int>, double> pair in matrix)
            {
                if (pair.Key.Item1 >= pair.Key.Item2 && pair.Value != 0)
                {
                    li.Add(pair.Key.Item1);
                    lj.Add(pair.Key.Item2);
                    lv.Add(pair.Value);
                }
            }
            int[]    qsubi = li.ToArray();
            int[]    qsubj = lj.ToArray();
            double[] qval  = lv.ToArray();
            #endregion

            #region Constraints
            for (int frame = 0; frame < nodePool.Count(); frame++)
            {
                for (int i = 0; i < nodePool[frame].Count - 1; i++)
                {
                    var nodeUp   = nodePool[frame][i];
                    var nodeDown = nodePool[frame][i + 1];
                    if (nodeUp.type == NodeType.Segment && nodeDown.type == NodeType.Segment &&
                        nodeUp.parent == nodeDown.parent)
                    {
                        inner.Add(new Tuple <int, int>(index[nodeUp], index[nodeDown]));
                    }
                    else
                    {
                        outer.Add(new Tuple <int, int>(index[nodeUp], index[nodeDown]));
                    }
                }
            }
            int             NumConstraint = inner.Count + outer.Count;
            int[][]         asub          = new int[NumVariable][];
            double[][]      aval          = new double[NumVariable][];
            List <int>[]    asubList      = new List <int> [NumVariable];
            List <double>[] avalList      = new List <double> [NumVariable];
            for (int i = 0; i < NumVariable; ++i)
            {
                asubList[i] = new List <int>();
                avalList[i] = new List <double>();
            }
            for (int i = 0; i < inner.Count; i++)
            {
                Tuple <int, int> pair = inner[i];
                int x = pair.Item1;
                int y = pair.Item2;
                asubList[x].Add(i);
                avalList[x].Add(-1);
                asubList[y].Add(i);
                avalList[y].Add(1);
            }
            for (int i = 0; i < outer.Count; i++)
            {
                int j = i + inner.Count;
                Tuple <int, int> pair = outer[i];
                int x = pair.Item1;
                int y = pair.Item2;
                asubList[x].Add(j);
                avalList[x].Add(-1);
                asubList[y].Add(j);
                avalList[y].Add(1);
            }
            for (int i = 0; i < NumVariable; ++i)
            {
                asub[i] = asubList[i].ToArray();
                aval[i] = avalList[i].ToArray();
            }
            mosek.boundkey[] bkc = new mosek.boundkey[NumConstraint];
            double[]         blc = new double[NumConstraint];
            double[]         buc = new double[NumConstraint];
            for (int i = 0; i < inner.Count; ++i)
            {
                bkc[i] = mosek.boundkey.fx;
                blc[i] = _app.Status.Config.Style.DefaultInnerGap;
                buc[i] = _app.Status.Config.Style.DefaultInnerGap;
            }
            for (int i = inner.Count; i < inner.Count + outer.Count; ++i)
            {
                bkc[i] = mosek.boundkey.lo;
                blc[i] = _app.Status.Config.Style.OuterGap;
                buc[i] = 1000;
            }
            double[]         blx = new double[NumVariable];
            double[]         bux = new double[NumVariable];
            mosek.boundkey[] bkx = new mosek.boundkey[NumVariable];
            for (int i = 0; i < NumVariable; ++i)
            {
                bkx[i] = mosek.boundkey.ra;
                blx[i] = -12000;
                bux[i] = 12000;
            }
            #endregion

            #region Mosek
            try
            {
                env = new mosek.Env();
                env.init();

                task = new mosek.Task(env, 0, 0);
                task.putmaxnumvar(NumVariable);
                task.putmaxnumcon(NumConstraint);

                task.append(mosek.accmode.con, NumConstraint);
                task.append(mosek.accmode.var, NumVariable);

                task.putcfix(0.0);

                for (int j = 0; j < NumVariable; ++j)
                {
                    task.putcj(j, 0);
                    task.putbound(mosek.accmode.var, j, bkx[j], blx[j], bux[j]);

                    task.putavec(mosek.accmode.var, j, asub[j], aval[j]);
                }

                for (int i = 0; i < NumConstraint; ++i)
                {
                    task.putbound(mosek.accmode.con, i, bkc[i], blc[i], buc[i]);
                }

                task.putobjsense(mosek.objsense.minimize);
                task.putqobj(qsubi, qsubj, qval);
            }
            catch (mosek.Exception e)
            {
                Console.WriteLine(e.Code);
                Console.WriteLine(e);
            }
            #endregion
        }