/// <summary> /// Randomly generates a firm object (production technology and output market parameters). /// </summary> /// <param name="ip">A pointer to the collection of input parameters.</param> /// <param name="FirmID">Unique identifier for this firm (run number)</param> public Firm(InputParameters ip, int FirmID) { // Choose random values for DISP2 (the top DISP1 resources // account for DISP2 percent of total resource costs), and // density (sparsity) of resource consumption pattern matrix this.g = GenRandNumbers.GenUniformDbl(ip.DISP2_MIN, ip.DISP2_MAX); this.d = GenRandNumbers.GenUniformDbl(ip.DNS_MIN, ip.DNS_MAX); // Generate the true product margins and the true, optimal // decision vector. Keep generating new margins until there // is at least one product in the optimal mix. RowVector MAR, DECT0; do { MAR = this.GenMargins(ip); DECT0 = MAR.Map(x => (x < 1.0) ? 0.0 : 1.0); } while (DECT0.TrueForAll(x => x == 0.0)); // Generate vector of maximum production quantities this.mxq = this.GenMXQ(ip); // And associated vector of optimal production quantities ColumnVector QT = mxq.ewMultiply(DECT0); // Flowchart 5.1 - Create resource consumption pattern matrix this.res_cons_pat = GenResConsPat(ip); // Flowchart 5.2 - Compute TRU // Calculate vector of total units of resource // consumption, by product ColumnVector TRU = this.CalcResConsumption(QT); // Flowchart 5.3 - Compute MAXRU // Calculate resource consumption under the assumption // that all products are produced at maximum quantity ColumnVector MAXRU = this.CalcResConsumption(mxq); RowVector RCC, PC_B, RCCN; double TCT0; #region Flowchart 5.4 - Generate RCC, RCU, and RCCN /* -------------------------------- */ // Flowchart 5.4(a)-(g) // Generate vector of total resource costs (RCC) RCC = GenRCC(ip); /* -------------------------------- */ // Flowchart 5.4(h) // Now generate unit resource costs (RCU) by doing element-wise // division of RCC by MAXRU this.rcu = RCC.Map((x, i) => x / MAXRU[i]); /* -------------------------------- */ // Flowchart 5.4(i) // Compute new RCC vector (RCCN) based on unit resource // costs (RCU) and true unit resource consumption (TRU) RCCN = this.rcu.ewMultiply(TRU); // Check to see if the first resource (RCCN[0]) is the largest. // If not, increase RCU[0] by just enough to make it so. if (RCCN[0] < RCCN.Skip(1).Max() + 1) { RCCN[0] = Math.Ceiling(RCCN.Max()) + 1.0; this.rcu[0] = RCCN[0] / TRU[0]; } #endregion // Flowchart 5.5 - Calculate PC_B // Calculate true unit product costs PC_B = this.CalcTrueProductCosts(); // Flowchart 5.6 - Compute total costs TCT0 // Compute total costs TCT0 = this.CalcTotCosts(QT); // Flowchart 5.7 - Rename RCCN to RCC RCC = RCCN; initial_rcc = RCC; #region Flowchart 5.8 - Calculate SP, TRV0, PROFITT0 // Calculate product selling prices, total revenue, and profit this.sp = PC_B.ewMultiply(MAR); double TRV0 = this.sp * QT; this.profitt0 = TRV0 - TCT0; #endregion // 5.9(a) Create RANK vector // Note: this method provides a stable sort. It's important to use a stable sort. // LOOKUP IN VERSION.TXT WHY IT'S IMPORTANT TO USE A STABLE SORT HERE. initial_rank = Enumerable.Range(0, RCC.Dimension).OrderByDescending(i => RCC[i]).ToArray(); #region Flowchart 5.9(b) - Create RES_CONS_PAT_PRCT this.res_cons_pat_prct = new RectangularMatrix(ip.RCP, ip.CO); for (int r = 0; r < this.res_cons_pat.RowCount; ++r) { RowVector rv = this.res_cons_pat.Row(r); if (TRU[r] != 0.0) { rv = rv.Map((alt_ij, col) => alt_ij * QT[col] / TRU[r]); if (Math.Abs(rv.Sum() - 1.0) > 0.01) { throw new ApplicationException("Sum of row of RES_CONS_PAT_PRCT not equal to 1."); } } else { rv = rv.Map(alt_ij => 0.0); } this.res_cons_pat_prct.CopyRowInto(rv, r); } #endregion #region Flowchart 5.9(c) - Create correlation matrix // Create correlation matrix for rows of RES_CONS_PAT_PRCT MultivariateSample mvs = new MultivariateSample(ip.RCP); for (int c = 0; c < this.res_cons_pat_prct.ColumnCount; ++c) { mvs.Add(this.res_cons_pat_prct.Column(c)); } this.pearsoncorr = new SymmetricMatrix(ip.RCP); for (int i = 0; i < mvs.Dimension; ++i) { for (int j = i; j < mvs.Dimension; ++j) { //PearsonCorr[i, j] = mvs.PearsonRTest( i, j ).Statistic; this.pearsoncorr[i, j] = mvs.TwoColumns(i, j).PearsonRTest().Statistic; } } #endregion // Flowchart 5.10 - Logging true system // Note: I'm deliberately passing copies of the fields MXQ, SP, etc. Output.LogFirm( ip, this, FirmID, MAR, DECT0, TRV0, TCT0, profitt0, RCC); }
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!"); }