private static Domain CalculateDomain(IVariable[] arguments)
        {
            if (arguments.All(a => a.IsBinary()))
            {
                return Domain.BinaryInteger;
            }

            if (IsDividingByConstant(arguments))
            {
                if (arguments.All(a => a.IsInteger()))
                {

                    if (arguments.All(a => a.IsPositiveOrZero() || a.IsBinary()))
                    {
                        return Domain.PositiveOrZeroInteger;
                    }
                    return Domain.AnyInteger;
                }
                else
                {
                    if (arguments.All(a => a.IsPositiveOrZero() || a.IsBinary()))
                    {
                        return Domain.PositiveOrZeroReal;
                    }
                    return Domain.AnyReal;
                }
            }

            if (arguments.All(a => a.IsPositiveOrZero() || a.IsBinary()))
            {
                return Domain.PositiveOrZeroInteger;
            }
            return Domain.AnyInteger;
        }
        private static Domain CalculateDomain(IVariable[] arguments)
        {
            Domain domain;
            if (MultiplyBinaryVariables(arguments))
            {
                domain = Domain.BinaryInteger;
            }
            else if (arguments.All(a => a.IsPositiveOrZero() || a.IsBinary()))
            {
                domain = arguments.Any(a => a.IsReal()) ? Domain.PositiveOrZeroReal : Domain.PositiveOrZeroInteger;
            }
            else
            {
                domain = arguments.Any(a => a.IsReal()) ? Domain.AnyReal : Domain.AnyInteger;
            }

            return arguments.All(a => a.IsConstant()) ? domain.MakeConstant() : domain;
        }
        private static IVariable CalculateForTwoVariables(IMilpManager milpManager, OperationType type, IVariable[] arguments)
        {
            if (arguments.All(a => a.IsConstant()))
            {
                var values = arguments.Select(a => a.ConstantValue.Value);
                var result = type == OperationType.Maximum ? values.Max() : values.Min();
                if (arguments.All(a => a.IsInteger()))
                {
                    return milpManager.FromConstant((int) result);
                }
                else
                {
                    return milpManager.FromConstant(result);
                }
            }
            var first = arguments[0];
            var second = arguments[1];

            IVariable max = milpManager.CreateAnonymous(CalculateDomain(arguments));
            IVariable min = milpManager.CreateAnonymous(CalculateDomain(arguments));

            max.Set(ConstraintType.GreaterOrEqual, first);
            max.Set(ConstraintType.GreaterOrEqual, second);
            min.Set(ConstraintType.LessOrEqual, first);
            min.Set(ConstraintType.LessOrEqual, second);

            max.Operation(OperationType.Subtraction, min)
                .Set(ConstraintType.Equal,
                    first.Operation(OperationType.Subtraction, second).Operation(OperationType.AbsoluteValue));

            max.ConstantValue = arguments.All(a => a.ConstantValue.HasValue)
                ? Math.Max(arguments[0].ConstantValue.Value, arguments[1].ConstantValue.Value)
                : (double?)null;
            min.ConstantValue = arguments.All(a => a.ConstantValue.HasValue)
                ? Math.Min(arguments[0].ConstantValue.Value, arguments[1].ConstantValue.Value)
                : (double?)null;
            max.Expression = $"max({arguments[0].FullExpression()}, {arguments[1].FullExpression()}";
            min.Expression = $"min({arguments[0].FullExpression()}, {arguments[1].FullExpression()}";
            return type == OperationType.Maximum ? max : min;
        }
        private static Domain CalculateDomain(IVariable[] arguments)
        {
            if (arguments.All(a => a.IsPositiveOrZero() || a.IsBinary()))
            {
                if (arguments.Any(a => a.IsReal()))
                {
                    return arguments.Any(a => a.IsNotConstant()) ? Domain.PositiveOrZeroReal : Domain.PositiveOrZeroConstantReal;
                }

                return arguments.Any(a => a.IsNotConstant()) ? Domain.PositiveOrZeroInteger : Domain.PositiveOrZeroConstantInteger;
            }

            if (arguments.Any(a => a.IsReal()))
            {
                return arguments.Any(a => a.IsNotConstant()) ? Domain.AnyReal : Domain.AnyConstantReal;
            }

            return arguments.Any(a => a.IsNotConstant()) ? Domain.AnyInteger : Domain.AnyConstantInteger;
        }
 private static bool MultiplyAnyIntegers(IVariable[] arguments)
 {
     return arguments.All(a => a.IsInteger());
 }
 private static bool MultiplyOnlyConstants(IVariable[] arguments)
 {
     return arguments.All(a => a.IsConstant());
 }
 private static bool MultiplyBinaryVariables(IVariable[] arguments)
 {
     return arguments.All(a => a.IsBinary());
 }