1 /* Copyright (c) 2012 Massachusetts Institute of Technology
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 #include "model/Model.h"
26 #include "util/Result.h"
31 using LibUtil::deletePtrMap
;
32 using LibUtil::clonePtrMap
;
34 Model::SubModel::SubModel(Model
* model_
, double num_models_
)
35 : m_model_(model_
), m_num_models_(num_models_
)
38 Model::SubModel::~SubModel()
43 Model
* Model::SubModel::getModel()
48 const Model
* Model::SubModel::getModel() const
53 double Model::SubModel::getNumModels() const
58 Model::SubModel
* Model::SubModel::clone() const
60 return new SubModel(*this);
63 Model::SubModel::SubModel(const SubModel
& sub_model_
)
65 m_model_
= sub_model_
.m_model_
->clone();
66 m_num_models_
= sub_model_
.m_num_models_
;
69 const char Model::TYPE_SEPARATOR
[] = ">>";
70 const char Model::HIERARCHY_SEPARATOR
[] = "->";
71 const char Model::SUBFIELD_SEPARATOR
[] = ":";
72 const char Model::DETAIL_SEPARATOR
[] = "@";
74 Model::Model(const String
& instance_name_
, const TechModel
* tech_model_
)
75 : m_instance_name_(instance_name_
), m_tech_model_(tech_model_
),
76 m_constructed_(false), m_updated_(false), m_evaluated_(false)
78 m_property_names_
= new vector
<String
>;
79 m_parameter_names_
= new vector
<String
>;
80 m_parameters_
= new ParameterMap();
81 m_properties_
= new PropertyMap();
82 m_generated_properties_
= new PropertyMap();
83 m_sub_instances_
= new Map
<SubModel
*>();
84 m_event_map_
= new Map
<Result
*>();
85 m_area_map_
= new Map
<Result
*>();
86 m_ndd_power_map_
= new Map
<Result
*>();
91 // Clear parameter names
92 delete m_parameter_names_
;
93 // Clear property name
94 delete m_property_names_
;
99 // Clear input properties
100 delete m_properties_
;
101 m_properties_
= NULL
;
103 // Clear generated properties
104 delete m_generated_properties_
;
105 m_generated_properties_
= NULL
;
108 deletePtrMap
<SubModel
>(m_sub_instances_
);
109 m_sub_instances_
= NULL
;
112 deletePtrMap
<Result
>(m_event_map_
);
114 deletePtrMap
<Result
>(m_area_map_
);
116 deletePtrMap
<Result
>(m_ndd_power_map_
);
117 m_ndd_power_map_
= NULL
;
120 void Model::setInstanceName(const String
& instance_name_
)
122 m_instance_name_
= instance_name_
;
126 const String
& Model::getInstanceName() const
128 return m_instance_name_
;
131 void Model::setIsTopModel(bool is_top_model_
)
133 m_is_top_model_
= is_top_model_
;
137 bool Model::getIsTopModel() const
139 return m_is_top_model_
;
142 //-------------------------------------------------------------------------
143 // Parameters and properties checks
144 //-------------------------------------------------------------------------
145 void Model::addParameterName(const String
& parameter_name_
)
147 ASSERT(!m_constructed_
, "[Error] " + getInstanceName() +
148 " -> Cannot add additional parameters names after model is constructed!");
149 m_parameter_names_
->push_back(parameter_name_
);
154 void Model::addParameterName(const String
& parameter_name_
, const String
& parameter_default_
)
156 ASSERT(!m_constructed_
, "[Error] " + getInstanceName() +
157 " -> Cannot add additional parameters names after model is constructed!");
158 m_parameter_names_
->push_back(parameter_name_
);
159 setParameter(parameter_name_
, parameter_default_
);
163 const vector
<String
>* Model::getParameterNames() const
165 return m_parameter_names_
;
168 void Model::addPropertyName(const String
& property_name_
)
170 ASSERT(!m_constructed_
, "[Error] " + getInstanceName() +
171 " -> Cannot add additional property names after model is constructed!");
172 m_property_names_
->push_back(property_name_
);
176 void Model::addPropertyName(const String
& property_name_
, const String
& property_default_
)
178 ASSERT(!m_constructed_
, "[Error] " + getInstanceName() +
179 " -> Cannot add additional property names after model is constructed!");
180 m_property_names_
->push_back(property_name_
);
181 setProperty(property_name_
, property_default_
);
185 const vector
<String
>* Model::getPropertyNames() const
187 return m_property_names_
;
190 void Model::checkParameters() const
192 String missing_parameters
= "";
194 for(int i
= 0; i
< (int)m_parameter_names_
->size(); ++i
)
196 const String
& parameter_name
= m_parameter_names_
->at(i
);
197 if (!m_parameters_
->keyExist(parameter_name
))
198 missing_parameters
+= " " + parameter_name
+ "\n";
201 ASSERT(missing_parameters
.size() == 0, "[Error] " + m_instance_name_
+
202 " -> Missing parameters:\n" + missing_parameters
);
206 void Model::checkProperties() const
208 String missing_properties
= "";
210 for(int i
= 0; i
< (int)m_property_names_
->size(); ++i
)
212 const String
& property_name
= m_property_names_
->at(i
);
213 if (!m_properties_
->keyExist(property_name
))
214 missing_properties
+= " " + property_name
+ "\n";
217 ASSERT(missing_properties
.size() == 0, "[Error] " + m_instance_name_
+
218 " -> Missing properties:\n" + missing_properties
);
221 //-------------------------------------------------------------------------
223 //-------------------------------------------------------------------------
224 // Parameters Manipulation
225 //-------------------------------------------------------------------------
226 const ParameterMap
* Model::getParameters() const
228 return m_parameters_
;
231 const String
Model::getParameter(const String
& parameter_name_
) const
233 return m_parameters_
->get(parameter_name_
);
236 void Model::setParameter(const String
& parameter_name_
, const String
& parameter_value_
)
238 ASSERT(!m_constructed_
, "[Error] " + getInstanceName() +
239 " -> Cannot set parameters after model is constructed!");
240 m_parameters_
->set(parameter_name_
, parameter_value_
);
242 //-------------------------------------------------------------------------
244 //-------------------------------------------------------------------------
245 // Properties Manipulation
246 //-------------------------------------------------------------------------
247 const PropertyMap
* Model::getProperties() const
249 return m_properties_
;
252 const String
Model::getProperty(const String
& property_name_
) const
254 return m_properties_
->get(property_name_
);
257 void Model::setProperty(const String
& property_name_
, const String
& property_value_
)
259 // If any properties changed, reset updated and evaluated flags
261 m_evaluated_
= false;
262 m_properties_
->set(property_name_
, property_value_
);
264 //-------------------------------------------------------------------------
266 PropertyMap
* Model::getGenProperties()
268 return m_generated_properties_
;
271 const PropertyMap
* Model::getGenProperties() const
273 return m_generated_properties_
;
276 void Model::addSubInstances(Model
* sub_instance_
, double num_sub_instances_
)
279 const String
& sub_instance_name
= sub_instance_
->getInstanceName();
281 // Check if the instance exists
282 if(m_sub_instances_
->keyExist(sub_instance_name
))
284 const String
& error_msg
= "[Error] " + m_instance_name_
+
285 " -> Instance exists (" + sub_instance_name
+ ")";
286 throw Exception(error_msg
);
289 // Check if the num_sub_instances_ is a positive number
290 ASSERT((num_sub_instances_
>= 0), "[Error] " + m_instance_name_
+
291 " -> Invalid number of instance (" + String(num_sub_instances_
) + ")");
294 m_sub_instances_
->set(sub_instance_name
, new SubModel(sub_instance_
, num_sub_instances_
));
298 Model
* Model::getSubInstance(const String
& sub_instance_name_
)
300 // Throw an Exception if the instance already exists
301 if(!m_sub_instances_
->keyExist(sub_instance_name_
))
303 const String
& error_msg
= "[Error] " + m_instance_name_
+
304 " -> Instance not exists (" + sub_instance_name_
+ ")";
305 throw Exception(error_msg
);
308 return m_sub_instances_
->get(sub_instance_name_
)->getModel();
311 const Model
* Model::getSubInstance(const String
& sub_instance_name_
) const
313 // Throw an Exception if the instance does not exist
314 if(!m_sub_instances_
->keyExist(sub_instance_name_
))
316 const String
& error_msg
= "[Error] " + m_instance_name_
+
317 " -> Instance not exists (" + sub_instance_name_
+ ")";
318 throw Exception(error_msg
);
321 return m_sub_instances_
->get(sub_instance_name_
)->getModel();
324 bool Model::hasSubInstance(const String
& sub_instance_name_
) const
326 return m_sub_instances_
->keyExist(sub_instance_name_
);
329 void Model::addAreaResult(Result
* area_
)
331 const String
& area_name
= area_
->getName();
333 // Throw an Exception if the area already exists
334 if(m_area_map_
->keyExist(area_name
))
336 const String
& error_msg
= "Internal error: area (" + area_name
+
338 throw Exception(error_msg
);
342 m_area_map_
->set(area_name
, area_
);
346 Result
* Model::getAreaResult(const String
& area_name_
)
348 return m_area_map_
->get(area_name_
);
351 const Result
* Model::getAreaResult(const String
& area_name_
) const
353 return m_area_map_
->get(area_name_
);
356 bool Model::hasAreaResult(const String
& area_name_
) const
358 return m_area_map_
->keyExist(area_name_
);
361 void Model::addNddPowerResult(Result
* ndd_power_
)
363 const String
& ndd_power_name
= ndd_power_
->getName();
365 // Throw an Exception if the ndd_power already exists
366 if(m_ndd_power_map_
->keyExist(ndd_power_name
))
368 const String
& error_msg
= "Internal error: ndd_power (" + ndd_power_name
+
370 throw Exception(error_msg
);
374 m_ndd_power_map_
->set(ndd_power_name
, ndd_power_
);
378 Result
* Model::getNddPowerResult(const String
& ndd_power_name_
)
380 return m_ndd_power_map_
->get(ndd_power_name_
);
383 const Result
* Model::getNddPowerResult(const String
& ndd_power_name_
) const
385 return m_ndd_power_map_
->get(ndd_power_name_
);
388 bool Model::hasNddPowerResult(const String
& ndd_power_name_
) const
390 return m_ndd_power_map_
->keyExist(ndd_power_name_
);
393 void Model::addEventResult(Result
* event_
)
395 const String
& event_name
= event_
->getName();
397 // Throw an Exception if the event already exists
398 if(m_event_map_
->keyExist(event_name
))
400 const String
& error_msg
= "Internal error: event (" + event_name
+
402 throw Exception(error_msg
);
406 m_event_map_
->set(event_name
, event_
);
410 Result
* Model::getEventResult(const String
& event_name_
)
412 return m_event_map_
->get(event_name_
);
415 const Result
* Model::getEventResult(const String
& event_name_
) const
417 return m_event_map_
->get(event_name_
);
420 bool Model::hasEventResult(const String
& event_name_
) const
422 return m_event_map_
->keyExist(event_name_
);
425 const TechModel
* Model::getTechModel() const
427 return m_tech_model_
;
430 const void* Model::parseQuery(const String
& query_type_
, const String
& query_hier_
, const String
& query_sub_field_
)
432 // Break query by hierarchy separator
433 vector
<String
> hier_split
= query_hier_
.splitByString(HIERARCHY_SEPARATOR
);
435 // Check if the query_hier matches the instance name
436 ASSERT((hier_split
[0] == m_instance_name_
), "[Error] " +
437 m_instance_name_
+ " -> Mismatch in instance name (" +
438 hier_split
[0] + ")");
440 // If there is no more hierarchy separator, this process the query
441 if(hier_split
.size() == 1)
444 return processQuery(query_type_
, query_sub_field_
);
448 // Reconstruct the query
449 String temp_query_hier
= hier_split
[1];
450 for(int i
= 2; i
< (int)hier_split
.size(); ++i
)
452 temp_query_hier
+= HIERARCHY_SEPARATOR
+ hier_split
[i
];
455 // Get sub instance's name
456 const String
& temp_sub_instance_name
= hier_split
[1];
457 ASSERT(m_sub_instances_
->keyExist(temp_sub_instance_name
), "[Error] " +
458 m_instance_name_
+ " -> No sub-instances queried (" +
459 temp_sub_instance_name
+ ")");
461 return m_sub_instances_
->get(temp_sub_instance_name
)->getModel()->parseQuery(query_type_
, temp_query_hier
, query_sub_field_
);
465 const void* Model::processQuery(const String
& query_type_
, const String
& query_sub_field_
)
467 if(query_type_
== "Property")
469 return getProperties();
471 else if(query_type_
== "Parameter")
473 return getParameters();
475 else if(query_type_
.contain("Hier"))
479 else if(query_type_
== "Area")
481 return queryArea(query_sub_field_
);
483 else if(query_type_
== "NddPower")
485 return queryNddPower(query_sub_field_
);
487 else if(query_type_
== "Energy")
489 return queryEventEnergyCost(query_sub_field_
);
493 const String
& error_msg
= "[Error] " + m_instance_name_
+ " -> Unknown query type (" + query_type_
+ ")";
494 throw Exception(error_msg
);
499 const Result
* Model::queryArea(const String
& area_name_
) const
501 ASSERT(m_area_map_
->keyExist(area_name_
), "[Error] " + m_instance_name_
+
502 " -> Unknown queried area name (" + area_name_
+ ")");
503 return m_area_map_
->get(area_name_
);
506 const Result
* Model::queryNddPower(const String
& ndd_power_name_
)
508 ASSERT(m_ndd_power_map_
->keyExist(ndd_power_name_
), "[Error] " + m_instance_name_
+
509 " -> Unknown queried ndd power name (" + ndd_power_name_
+ ")");
512 return m_ndd_power_map_
->get(ndd_power_name_
);
515 const Result
* Model::queryEventEnergyCost(const String
& event_name_
)
517 ASSERT(m_event_map_
->keyExist(event_name_
), "[Error] " + m_instance_name_
+
518 " -> Unknown queried event name (" + event_name_
+ ")");
521 return m_event_map_
->get(event_name_
);
524 // Update checks whether the model needs updating, whether all properties have been specified,
525 // and calls updateModel if update is necessary
526 void Model::construct()
528 // Model should not be constructed yet
529 ASSERT(!m_constructed_
, "[Error] " + getInstanceName() + " -> Cannot construct an already contructed model!");
530 // Check if whether all needed parameters are defined
533 m_constructed_
= true;
535 m_evaluated_
= false;
539 // Update checks whether the model needs updating, whether all properties have been specified,
540 // and calls updateModel if update is necessary
543 // Model should be constructed
544 ASSERT(m_constructed_
, "[Error] " + getInstanceName() + " -> Cannot update an unconstructed model!");
545 // If the model needs updating (due to property change)
546 // an update is necessary
549 // Check if all properties needed exist
553 m_evaluated_
= false;
558 // Evaluate checks whether the model needs to be evaluated.
559 void Model::evaluate()
561 // Model should be constructed
562 ASSERT(m_constructed_
, "[Error] " + getInstanceName() + " -> Cannot evaluate an unconstructed model!");
563 // Model should be updated
564 ASSERT(m_updated_
, "[Error] " + getInstanceName() + " -> Cannot evaluate without first updating!");
565 // If the model needs evaluating
575 void Model::use(const String
& event_name_
)
577 useModel(event_name_
);
587 // By default, update model will iterate through all sub-instances and do updateModel on them
588 void Model::updateModel()
590 Map
<SubModel
*>::Iterator iter
= m_sub_instances_
->begin();
591 Map
<SubModel
*>::Iterator end
= m_sub_instances_
->end();
594 iter
->second
->getModel()->update();
600 // By default, update model will iterate through all sub-instances and do updateModel on them
601 void Model::evaluateModel()
603 Map
<SubModel
*>::Iterator iter
= m_sub_instances_
->begin();
604 Map
<SubModel
*>::Iterator end
= m_sub_instances_
->end();
607 iter
->second
->getModel()->evaluate();
613 void Model::useModel(const String
& /* event_name_ */)
616 void Model::useModel()
619 void Model::printHierarchy(const String
& query_type_
, const String
& query_sub_field_
, const String
& prepend_str_
, int detail_level_
, ostream
& ost_
) const
621 if(query_type_
== "InstHier")
623 ost_
<< prepend_str_
<< getInstanceName() << endl
;
624 printInstHierarchy(prepend_str_
, detail_level_
, ost_
);
625 //if(detail_level_ > 0)
627 //for(Map<SubModel*>::ConstIterator it = m_sub_instances_->begin(); it != m_sub_instances_->end(); ++it)
629 //const Model* sub_model = (it->second)->getModel();
630 //String temp_prepend_str = prepend_str_ + " ";
631 //sub_model->printHierarchy(query_type_, query_sub_field_, temp_prepend_str, detail_level_ - 1, ost_);
637 const Map
<Result
*>* result_map
;
639 if(query_type_
== "AreaHier")
641 result_map
= m_area_map_
;
643 else if(query_type_
== "NddPowerHier")
645 result_map
= m_ndd_power_map_
;
647 else if(query_type_
== "EventHier")
649 result_map
= m_event_map_
;
653 const String
& error_msg
= "[Error] " + m_instance_name_
+ " -> Unknown query type (" + query_type_
+ ")";
654 throw Exception(error_msg
);
658 if(query_sub_field_
== "")
660 for(Map
<Result
*>::ConstIterator it
= result_map
->begin(); it
!= result_map
->end(); ++it
)
662 const Result
* result
= it
->second
;
663 ost_
<< prepend_str_
<< getInstanceName() << "->" << result
->getName() << endl
;
664 result
->printHierarchy(prepend_str_
, detail_level_
, ost_
);
669 const Result
* result
= result_map
->get(query_sub_field_
);
670 ost_
<< prepend_str_
<< getInstanceName() << "->" << result
->getName() << endl
;
671 result
->printHierarchy(prepend_str_
, detail_level_
, ost_
);
677 void Model::printInstHierarchy(const String
& prepend_str_
, int detail_level_
, ostream
& ost_
) const
679 if(detail_level_
> 0)
681 for(Map
<SubModel
*>::ConstIterator it
= m_sub_instances_
->begin(); it
!= m_sub_instances_
->end(); ++it
)
683 const Model
* sub_model
= it
->second
->getModel();
684 String temp_prepend_str
= prepend_str_
+ " ";
686 ost_
<< prepend_str_
<< " |--" << sub_model
->getInstanceName() << endl
;
687 sub_model
->printInstHierarchy(temp_prepend_str
, detail_level_
- 1, ost_
);
693 Model
* Model::clone() const
695 throw Exception(getInstanceName() + " -> Cannot be cloned!");
698 Model::Model(const Model
& model_
)
700 // Copy instance's name
701 m_instance_name_
= model_
.m_instance_name_
;
704 m_properties_
= model_
.m_properties_
->clone();
707 m_sub_instances_
= clonePtrMap(model_
.m_sub_instances_
);
709 // Clone events, area, ndd_power
710 m_event_map_
= clonePtrMap(model_
.m_event_map_
);
711 m_area_map_
= clonePtrMap(model_
.m_area_map_
);
712 m_ndd_power_map_
= clonePtrMap(model_
.m_ndd_power_map_
);
714 // Copy tech model pointer
715 m_tech_model_
= model_
.m_tech_model_
;