Example #1
0
        /// <summary>
        /// Creates a cost system. Assigns resources to pools and selects
        /// drivers for each pool.
        /// </summary>
        /// <param name="ip">An input parameters object.</param>
        /// <param name="firm">The firm upon which this cost system is based.</param>
        /// <param name="a">The number of activity cost pools to form.</param>
        /// <param name="p">A flag indicating method for assigning resources to cost pools.
        /// See input file cheat sheet for details.</param>
        /// <param name="r">A flag indicating which resources in the pools
        /// will be used to form drivers. See input file cheat sheet for details.</param>
        public CostSys(
            InputParameters ip,
            Firm firm,
            int a,
            int p,
            int r)
        {
            this.firm = firm;
            RowVector RCC = firm.Initial_RCC;

            int[]           RANK = firm.Initial_RANK;
            SymmetricMatrix CORR = firm.PEARSONCORR;

            this.a = a;
            this.p = p;
            this.r = r;

            if (a != 1)
            {
                #region Code shared in flowchart 6.1, 6.2, and 6.3

                // Segregate resources into big ones that will each
                // seed a pool, and miscellaneous resources.
                // The first (a-1) resources get their own pools.
                List <int> bigResources  = RANK.Take(a - 1).ToList();
                List <int> miscResources = RANK.Skip(a - 1).ToList();

                // Create the set B and initialize the first
                // elements with the big pool resources.

                // Seeding big resources
                // Take each resource from bigPools, ane make it into a list
                // of length 1. Convert to an array of lists, and assign to B.
                B = bigResources.Select(elem => new List <int> {
                    elem
                }).ToArray();

                // Increase the length by 1, to make room for the miscellaneous
                // pool.
                Array.Resize(ref B, B.Length + 1);
                B[B.Length - 1] = new List <int>();

                #endregion

                // p == 0:
                // Seed (a-1) pools with the largest (a-1) resources.
                // All remaining resources assigned to miscellaneous pool
                if (p == 0)
                {
                    #region Flowchart 6.1

                    B[a - 1] = new List <int>(miscResources);

                    #endregion
                }
                // p == 1:
                // Seed acp-1 pools based on size. Check to see
                // the highest correlation for the remaining resources. Assign the
                // unassigned resource with the highest correlation to
                // the relevant ACP. Check to see if the value of remaining
                // ACP > MISCPOOLSIZE. If so, continue to find the next highest
                // correlation, assign and check. When remaining value < 20%,
                // then pool everything into misc.
                else if (p == 1)
                {
                    #region Flowchart 6.2

                    // This query iterates over miscResources. For each one, it
                    // computes the correlation with every bigResource, and forms
                    // a record {smallResourceIndex, index of big pool (in B), correlation }.
                    // Order this list of records in descending order and keep the first one.
                    // This first one is the pool to which the small resources will be allocated
                    // if the correlation is sufficiently high.
                    var query =
                        miscResources.Select(smallRes => bigResources.Select((bigRes, i) => new { smallRes, BigPoolNum = i, correl = CORR[bigRes, smallRes] }).OrderByDescending(x => x.correl).First());
                    // Order the small resources by correlation with big resources. Thus,
                    // if resource 7 is most correlated with big pool resource 0 (92%),
                    // and resource 12 is most correlated with big pool resource 1 (83%),
                    // 7 will be ahead of 12 in myArray.
                    var myArray = query.OrderByDescending(x => x.correl).ToArray();

                    // The following block makes sure that at least one nonzero
                    // resource is allocated to the last pool. The only time this
                    // fails is if all miscellaneous resources are zero.
                    int lastResourceToAllocate;
                    {
                        // Convert each record in myArray to the value of the resource
                        // cost pool represented by that resource
                        var moo = myArray.Select(x => RCC[x.smallRes]);
                        // Convert each element of moo to the value of the remaining
                        // resources in the array at this point.
                        var moo2 = moo.Select((_, i) => moo.Skip(i).Sum());

                        List <double> ld = moo2.ToList();
                        // If the list contains a 0, that means there are one or
                        // more zero resources. Find the index of the first one,
                        // or if there isn't one, use the end of the array.
                        if (ld.Contains(0.0))
                        {
                            lastResourceToAllocate = ld.IndexOf(0.0) - 1;
                        }
                        else
                        {
                            lastResourceToAllocate = myArray.Length;
                        }
                    }

                    double TR = RCC.Sum();
                    double notYetAllocated = miscResources.Aggregate(0.0, (acc, indx) => acc + RCC[indx]);
                    bool   cutoffReached   = (notYetAllocated / TR) < ip.MISCPOOLSIZE;

                    for (int k = 0; (k < lastResourceToAllocate) && !cutoffReached; ++k)
                    {
                        var q = myArray[k];

                        if (q.correl >= ip.CC)
                        {
                            B[q.BigPoolNum].Add(q.smallRes);
                            miscResources.Remove(q.smallRes);
                        }
                        else
                        {
                            break;
                        }

                        notYetAllocated = miscResources.Aggregate(0.0, (acc, indx) => acc + RCC[indx]);
                        cutoffReached   = (notYetAllocated / TR) < ip.MISCPOOLSIZE;
                    }

                    // Check if there is anything left in miscResources
                    // If yes, throw it in the miscellaneous pool (B.Last()).
                    if (miscResources.Count > 0)
                    {
                        B.Last().AddRange(miscResources);
                    }
                    // If not, remove the last allocated resource (myArray.Last())
                    // from the pool to which it was allocated, and place it in the
                    // miscellaneous pool.
                    else
                    {
                        var q = myArray.Last();
                        B[q.BigPoolNum].Remove(q.smallRes);
                        B.Last().Add(q.smallRes);
                    }

                    #endregion
                }
                // p == 2:
                // Seed each of the (a-1) cost pools with the largest resources.
                // Allocate the remaining resources to the (a-1) pools at random.
                // However, ensure that enough resources are in the last pool.
                // The fraction of resources in the last pool is MISCPOOLSIZE.
                else if (p == 2)
                {
                    #region Flowchart 6.3

                    double TR = RCC.Sum();
                    // Magnitude of resources not yet allocated
                    double notYetAllocated = miscResources.Aggregate(0.0, (acc, indx) => acc + RCC[indx]);
                    // Fraction of resources not yet allocated
                    double miscPoolPrct = notYetAllocated / TR;

                    // Logic: Check if the fraction of resources in
                    // miscResources is greater than the cap (ip.MISCPOOLSIZE).
                    // If yes, take the first resource from miscResources
                    // and put it in one of the big pools, chosen at random.
                    // If the fraction of resources in miscResources is still
                    // greater than the cap, repeat the loop. Otherwise,
                    // stop and put the remaining resources in the last pool.
                    //
                    // Also stop under the following condition. Assume the head
                    // of the miscResources list is allocated. Is the value of the
                    // remaining resources in miscResources (the tail) greater than
                    // zero? If not, stop. There has to be at least one non-zero
                    // resource in the last pool.
                    while (
                        (miscPoolPrct > ip.MISCPOOLSIZE) &&
                        (miscResources.Skip(1).Aggregate(0.0, (acc, indx) => acc + RCC[indx]) > 0.0)
                        )
                    {
                        // Pick a pool at random to get the next resource
                        int poolIndx = (int)GenRandNumbers.GenUniformInt(0, a - 2);
                        B[poolIndx].Add(miscResources.First());
                        miscResources.RemoveAt(0);

                        notYetAllocated = miscResources.Aggregate(0.0, (acc, indx) => acc + RCC[indx]);
                        miscPoolPrct    = notYetAllocated / TR;
                    }

                    B.Last().AddRange(miscResources);

                    #endregion
                }
                // p == 3:
                // Seed the first pool with the largest resource.
                // Iterate over the other pools. For each pool, select a seed resource:
                // This is the largest of the remaining, unassigned resources, and
                // assign it to the pool.
                // Form a correlation vector (a list), which is the correlation
                // of each resource in remainingResources with the seed resource.
                // If the highest correlation is greater than ip.CC, there are
                // enough remaining resources to fill the remaining pools, and
                // satisfy the constraint about the miscellaneous pool size,
                //assign resource with the highest correlation to the current pool.
                // Once there are just as many resources remaining as there are pools,
                // assign one resource to each remaining pool.
                else if (p == 3)
                {
                    #region Flowchart 6.4

                    // Initialize B
                    for (int i = 0; i < B.Length; ++i)
                    {
                        B[i] = new List <int>();
                    }

                    // Seed the first pool with the largest resource
                    B[0].Add(RANK[0]);
                    List <int> remainingResources = RANK.Skip(1).ToList();

                    // Assign all zero resources to the last (miscellaneous) pool.
                    // That way, each of the remaining pools is guaranteed to have
                    // a nonzero resource.
                    // This only works if there are at least as many nonzero resources
                    // as there are pools. If not, then skip this step so that each
                    // pool has at least one resource.
                    int numZeroResources = remainingResources.Count(res => RCC[res] == 0.0);
                    if (RCC.Dimension - numZeroResources >= B.Length)
                    {
                        while (RCC[remainingResources.Last()] == 0.0)
                        {
                            B.Last().Add(remainingResources.Last());
                            remainingResources.RemoveAt(remainingResources.Count - 1);
                        }
                    }

                    // Iterate over the pools. For each pool, select a seed resource,
                    // which is the first resource assigned to the pool.
                    // Form a correlation vector (a list), which is the correlation
                    // of each resource in remainingResources with the seed resource.
                    // While max of the list is greater than ip.CC, and while
                    // the other conditions are satisfied, assign resource with the
                    // maximum correlation to the current pool.
                    // Once condition 2 is no longer true, there are just as many
                    // resources remaining as there are pools. The loop then assigns
                    // one resource to each remaining pool.
                    // Once condition 3 is no longer true, it assigns one resource
                    // to each pool, and all the remaining resources to the last pool.
                    for (int currentPool = 0; currentPool < B.Length - 1; ++currentPool)
                    {
                        int seedResource    = B[currentPool].First();
                        int poolsToBeFilled = B.Length - (currentPool + 1);

                        List <double> correlations = remainingResources.Select(res => CORR[res, seedResource]).ToList();
                        bool          cond1        = correlations.Max() > ip.CC;
                        bool          cond2        = remainingResources.Count > poolsToBeFilled;

                        // Magnitude of resources not yet allocated
                        double notYetAllocated = remainingResources.Aggregate(0.0, (acc, indx) => acc + RCC[indx]);
                        // Fraction of resources not yet allocated
                        double TR           = RCC.Sum();
                        double miscPoolPrct = notYetAllocated / TR;
                        bool   cond3        = miscPoolPrct > ip.MISCPOOLSIZE;

                        while (cond1 && cond2 && cond3)
                        {
                            // Find the index of the resource with the maximum correlation
                            // with the seed resource
                            double maxCorr     = correlations.Max();
                            int    maxCorrIndx = remainingResources[correlations.IndexOf(maxCorr)];

                            // Add it to the current pool
                            B[currentPool].Add(maxCorrIndx);

                            // Remove it from the remainingResources list
                            remainingResources.RemoveAt(correlations.IndexOf(maxCorr));
                            correlations.Remove(maxCorr);

                            // Recompute loop termination conditions
                            cond1           = correlations.Max() > ip.CC;
                            cond2           = remainingResources.Count > poolsToBeFilled;
                            notYetAllocated = remainingResources.Aggregate(0.0, (acc, indx) => acc + RCC[indx]);
                            miscPoolPrct    = notYetAllocated / TR;
                            cond3           = miscPoolPrct > ip.MISCPOOLSIZE;
                        }

                        B[currentPool + 1].Add(remainingResources[0]);
                        remainingResources.RemoveAt(0);
                    }

                    B.Last().AddRange(remainingResources);

                    #endregion
                }
                else
                {
                    throw new ApplicationException("Invalid value of p.");
                }
            }
            else
            {
                #region Flowchart 6.5

                B = new List <int>[] { new List <int>(RANK) };

                #endregion
            }

            // The fraction of RCC that is in the miscellaneous (last)
            // activity cost pool.
            double miscPoolSize = B.Last().Aggregate(0.0, (acc, i) => acc + RCC[i]) / RCC.Sum();

            #region Flowchart 6.5 -- Choosing drivers

            // For each element of B, which is a list of resource indexes,
            // sort it in descending order by pool size (RCC[element]).
            // Technically, this is unnecessary, since elements should have
            // been added to the lists in B in descending order. But instead
            // of assuming that, since that could change in the future,
            // I am going to re-sort. Heck, it's only one line of code,
            // plus this essay of a comment that I just wrote.
            {
                var query = B.Select(list => list.OrderByDescending(indx => RCC[indx]));

                int numToTake;
                if (r == 0)
                {
                    numToTake = 1;
                }
                else if (r == 1)
                {
                    numToTake = ip.NUM;
                }
                else
                {
                    throw new ApplicationException("Invalid value of r in FalseSys.cs.");
                }

                // This iterates over every list in query, and replaces that list
                // with a list containing only the first numToTake elements.
                var drivers = query.Select(list => list.Take(numToTake).ToList());
                D = drivers.ToArray();
            }
            #endregion
        }
Example #2
0
 /// <summary>
 /// Generates a random vector of capacities (maximum production
 /// quantities). Each element is drawn from discrete U[10,40].
 /// </summary>
 /// <param name="ip">The current InputParameters object</param>
 /// <returns>A [CO x 1] vector, each element drawn from
 /// the *discrete* distribution U[10,40].</returns>
 private ColumnVector GenMXQ(InputParameters ip)
 {
     return(new ColumnVector(ip.CO).Map(x => GenRandNumbers.GenUniformInt(10, 40)));
 }