1/* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
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:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
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
19 * THE SOFTWARE.
20 */
21
22#include "model/Model.h"
23
24#include <vector>
25
26#include "util/Result.h"
27
28namespace DSENT
29{
30    using std::vector;
31    using LibUtil::deletePtrMap;
32    using LibUtil::clonePtrMap;
33
34    Model::SubModel::SubModel(Model* model_, double num_models_)
35        : m_model_(model_), m_num_models_(num_models_)
36    {}
37
38    Model::SubModel::~SubModel()
39    {
40        delete m_model_;
41    }
42
43    Model* Model::SubModel::getModel()
44    {
45        return m_model_;
46    }
47
48    const Model* Model::SubModel::getModel() const
49    {
50        return m_model_;
51    }
52
53    double Model::SubModel::getNumModels() const
54    {
55        return m_num_models_;
56    }
57
58    Model::SubModel* Model::SubModel::clone() const
59    {
60        return new SubModel(*this);
61    }
62
63    Model::SubModel::SubModel(const SubModel& sub_model_)
64    {
65        m_model_ = sub_model_.m_model_->clone();
66        m_num_models_ = sub_model_.m_num_models_;
67    }
68
69    const char Model::TYPE_SEPARATOR[] = ">>";
70    const char Model::HIERARCHY_SEPARATOR[] = "->";
71    const char Model::SUBFIELD_SEPARATOR[] = ":";
72    const char Model::DETAIL_SEPARATOR[] = "@";
73
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)
77    {
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*>();
87    }
88
89    Model::~Model()
90    {
91        // Clear parameter names
92        delete m_parameter_names_;
93        // Clear property name
94        delete m_property_names_;
95
96        // Clear parameters
97        delete m_parameters_;
98        m_parameters_ = NULL;
99        // Clear input properties
100        delete m_properties_;
101        m_properties_ = NULL;
102
103        // Clear generated properties
104        delete m_generated_properties_;
105        m_generated_properties_ = NULL;
106
107        // Clear sub models
108        deletePtrMap<SubModel>(m_sub_instances_);
109        m_sub_instances_ = NULL;
110
111        // Clear all results
112        deletePtrMap<Result>(m_event_map_);
113        m_event_map_ = NULL;
114        deletePtrMap<Result>(m_area_map_);
115        m_area_map_ = NULL;
116        deletePtrMap<Result>(m_ndd_power_map_);
117        m_ndd_power_map_ = NULL;
118    }
119
120    void Model::setInstanceName(const String& instance_name_)
121    {
122        m_instance_name_ = instance_name_;
123        return;
124    }
125
126    const String& Model::getInstanceName() const
127    {
128        return m_instance_name_;
129    }
130
131    void Model::setIsTopModel(bool is_top_model_)
132    {
133        m_is_top_model_ = is_top_model_;
134        return;
135    }
136
137    bool Model::getIsTopModel() const
138    {
139        return m_is_top_model_;
140    }
141
142    //-------------------------------------------------------------------------
143    //  Parameters and properties checks
144    //-------------------------------------------------------------------------
145    void Model::addParameterName(const String& parameter_name_)
146    {
147        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
148            " -> Cannot add additional parameters names after model is constructed!");
149        m_parameter_names_->push_back(parameter_name_);
150
151        return;
152    }
153
154    void Model::addParameterName(const String& parameter_name_, const String& parameter_default_)
155    {
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_);
160        return;
161    }
162
163    const vector<String>* Model::getParameterNames() const
164    {
165        return m_parameter_names_;
166    }
167
168    void Model::addPropertyName(const String& property_name_)
169    {
170        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
171            " -> Cannot add additional property names after model is constructed!");
172        m_property_names_->push_back(property_name_);
173        return;
174    }
175
176    void Model::addPropertyName(const String& property_name_, const String& property_default_)
177    {
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_);
182        return;
183    }
184
185    const vector<String>* Model::getPropertyNames() const
186    {
187        return m_property_names_;
188    }
189
190    void Model::checkParameters() const
191    {
192        String missing_parameters = "";
193
194        for(int i = 0; i < (int)m_parameter_names_->size(); ++i)
195        {
196            const String& parameter_name = m_parameter_names_->at(i);
197            if (!m_parameters_->keyExist(parameter_name))
198                missing_parameters += "    " + parameter_name + "\n";
199        }
200
201        ASSERT(missing_parameters.size() == 0, "[Error] " + m_instance_name_ +
202                " -> Missing parameters:\n" + missing_parameters);
203        return;
204    }
205
206    void Model::checkProperties() const
207    {
208        String missing_properties = "";
209
210        for(int i = 0; i < (int)m_property_names_->size(); ++i)
211        {
212            const String& property_name = m_property_names_->at(i);
213            if (!m_properties_->keyExist(property_name))
214                missing_properties += "    " + property_name + "\n";
215        }
216
217        ASSERT(missing_properties.size() == 0, "[Error] " + m_instance_name_ +
218                " -> Missing properties:\n" + missing_properties);
219        return;
220    }
221    //-------------------------------------------------------------------------
222
223    //-------------------------------------------------------------------------
224    //  Parameters Manipulation
225    //-------------------------------------------------------------------------
226    const ParameterMap* Model::getParameters() const
227    {
228        return m_parameters_;
229    }
230
231    const String Model::getParameter(const String& parameter_name_) const
232    {
233        return m_parameters_->get(parameter_name_);
234    }
235
236    void Model::setParameter(const String& parameter_name_, const String& parameter_value_)
237    {
238        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
239            " -> Cannot set parameters after model is constructed!");
240        m_parameters_->set(parameter_name_, parameter_value_);
241    }
242    //-------------------------------------------------------------------------
243
244    //-------------------------------------------------------------------------
245    // Properties Manipulation
246    //-------------------------------------------------------------------------
247    const PropertyMap* Model::getProperties() const
248    {
249        return m_properties_;
250    }
251
252    const String Model::getProperty(const String& property_name_) const
253    {
254        return m_properties_->get(property_name_);
255    }
256
257    void Model::setProperty(const String& property_name_, const String& property_value_)
258    {
259        // If any properties changed, reset updated and evaluated flags
260        m_updated_ = false;
261        m_evaluated_ = false;
262        m_properties_->set(property_name_, property_value_);
263    }
264    //-------------------------------------------------------------------------
265
266    PropertyMap* Model::getGenProperties()
267    {
268        return m_generated_properties_;
269    }
270
271    const PropertyMap* Model::getGenProperties() const
272    {
273        return m_generated_properties_;
274    }
275
276    void Model::addSubInstances(Model* sub_instance_, double num_sub_instances_)
277    {
278        // Get instance name
279        const String& sub_instance_name = sub_instance_->getInstanceName();
280
281        // Check if the instance exists
282        if(m_sub_instances_->keyExist(sub_instance_name))
283        {
284            const String& error_msg = "[Error] " + m_instance_name_ +
285            " -> Instance exists (" + sub_instance_name + ")";
286            throw Exception(error_msg);
287        }
288
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_) + ")");
292
293        // Add the instance
294        m_sub_instances_->set(sub_instance_name, new SubModel(sub_instance_, num_sub_instances_));
295        return;
296    }
297
298    Model* Model::getSubInstance(const String& sub_instance_name_)
299    {
300        // Throw an Exception if the instance already exists
301        if(!m_sub_instances_->keyExist(sub_instance_name_))
302        {
303            const String& error_msg = "[Error] " + m_instance_name_ +
304            " -> Instance not exists (" + sub_instance_name_ + ")";
305            throw Exception(error_msg);
306        }
307
308        return m_sub_instances_->get(sub_instance_name_)->getModel();
309    }
310
311    const Model* Model::getSubInstance(const String& sub_instance_name_) const
312    {
313        // Throw an Exception if the instance does not exist
314        if(!m_sub_instances_->keyExist(sub_instance_name_))
315        {
316            const String& error_msg = "[Error] " + m_instance_name_ +
317            " -> Instance not exists (" + sub_instance_name_ + ")";
318            throw Exception(error_msg);
319        }
320
321        return m_sub_instances_->get(sub_instance_name_)->getModel();
322    }
323
324    bool Model::hasSubInstance(const String& sub_instance_name_) const
325    {
326        return m_sub_instances_->keyExist(sub_instance_name_);
327    }
328
329    void Model::addAreaResult(Result* area_)
330    {
331        const String& area_name = area_->getName();
332
333        // Throw an Exception if the area already exists
334        if(m_area_map_->keyExist(area_name))
335        {
336            const String& error_msg = "Internal error: area (" + area_name +
337                ") exists";
338            throw Exception(error_msg);
339        }
340
341        // Add the area
342        m_area_map_->set(area_name, area_);
343        return;
344    }
345
346    Result* Model::getAreaResult(const String& area_name_)
347    {
348        return m_area_map_->get(area_name_);
349    }
350
351    const Result* Model::getAreaResult(const String& area_name_) const
352    {
353        return m_area_map_->get(area_name_);
354    }
355
356    bool Model::hasAreaResult(const String& area_name_) const
357    {
358        return m_area_map_->keyExist(area_name_);
359    }
360
361    void Model::addNddPowerResult(Result* ndd_power_)
362    {
363        const String& ndd_power_name = ndd_power_->getName();
364
365        // Throw an Exception if the ndd_power already exists
366        if(m_ndd_power_map_->keyExist(ndd_power_name))
367        {
368            const String& error_msg = "Internal error: ndd_power (" + ndd_power_name +
369                ") exists";
370            throw Exception(error_msg);
371        }
372
373        // Add the ndd_power
374        m_ndd_power_map_->set(ndd_power_name, ndd_power_);
375        return;
376    }
377
378    Result* Model::getNddPowerResult(const String& ndd_power_name_)
379    {
380        return m_ndd_power_map_->get(ndd_power_name_);
381    }
382
383    const Result* Model::getNddPowerResult(const String& ndd_power_name_) const
384    {
385        return m_ndd_power_map_->get(ndd_power_name_);
386    }
387
388    bool Model::hasNddPowerResult(const String& ndd_power_name_) const
389    {
390        return m_ndd_power_map_->keyExist(ndd_power_name_);
391    }
392
393    void Model::addEventResult(Result* event_)
394    {
395        const String& event_name = event_->getName();
396
397        // Throw an Exception if the event already exists
398        if(m_event_map_->keyExist(event_name))
399        {
400            const String& error_msg = "Internal error: event (" + event_name +
401                ") exists";
402            throw Exception(error_msg);
403        }
404
405        // Add the event
406        m_event_map_->set(event_name, event_);
407        return;
408    }
409
410    Result* Model::getEventResult(const String& event_name_)
411    {
412        return m_event_map_->get(event_name_);
413    }
414
415    const Result* Model::getEventResult(const String& event_name_) const
416    {
417        return m_event_map_->get(event_name_);
418    }
419
420    bool Model::hasEventResult(const String& event_name_) const
421    {
422        return m_event_map_->keyExist(event_name_);
423    }
424
425    const TechModel* Model::getTechModel() const
426    {
427        return m_tech_model_;
428    }
429
430    const void* Model::parseQuery(const String& query_type_, const String& query_hier_, const String& query_sub_field_)
431    {
432        // Break query by hierarchy separator
433        vector<String> hier_split = query_hier_.splitByString(HIERARCHY_SEPARATOR);
434
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] + ")");
439
440        // If there is no more hierarchy separator, this process the query
441        if(hier_split.size() == 1)
442        {
443            // Query the model
444            return processQuery(query_type_, query_sub_field_);
445        }
446        else
447        {
448            // Reconstruct the query
449            String temp_query_hier = hier_split[1];
450            for(int i = 2; i < (int)hier_split.size(); ++i)
451            {
452                temp_query_hier += HIERARCHY_SEPARATOR + hier_split[i];
453            }
454
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 + ")");
460
461            return m_sub_instances_->get(temp_sub_instance_name)->getModel()->parseQuery(query_type_, temp_query_hier, query_sub_field_);
462        }
463    }
464
465    const void* Model::processQuery(const String& query_type_, const String& query_sub_field_)
466    {
467        if(query_type_ == "Property")
468        {
469            return getProperties();
470        }
471        else if(query_type_ == "Parameter")
472        {
473            return getParameters();
474        }
475        else if(query_type_.contain("Hier"))
476        {
477            return this;
478        }
479        else if(query_type_ == "Area")
480        {
481            return queryArea(query_sub_field_);
482        }
483        else if(query_type_ == "NddPower")
484        {
485            return queryNddPower(query_sub_field_);
486        }
487        else if(query_type_ == "Energy")
488        {
489            return queryEventEnergyCost(query_sub_field_);
490        }
491        else
492        {
493            const String& error_msg = "[Error] " + m_instance_name_ + " -> Unknown query type (" + query_type_ + ")";
494            throw Exception(error_msg);
495            return NULL;
496        }
497    }
498
499    const Result* Model::queryArea(const String& area_name_) const
500    {
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_);
504    }
505
506    const Result* Model::queryNddPower(const String& ndd_power_name_)
507    {
508        ASSERT(m_ndd_power_map_->keyExist(ndd_power_name_), "[Error] " + m_instance_name_ +
509                " -> Unknown queried ndd power name (" + ndd_power_name_ + ")");
510
511        use("Idle");
512        return m_ndd_power_map_->get(ndd_power_name_);
513    }
514
515    const Result* Model::queryEventEnergyCost(const String& event_name_)
516    {
517        ASSERT(m_event_map_->keyExist(event_name_), "[Error] " + m_instance_name_ +
518                " -> Unknown queried event name (" + event_name_ + ")");
519
520        use(event_name_);
521        return m_event_map_->get(event_name_);
522    }
523
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()
527    {
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
531        checkParameters();
532        constructModel();
533        m_constructed_ = true;
534        m_updated_ = false;
535        m_evaluated_ = false;
536        return;
537    }
538
539    // Update checks whether the model needs updating, whether all properties have been specified,
540    // and calls updateModel if update is necessary
541    void Model::update()
542    {
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
547        if (!m_updated_)
548        {
549            // Check if all properties needed exist
550            checkProperties();
551            updateModel();
552            m_updated_ = true;
553            m_evaluated_ = false;
554        }
555        return;
556    }
557
558    // Evaluate checks whether the model needs to be evaluated.
559    void Model::evaluate()
560    {
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
566        if (!m_evaluated_)
567        {
568            evaluateModel();
569            m_evaluated_ = true;
570        }
571
572        return;
573    }
574
575    void Model::use(const String& event_name_)
576    {
577        useModel(event_name_);
578        return;
579    }
580
581    void Model::use()
582    {
583        useModel();
584        return;
585    }
586
587    // By default, update model will iterate through all sub-instances and do updateModel on them
588    void Model::updateModel()
589    {
590        Map<SubModel*>::Iterator iter = m_sub_instances_->begin();
591        Map<SubModel*>::Iterator end = m_sub_instances_->end();
592        while (iter != end)
593        {
594            iter->second->getModel()->update();
595            iter++;
596        }
597        return;
598    }
599
600    // By default, update model will iterate through all sub-instances and do updateModel on them
601    void Model::evaluateModel()
602    {
603        Map<SubModel*>::Iterator iter = m_sub_instances_->begin();
604        Map<SubModel*>::Iterator end = m_sub_instances_->end();
605        while (iter != end)
606        {
607            iter->second->getModel()->evaluate();
608            iter++;
609        }
610        return;
611    }
612
613    void Model::useModel(const String& /* event_name_ */)
614    {}
615
616    void Model::useModel()
617    {}
618
619    void Model::printHierarchy(const String& query_type_, const String& query_sub_field_, const String& prepend_str_, int detail_level_, ostream& ost_) const
620    {
621        if(query_type_ == "InstHier")
622        {
623            ost_ << prepend_str_ << getInstanceName() << endl;
624            printInstHierarchy(prepend_str_, detail_level_, ost_);
625            //if(detail_level_ > 0)
626            //{
627                //for(Map<SubModel*>::ConstIterator it = m_sub_instances_->begin(); it != m_sub_instances_->end(); ++it)
628                //{
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_);
632                //}
633            //}
634        }
635        else
636        {
637            const Map<Result*>* result_map;
638
639            if(query_type_ == "AreaHier")
640            {
641                result_map = m_area_map_;
642            }
643            else if(query_type_ == "NddPowerHier")
644            {
645                result_map = m_ndd_power_map_;
646            }
647            else if(query_type_ == "EventHier")
648            {
649                result_map = m_event_map_;
650            }
651            else
652            {
653                const String& error_msg = "[Error] " + m_instance_name_ + " -> Unknown query type (" + query_type_ + ")";
654                throw Exception(error_msg);
655                return;
656            }
657
658            if(query_sub_field_ == "")
659            {
660                for(Map<Result*>::ConstIterator it = result_map->begin(); it != result_map->end(); ++it)
661                {
662                    const Result* result = it->second;
663                    ost_ << prepend_str_ << getInstanceName() << "->" << result->getName() << endl;
664                    result->printHierarchy(prepend_str_, detail_level_, ost_);
665                }
666            }
667            else
668            {
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_);
672            }
673        }
674        return;
675    }
676
677    void Model::printInstHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const
678    {
679        if(detail_level_ > 0)
680        {
681            for(Map<SubModel*>::ConstIterator it = m_sub_instances_->begin(); it != m_sub_instances_->end(); ++it)
682            {
683                const Model* sub_model = it->second->getModel();
684                String temp_prepend_str = prepend_str_ + "    ";
685
686                ost_ << prepend_str_ << " |--" << sub_model->getInstanceName() << endl;
687                sub_model->printInstHierarchy(temp_prepend_str, detail_level_ - 1, ost_);
688            }
689        }
690        return;
691    }
692
693    Model* Model::clone() const
694    {
695        throw Exception(getInstanceName() + " -> Cannot be cloned!");
696    }
697
698    Model::Model(const Model& model_)
699    {
700        // Copy instance's name
701        m_instance_name_ = model_.m_instance_name_;
702
703        // Clone properties
704        m_properties_ = model_.m_properties_->clone();
705
706        // Clone instances
707        m_sub_instances_ = clonePtrMap(model_.m_sub_instances_);
708
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_);
713
714        // Copy tech model pointer
715        m_tech_model_ = model_.m_tech_model_;
716    }
717
718} // namespace DSENT
719
720