带有/不带解算器的C#简约约束加权平均算法 [英] C# Simple Constrained Weighted Average Algorithm with/without Solver

查看:57
本文介绍了带有/不带解算器的C#简约约束加权平均算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有点新手用这些东西,但我不知道为什么我不能用Microsoft Solver Foundation解决这个看似简单的问题,有人请求帮助!

Bit of a newbie with this stuff but I'm at a loss as to why I can't get this seemingly simple problem solved using Microsoft Solver Foundation, someone please help!

我需要的是修改某些观察的权重(数字),以确保没有1个观察者的体重超过25%。这是为了稍后使用此算法的结果计算约束加权平均值。

All I need is to modify the weights (numbers) of certain observations to ensure that no 1 observation's weight AS A PERCENTAGE exceeds 25%. This is for the purposes of later calculating a constrained weighted average with the results of this algorithm.

例如,给定{45,100,33,500,28}的5个权重,我希望这个算法的结果是{45,
53 ,33, 53 ,28},其中2个数字必须减少,他们在新总数的25%门槛范围内( 212 = 45 + 53 + 33 + 53 + 28),而其他人则保持不变。

For example, given the 5 weights of { 45, 100, 33, 500, 28 }, I would expect the result of this algorithm to be { 45, 53, 33, 53, 28 }, where 2 of the numbers had to be reduced such that they're within the 25% threshold of the new total (212 = 45+53+33+53+28) while the others remained untouched.

我尝试使用Solver(请参阅下面的代码)重新创建这个简单的示例,仅仅是因为它告诉我解决方案是"不可行"的。它只返回所有1。对此有任何帮助将非常感谢,提前感谢。

I tried to recreate this simple example using Solver (please see code below) only for it to tell me that it is the solution is "Infeasible" and it just returns all 1s. Any help with this would be very much appreciated, thanks in advance.

PS 解决方案无需使用Solver,任何正确工作的替代方案都是受欢迎的,只要它在处理时速度很快相当数量的权重。

var solver = SolverContext.GetContext();
var model = solver.CreateModel();

var decisionList = new List<Decision>();
decisionList.Add(new Decision(Domain.IntegerRange(1, 45), "Dec1"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 100), "Dec2"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 33), "Dec3"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 500), "Dec4"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 28), "Dec5"));
model.AddDecisions(decisionList.ToArray());

int weightLimit = 25;
foreach (var decision in model.Decisions)
{
    model.AddConstraint(decision.Name + "weightLimit", 100 * (decision / Model.Sum(model.Decisions.ToArray())) <= weightLimit);
}
model.AddGoal("calcGoal", GoalKind.Maximize, Model.Sum(model.Decisions.ToArray()));

var solution = solver.Solve();
foreach (var decision in model.Decisions)
{
    Debug.Print(decision.GetDouble().ToString());
}
Debug.Print("Solution Quality: " + solution.Quality.ToString());



推荐答案

我认为无国界医生有问题,因为你正在改变模型(即有一个不断变化的数据集来搜索,所以没有它知道用来优化它的算法。但是,我想我想出了一个使用标准.NET。我用它获得了
的预期结果。它在VB.NET中,这是我的首选/更流利的语言。我认为转换它应该很容易。如果您有任何疑问,请告诉我,我会尽力帮助。

I think MSF was having issues because you are changing the model as you go (i.e. there is an ever changing dataset to search through), so there is no algorithm it knows to use to optimize it. However, I think I came up with one using standard .NET. I got your expected result with it. It's in VB.NET, which is my preferred/more fluent language. I think it should be pretty easy for you to convert though. If you have any questions, let me know and I'll try and help out as best I can.

 Dim numbers As New List(Of Integer) From {45, 100, 33, 500, 28}
        numbers.Sort()
        numbers.Reverse()   'should be in descending order now

        Dim threshold As Decimal = 0.25


        Dim increment As Integer = 1

        For i As Integer = 0 To numbers.Count - 1
            Do Until numbers(i) / numbers.Sum <= threshold
                For j As Integer = i To 0 Step -1
                    Do Until numbers(j) / numbers.Sum <= threshold
                        numbers(j) -= increment
                    Loop
                Next
            Loop
        Next
       
        Dim results As String = ""
        For Each num As Integer In numbers
            results += num.ToString & " / " & numbers.Sum.ToString & " = " & (num / numbers.Sum).ToString("F4") & Environment.NewLine
        Next

        MessageBox.Show(results)

P.S。谢谢你让我伸展自己的大脑。仔细考虑这一点非常令人耳目一新。

P.S. Thank you for letting my stretch my brain. This was quite refreshing to think through.

编辑2:

这是C#有一些补充。它还存储原始值(排序后)以便在结尾显示。

Here is the C# with some additions. It also stores the original values (after sorting) for display at the end.

List<int> numbers = new List<int> {45,100,33,500,28,89,5,1359,23549};
            numbers.Sort();
            numbers.Reverse();  //should be in descending order now

            List<int> original = new List<int>();
            original.AddRange(numbers);

            decimal threshold = 0.25M;

            int increment = 1;

            for (int i = 0; i < numbers.Count; i++)
            {
                while (!((decimal)numbers[i] / numbers.Sum() <= threshold))
                {
                    for (int j = i; j >= 0; j--)
                    {
                        while (!((decimal)numbers[j] / numbers.Sum() <= threshold))
                        {
                            numbers[j] -= increment;
                        }
                    }
                }
            }

            string results = "";
            for (int i = 0; i < numbers.Count; i++)
            {
                results += "Original: " + original[i].ToString() + " \t  Calc: " + numbers[i].ToString() + " / " + numbers.Sum().ToString() + " = " + ((decimal)numbers[i] / numbers.Sum()).ToString("F4") + Environment.NewLine;
            }

            MessageBox.Show(results);





这篇关于带有/不带解算器的C#简约约束加权平均算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆