예제 #1
0
 // Restore the domains of the variables which where reduced.
 public void UndoPropagation(Propagation propagation)
 {
     foreach (var reduction in propagation.Reductions)
     {
         Model.Variables[reduction.Variable].Domain.Values.Add(reduction.Value);
     }
 }
예제 #2
0
        // Forward propagation of the assigned value, based on the type of constraint.
        public Propagation PropagateAssignment(Variable variable, int value)
        {
            var propagation = new Propagation();

            propagation.IsValid = true;

            // Check each constraint that contains the assigned variable. Can be made
            // considerably faster by precomputing which constraint is used in which
            // variable, and storing this in the variable.
            for (int i = 0; i < Model.Constraints.Length; i++)
            {
                var constraint = Model.Constraints[i];
                if (constraint.ContainsVariable(variable.Id))
                {
                    switch (constraint)
                    {
                    case AllDifferentConstraint:
                        PropagateAllDifferentConstraint(variable, value, constraint, ref propagation);
                        break;

                    case MandatoryConstraint:
                        PropagateMandatoryConstraint(variable, value, constraint, ref propagation);
                        break;

                    case OptionalConstraint:
                        PropagateOptionalConstraint(variable, value, constraint, ref propagation);
                        break;

                    case AlternativeConstraint:
                        PropagateAlternativeConstraint(variable, value, constraint, ref propagation);
                        break;

                    case OrConstraint:
                        PropagateOrConstraint(variable, value, constraint, ref propagation);
                        break;

                    case RequiredConstraint:
                        PropagateRequiredConstraint(variable, value, constraint, ref propagation);
                        break;

                    case ExcludeConstraint:
                        PropagateExcludeConstraint(variable, value, constraint, ref propagation);
                        break;

                    default:
                        Debug.WriteLine($"Constraint of type '{constraint.GetType().Name}' does not support constraint propagation.");
                        break;
                    }

                    if (!propagation.IsValid)
                    {
                        return(propagation);
                    }
                }
            }
            return(propagation);
        }
예제 #3
0
        private void PropagateAllDifferentConstraint(Variable variable, int value, Constraint constraint, ref Propagation propagation)
        {
            // Check all the other variables that are shared in this constraint.
            for (int i = 0; i < constraint.Variables.Length; i++)
            {
                var otherVariable = constraint.Variables[i];

                // If the variable is set, and the domain of the other variable contains the
                // assigned value.
                if (!otherVariable.IsSet && otherVariable.Domain.Values.Contains(value))
                {
                    // Remove the value from the domain of the variable which shares a
                    // constraint with the assigned variable.
                    propagation.Add(otherVariable.Id, value);
                    otherVariable.Domain.Values.Remove(value);

                    // If the domain is reduced to zero, the propagation resulted in
                    // an inconsistent model. Set the flag, and return the reduced domains
                    // so they can be restored.
                    if (otherVariable.Domain.Values.Count == 0)
                    {
                        propagation.IsValid = false;
                        return;
                    }
                }
            }
        }
예제 #4
0
        private void PropagateExcludeConstraint(Variable variable, int value, Constraint constraint, ref Propagation propagation)
        {
            // In this case, if a variable is enabled then we must disable the other variable.
            var parent = constraint.Variables[PARENT];
            var child  = constraint.Variables[CHILD];
            var other  = variable.Id == parent.Id ? child : parent;

            if (!other.IsSet && value == ON && other.Domain.Values.Contains(ON))
            {
                propagation.Add(other.Id, ON);
                other.Domain.Values.Remove(ON);
                propagation.IsValid = other.Domain.Values.Count > 0;
            }
        }
예제 #5
0
        private void PropagateRequiredConstraint(Variable variable, int value, Constraint constraint, ref Propagation propagation)
        {
            // If the parent is enabled then the child must also be enabled.
            var parent = constraint.Variables[PARENT];
            var child  = constraint.Variables[CHILD];

            if (variable.Id == parent.Id && value == ON)
            {
                if (!child.IsSet && child.Domain.Values.Contains(OFF))
                {
                    propagation.Add(child.Id, OFF);
                    child.Domain.Values.Remove(OFF);
                    propagation.IsValid = child.Domain.Values.Count > 0;
                }
            }
        }
예제 #6
0
        private void PropagateOrConstraint(Variable variable, int value, Constraint constraint, ref Propagation propagation)
        {
            // In the case that the parent is enabled, we don't know which child to enable, so let the backtracker handle that.
            // In the case a child is enabled, we can disable the parent.
            var parent = constraint.Variables[PARENT];

            if (variable.Id != parent.Id && value == ON)
            {
                // In the case a child is enabled, we must also enable the parent.
                if (!parent.IsSet && value == ON && parent.Domain.Values.Contains(OFF))
                {
                    propagation.Add(parent.Id, OFF);
                    parent.Domain.Values.Remove(OFF);
                    propagation.IsValid = parent.Domain.Values.Count > 0;
                }
            }
        }
예제 #7
0
        private void PropagateAlternativeConstraint(Variable variable, int value, Constraint constraint, ref Propagation propagation)
        {
            // In the case that the parent is enabled, we don't know which child to enable, so let the backtracker handle that.
            // In the case a child is enabled, we can disable all the other children, because there can only be one enabled.
            var parent = constraint.Variables[PARENT];

            if (variable.Id != parent.Id && value == ON)
            {
                for (int i = 1; i < constraint.Variables.Length; i++)
                {
                    var other = constraint.Variables[i];
                    if (!other.IsSet && other.Id != variable.Id && other.Domain.Values.Contains(1))
                    {
                        propagation.Add(other.Id, ON);
                        other.Domain.Values.Remove(ON);
                        if (other.Domain.Values.Count == 0)
                        {
                            propagation.IsValid = false;
                            return;
                        }
                    }
                }
                // In the case a child is enabled, we must also enable the parent.
                if (!parent.IsSet && value == ON && parent.Domain.Values.Contains(OFF))
                {
                    propagation.Add(parent.Id, OFF);
                    parent.Domain.Values.Remove(OFF);
                    propagation.IsValid = parent.Domain.Values.Count > 0;
                }
            }
        }
예제 #8
0
        private void PropagateOptionalConstraint(Variable variable, int value, Constraint constraint, ref Propagation propagation)
        {
            // The only case that can be handled is when the child is turned on, the parent must also be turned on.
            var parent = constraint.Variables[PARENT];
            var child  = constraint.Variables[CHILD];

            if (value == ON && variable.Id == child.Id)
            {
                if (!parent.IsSet && parent.Domain.Values.Contains(OFF))
                {
                    propagation.Add(parent.Id, OFF);
                    parent.Domain.Values.Remove(OFF);
                    propagation.IsValid = parent.Domain.Values.Count > 0;
                }
            }
        }
예제 #9
0
        private void PropagateMandatoryConstraint(Variable variable, int value, Constraint constraint, ref Propagation propagation)
        {
            // In the case of a mandatory, if a variable is enabled, we also want to enable the other
            // variable. This means that if the variable is enabled, we need to remove 0 from the domain of the other variable.
            // We can simply swap the on/off by taking the XOR of the value with 1.
            value ^= 1;

            // Then we find the other variable.
            var parent = constraint.Variables[PARENT];
            var child  = constraint.Variables[CHILD];
            var other  = variable.Id == parent.Id ? child : parent;

            // And finally remove the value from the domain of the other variable.
            if (!other.IsSet && other.Domain.Values.Contains(value))
            {
                propagation.Add(other.Id, value);
                other.Domain.Values.Remove(value);
                propagation.IsValid = other.Domain.Values.Count > 0;
            }
        }