Пример #1
0
        static void Main()
        {
            // We are looking for the optimal mix of two materials that have different properties.
            // Each material is made up of particles of different sizes, think two types of gravel
            // that have different size rocks in them.
            // We measure the properties of the material by measuring the volume of material that
            // can pass through two different sieves:
            // Sieve 1, for example, has 10mm holes in it.
            // Sieve 2, for example, has 2mm holes in it.

            // For each material we measure the volume (in %) of the material that can pass through each sieve.
            // Material 1:
            //  - 70% passes through sieve 1
            //  - 30% also passes through sieve 2
            // So that means:
            //  - 30% of the volume of material 1 are particles > 10 mm
            //  - 40% of the volume of material 1 are particles <= 10 mm and > 2 mm
            //  - 30% of the volume of material 1 are particles < 2 mm
            // Material 2 has different properties:
            //  - 90% passes through sieve 1
            //  - 75% also passes through sieve 2

            // Our goal is to find a mix of both materials that comes as close as possible to
            // our target particle distribution.
            // For this example, let's say we want:
            // Target mix:
            //  - 80% passes through sieve 1
            //  - 50% also passes through sieve 2

            // Se would like to find out how to mix both materials (what % of each in the mix) so that
            // the mix has the desired properties?

            // Creating the model.
            // [START model]
            CpModel model = new CpModel();
            // [END model]

            // [START variables]
            // These are the variables we are actually interested in.
            // The volume percentages of each material in the mix. How much (in %) of each material should we put in the mix?
            IntVar volPctMaterial1 = model.NewIntVar(0, 10000, "v%1");
            IntVar volPctMaterial2 = model.NewIntVar(0, 10000, "v%2");

            // The rest of the variables are intermediate variables.
            // First we have the percentages of the mix that pass through both sieves.
            // These should be as close as possible to our target (80/50 in our example).
            IntVar sieve1PassPctForMix = model.NewIntVar(0, 100000000, "Y1");
            IntVar sieve2PassPctForMix = model.NewIntVar(0, 100000000, "Y2");

            // These variables will contain the difference between the actual and target pass percentages for the mix.
            // For example: if the target is 80% through sieve 1, but our solution finds a mix where 75% passes through sieve 1,
            // then the passPctDeltaForSieve1 is 5% (80% - 75%).
            IntVar passPctDeltaSieve1 = model.NewIntVar(-100000000, 100000000, "passPctDeltaSieve1");
            IntVar passPctDeltaSieve2 = model.NewIntVar(-100000000, 100000000, "passPctDeltaSieve2");

            // These variables are the ABS() (positive) values of our delta variables.
            // We will optimize for the lowest sum of these ABS() delta variables, so that our mix comes as close as
            // possible to our desired pass percentages.
            IntVar passPctDeltaAbsSieve1 = model.NewIntVar(0, 100000000, "passPctDeltaAbsSieve1");
            IntVar passPctDeltaAbsSieve2 = model.NewIntVar(0, 100000000, "passPctDeltaAbsSieve2");

            // [END variables]

            // [START constraints]
            // Add the mixture pass percentage constraints (Y1 = v%1*Y11 + v%2*Y12 + ... +  v%n*Y1n).
            // The formula for the amount of the mix that passes through each sieve is the weighted sum of the pass
            // percentages of the materials in the mix.
            // For example: if the mix is 50% material 1, 50% material 2, and 70% of material 1 passes through sieve 1,
            // while 90% of material 2 passes through sieve 1,
            // then 80% of the mix would pass through sieve 1 (= 50%*70% + 50%*90%).
            model.Add(sieve1PassPctForMix == 7000 * volPctMaterial1 + 9000 * volPctMaterial2);
            model.Add(sieve2PassPctForMix == 3000 * volPctMaterial1 + 7500 * volPctMaterial2);

            // The volume percentages should add up to 100% constraint.
            // The mix can for example be 40% material 1, 60% material 2: 40 + 60 = 100
            model.Add(volPctMaterial1 + volPctMaterial2 == 10000);

            // We calculate the difference between our target pass percentages and our target
            model.Add(passPctDeltaSieve1 == sieve1PassPctForMix - 80000000);
            model.Add(passPctDeltaSieve2 == sieve2PassPctForMix - 50000000);

            // We now calculate the absolute values of these differences, so we can minimize their sum.
            model.AddAbsEquality(passPctDeltaAbsSieve1, passPctDeltaSieve1);
            model.AddAbsEquality(passPctDeltaAbsSieve2, passPctDeltaSieve2);

            // Uncommenting the line below makes the solution INFEASIBLE.  Why?
            model.Add(volPctMaterial2 == 3000); // 30% of the mix needs to be material 2

            // [END constraints]
            // We minimize the sum of the absolute difference between the actual and target pass percentages for the mix.
            model.Minimize(new SumArray(new IntVar[] {
                passPctDeltaAbsSieve1,
                passPctDeltaAbsSieve2,
            }));

            // [START solve]
            CpSolver       solver = new CpSolver();
            CpSolverStatus status = solver.Solve(model);

            // [END solve]

            if (status == CpSolverStatus.Feasible || status == CpSolverStatus.Optimal)
            {
                Console.WriteLine("ObjectiveValue: " + solver.ObjectiveValue);

                Console.WriteLine("volPctMaterial1 = " + solver.Value(volPctMaterial1));
                Console.WriteLine("volPctMaterial2 = " + solver.Value(volPctMaterial2));
                Console.WriteLine("sieve1PassPctForMix (Y1) = " + solver.Value(sieve1PassPctForMix));
                Console.WriteLine("sieve2PassPctForMix (Y2) = " + solver.Value(sieve2PassPctForMix));
                Console.WriteLine("passPctDeltaSieve1 = " + solver.Value(passPctDeltaSieve1));
                Console.WriteLine("passPctDeltaSieve2 = " + solver.Value(passPctDeltaSieve2));
                Console.WriteLine("passPctDeltaAbsSieve1 = " + solver.Value(passPctDeltaAbsSieve1));
                Console.WriteLine("passPctDeltaAbsSieve2 = " + solver.Value(passPctDeltaAbsSieve2));
            }
            else
            {
                Console.WriteLine("Status was " + status + ", which is not feasible.  Response stats: " + solver.ResponseStats());
            }

            Console.ReadLine();
        }