/// <summary> /// Assuming the firm implements decision DECF0, this method computes /// reported costs for this cost system, which are used to compute the firm's updated decision. /// It iterates using the updated decision as the new starting decision until a terminal outcome /// (e.g. equilibrium, cycle) is reached. /// </summary> /// <param name="ip">The current InputParameters object</param> /// <param name="DECF0">The starting decision.</param> /// <returns>Returns the outcome of iterations and the final decision.</returns> public (CostSystemOutcomes stopCode, RowVector DECF1) EquilibriumCheck(InputParameters ip, RowVector DECF0) { #region Make local copies of firm-level variables ColumnVector MXQ = this.firm.MXQ; RowVector SP = this.firm.SP; #endregion // The initial vector of production quantities, given // starting decision DECF0 ColumnVector q0 = MXQ.ewMultiply(DECF0); // A list of past decisions made during the iteration process. // If a decision appears twice on this list, then a cycle exists. List <RowVector> pastDecisions = new List <RowVector> { DECF0 }; // The "next" decision that the firm would make. Assume the firm // starts with DECF0, computes resulting resource consumption, // and reported costs (through the cost system). Given reported // costs, it updates its decision to DECF1. RowVector DECF1; bool foundThisDecisionBefore; double MAR_DROP = 1.0 - ip.HYSTERESIS; double MAR_MAKE = 1.0 + ip.HYSTERESIS; CostSystemOutcomes stopCode = CostSystemOutcomes.Unassigned; bool done; do { RowVector PC_R = CalcReportedCosts(ip, DECF0); if (PC_R.Contains(double.NaN)) { DECF1 = PC_R.Map(x => double.NaN); } else { double[] MAR = PC_R.Zip(SP, (pc_r, sp) => sp / pc_r).ToArray(); var decf1 = MAR.Zip(q0, (mar, q) => (q > 0.0) ? ((mar <= MAR_DROP) ? 0.0 : 1.0) : ((mar > MAR_MAKE) ? 1.0 : 0.0)); DECF1 = new RowVector(decf1.ToList()); } ColumnVector q1 = MXQ.ewMultiply(DECF1); if (!(foundThisDecisionBefore = pastDecisions.Contains(DECF1))) { pastDecisions.Add(DECF1); } //double ExpectedCosts = PC_R * q1; //double TCF0 = this.firm.CalcTotCosts(q1); done = true; //if (q1 == q0) { if (DECF1 == DECF0) { stopCode = CostSystemOutcomes.Equilibrium; } else if (q1.TrueForAll(qty => qty == 0.0)) { stopCode = CostSystemOutcomes.ZeroMix; } else if (foundThisDecisionBefore) { stopCode = CostSystemOutcomes.Cycle; } else if (DECF1.Contains(double.NaN)) { stopCode = CostSystemOutcomes.NaN; } else { done = false; } if (!done) { DECF0 = DECF1; q0 = q1; } } while (!done); return(stopCode, DECF1); }
static void Main(string[] args) { #region Console header DrawASCIIart(); #endregion #region Read input file and create InputParameters object FileInfo inputFile = new FileInfo(Environment.CurrentDirectory + @"\input.txt"); if (!inputFile.Exists) { Console.WriteLine("Could not find input file: \n{0}", inputFile.FullName); Console.WriteLine("Aborting. Press ENTER to end the program."); Console.ReadLine(); return; } InputParameters ip = new InputParameters(inputFile); #endregion #region Make a copy of the input file // We found it helpful to make a copy of the input file every time we ran the // simulation. We stamp the copy's filename with the date and time so that // we know which results files correspond to which input file. DateTime dt = DateTime.Now; string inputFileCopyName = String.Format( "input {0:D2}-{1:D2}-{2:D4} {3:D2}h {4:D2}m {5:D2}s, seed {6:G}.txt", dt.Month, dt.Day, dt.Year, dt.Hour, dt.Minute, dt.Second, GenRandNumbers.GetSeed() ); FileInfo inputFileCopy = new FileInfo(Environment.CurrentDirectory + @"\" + inputFileCopyName); inputFile.CopyTo(inputFileCopy.FullName, true); File.SetCreationTime(inputFileCopy.FullName, dt); File.SetLastWriteTime(inputFileCopy.FullName, dt); #endregion #region Create output files Output.CreateOutputFiles(ip); #endregion #region Generate Sample of Firms and their Cost Systems Firm[] sampleFirms = new Firm[ip.NUM_FIRMS]; for (int firmID = 1; firmID <= ip.NUM_FIRMS; ++firmID) { Console.WriteLine( "Starting firm {0:D3} of {1}", firmID + 1, sampleFirms.Length ); Firm f = new Firm(ip, firmID); sampleFirms[firmID - 1] = f; for (int a_indx = 0; a_indx < ip.ACP.Count; ++a_indx) { int a = ip.ACP[a_indx]; for (int p_indx = 0; p_indx < ip.PACP.Count; ++p_indx) { int p = ip.PACP[p_indx]; for (int r_indx = 0; r_indx < ip.PDR.Count; ++r_indx) { int r = ip.PDR[r_indx]; // Create a cost system CostSys costsys = new CostSys(ip, f, a, p, r); f.costSystems.Add(costsys); int costSysID = f.costSystems.Count; Output.LogCostSys(costsys, firmID, costSysID); // Generate a starting decision for the cost system. RowVector startingDecision; if (ip.STARTMIX == 0) { startingDecision = f.CalcOptimalDecision(); } else { var ones = Enumerable.Repeat(1.0, ip.CO).ToList(); startingDecision = new RowVector(ones); for (int i = 0; i < startingDecision.Dimension; ++i) { if (GenRandNumbers.GenUniformDbl() < ip.EXCLUDE) { startingDecision[i] = 0.0; } } } /* Examine error in cost from implementing this decision. * Assume the firm implements the decision startingDecision. Upon * doing so, it will observe total resource consumption. It will then * allocate resources to cost pools, as per the B parameter of the cost * system, choose drivers as per the D parameter of the cost system, * and then allocate resources to cost objects and compute reported costs. * The reported costs are returned as PC_R. The difference * between these and the true benchmark costs (PC_B) is used to compute * the mean percent error in costs. */ RowVector PC_R = costsys.CalcReportedCosts(ip, startingDecision); RowVector PC_B = f.CalcTrueProductCosts(); double MPE = PC_B.Zip(PC_R, (pc_b, pc_r) => Math.Abs(pc_b - pc_r) / pc_b).Sum() / PC_B.Dimension; Output.LogCostSysError(costsys, firmID, costSysID, startingDecision, PC_B, PC_R, MPE); /* Assume the firm implements the decision startingDecision. Upon * doing so, it will observe total resource consumption. It will then * allocate resources to cost pools, as per the B parameter of the cost * system, choose drivers as per the D parameter of the cost system, * and then allocate resources to cost objects and compute reported costs. * The reported costs are returned as PC_R. Upon observing the * reported costs, the firm may wish to update its original decision. When * it implements the updated decision, costs will change again. The outcome * of this process will either be an equilibrium decision (fixed point), or * a cycle of decisions. */ (CostSystemOutcomes stopCode, RowVector endingDecision) = costsys.EquilibriumCheck(ip, startingDecision); Output.LogCostSysLoop(costsys, firmID, costSysID, startingDecision, endingDecision, stopCode); } } } } #endregion Console.WriteLine("Writing output files..."); Output.WriteOutput(); Console.WriteLine("Done!"); }