Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带/不带解算器的C#简单约束加权平均算法 我不明白为什么我不能用微软Salver基金会解决这个看似简单的问题。_C#_Algorithm_Solver_Weighted Average_Ms Solver Foundation - Fatal编程技术网

带/不带解算器的C#简单约束加权平均算法 我不明白为什么我不能用微软Salver基金会解决这个看似简单的问题。

带/不带解算器的C#简单约束加权平均算法 我不明白为什么我不能用微软Salver基金会解决这个看似简单的问题。,c#,algorithm,solver,weighted-average,ms-solver-foundation,C#,Algorithm,Solver,Weighted Average,Ms Solver Foundation,我只需要修改某些观察的权重(数字),以确保没有一个观察的权重百分比超过25%。这是为了以后使用该算法的结果计算约束加权平均值 例如,给定5个权重{45,100,33,500,28},我希望这个算法的结果是{45,53,33,53,28},其中2个数字必须减少,以使它们在新总数的25%阈值内(212=45+53+33+53+28)而其他人则保持原样。请注意,尽管最初,第二个100的权重仅为总权重(706)的14%,但由于第四个500的权重减少,它随后推高了其他观察值的%,这是唯一的挑战 我试图重新

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

例如,给定5个权重{45,100,33,500,28},我希望这个算法的结果是{45,53,33,53,28},其中2个数字必须减少,以使它们在新总数的25%阈值内(212=45+53+33+53+28)而其他人则保持原样。请注意,尽管最初,第二个100的权重仅为总权重(706)的14%,但由于第四个500的权重减少,它随后推高了其他观察值的%,这是唯一的挑战

我试图重新创建这个使用解算器,只是为了它告诉我,这个解决方案是“不可行的”,它只是返回所有的1更新:解决方案不需要使用解算器,只要在处理适当数量的权重时速度快,任何替代方案都是受欢迎的

var solver=SolverContext.GetContext();
var model=solver.CreateModel();
var decisionList=新列表();
decisionList.Add(新决策(Domain.integragerage(1,45),“Dec1”);
decisionList.Add(新决策(Domain.integragerage(1100),“Dec2”);
decisionList.Add(新决策(Domain.integragerage(1,33),“Dec3”);
decisionList.Add(新决策(Domain.integragerage(1500),“Dec4”);
decisionList.Add(新决策(Domain.integragerage(1,28),“Dec5”);
model.AddDecisions(decisionList.ToArray());
int-weightLimit=25;
foreach(模型中的var决策。决策)
{

model.AddConstraint(decision.Name+“weightLimit”,100*(decision/model.Sum(model.Decisions.ToArray())我放弃了解算器b/c它没有达到它的名字imo(或者我没有达到它的标准:)).下面是我登陆的地方。由于此函数被多次使用,并且在大量输入权重列表中使用,因此效率和性能是关键,因此此函数尝试尽可能少地进行迭代(尽管有人建议改进,请告诉我)。结果用于加权平均值,因此我使用“AttributeWeightPair”为了存储值(属性)及其权重,下面的函数在给定这些AWP的列表时修改权重,使其在约束范围内。该函数假设权重限制以a%的形式传入,例如,25%以25的形式传入,而不是0.25的形式传入——好的,我将不再说明代码中显而易见的内容-因此它是:

    public static List<AttributeWeightPair<decimal>> WeightLimiter(List<AttributeWeightPair<decimal>> source, decimal weightLimit)
    {
        weightLimit /= 100; //convert to percentage

        var zeroWeights = source.Where(w => w.Weight == 0).ToList();
        var nonZeroWeights = source.Where(w => w.Weight > 0).ToList();

        if (nonZeroWeights.Count == 0)
            return source;

        //return equal weights if given infeasible constraint
        if ((1m / nonZeroWeights.Count()) > weightLimit)
        {
            nonZeroWeights.ForEach(w => w.Weight = 1);
            return nonZeroWeights.Concat(zeroWeights).ToList();
        }

        //return original list if weight-limiting is unnecessary
        if ((nonZeroWeights.Max(w => w.Weight) / nonZeroWeights.Sum(w => w.Weight)) <= weightLimit)
        {
            return source;
        }

        //sort (ascending) and store original weights
        nonZeroWeights = nonZeroWeights.OrderBy(w => w.Weight).ToList();
        var originalWeights = nonZeroWeights.Select(w => w.Weight).ToList();

        //set starting point and determine direction from there
        var initialSumWeights = nonZeroWeights.Sum(w => w.Weight);
        var initialLimit = weightLimit * initialSumWeights;
        var initialSuspects = nonZeroWeights.Where(w => w.Weight > initialLimit).ToList();
        var initialTarget = weightLimit * (initialSumWeights - (initialSuspects.Sum(w => w.Weight) - initialLimit * initialSuspects.Count()));
        var antepenultimateIndex = Math.Max(nonZeroWeights.FindLastIndex(w => w.Weight <= initialTarget), 1); //needs to be at least 1        
        for (int i = antepenultimateIndex; i < nonZeroWeights.Count(); i++)
        {
            nonZeroWeights[i].Weight = originalWeights[antepenultimateIndex - 1]; //set cap equal to the preceding weight
        }
        bool goingUp = (nonZeroWeights[antepenultimateIndex].Weight / nonZeroWeights.Sum(w => w.Weight)) > weightLimit ? false : true;

        //Procedure 1 - find the weight # at which a cap would result in a weight % just UNDER the weight limit
        int penultimateIndex = antepenultimateIndex;
        bool justUnderTarget = false;          
        while (!justUnderTarget)
        {
            for (int i = penultimateIndex; i < nonZeroWeights.Count(); i++)
            {
                nonZeroWeights[i].Weight = originalWeights[penultimateIndex - 1]; //set cap equal to the preceding weight
            }

            var currentMaxPcntWeight = nonZeroWeights[penultimateIndex].Weight / nonZeroWeights.Sum(w => w.Weight);
            if (currentMaxPcntWeight == weightLimit) 
            {
                return nonZeroWeights.Concat(zeroWeights).ToList();
            }
            else if (goingUp && currentMaxPcntWeight < weightLimit)
            {
                nonZeroWeights[penultimateIndex].Weight = originalWeights[penultimateIndex]; //reset
                if (penultimateIndex < nonZeroWeights.Count() - 1)
                    penultimateIndex++; //move up
                else break;
            }
            else if (!goingUp && currentMaxPcntWeight > weightLimit)
            {
                if (penultimateIndex > 1)
                    penultimateIndex--; //move down
                else break;
            }
            else
            {
                justUnderTarget = true;
            }
        }

        if (goingUp) //then need to back up a step
        {
            penultimateIndex = (penultimateIndex > 1 ? penultimateIndex - 1 : 1);
            for (int i = penultimateIndex; i < nonZeroWeights.Count(); i++)
            {
                nonZeroWeights[i].Weight = originalWeights[penultimateIndex - 1];
            }
        }

        //Procedure 2 - increment the modified weights (subject to a cap equal to their original values) until the weight limit is hit (allowing a very slight overage for the last term in some cases)
        int ultimateIndex = penultimateIndex;
        var sumWeights = nonZeroWeights.Sum(w => w.Weight); //use this counter instead of summing every time for condition check within loop
        bool justOverTarget = false;
        while (!justOverTarget)
        {
            for (int i = ultimateIndex; i < nonZeroWeights.Count(); i++)
            {
                if (nonZeroWeights[i].Weight + 1 > originalWeights[i])
                {
                    if (ultimateIndex < nonZeroWeights.Count() - 1)
                        ultimateIndex++;
                    else justOverTarget = true;
                }
                else
                {
                    nonZeroWeights[i].Weight++;
                    sumWeights++;
                }
            }

            if ((nonZeroWeights.Last().Weight / sumWeights) >= weightLimit)
            {
                justOverTarget = true;
            }
        }

        return nonZeroWeights.Concat(zeroWeights).ToList();
    }

    public class AttributeWeightPair<T>
    {
        public T Attribute { get; set; }
        public decimal? Weight { get; set; }
        public AttributeWeightPair(T attribute, decimal? count)
        {
            this.Attribute = attribute;
            this.Weight = count;
        }
    }
公共静态列表权重限制器(列表源,十进制权重限制)
{
weightLimit/=100;//转换为百分比
var zerowweights=source.Where(w=>w.Weight==0.ToList();
var non-zerowweights=source.Where(w=>w.Weight>0.ToList();
if(non-zerowweights.Count==0)
返回源;
//如果给定不可行约束,则返回相等的权重
if((1m/non-zerowits.Count())>weightLimit)
{
非零权重。ForEach(w=>w.Weight=1);
返回non-zerowweights.Concat(zerowweights.ToList();
}
//如果不需要重量限制,请返回原始列表
if((nonzerowweights.Max(w=>w.Weight)/nonzerowweights.Sum(w=>w.Weight))w.Weight.ToList();
var originalWeights=non-zerowweights.Select(w=>w.Weight.ToList();
//设置起点并从那里确定方向
var initialSumWeights=非零权重.Sum(w=>w.Weight);
var initialLimit=权重限制*initialSumWeights;
var initialSuspects=non-zerowweights.Where(w=>w.Weight>initialLimit).ToList();
var initialTarget=weightLimit*(initialSumWeights-(initialSumSumWeights.Sum(w=>w.Weight)-initialLimit*initialSumWeights.Count());
var antepenultimateIndex=Math.Max(非零权重.FindLastIndex(w=>w.Weight w.Weight))>weightLimit?false:true;
//程序1-找到重量#在该重量下,上限将导致重量%刚好低于重量限制
int penultimateIndex=前penultimateIndex;
bool justUnderTarget=false;
而(!justUnderTarget)
{
对于(int i=penultimateIndex;iw.Weight);
如果(currentMaxPcntWeight==权重限制)
{
返回non-zerowweights.Concat(zerowweights.ToList();
}
否则如果(goingUp¤tMaxPcntWeight<重量限制)
{
非零权重[penultimateIndex]。权重=原始权重[penultimateIndex];//重置
if(penultimateIndex<非零权重.Count()-1)
penultimateIndex++;//上移
否则就断了;
}
如果(!goingUp&¤tMaxPcntWeight>weightLimit),则为else
{
如果(倒数第二个索引>1)
倒数第二个索引--;//下移
否则就断了;
}
其他的
{
justUnderTarget=正确;
}
}
if(goingUp)//则需要备份一个步骤
{
penultimateIndex=(penultimateIndex>1?penultimateIndex-1:1);
对于(int i=penultimateIndex;i    public static List<AttributeWeightPair<decimal>> WeightLimiter(List<AttributeWeightPair<decimal>> source, decimal weightLimit)
    {
        weightLimit /= 100; //convert to percentage

        var zeroWeights = source.Where(w => w.Weight == 0).ToList();
        var nonZeroWeights = source.Where(w => w.Weight > 0).ToList();

        if (nonZeroWeights.Count == 0)
            return source;

        //return equal weights if given infeasible constraint
        if ((1m / nonZeroWeights.Count()) > weightLimit)
        {
            nonZeroWeights.ForEach(w => w.Weight = 1);
            return nonZeroWeights.Concat(zeroWeights).ToList();
        }

        //return original list if weight-limiting is unnecessary
        if ((nonZeroWeights.Max(w => w.Weight) / nonZeroWeights.Sum(w => w.Weight)) <= weightLimit)
        {
            return source;
        }

        //sort (ascending) and store original weights
        nonZeroWeights = nonZeroWeights.OrderBy(w => w.Weight).ToList();
        var originalWeights = nonZeroWeights.Select(w => w.Weight).ToList();

        //set starting point and determine direction from there
        var initialSumWeights = nonZeroWeights.Sum(w => w.Weight);
        var initialLimit = weightLimit * initialSumWeights;
        var initialSuspects = nonZeroWeights.Where(w => w.Weight > initialLimit).ToList();
        var initialTarget = weightLimit * (initialSumWeights - (initialSuspects.Sum(w => w.Weight) - initialLimit * initialSuspects.Count()));
        var antepenultimateIndex = Math.Max(nonZeroWeights.FindLastIndex(w => w.Weight <= initialTarget), 1); //needs to be at least 1        
        for (int i = antepenultimateIndex; i < nonZeroWeights.Count(); i++)
        {
            nonZeroWeights[i].Weight = originalWeights[antepenultimateIndex - 1]; //set cap equal to the preceding weight
        }
        bool goingUp = (nonZeroWeights[antepenultimateIndex].Weight / nonZeroWeights.Sum(w => w.Weight)) > weightLimit ? false : true;

        //Procedure 1 - find the weight # at which a cap would result in a weight % just UNDER the weight limit
        int penultimateIndex = antepenultimateIndex;
        bool justUnderTarget = false;          
        while (!justUnderTarget)
        {
            for (int i = penultimateIndex; i < nonZeroWeights.Count(); i++)
            {
                nonZeroWeights[i].Weight = originalWeights[penultimateIndex - 1]; //set cap equal to the preceding weight
            }

            var currentMaxPcntWeight = nonZeroWeights[penultimateIndex].Weight / nonZeroWeights.Sum(w => w.Weight);
            if (currentMaxPcntWeight == weightLimit) 
            {
                return nonZeroWeights.Concat(zeroWeights).ToList();
            }
            else if (goingUp && currentMaxPcntWeight < weightLimit)
            {
                nonZeroWeights[penultimateIndex].Weight = originalWeights[penultimateIndex]; //reset
                if (penultimateIndex < nonZeroWeights.Count() - 1)
                    penultimateIndex++; //move up
                else break;
            }
            else if (!goingUp && currentMaxPcntWeight > weightLimit)
            {
                if (penultimateIndex > 1)
                    penultimateIndex--; //move down
                else break;
            }
            else
            {
                justUnderTarget = true;
            }
        }

        if (goingUp) //then need to back up a step
        {
            penultimateIndex = (penultimateIndex > 1 ? penultimateIndex - 1 : 1);
            for (int i = penultimateIndex; i < nonZeroWeights.Count(); i++)
            {
                nonZeroWeights[i].Weight = originalWeights[penultimateIndex - 1];
            }
        }

        //Procedure 2 - increment the modified weights (subject to a cap equal to their original values) until the weight limit is hit (allowing a very slight overage for the last term in some cases)
        int ultimateIndex = penultimateIndex;
        var sumWeights = nonZeroWeights.Sum(w => w.Weight); //use this counter instead of summing every time for condition check within loop
        bool justOverTarget = false;
        while (!justOverTarget)
        {
            for (int i = ultimateIndex; i < nonZeroWeights.Count(); i++)
            {
                if (nonZeroWeights[i].Weight + 1 > originalWeights[i])
                {
                    if (ultimateIndex < nonZeroWeights.Count() - 1)
                        ultimateIndex++;
                    else justOverTarget = true;
                }
                else
                {
                    nonZeroWeights[i].Weight++;
                    sumWeights++;
                }
            }

            if ((nonZeroWeights.Last().Weight / sumWeights) >= weightLimit)
            {
                justOverTarget = true;
            }
        }

        return nonZeroWeights.Concat(zeroWeights).ToList();
    }

    public class AttributeWeightPair<T>
    {
        public T Attribute { get; set; }
        public decimal? Weight { get; set; }
        public AttributeWeightPair(T attribute, decimal? count)
        {
            this.Attribute = attribute;
            this.Weight = count;
        }
    }