Beispiel #1
0
    [Test] public void DirectSimplex()
    {
        var x1 = Variable.Input("X1");
        var x2 = Variable.Input("X2");
        var x3 = Variable.Input("X3");
        var s1 = Variable.Slack("S1");
        var s2 = Variable.Slack("S2");
        var s3 = Variable.Slack("S3");

        var c1 = Constraint.LessThanOrEqualTo("C1", 8, x1.As(2), x2.As(3));
        var c2 = Constraint.LessThanOrEqualTo("C2", 10, x2.As(2), x3.As(5));
        var c3 = Constraint.LessThanOrEqualTo("C3", 15, x1.As(3), x2.As(2), x3.As(4));

        var solverIteration = new SolverIteration
        {
            ObjectiveVariables = new BigRational[] { 3, 5, 4, 0, 0, 0 },
            Variables          = new[] { x1, x2, x3, s1, s2, s3 },
            Bases             = new[] { s1, s2, s3 },
            BaseVariables     = new BigRational[] { 8, 10, 15 },
            DecisionVariables = new BigRational[] { -3, -5, -4, 0, 0, 0 },
            InputGrid         = new[]
            {
                new BigRational[] { 2, 3, 0, 1, 0, 0 },
                new BigRational[] { 0, 2, 5, 0, 1, 0 },
                new BigRational[] { 3, 2, 4, 0, 0, 1 }
            }
        };

        var res = LinearModelSolver.Simplex(solverIteration, new List <Constraint>(new[] { c1, c2, c3 }));

        Assert.IsTrue(res.Result == SolvedResult.Optimized);

        Assert.AreEqual(new BigRational(765, 41), res.Z);
    }
    //Compute SolverIteration from preceding iteration
    private static SolverIteration ComputeIteration(SolverIteration previous)
    {
        SolverIteration iteration = previous.Copy();

        var column = IncomingVariable(iteration.DecisionVariables);

        var row = LeavingVariable(GetColumn(iteration.InputGrid, column),
                                  iteration.BaseVariables);

        var variable = iteration.InputGrid[row][column];
        var rowArray = iteration.InputGrid[row];

        for (int i = 0; i < rowArray.Length; i++)
        {
            rowArray[i] /= variable;
        }

        iteration.BaseVariables[row] /= variable;

        for (int i = 0; i < iteration.InputGrid.Length; i++)
        {
            if (i == row)
            {
                continue;
            }
            var value = iteration.InputGrid[i][column];
            for (int j = 0; j < iteration.InputGrid[i].Length; j++)
            {
                iteration.InputGrid[i][j] -= value * iteration.InputGrid[row][j];
            }
            iteration.BaseVariables[i] -= value * iteration.BaseVariables[row];
        }

        var val = iteration.DecisionVariables[column];

        for (int i = 0; i < iteration.DecisionVariables.Length; i++)
        {
            iteration.DecisionVariables[i] -=
                val * iteration.InputGrid[row][i];
        }

        iteration.Bases[row] = iteration.Variables[column];

        iteration.Z = 0;
        for (var i = 0; i < iteration.Bases.Length; i++)
        {
            var baseVar = iteration.Bases[i];
            iteration.Z += GetVariableObjective(baseVar, iteration) * iteration.BaseVariables[i];
        }

        previous.SelectedGridPositions = (row, column);

        return(iteration);
    }
    //Run simplex algorithm starting from an initial SolverIteration
    public static SolvedModel Simplex(SolverIteration initialIteration, List <Constraint> constraints)
    {
        var             listIterations   = new List <SolverIteration>(new [] { initialIteration });
        SolverIteration currentIteration = initialIteration;

        while (true)
        {
            if (currentIteration.DecisionVariables.All(dv => dv >= 0))
            {
                var model = new SolvedModel
                {
                    SimplexIterations = listIterations,
                    Constraints       = constraints.ToList(),
                    Variables         = currentIteration.Variables.ToList(),
                    Z = currentIteration.Z
                };

                //Initialize dir for all vars
                foreach (var variable in currentIteration.Variables)
                {
                    model.ObjectiveResult[variable] = BigRational.Zero;
                }

                for (int i = 0; i < currentIteration.Bases.Length; i++)
                {
                    model.ObjectiveResult[currentIteration.Bases[i]] = currentIteration.BaseVariables[i];
                }

                model.Result =
                    constraints.All(c => ConstraintPasses(c, model.ObjectiveResult)) ?
                    SolvedResult.Optimized :
                    SolvedResult.Infeasible;

                return(model);
            }

            try
            {
                currentIteration = ComputeIteration(currentIteration);
                listIterations.Add(currentIteration);
            }
            catch (UnboundedException)
            {
                return(new SolvedModel
                {
                    Variables = initialIteration.Variables.ToList(),
                    Constraints = constraints.ToList(),
                    SimplexIterations = listIterations,
                    Result = SolvedResult.Unbounded
                });
            }
        }
    }
    //Get objective value of variable from current iteration
    private static BigRational GetVariableObjective(Variable variable, SolverIteration iteration)
    {
        var columnIndex = Array.IndexOf(iteration.Variables, variable);

        if (columnIndex == -1)
        {
            return(0);
        }
        else
        {
            return(iteration.ObjectiveVariables[columnIndex]);
        }
    }
    //Remove artificial variable indexes after two-phases finishes
    public static SolverIteration RemoveIndexes(SolverIteration iteration, int cutoffIndex)
    {
        var cutIteration = iteration.Copy();

        var variables          = iteration.Variables.Take(cutoffIndex).ToArray();
        var objectiveVariables = iteration.ObjectiveVariables.Take(cutoffIndex)
                                 .ToArray();
        var decisionVariables = iteration.DecisionVariables.Take(cutoffIndex)
                                .ToArray();
        var inputGrid = new List <BigRational[]>();

        for (int i = 0; i < iteration.InputGrid.Length; i++)
        {
            inputGrid.Add(iteration.InputGrid[i].Take(cutoffIndex).ToArray());
        }

        cutIteration.Variables          = variables;
        cutIteration.ObjectiveVariables = objectiveVariables;
        cutIteration.DecisionVariables  = decisionVariables;
        cutIteration.InputGrid          = inputGrid.ToArray();
        return(cutIteration);
    }
Beispiel #6
0
    [Test] public void DirectTwoPhases()
    {
        var x1 = new Variable {
            Name = "X1", Type = VariableType.Input
        };
        var x2 = new Variable {
            Name = "X2", Type = VariableType.Input
        };
        var s1 = new Variable {
            Name = "S1", Type = VariableType.Slack
        };
        var s2 = new Variable {
            Name = "S2", Type = VariableType.Slack
        };
        var a1 = new Variable {
            Name = "A1", Type = VariableType.Artificial
        };
        var a2 = new Variable {
            Name = "A2", Type = VariableType.Artificial
        };
        var c1 = new Constraint
        {
            Name      = "C1", ConstraintType = ConstraintType.GreaterThanOrEqualTo,
            Variables = new List <ValueVariable>(new[]
            {
                new ValueVariable {
                    Variable = x1, Coefficient = 2
                },
                new ValueVariable {
                    Variable = x2, Coefficient = 1
                },
            }),
            ConstraintValue = 4
        };
        var c2 = new Constraint
        {
            Name      = "C2", ConstraintType = ConstraintType.GreaterThanOrEqualTo,
            Variables = new List <ValueVariable>(new[]
            {
                new ValueVariable {
                    Variable = x1, Coefficient = 1
                },
                new ValueVariable {
                    Variable = x2, Coefficient = 7
                },
            }),
            ConstraintValue = 7
        };

        var solverIteration = new SolverIteration
        {
            ObjectiveVariables = new BigRational[] { -1, -1, 0, 0, 0, 0 },
            Variables          = new[] { x1, x2, s1, s2, a1, a2 },
            Bases             = new[] { x1, x2 },
            BaseVariables     = new BigRational[] { 4, 7 },
            DecisionVariables = new BigRational[] { -3, -8, 1, 1, 0, 0 },
            InputGrid         = new[]
            {
                new BigRational[] { 2, 1, -1, 0, 1, 0 },
                new BigRational[] { 1, 7, 0, -1, 0, 1 },
            }
        };

        var res = LinearModelSolver.TwoPhases(solverIteration, new List <Constraint>(new[] { c1, c2 }));

        Assert.AreEqual(new BigRational(-31, 13), res.Z);
    }
    //Run two-phases simplex algorithm starting from an initial SolverIteration
    public static SolvedModel TwoPhases(SolverIteration initialIteration, List <Constraint> constraints)
    {
        var twoPhasesInitialIteration = initialIteration.Copy();
        int artificialCutoff          = -1;

        for (int i = 0; i < initialIteration.Variables.Length; i++)
        {
            if (initialIteration.Variables[i].Type == VariableType.Artificial)
            {
                artificialCutoff = i;
                break;
            }
        }

        if (artificialCutoff == -1)
        {
            throw new ArgumentException();
        }

        var twoPhasesObjective = Enumerable.Repeat <BigRational>(
            BigRational.One, twoPhasesInitialIteration.Variables.Length).ToArray();

        for (int i = 0; i < artificialCutoff; i++)
        {
            twoPhasesObjective[i] = 0;
        }

        twoPhasesInitialIteration.ObjectiveVariables = twoPhasesObjective;

        var twoPhaseBases = twoPhasesInitialIteration
                            .Variables.Skip(
            twoPhasesInitialIteration.Variables.Length - twoPhasesInitialIteration.Bases.Length)
                            .ToArray();

        twoPhasesInitialIteration.Bases = twoPhaseBases;

        for (int i = 0; i < twoPhasesInitialIteration.Variables.Length; i++)
        {
            BigRational Zj = BigRational.Zero;

            for (int j = 0; j < twoPhasesInitialIteration.Bases.Length; j++)
            {
                var rowVariable       = twoPhasesInitialIteration.Bases[j];
                var rowObjectiveIndex = Array.IndexOf(twoPhasesInitialIteration.Variables, rowVariable);
                var rowObjective      = twoPhasesInitialIteration.ObjectiveVariables[rowObjectiveIndex];
                Zj += twoPhasesInitialIteration.InputGrid[j][i] * rowObjective;
            }

            twoPhasesInitialIteration.DecisionVariables[i] = twoPhasesInitialIteration.ObjectiveVariables[i] - Zj;
        }

        twoPhasesInitialIteration.Z = 0;
        for (var i = 0; i < twoPhasesInitialIteration.Bases.Length; i++)
        {
            var baseVar     = twoPhasesInitialIteration.Bases[i];
            var columnIndex = Array.IndexOf(twoPhasesInitialIteration.Variables, baseVar);
            twoPhasesInitialIteration.Z += twoPhasesInitialIteration.BaseVariables[i] * twoPhasesInitialIteration.ObjectiveVariables[columnIndex];
        }

        var solvedTwoPhases = Simplex(twoPhasesInitialIteration, constraints);

        solvedTwoPhases.TwoPhasesIterations = solvedTwoPhases.SimplexIterations;
        solvedTwoPhases.SimplexIterations   = new List <SolverIteration>();

        if (solvedTwoPhases.Result != SolvedResult.Optimized)
        {
            return(solvedTwoPhases);
        }
        if (solvedTwoPhases.Z != 0)
        {
            solvedTwoPhases.Result = SolvedResult.Unbounded;
            return(solvedTwoPhases);
        }
        var finalIteration = solvedTwoPhases.TwoPhasesIterations.Last();

        for (int i = 0; i < finalIteration.Bases.Length; i++)
        {
            if (finalIteration.Bases[i].Type == VariableType.Artificial &&
                finalIteration.BaseVariables[i] > 0)
            {
                solvedTwoPhases.Result = SolvedResult.Infeasible;
                return(solvedTwoPhases);
            }
        }

        finalIteration = RemoveIndexes(
            finalIteration.Copy(), artificialCutoff);

        finalIteration.ObjectiveVariables = initialIteration.ObjectiveVariables.Take(artificialCutoff).ToArray();
        finalIteration.Z = 0;
        for (var i = 0; i < finalIteration.Bases.Length; i++)
        {
            var baseVar     = finalIteration.Bases[i];
            var columnIndex = Array.IndexOf(finalIteration.Variables, baseVar);
            if (columnIndex == -1)
            {
                finalIteration.Z += 0;
            }
            else
            {
                finalIteration.Z += finalIteration.BaseVariables[i] * finalIteration.ObjectiveVariables[columnIndex];
            }
        }

        for (int i = 0; i < finalIteration.Variables.Length; i++)
        {
            var zj = -GetColumn(finalIteration.InputGrid, i).Sum();
            var cj = finalIteration.ObjectiveVariables[i];
            finalIteration.DecisionVariables[i] =
                -GetColumn(finalIteration.InputGrid, i).Sum() - finalIteration.ObjectiveVariables[i];
        }

        var simplexResult = Simplex(finalIteration, constraints);

        simplexResult.TwoPhasesIterations = solvedTwoPhases.TwoPhasesIterations;
        return(simplexResult);
    }
    //Build first SolverIteration from LinearModel
    public static SolverIteration BuildFirstIteration(LinearModel model)
    {
        var variables   = model.Variables.ToList();
        var constraints = model.Constraints.Select(c => c.Copy()).ToList();
        var objectives  = model.ObjectiveFunction
                          .Select(vv => vv.Coefficient).ToList();

        if (model.Objective == Objective.MIN)
        {
            objectives = objectives.Select(o => o * -1).ToList();
        }

        var inputGrid = new List <List <BigRational> >();

        int slackCount      = 0;
        int artificialCount = 0;

        foreach (var constraint in constraints)
        {
            if (constraint.ConstraintValue < 0)
            {
                switch (constraint.ConstraintType)
                {
                case ConstraintType.LessThanOrEqualTo:
                    constraint.ConstraintType = ConstraintType.GreaterThanOrEqualTo;
                    break;

                case ConstraintType.GreaterThanOrEqualTo:
                    constraint.ConstraintType = ConstraintType.LessThanOrEqualTo;
                    break;

                case ConstraintType.EqualTo:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                for (int i = 0; i < constraint.Variables.Count; i++)
                {
                    constraint.Variables[i].Coefficient *= -1;
                }

                constraint.ConstraintValue *= -1;
            }

            switch (constraint.ConstraintType)
            {
            case ConstraintType.LessThanOrEqualTo:
            {
                var slack = new Variable {
                    Name = $"S{++slackCount}", Type = VariableType.Slack
                };
                variables.Add(slack);
                objectives.Add(0);
                constraint.Variables.Add(new ValueVariable {
                        Variable = slack, Coefficient = 1
                    });
                break;
            }

            case ConstraintType.GreaterThanOrEqualTo:
            {
                var slack = new Variable {
                    Name = $"S{++slackCount}", Type = VariableType.Slack
                };
                var artificial = new Variable {
                    Name = $"A{++artificialCount}", Type = VariableType.Artificial
                };
                variables.Add(slack);
                objectives.Add(BigRational.Zero);
                variables.Add(artificial);
                objectives.Add(BigRational.Zero);
                constraint.Variables.Add(new ValueVariable {
                        Variable = slack, Coefficient = -1
                    });
                constraint.Variables.Add(new ValueVariable {
                        Variable = artificial, Coefficient = 1
                    });
                break;
            }

            case ConstraintType.EqualTo:
            {
                var artificial = new Variable {
                    Name = $"A{++artificialCount}", Type = VariableType.Artificial
                };
                variables.Add(artificial);
                objectives.Add(0);
                constraint.Variables.Add(new ValueVariable {
                        Variable = artificial, Coefficient = 1
                    });
                break;
            }

            default:
                throw new ArgumentOutOfRangeException();
            }
        }

        variables.Sort((v1, v2) => v1.Type - v2.Type);

        foreach (var constraint in constraints)
        {
            foreach (var missingVariable in variables.Except(constraint.Variables.Select(vv => vv.Variable)))
            {
                constraint.Variables.Add(missingVariable.As(0));
            }
        }

        foreach (var constraint in constraints)
        {
            constraint.Variables.Sort((vv1, vv2) =>
                                      variables.IndexOf(vv1.Variable) - variables.IndexOf(vv2.Variable));
        }

        inputGrid = constraints
                    .Select(c => c.Variables
                            .Select(v => v.Coefficient).ToList())
                    .ToList();

        var firstIteration = new SolverIteration
        {
            Variables          = variables.ToArray(),
            Z                  = BigRational.Zero,
            ObjectiveVariables = objectives.ToArray(),
            DecisionVariables  = objectives.Select(o => o * -1).ToArray(),
            BaseVariables      = constraints.Select(c => c.ConstraintValue).ToArray(),
            Bases              = variables.Skip(variables.Count - constraints.Count).ToArray(),
            InputGrid          = inputGrid.Select(r => r.ToArray()).ToArray()
        };

        return(firstIteration);
    }
Beispiel #9
0
        private void BuildGrid(SolverIteration iterationBase)
        {
            //Set grid alignment
            Grid.HorizontalAlignment = HorizontalAlignment.Left;
            Grid.VerticalAlignment   = VerticalAlignment.Top;

            //Clear previous grid info
            Grid.Children.Clear();
            Grid.ColumnDefinitions.Clear();
            Grid.RowDefinitions.Clear();

            //Default columns
            var baseColumn = new ColumnDefinition();

            Grid.ColumnDefinitions.Add(baseColumn);
            var objectiveColumn = new ColumnDefinition();

            Grid.ColumnDefinitions.Add(objectiveColumn);

            foreach (var _ in iterationBase.Variables)
            {
                Grid.ColumnDefinitions.Add(new ColumnDefinition());
            }

            var objectiveRow = new RowDefinition();

            Grid.RowDefinitions.Add(objectiveRow);
            var nameRow = new RowDefinition();

            Grid.RowDefinitions.Add(nameRow);
            foreach (var _ in Model.Constraints)
            {
                Grid.RowDefinitions.Add(new RowDefinition());
            }
            var decisionRow = new RowDefinition();

            Grid.RowDefinitions.Add(decisionRow);

            //Size rows and columns
            // var gridWidth = Grid.Width;
            // var cellWidth = gridWidth / Grid.ColumnDefinitions.Count;
            //
            //
            // var gridHeight = Grid.Height;
            // var cellHeight = gridHeight / Grid.RowDefinitions.Count;
            //
            //
            // foreach (var columnDefinition in Grid.ColumnDefinitions)
            // {
            //     columnDefinition.Width = new GridLength(cellWidth);
            // }
            //
            // foreach (var rowDefinition in Grid.RowDefinitions)
            // {
            //     rowDefinition.Height = new GridLength(cellHeight);
            // }

            //Build grid rectangles
            var rects = new List <List <Rectangle> >();

            for (int i = 0; i < Grid.RowDefinitions.Count; i++)
            {
                var rectR = new List <Rectangle>();
                for (int j = 0; j < Grid.ColumnDefinitions.Count; j++)
                {
                    var rect = new Rectangle {
                        Stroke = Brushes.Black, Fill = Brushes.Transparent
                    };
                    rectR.Add(rect);
                    Grid.SetRow(rect, i);
                    Grid.SetColumn(rect, j);
                    Grid.Children.Add(rect);
                }
                rects.Add(rectR);
            }
            Rectangles = rects.Select(r => r.ToArray()).ToArray();

            //Build default grid blocks
            Tableau = new TextBlock
            {
                Text                = "Tableau",
                FontWeight          = FontWeights.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };
            Rectangles[0][0].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(Tableau, 0);
            Grid.SetColumn(Tableau, 0);
            Grid.Children.Add(Tableau);

            var baseBlock = new TextBlock
            {
                Text                = "Base",
                FontWeight          = FontWeights.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            Rectangles[1][0].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(baseBlock, 1);
            Grid.SetColumn(baseBlock, 0);
            Grid.Children.Add(baseBlock);

            var b = new TextBlock
            {
                Text                = "b",
                FontWeight          = FontWeights.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };;

            Rectangles[1][1].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(b, 1);
            Grid.SetColumn(b, 1);
            Grid.Children.Add(b);

            var z = new TextBlock
            {
                Text                = "Z",
                FontWeight          = FontWeights.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            Rectangles[Grid.RowDefinitions.Count - 1][0].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(z, Grid.RowDefinitions.Count - 1);
            Grid.SetColumn(z, 0);
            Grid.Children.Add(z);

            Z = new TextBlock
            {
                Text                = "0",
                FontWeight          = FontWeights.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };;
            Grid.SetRow(Z, Grid.RowDefinitions.Count - 1);
            Grid.SetColumn(Z, 1);
            Grid.Children.Add(Z);

            var objectiveBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.ColumnDefinitions.Count; i++)
            {
                var block = new TextBlock {
                    Text = $"X{i-1}",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                objectiveBlocks.Add(block);
                Grid.SetRow(block, 0);
                Grid.SetColumn(block, i);
                Grid.Children.Add(block);
            }

            ObjectiveRows = objectiveBlocks.ToArray();

            var variableBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.ColumnDefinitions.Count; i++)
            {
                var block = new TextBlock {
                    Text                = $"X{i-1}",
                    FontWeight          = FontWeights.Bold,
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                variableBlocks.Add(block);
                Rectangles[1][i].Fill = Brushes.CadetBlue;
                Grid.SetRow(block, 1);
                Grid.SetColumn(block, i);
                Grid.Children.Add(block);
            }
            Variables = variableBlocks.ToArray();

            var baseBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.RowDefinitions.Count - 1; i++)
            {
                var block = new TextBlock {
                    Text = $"X{i-1}",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                baseBlocks.Add(block);
                Grid.SetRow(block, i);
                Grid.SetColumn(block, 0);
                Grid.Children.Add(block);
            }
            Bases = baseBlocks.ToArray();

            var baseVarBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.RowDefinitions.Count - 1; i++)
            {
                var block = new TextBlock {
                    Text = $"0",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                baseVarBlocks.Add(block);
                Grid.SetRow(block, i);
                Grid.SetColumn(block, 1);
                Grid.Children.Add(block);
            }

            BaseVariables = baseVarBlocks.ToArray();

            var varGrid = new List <List <TextBlock> >();

            for (int i = 2; i < Grid.RowDefinitions.Count - 1; i++)
            {
                var varRow = new List <TextBlock>();
                for (int j = 2; j < Grid.ColumnDefinitions.Count; j++)
                {
                    var block = new TextBlock
                    {
                        Text = $"0",
                        VerticalAlignment   = VerticalAlignment.Center,
                        HorizontalAlignment = HorizontalAlignment.Center
                    };
                    varRow.Add(block);
                    Grid.SetRow(block, i);
                    Grid.SetColumn(block, j);
                    Grid.Children.Add(block);
                }
                varGrid.Add(varRow);
            }

            VariableGrid = varGrid.Select(r => r.ToArray()).ToArray();

            var decisionVars = new List <TextBlock>();

            for (int i = 2; i < Grid.ColumnDefinitions.Count; i++)
            {
                var block = new TextBlock
                {
                    Text = $"0",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                decisionVars.Add(block);
                Grid.SetColumn(block, i);
                Grid.SetRow(block, Grid.RowDefinitions.Count - 1);
                Grid.Children.Add(block);
            }
            DecisionVariables = decisionVars.ToArray();

            //BackButton.Content = Resources["BackArrowEnabled"];
            //https://stackoverflow.com/questions/3789256/wpf-gridlines-changing-style
            //https://www.c-sharpcorner.com/UploadFile/mahesh/grid-in-wpf/#:~:text=The%20ColumnDefinitions%20property%20is%20used,three%20rows%20to%20a%20grid.&text=Any%20control%20in%20WPF%20can,Row%20and%20Grid.
        }
        public void BuildGrid(SolverIteration iterationBase)
        {
            //Set grid alignment
            Grid.HorizontalAlignment = HorizontalAlignment.Left;
            Grid.VerticalAlignment   = VerticalAlignment.Top;

            //Clear previous grid info
            Grid.Children.Clear();
            Grid.ColumnDefinitions.Clear();
            Grid.RowDefinitions.Clear();

            //Default columns
            var baseColumn = new ColumnDefinition();

            Grid.ColumnDefinitions.Add(baseColumn);
            var objectiveColumn = new ColumnDefinition();

            Grid.ColumnDefinitions.Add(objectiveColumn);

            foreach (var _ in iterationBase.Variables)
            {
                Grid.ColumnDefinitions.Add(new ColumnDefinition());
            }

            var objectiveRow = new RowDefinition();

            Grid.RowDefinitions.Add(objectiveRow);
            var nameRow = new RowDefinition();

            Grid.RowDefinitions.Add(nameRow);
            foreach (var _ in Model.Constraints)
            {
                Grid.RowDefinitions.Add(new RowDefinition());
            }
            var decisionRow = new RowDefinition();

            Grid.RowDefinitions.Add(decisionRow);

            //Size rows and columns
            var init = Grid.IsInitialized;

            //var gridWidth = 774d;
            var gridWidth = Grid.Width;
            var cellWidth = gridWidth / Grid.ColumnDefinitions.Count;

            //var gridHeight = 375.04d;
            var gridHeight = Grid.Height;
            var cellHeight = gridHeight / Grid.RowDefinitions.Count;

            foreach (var columnDefinition in Grid.ColumnDefinitions)
            {
                columnDefinition.Width = new GridLength(cellWidth);
            }

            foreach (var rowDefinition in Grid.RowDefinitions)
            {
                rowDefinition.Height = new GridLength(cellHeight);
            }

            //Build grid rectangles
            var rects = new List <List <Rectangle> >();

            for (int i = 0; i < Grid.RowDefinitions.Count; i++)
            {
                var rectR = new List <Rectangle>();
                for (int j = 0; j < Grid.ColumnDefinitions.Count; j++)
                {
                    var rect = new Rectangle {
                        Stroke = Brushes.Black, Fill = Brushes.Transparent,
                    };
                    var border = new Border {
                        BorderBrush = Brushes.Black, BorderThickness = new Thickness(1)
                    };
                    rectR.Add(rect);
                    Grid.SetRow(rect, i);
                    Grid.SetRow(border, i);
                    Grid.SetColumn(rect, j);
                    Grid.SetColumn(border, j);
                    Grid.Children.Add(rect);
                    Grid.Children.Add(border);
                }
                rects.Add(rectR);
            }
            Rectangles = rects.Select(r => r.ToArray()).ToArray();

            //Build default grid blocks
            Tableau = new TextBlock
            {
                Text                = "Tableau",
                FontWeight          = FontWeight.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };
            Rectangles[0][0].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(Tableau, 0);
            Grid.SetColumn(Tableau, 0);
            Grid.Children.Add(Tableau);

            var baseBlock = new TextBlock
            {
                Text                = "Base",
                FontWeight          = FontWeight.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            Rectangles[1][0].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(baseBlock, 1);
            Grid.SetColumn(baseBlock, 0);
            Grid.Children.Add(baseBlock);

            var b = new TextBlock
            {
                Text                = "b",
                FontWeight          = FontWeight.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };;

            Rectangles[1][1].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(b, 1);
            Grid.SetColumn(b, 1);
            Grid.Children.Add(b);

            var z = new TextBlock
            {
                Text                = "Z",
                FontWeight          = FontWeight.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            Rectangles[Grid.RowDefinitions.Count - 1][0].Fill = new SolidColorBrush(Colors.CadetBlue);
            Grid.SetRow(z, Grid.RowDefinitions.Count - 1);
            Grid.SetColumn(z, 0);
            Grid.Children.Add(z);

            Z = new TextBlock
            {
                Text                = "0",
                FontWeight          = FontWeight.Bold,
                VerticalAlignment   = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };
            Grid.SetRow(Z, Grid.RowDefinitions.Count - 1);
            Grid.SetColumn(Z, 1);
            Grid.Children.Add(Z);

            var objectiveBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.ColumnDefinitions.Count; i++)
            {
                var block = new TextBlock {
                    Text = $"X{i-1}",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                objectiveBlocks.Add(block);
                Grid.SetRow(block, 0);
                Grid.SetColumn(block, i);
                Grid.Children.Add(block);
            }

            ObjectiveRows = objectiveBlocks.ToArray();

            var variableBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.ColumnDefinitions.Count; i++)
            {
                var block = new TextBlock {
                    Text                = $"X{i-1}",
                    FontWeight          = FontWeight.Bold,
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                variableBlocks.Add(block);
                Rectangles[1][i].Fill = Brushes.CadetBlue;
                Grid.SetRow(block, 1);
                Grid.SetColumn(block, i);
                Grid.Children.Add(block);
            }
            Variables = variableBlocks.ToArray();

            var baseBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.RowDefinitions.Count - 1; i++)
            {
                var block = new TextBlock {
                    Text = $"X{i-1}",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                baseBlocks.Add(block);
                Grid.SetRow(block, i);
                Grid.SetColumn(block, 0);
                Grid.Children.Add(block);
            }
            Bases = baseBlocks.ToArray();

            var baseVarBlocks = new List <TextBlock>();

            for (int i = 2; i < Grid.RowDefinitions.Count - 1; i++)
            {
                var block = new TextBlock {
                    Text = $"0",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                baseVarBlocks.Add(block);
                Grid.SetRow(block, i);
                Grid.SetColumn(block, 1);
                Grid.Children.Add(block);
            }

            BaseVariables = baseVarBlocks.ToArray();

            var varGrid = new List <List <TextBlock> >();

            for (int i = 2; i < Grid.RowDefinitions.Count - 1; i++)
            {
                var varRow = new List <TextBlock>();
                for (int j = 2; j < Grid.ColumnDefinitions.Count; j++)
                {
                    var block = new TextBlock
                    {
                        Text = $"0",
                        VerticalAlignment   = VerticalAlignment.Center,
                        HorizontalAlignment = HorizontalAlignment.Center
                    };
                    varRow.Add(block);
                    Grid.SetRow(block, i);
                    Grid.SetColumn(block, j);
                    Grid.Children.Add(block);
                }
                varGrid.Add(varRow);
            }

            VariableGrid = varGrid.Select(r => r.ToArray()).ToArray();

            var decisionVars = new List <TextBlock>();

            for (int i = 2; i < Grid.ColumnDefinitions.Count; i++)
            {
                var block = new TextBlock
                {
                    Text = $"0",
                    VerticalAlignment   = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                decisionVars.Add(block);
                Grid.SetColumn(block, i);
                Grid.SetRow(block, Grid.RowDefinitions.Count - 1);
                Grid.Children.Add(block);
            }
            DecisionVariables = decisionVars.ToArray();
        }