source: observatorio/simulacion/ModuloDinamico/simulator.C

simulacion
Last change on this file was a0523b8, checked in by Alejandro <amujica@…>, 9 years ago

Correcciones al simulador (segunda validacion)

  • Property mode set to 100644
File size: 33.2 KB
Line 
1/*
2  Copyright (C) 2014
3  Alejandro Mujica (amujica@cenditel.gob.ve)
4  José Ruiz (jruiz@cenditel.gob.ve)
5  Julie Vera (jvera@cenditel.gob.ve)
6 
7  CENDITEL Fundación Centro Nacional de Desarrollo e Investigación en
8  Tecnologías Libres
9 
10  Este programa es software libre; Usted puede usarlo bajo los términos de la
11  licencia de software GPL versión 2.0 de la Free Software Foundation.
12 
13  Este programa se distribuye con la esperanza de que sea útil, pero SIN
14  NINGUNA GARANTÍA; tampoco las implícitas garantías de MERCANTILIDAD o
15  ADECUACIÓN A UN PROPÓSITO PARTICULAR.
16  Consulte la licencia GPL para más detalles. Usted debe recibir una copia
17  de la GPL junto con este programa; si no, escriba a la Free Software
18  Foundation Inc. 51 Franklin Street,5 Piso, Boston, MA 02110-1301, USA.
19*/
20
21/*
22  Autor:             Alejandro J. Mujica
23  Fecha de creación: 14/11/2014
24  Este archivo contiene la implementación de la función que ejecuta la
25  simulación de una red productiva con descrita en un archivo xml. Además
26  contiene funciones de modularización de la simulación. Esta función
27  fue creada con la pretensión de crear el módulo para Python.
28*/
29
30# include <simulator.H>
31
32// Cuenta la cantidad de arcos de salida de un nodo de un grafo.
33size_t count_output_arcs(Graph & network, Graph::Node * node)
34{
35  size_t counter = 0;
36
37  for (Graph::Node_Arc_Iterator it(node); it.has_current(); it.next())
38    {
39      Graph::Arc * arc = it.get_current();
40
41      Graph::Node * src = network.get_src_node(arc);
42
43      // Cuento solamente los arcos para los que el nodo dado es fuente.
44      if (src == node)
45        ++counter;
46    }
47
48  return counter;
49}
50
51/* Crea el estado inicial de simulación para un nodo de tipo producto (productos
52   pertenecientes a UE registradas en SIGESIC).
53*/
54void init_product(Graph & network, Graph::Node * ptr_node)
55{
56  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
57
58  Good * ptr_good = ptr_node->get_info().get();
59
60  size_t num_output_arcs = count_output_arcs(network, ptr_node);
61
62  Product * ptr_product = static_cast<Product *>(ptr_good);
63
64  Product_Simulation_Attributes state_0;
65
66  state_0.state_number = 0;
67  state_0.production = ptr_product->get_production();
68  state_0.stock = 0.0;
69  state_0.internal_sales = ptr_product->get_internal_sales();
70  state_0.external_sales = num_output_arcs == 0 ?
71                           ptr_product->get_production() *
72                           ptr_product->get_price() :
73                           ptr_product->get_external_sales();
74  state_0.internal_requested_quantity =
75    state_0.internal_sales / ptr_product->get_price();
76  state_0.external_requested_quantity =
77    state_0.external_sales / ptr_product->get_price();
78
79  state_0.num_employees = ptr_product->get_num_employees();
80  state_0.daily_wage = exo_var.get_average_salary() / DAYS_IN_A_YEAR;
81  state_0.other_wage = exo_var.get_average_salary() * WAGE_PROPORTION;
82  state_0.other_daily_wage = state_0.other_wage / DAYS_IN_A_YEAR;
83  state_0.daily_feeding_coupon = exo_var.UT_at(0) * UT_PROPORTION;
84  state_0.feeding_coupon = state_0.daily_feeding_coupon * DAYS_IN_A_YEAR;
85  state_0.integral_wage = exo_var.get_average_salary() +
86                          state_0.other_wage + state_0.feeding_coupon;
87
88  state_0.administrative_staff_cost =
89    state_0.integral_wage * ptr_product->get_num_administrative_staff();
90
91  state_0.labor_cost = state_0.integral_wage * state_0.num_employees;
92
93  state_0.input_cost = 0.0;
94
95  for (Graph::Node_Arc_Iterator it(ptr_node); it.has_current(); it.next())
96    {
97      Graph::Arc * ptr_arc = it.get_current();
98
99      Graph::Node * ptr_src_node = network.get_src_node(ptr_arc);
100
101      if (ptr_src_node == ptr_node)
102        continue;
103
104      IP_Relationship & ip_rel = ptr_arc->get_info();
105
106      state_0.input_cost += ip_rel.get_purchase_price() *
107                            ip_rel.get_bought_quantity();
108    }
109
110  state_0.price = ptr_product->get_price();
111
112  state_0.income = state_0.production * state_0.price;
113
114  real partial_cost = state_0.administrative_staff_cost +
115                      state_0.labor_cost + state_0.input_cost;
116
117  state_0.other_cost = std::abs(state_0.income - partial_cost);
118
119  state_0.total_cost = partial_cost + state_0.other_cost;
120
121  state_0.unitarian_administrative_staff_cost =
122    state_0.administrative_staff_cost / state_0.production;
123
124  state_0.unitarian_labor_cost = state_0.labor_cost / state_0.production;
125
126  state_0.input_cost_per_unit = state_0.input_cost / state_0.production;
127
128  state_0.other_unitarian_cost = state_0.other_cost / state_0.production;
129
130  state_0.economic_status = state_0.income - state_0.total_cost;
131
132  ptr_product->add_simulation_attributes(state_0);
133}
134
135/* Crea el estado inicial de simulación para un nodo de tipo insumo (productos
136   pertenecientes a UE nacionales no registradas en SIGESIC).
137*/
138void init_input(Graph::Node * ptr_node)
139{
140  Good * ptr_good = ptr_node->get_info().get();
141
142  Input * ptr_input = static_cast<Input *>(ptr_good);
143
144  Input_Simulation_Attributes state_0;
145
146  state_0.state_number = 0;
147
148  state_0.production = (ptr_input->get_internal_sales() +
149                        ptr_input->get_external_sales()) /
150                        ptr_input->get_price();
151  state_0.stock = 0.0;
152  state_0.internal_sales = ptr_input->get_internal_sales();
153  state_0.external_sales = ptr_input->get_external_sales();
154  state_0.internal_requested_quantity =
155    state_0.internal_sales / ptr_input->get_price();
156  state_0.external_requested_quantity =
157    state_0.external_sales / ptr_input->get_price();
158  state_0.price = ptr_input->get_price();
159
160  ptr_input->add_simulation_attributes(state_0); 
161}
162
163/* Crea el estado inicial de simulación para un nodo de tipo producto importado
164   (productos pertenecientes a UE extranjeras).
165*/
166void init_imported_product(Graph::Node * ptr_node)
167{
168  Good * ptr_good = ptr_node->get_info().get();
169
170  Imported_Product * ptr_imported_product =
171    static_cast<Imported_Product *>(ptr_good);
172
173  Imported_Product_Simulation_Attributes state_0;
174
175  state_0.state_number = 0;
176  state_0.imports = ptr_imported_product->get_imports();
177  state_0.stock = 0.0;
178  state_0.sales = ptr_imported_product->get_sale();
179  state_0.requested_quantity = ptr_imported_product->get_requested_quantity();
180  state_0.price = ptr_imported_product->get_price();
181
182  ptr_imported_product->add_simulation_attributes(state_0);
183}
184
185// Asigna los estados iniciales de simulación para cada nodo y arco del grafo
186void init_network(Graph & network)
187{
188  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
189
190  exo_var.set_average_salary(exo_var.get_average_salary() * NUM_MONTHS);
191
192  for (Graph::Node_Iterator it(network); it.has_current(); it.next())
193    {
194      Graph::Node * ptr_node = it.get_current();
195
196      switch (ptr_node->get_info()->get_type())
197        {
198        case PRODUCT:
199          init_product(network, ptr_node);
200          break;
201
202        case INPUT:
203          init_input(ptr_node);
204          break;
205
206        case IMPORTED_PRODUCT:
207          init_imported_product(ptr_node);
208          break;
209        }
210    }
211
212  for (Graph::Arc_Iterator it(network); it.has_current(); it.next())
213    {
214      Graph::Arc * ptr_arc = it.get_current();
215
216      IP_Relationship & ip_rel = ptr_arc->get_info();
217
218      IP_Simulation_Attributes state_0;
219
220      state_0.state_number = 0;
221
222      state_0.purchase_price = ip_rel.get_purchase_price();
223
224      state_0.bought_quantity = ip_rel.get_bought_quantity();
225
226      ip_rel.add_simulation_attributes(state_0);
227    }
228}
229
230/* Una red productiva es realmente un digrafo, la red fue modelada con grafo
231   para poder efectuar navegación hacia los nodos de atrás. Para esta
232   construcción se asume una convención de que si el nodo s va detrás de t,
233   en un digrafo el arco sería s -> t y en el grafo se respeta ese orden
234   teniendo los arcos s -- t.
235
236   Esta función toma el grafo y lo convierte en un digrafo para aplicar sobre
237   éste el algoritmo de construcción de rangos topológicos.
238
239   En los nodos del digrafo se almacenan los punteros a los nodos del grafo y
240   análogamente se hace con los arcos, pues los rangos topológicos son
241   requeridos para hacer los recorridos por el grafo por cada nivel topológico
242   desde el más alto hasta el más bajo, pero finalmente el proceso de simulación
243   se efectúa sobre los nodos del grafo (y no los del digrafo) porque se
244   requiere navegación hacia atrás.
245*/
246void graph_to_digraph(Graph & graph, Digraph & digraph)
247{
248  Map<Graph::Node *, Digraph::Node *> map;
249
250  for (Graph::Node_Iterator it(graph); it.has_current(); it.next())
251    {
252      Graph::Node * p = it.get_current();
253
254      Digraph::Node * q = digraph.insert_node(p);
255
256      map.insert(p, q);
257    }
258
259  for (Graph::Arc_Iterator it(graph); it.has_current(); it.next())
260    {
261      Graph::Arc * a = it.get_current();
262
263      Graph::Node * gs = graph.get_src_node(a);
264      Graph::Node * gt = graph.get_tgt_node(a);
265
266      Digraph::Node * ds = map.find(gs);
267      Digraph::Node * dt = map.find(gt);
268
269      digraph.insert_arc(ds, dt, a);
270    }
271}
272
273// Libera las listas que almacenan cada nivel topológico.
274void free_ranks(Rank_Type & ranks)
275{
276  for (Rank_Type::Iterator it(ranks); it.has_current(); it.next())
277    delete it.get_current();
278}
279
280
281/* Trunca la producción en el nodo según lo que permitan los insumos, la
282   cantidad requeridad de cada insumo se añade a la demanda interna del insumo,
283   una vez  que se tiene la cantidad posible de producción, se actualiza la
284   cantidad comprada en la relación a la cantidad que realmente necesita, lo que
285   sobre de cada arco se añade al stock del proveedor.
286*/
287void truncate_production_by_inputs(Graph & network, Graph::Node * node,
288                                   const size_t & t)
289{
290  Good * ptr_good = node->get_info().get();
291
292  // Inicializo la máxima producción posible en tendiendo a infinito
293  real max_possible_production = std::numeric_limits<real>::max();
294
295  // Producción deseada por el nodo.
296  real & production = ptr_good->production_at(t);
297
298  // Recorro los arcos de entrada
299  for (Graph::Node_Arc_Iterator it(node); it.has_current(); it.next())
300    {
301      Graph::Arc * arc = it.get_current();
302
303      Graph::Node * src_node = network.get_src_node(arc);
304
305      // Ignoro los arcos de salida
306      if (src_node == node)
307        continue;
308
309      IP_Relationship & ip_rel = arc->get_info();
310
311      IP_Simulation_Attributes & ip_sim_attr =
312        ip_rel.get_simulation_attributes_at(t);
313
314      // Cantidad requerida del proveedor.
315      real requested_quantity = production * ip_rel.get_requested_quantity();
316
317      // Incrementa la demanda interna al proveedor
318      src_node->get_info()->internal_requested_quantity_at(t) +=
319        requested_quantity;
320
321      I(ip_sim_attr.bought_quantity > 0.0);
322
323      real possible_production = ip_rel.get_requested_quantity() *
324                                 ip_sim_attr.bought_quantity;
325
326      if (possible_production == 0.0)
327        {
328          std::cout << "RQ: " << ip_rel.get_requested_quantity() << " - "
329                    << "BQ: " << ip_sim_attr.bought_quantity << '\n';
330        }
331
332      // Se actualiza la máxima producción posible.
333      if (possible_production < max_possible_production)
334        max_possible_production = possible_production;
335    }
336
337  /* Aquí trunco la producción con el mínimo entre máxima producción posible y
338     la producción actual.
339  */
340  production = std::min<real>(production, max_possible_production);
341
342  /* Nuevamente recorro los arcos de entrada para asignar la cantidad que
343     realmente comprará del insumo.
344  */
345  for (Graph::Node_Arc_Iterator it(node); it.has_current(); it.next())
346    {
347      Graph::Arc * arc = it.get_current();
348
349      Graph::Node * src_node = network.get_src_node(arc);
350
351      // Ignoro los arcos de salida
352      if (src_node == node)
353        continue;
354
355      IP_Relationship & ip_rel = arc->get_info();
356
357      IP_Simulation_Attributes & ip_sim_attr =
358        ip_rel.get_simulation_attributes_at(t);
359
360      // Cantidad que comprará.
361      real requested_quantity = production * ip_rel.get_requested_quantity();
362
363      /* La diferencia entre la cantidad en el arco y la cantidad que comprará
364         se almacena en el stock del proveedor. cantidad en arco >= cantidad
365         que comprará.
366      */
367      real diff = ip_sim_attr.bought_quantity - requested_quantity;
368
369      ip_sim_attr.bought_quantity = requested_quantity;
370
371      src_node->get_info()->stock_at(t) += diff;
372
373      src_node->get_info()->internal_sales_at(t) += ip_sim_attr.bought_quantity;
374  }
375}
376
377/* Distribuye la cantidad de producto que el nodo tenga para vender en la red
378   hacia sus arcos de salida. El valor se asigna en la variable que almacena la
379   cantidad comprada, sin embargo, cuando el nodo comprador 'decida' cuánto
380   producto generará, actualizará estos valores a la cantidad que realmente
381   necesite comprar.
382
383   La distribución de la cantidad se hace proporcional a los montos pagados por
384   cada comprador en el estado de simulación anterior.
385*/
386void distribute_internal_production(Graph & network, Graph::Node * node,
387                                    const real & internal_quantity,
388                                    const size_t & t)
389{
390  real total_amount = 0.0;
391
392  for (Graph::Node_Arc_Iterator it(node); it.has_current(); it.next())
393    {
394      Graph::Arc * arc = it.get_current();
395
396      Graph::Node * tgt_node = network.get_tgt_node(arc);
397
398      if (tgt_node == node)
399        continue;
400
401      // Añado atributos de simulación para el tiempo t.
402      IP_Simulation_Attributes & ip_sim_attr_t =
403        arc->get_info().add_simulation_attributes(IP_Simulation_Attributes());
404
405      ip_sim_attr_t.state_number = t;
406
407      IP_Simulation_Attributes & ip_sim_attr_t_1 =
408        arc->get_info().get_simulation_attributes_at(t - 1);
409
410      total_amount += (ip_sim_attr_t_1.bought_quantity *
411                       ip_sim_attr_t_1.purchase_price);
412    }
413
414  for (Graph::Node_Arc_Iterator it(node); it.has_current(); it.next())
415    {
416      Graph::Arc * arc = it.get_current();
417
418      Graph::Node * tgt_node = network.get_tgt_node(arc);
419
420      if (tgt_node == node)
421        continue;
422
423      IP_Simulation_Attributes & ip_sim_attr_t =
424        arc->get_info().get_simulation_attributes_at(t);
425
426      IP_Simulation_Attributes & ip_sim_attr_t_1 =
427        arc->get_info().get_simulation_attributes_at(t - 1);
428
429      real amount = ip_sim_attr_t_1.bought_quantity *
430                    ip_sim_attr_t_1.purchase_price;
431
432      I(internal_quantity > 0.0);
433
434      I(total_amount > 0.0);
435
436      real proportion = total_amount == 0.0 ? 0.0 : amount / total_amount;
437
438      ip_sim_attr_t.bought_quantity = internal_quantity * proportion;
439
440      I(ip_sim_attr_t.bought_quantity > 0.0);
441    }
442}
443
444/* Función de redondeo especial.
445
446   Un número real se puede dividir en parte entera + parte decimal, si la parte
447   decimal es menor que 0.5 entonces se redondea a 0.5, de lo contrario se
448   redondea a 1.
449
450   Para el número de empleados requeridos por una UE, tener 0.5 empleados quiere
451   decir que tiene un empleado contratado a medio tiempo.
452*/
453real special_round(const real & num)
454{
455  long int_part = (long) num;
456
457  real dec_part = num - (real) int_part;
458
459  I(dec_part < 1);
460
461  if (dec_part == 0.0)
462    return (real) int_part;
463  else if (dec_part < 0.5)
464    return (real) int_part + 0.5;
465  else
466    return (real) int_part + 1.0;
467}
468
469/* Functor para calcular la demanda externa para nodos de cualquier nivel
470   topológico en la red excepto los del último nivel.
471*/
472struct Any_Level_Node
473{
474  void operator () (Product_Simulation_Attributes & sat,
475                    Product_Simulation_Attributes & sat_1, gsl_rng * rng,
476                    const size_t &)
477  {
478    sat.external_requested_quantity =
479      sat_1.external_requested_quantity * RANDOM_UNIF(0.0, 2.0);
480  }
481};
482
483/* Functor para calcular la demanda externa para nodos de cualquier del último
484   nivel topológico en la red.
485*/
486struct Last_Level_Node
487{
488  void operator () (Product_Simulation_Attributes & sat,
489                    Product_Simulation_Attributes & sat_1, gsl_rng *,
490                    const size_t & t)
491  {
492    Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
493
494    sat.external_requested_quantity =
495      sat_1.external_requested_quantity *
496      (1.0 + exo_var.rate_of_change_in_final_demand_at(t) / 100.0);
497  }
498};
499
500/* Calcula la nueva producción para un nodo de tipo producto.
501
502   La función es de tipo plantilla para pasar como parámetro el functor de
503   cálculo de la demanda externa, éste cálculo cambia cuando se trata de un nodo
504   del último nivel topológico respecto a lo de los otros niveles.
505*/
506template <class Update_External_Request>
507void compute_product_production(Graph & network, Graph::Node * node,
508                                const size_t & t, gsl_rng * rng)
509{
510  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
511
512  Good * ptr_good = node->get_info().get();
513
514  Product * ptr_product = static_cast<Product *>(ptr_good);
515
516  Product_Simulation_Attributes & sim_attr_t =
517    ptr_product->add_simulation_attributes(Product_Simulation_Attributes());
518
519  sim_attr_t.state_number = t;
520
521  Product_Simulation_Attributes & sim_attr_t_1 =
522    ptr_product->get_simulation_attributes_at(t - 1);
523
524  real total_requested_quantity = sim_attr_t_1.internal_requested_quantity +
525                                  sim_attr_t_1.external_requested_quantity;
526
527  // Media para la nueva producción: cantidad total demandada - stock.
528  real mean = total_requested_quantity - sim_attr_t_1.stock;
529
530  // Varianza para la nueva producción.
531  const real sigma = mean * exo_var.get_sigma() / 100.0;
532
533  // La nueva producción viene dada por el valor aleatorio.
534  real new_production = std::max<real>(0.0, RANDOM_NORMAL(mean, sigma));
535
536  sim_attr_t.production =
537    std::min<real>(new_production, ptr_product->get_production_capacity());
538
539  truncate_production_by_inputs(network, node, t);
540
541  // Cantidad de producto disponible para venta.
542  real available_quantity = sim_attr_t.production + sim_attr_t_1.stock;
543
544  // Proporción de demanda interna.
545  real internal_request_proportion =
546    sim_attr_t_1.internal_requested_quantity / total_requested_quantity;
547
548  // Cantidad para repartir a los arcos.
549  real internal_quantity = available_quantity * internal_request_proportion;
550
551  distribute_internal_production(network, node, internal_quantity, t);
552
553  // Cantidad para satisfacer demanda externa.
554  real external_quantity = available_quantity - internal_quantity;
555
556  /* Asigno a las ventas externas el valor mínimo entre demanda externa en
557     (t- 1)y lo que tenga de producción para satisfacer la demanda externa.
558  */
559  sim_attr_t.external_sales =
560    std::min<real>(external_quantity, sim_attr_t_1.external_requested_quantity);
561
562  // Almaceno en stock lo que quede de las ventas externas.
563  real diff =  external_quantity - sim_attr_t.external_sales;
564  sim_attr_t.stock += diff;
565
566  // Calculo la nueva demanda externa.
567  Update_External_Request()(sim_attr_t, sim_attr_t_1, rng, t);
568
569  /* Calcular número de personal
570
571     cantidad de horas(t) = producción(t) * relación horas-hombre.
572
573     cantidad de empleados = cantidad de horas(t) / (jornada * 231)
574
575     La cantidad de empleados es un número real el cual puede ser dividido en
576     su parte entera y decimal, si la parte decimal es mayor que 0 y menor que
577     0.5 entonces ésta se redondea a 0.5, de lo contrario se redondea a 1.
578
579     La parte decimal en 0.5 representa un empleado a medio tiempo.
580   */
581  real requested_num_hours = sim_attr_t.production *
582                             ptr_product->get_relationship_manhours();
583
584  real num_employees = requested_num_hours /
585                       (ptr_product->get_workday() * WORKED_DAYS_IN_A_YEAR);
586
587  sim_attr_t.num_employees = special_round(num_employees);
588}
589
590// Calcula la nueva producción para un nodo de tipo insumo.
591void compute_input_production(Graph & network, Graph::Node * node,
592                              const size_t & t, gsl_rng * rng)
593{
594  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
595
596  Good * ptr_good = node->get_info().get();
597
598  Input * ptr_input = static_cast<Input *>(ptr_good);
599
600  Input_Simulation_Attributes & sim_attr_t =
601    ptr_input->add_simulation_attributes(Input_Simulation_Attributes());
602
603  sim_attr_t.state_number = t;
604
605  Input_Simulation_Attributes & sim_attr_t_1 =
606    ptr_input->get_simulation_attributes_at(t - 1);
607
608  real total_requested_quantity = sim_attr_t_1.internal_requested_quantity +
609                                  sim_attr_t_1.external_requested_quantity;
610
611  // Media para la nueva producción: cantidad total demandada - stock.
612  real mean = total_requested_quantity - sim_attr_t_1.stock;
613
614  // Varianza para la nueva producción.
615  const real sigma = mean * exo_var.get_sigma() / 100.0;
616
617  // La nueva producción viene dada por el valor aleatorio.
618  sim_attr_t.production = std::max<real>(0.0, RANDOM_NORMAL(mean, sigma));
619
620  // Cantidad de producto disponible para venta.
621  real available_quantity = sim_attr_t.production + sim_attr_t_1.stock;
622
623  // Proporción de demanda interna.
624  real internal_request_proportion =
625    sim_attr_t_1.internal_requested_quantity / total_requested_quantity;
626
627  // Cantidad para repartir a los arcos.
628  real internal_quantity = available_quantity * internal_request_proportion;
629
630  distribute_internal_production(network, node, internal_quantity, t);
631
632  // Cantidad para satisfacer demanda externa.
633  real external_quantity = available_quantity - internal_quantity;
634
635  /* Asigno a las ventas externas el valor mínimo entre demanda externa en
636     (t- 1)y lo que tenga de producción para satisfacer la demanda externa.
637  */
638  sim_attr_t.external_sales =
639    std::min<real>(external_quantity, sim_attr_t_1.external_requested_quantity);
640
641  // Calculo la nueva demanda externa.
642  sim_attr_t.external_requested_quantity =
643    sim_attr_t_1.external_requested_quantity * RANDOM_UNIF(0.0, 2.0);
644
645  // Almaceno en stock lo que quede de las ventas externas.
646  real diff =  external_quantity - sim_attr_t.external_sales;
647
648  sim_attr_t.stock += diff;
649}
650
651// Calcula la nueva producción para un nodo de tipo producto importado.
652void compute_imported_product_production(Graph & network, Graph::Node * node,
653                                         const size_t & t, gsl_rng * rng)
654{
655  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
656
657  Good * ptr_good = node->get_info().get();
658
659  Imported_Product * ptr_imported_product =
660    static_cast<Imported_Product *>(ptr_good);
661
662  Imported_Product_Simulation_Attributes & sim_attr_t =
663    ptr_imported_product->add_simulation_attributes(
664      Imported_Product_Simulation_Attributes()
665    );
666
667  sim_attr_t.state_number = t;
668
669  Imported_Product_Simulation_Attributes & sim_attr_t_1 =
670    ptr_imported_product->get_simulation_attributes_at(t - 1);
671
672  // Media para la nueva producción: cantidad total demandada - stock.
673  real mean = sim_attr_t_1.requested_quantity - sim_attr_t_1.stock;
674
675  // Varianza para la nueva producción.
676  const real sigma = mean * exo_var.get_sigma() / 100.0;
677
678  // La nueva producción viene dada por el valor aleatorio.
679  sim_attr_t.imports = std::max<real>(0.0, RANDOM_NORMAL(mean, sigma));
680
681  // Cantidad de producto disponible para venta.
682  real available_quantity = sim_attr_t.imports + sim_attr_t_1.stock;
683
684  distribute_internal_production(network, node, available_quantity, t);
685}
686
687/* Recorre los rangos topológicos de la red productiva para calcular las nuevas
688   producciones en cada nodo.
689
690   Para los nodos de tipo producto se cuentan los arcos de salida, si no tiene,
691   entonces se llama a la función de cálculo para productos con el functor de
692   cálculo de demanda externa para nodos de último nivel. En caso contrario se
693   llama a la función con el functor que calcula la demanda externa para nodos
694   que no son del último nivel.
695*/
696void compute_productions(Graph & network, Rank_Type & ranks, const size_t & t,
697                         gsl_rng * rng)
698{
699  for (Rank_Type::Iterator it(ranks); it.has_current(); it.next())
700    {
701      Level * level = it.get_current();
702
703      for (Level::Iterator lit(*level); lit.has_current(); lit.next())
704        {
705          Digraph::Node * dnode = lit.get_current();
706
707          Graph::Node * node = dnode->get_info();
708
709          switch (node->get_info()->get_type())
710            {
711            case PRODUCT:
712              if (count_output_arcs(network, node) == 0)
713                compute_product_production<Last_Level_Node>(network, node, t,
714                                                            rng);             
715              else
716                compute_product_production<Any_Level_Node>(network, node, t,
717                                                           rng);
718              break;
719            case INPUT:
720              compute_input_production(network, node, t, rng);
721              break;
722            case IMPORTED_PRODUCT:
723              compute_imported_product_production(network, node, t, rng);
724              break;
725            }
726        }
727    }
728}
729
730/* Actualiza los precios de venta de los productos en los arcos de salida. El
731   nuevo precio de venta es el precio unitario del producto (costo total de
732   producción) agregándole el porcentaje de ganancia.
733*/
734void update_price_in_output_arcs(Graph & network, Graph::Node * node,
735                                 const size_t & t)
736{
737  const real & new_price = node->get_info()->price_at(t);
738
739  for (Graph::Node_Arc_Iterator it(node); it.has_current(); it.next())
740    {
741      Graph::Arc * arc = it.get_current();
742
743      Graph::Node * tgt = network.get_tgt_node(arc);
744
745      // Ignoro arcos de entrada
746      if (node == tgt)
747        continue;
748
749      IP_Relationship & ip_rel = arc->get_info();
750
751      IP_Simulation_Attributes & sim_attr =
752        ip_rel.get_simulation_attributes_at(t);
753
754      // Al precio de venta se le incrementa la tasa de ganancia.
755      sim_attr.purchase_price = new_price;
756    }
757}
758
759// Cálcula el costo de insumos para un producto.
760real compute_input_cost(Graph & network, Graph::Node * node, const size_t & t)
761{
762  real input_cost = 0.0;
763
764  for (Graph::Node_Arc_Iterator it(node); it.has_current(); it.next())
765    {
766      Graph::Arc * arc = it.get_current();
767
768      Graph::Node * src = network.get_src_node(arc);
769
770      // Ignoro arcos de salida
771      if (node == src)
772        continue;
773
774      IP_Relationship & ip_rel = arc->get_info();
775
776      IP_Simulation_Attributes & sim_attr =
777        ip_rel.get_simulation_attributes_at(t);
778
779      input_cost += (sim_attr.purchase_price * sim_attr.bought_quantity);
780    }
781
782  return input_cost;
783}
784
785/* Calcula los nuevos costos para un nodo de tipo producto, los nuevos salarios
786   y el costo unitario de producción.
787*/
788void compute_product_price(Graph & network, Graph::Node * node,
789                           const size_t & t)
790{
791  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
792
793  Good * ptr_good = node->get_info().get();
794
795  Product * ptr_product = static_cast<Product *>(ptr_good);
796
797  Product_Simulation_Attributes & sim_attr_t =
798    ptr_product->get_simulation_attributes_at(t);
799
800  Product_Simulation_Attributes & sim_attr_t_1 =
801    ptr_product->get_simulation_attributes_at(t - 1);
802
803  // Actualización de salarios
804
805  sim_attr_t.daily_wage = sim_attr_t_1.daily_wage *
806                         (1.0 + exo_var.rate_of_change_of_salary_at(t) / 100.0);
807
808  // Nuevo salario anual
809  real wage = sim_attr_t.daily_wage * DAYS_IN_A_YEAR;
810
811  sim_attr_t.other_wage = wage * WAGE_PROPORTION;
812  sim_attr_t.other_daily_wage = sim_attr_t.other_wage / DAYS_IN_A_YEAR;
813
814  sim_attr_t.daily_feeding_coupon = exo_var.UT_at(t) * UT_PROPORTION;
815
816  sim_attr_t.feeding_coupon = sim_attr_t.daily_feeding_coupon * DAYS_IN_A_YEAR;
817
818  sim_attr_t.integral_wage = wage + sim_attr_t.other_wage +
819                             sim_attr_t.feeding_coupon;
820
821  // Actualización de costos
822
823  // Cálculo de costos administrativos
824  sim_attr_t.administrative_staff_cost =
825    ptr_product->get_num_administrative_staff() * sim_attr_t.integral_wage;
826  sim_attr_t.unitarian_administrative_staff_cost =
827    sim_attr_t.administrative_staff_cost / sim_attr_t.production;
828
829  // Cálculo de costos en mano de obra
830  sim_attr_t.labor_cost = sim_attr_t.num_employees * sim_attr_t.integral_wage;
831  sim_attr_t.unitarian_labor_cost =
832    sim_attr_t.labor_cost / sim_attr_t.production;
833
834    // Actualización de costo de insumos.
835  real input_cost = compute_input_cost(network, node, t);
836
837  if (input_cost == 0.0) // No tenía insumos, cambia por tasa de precios
838    sim_attr_t.input_cost = sim_attr_t_1.input_cost *
839                            (1.0 + exo_var.rate_of_price_change_at(t) / 100.0);
840  else
841    sim_attr_t.input_cost = input_cost;
842
843  sim_attr_t.input_cost_per_unit =
844    sim_attr_t.input_cost / sim_attr_t.production;
845
846  // Actualización de otros costos
847  sim_attr_t.other_cost = sim_attr_t_1.other_cost *
848                          (1.0 + exo_var.rate_of_price_change_at(t) / 100.0);
849  sim_attr_t.other_unitarian_cost =
850    sim_attr_t.other_cost / sim_attr_t.production;
851
852  sim_attr_t.total_cost = sim_attr_t.administrative_staff_cost +
853                          sim_attr_t.labor_cost + sim_attr_t.input_cost +
854                          sim_attr_t.other_cost;
855
856  sim_attr_t.price = (sim_attr_t.unitarian_administrative_staff_cost +
857                     sim_attr_t.unitarian_labor_cost +
858                     sim_attr_t.input_cost_per_unit +
859                     sim_attr_t.other_unitarian_cost)  *
860                     (1.0 + exo_var.rate_of_gain_at(t) / 100.0);
861
862  sim_attr_t.internal_sales *= sim_attr_t.price;
863
864  sim_attr_t.external_sales *= sim_attr_t.price;
865
866  update_price_in_output_arcs(network, node, t);
867
868  sim_attr_t.economic_status = sim_attr_t.income - sim_attr_t.total_cost;
869}
870
871// Calcula el costo unitario de producción para un nodo de tipo insumo.
872void compute_input_price(Graph & network, Graph::Node * node,
873                         const size_t & t)
874{
875  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
876
877  Good * ptr_good = node->get_info().get();
878
879  Input * ptr_input = static_cast<Input *>(ptr_good);
880
881  Input_Simulation_Attributes & sim_attr_t =
882    ptr_input->get_simulation_attributes_at(t);
883
884  Input_Simulation_Attributes & sim_attr_t_1 =
885    ptr_input->get_simulation_attributes_at(t - 1);
886
887  sim_attr_t.price = sim_attr_t_1.price *
888                     (1.0 + exo_var.rate_of_price_change_at(t) / 100.0);
889
890  sim_attr_t.internal_sales *= sim_attr_t.price;
891
892  sim_attr_t.external_sales *= sim_attr_t.price;
893
894  update_price_in_output_arcs(network, node, t);
895}
896
897/* Calcula el costo unitario de producción para un nodo de tipo producto
898   importado.
899*/
900void compute_imported_product_price(Graph & network, Graph::Node * node,
901                                    const size_t & t)
902{
903  Exogenous_Variables & exo_var = Exogenous_Variables::get_instance();
904
905  Good * ptr_good = node->get_info().get();
906
907  Imported_Product * ptr_imported_product =
908    static_cast<Imported_Product *>(ptr_good);
909
910  Imported_Product_Simulation_Attributes & sim_attr_t =
911    ptr_imported_product->get_simulation_attributes_at(t);
912
913  Imported_Product_Simulation_Attributes & sim_attr_t_1 =
914    ptr_imported_product->get_simulation_attributes_at(t - 1);
915
916  sim_attr_t.price = sim_attr_t_1.price *
917                     (1.0 + exo_var.nominal_exchange_rate_at(t) / 100.0);
918
919  update_price_in_output_arcs(network, node, t);
920}
921
922/* Recorre los rangos topológicos de la red productiva para calcular los nuevos
923   precios en cada nodo.
924*/
925void compute_new_prices(Graph & network, Rank_Type & ranks,
926                        const size_t & t)
927{
928  for (Rank_Type::Iterator it(ranks); it.has_current(); it.next())
929    {
930      Level * level = it.get_current();
931
932      for (Level::Iterator lit(*level); lit.has_current(); lit.next())
933        {
934          Digraph::Node * dnode = lit.get_current();
935
936          Graph::Node * node = dnode->get_info();
937
938          switch (node->get_info()->get_type())
939            {
940            case PRODUCT:
941              compute_product_price(network, node, t);
942              break;
943            case INPUT:
944              compute_input_price(network, node, t);
945              break;
946            case IMPORTED_PRODUCT:
947              compute_imported_product_price(network, node, t);
948              break;
949            }
950        }
951    }
952}
953
954/* Función que efectúa la simulación sobre la red productiva descrita en un
955   archivo xml.
956*/
957int simulate(const char * const input_file_name,
958             const char * const output_file_name)
959{
960  // Inicialización del generador de números aleatorios.
961  gsl_rng * rng = gsl_rng_alloc(gsl_rng_mt19937);
962  gsl_rng_set(rng, time(0));
963
964  Graph network;
965
966  Digraph aux_network;
967
968  Rank_Type ranks;
969
970  IO_Manager io_manager;
971
972  // Lectura del grafo descrito en el archivo xml.
973  io_manager.read_graph_from_xml(input_file_name, network);
974
975  // Lectura de las variables exógenas del sistema descritas en el archivo xml.
976  io_manager.load_exogenous_variables_from_xml(input_file_name);
977
978  // Asignación de valores al estado inicial de la simulación.
979  init_network(network);
980
981  // Conversión de grafo a digrafo.
982  graph_to_digraph(network, aux_network);
983
984  // Cálculo de los rangos topológicos.
985  Q_Topological_Sort<Digraph>()(aux_network, ranks);
986
987  const size_t & max_t = Exogenous_Variables::get_instance().get_num_it();
988
989  // Bucle de la simulación.
990  for (size_t t = 1; t <= max_t; ++t)
991    {
992      compute_productions(network, ranks, t, rng);
993
994      compute_new_prices(network, ranks, t);
995    }
996
997  // Libera la memoria rangos topológicos.
998  free_ranks(ranks);
999
1000  // Libera la memoria del generador de números aleatorios.
1001  gsl_rng_free(rng); 
1002
1003  // Escribe la red
1004  io_manager.add_sim_graph_to_xml(network, input_file_name, output_file_name);
1005
1006  return 0;
1007}
1008
Note: See TracBrowser for help on using the repository browser.