Merge branch 'vaskeEmFix' of git://disco.cse.ucsc.edu/libDAI into mergeVaskeEmFix
[libdai.git] / include / dai / properties.h
1 /* Copyright (C) 2006-2008 Joris Mooij [joris dot mooij at tuebingen dot mpg dot de]
2 Radboud University Nijmegen, The Netherlands /
3 Max Planck Institute for Biological Cybernetics, Germany
4
5 This file is part of libDAI.
6
7 libDAI is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 libDAI is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with libDAI; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22
23 /// \file
24 /// \brief Defines the Property and PropertySet classes
25 /// \todo Improve documentation
26
27
28 #ifndef __defined_libdai_properties_h
29 #define __defined_libdai_properties_h
30
31
32 #include <iostream>
33 #include <sstream>
34 #include <boost/any.hpp>
35 #include <map>
36 #include <vector>
37 #include <cassert>
38 #include <typeinfo>
39 #include <dai/exceptions.h>
40 #include <dai/util.h>
41 #include <boost/lexical_cast.hpp>
42
43
44 namespace dai {
45
46
47 /// Type of the key of a Property
48 typedef std::string PropertyKey;
49
50 /// Type of the value of a Property
51 typedef boost::any PropertyValue;
52
53 /// A Property is a pair of a key and a corresponding value
54 typedef std::pair<PropertyKey, PropertyValue> Property;
55
56
57 /// Writes a Property object to an output stream
58 std::ostream& operator<< (std::ostream & os, const Property & p);
59
60
61 /// Represents a set of properties, mapping keys (of type PropertyKey) to values (of type PropertyValue)
62 class PropertySet : private std::map<PropertyKey, PropertyValue> {
63 public:
64 /// Default constructor
65 PropertySet() {}
66
67 /// Construct PropertySet from a string
68 PropertySet( const std::string &s ) {
69 std::stringstream ss;
70 ss << s;
71 ss >> *this;
72 }
73
74 /// Gets a property
75 const PropertyValue & Get(const PropertyKey &key) const {
76 PropertySet::const_iterator x = find(key);
77 #ifdef DAI_DEBUG
78 if( x == this->end() )
79 std::cerr << "PropertySet::Get cannot find property " << key << std::endl;
80 #endif
81 assert( x != this->end() );
82 return x->second;
83 }
84
85 /// Sets a property
86 PropertySet & Set(const PropertyKey &key, const PropertyValue &val) { this->operator[](key) = val; return *this; }
87
88 /// Set properties according to those in newProps, overriding properties that already exist with new values
89 PropertySet & Set( const PropertySet &newProps ) {
90 const std::map<PropertyKey, PropertyValue> *m = &newProps;
91 foreach(value_type i, *m)
92 Set( i.first, i.second );
93 return *this;
94 }
95
96 /// Gets a property, casted as ValueType
97 template<typename ValueType>
98 ValueType GetAs(const PropertyKey &key) const {
99 try {
100 return boost::any_cast<ValueType>(Get(key));
101 } catch( const boost::bad_any_cast & ) {
102 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' to desired type.");
103 return ValueType();
104 }
105 }
106
107 /// Converts a property from string to ValueType (if necessary)
108 template<typename ValueType>
109 void ConvertTo(const PropertyKey &key) {
110 PropertyValue val = Get(key);
111 if( val.type() != typeid(ValueType) ) {
112 assert( val.type() == typeid(std::string) );
113 try {
114 Set(key, boost::lexical_cast<ValueType>(GetAs<std::string>(key)));
115 } catch(boost::bad_lexical_cast &) {
116 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' from string to desired type.");
117 }
118 }
119 }
120
121 /// Converts a property from string to ValueType (if necessary)
122 template<typename ValueType>
123 ValueType getStringAs(const PropertyKey &key) const {
124 PropertyValue val = Get(key);
125 if( val.type() == typeid(ValueType) ) {
126 return boost::any_cast<ValueType>(val);
127 } else if( val.type() == typeid(std::string) ) {
128 try {
129 return boost::lexical_cast<ValueType>(GetAs<std::string>(key));
130 } catch(boost::bad_lexical_cast &) {
131 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' from string to desired type.");
132 }
133 } else
134 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' from string to desired type.");
135 return ValueType();
136 }
137
138 /// Converts a property from ValueType to string (if necessary)
139 template<typename ValueType>
140 PropertySet & setAsString(const PropertyKey &key, ValueType &val) {
141 try {
142 return Set( key, boost::lexical_cast<std::string>(val) );
143 } catch( boost::bad_lexical_cast & ) {
144 DAI_THROWE(IMPOSSIBLE_TYPECAST,"Cannot cast value of property '" + key + "' to string.");
145 }
146 }
147
148 /// Shorthand for (temporarily) adding properties, e.g. PropertySet p()("method","BP")("verbose",1)("tol",1e-9)
149 PropertySet operator()(const PropertyKey &key, const PropertyValue &val) const { PropertySet copy = *this; return copy.Set(key,val); }
150
151 std::vector< PropertyKey > keys() const {
152 std::vector< PropertyKey > result;
153 result.reserve(size());
154 PropertySet::const_iterator i = begin();
155 for ( ; i != end(); ++i) {
156 result.push_back(i->first);
157 }
158 return result;
159 }
160
161 /// Check if a property with the given key exists
162 bool hasKey(const PropertyKey &key) const { PropertySet::const_iterator x = find(key); return (x != this->end()); }
163
164 /// Returns a set containing all keys
165 std::set<PropertyKey> allKeys() const {
166 std::set<PropertyKey> res;
167 const_iterator i;
168 for( i = begin(); i != end(); i++ )
169 res.insert( i->first );
170 return res;
171 }
172
173 /// Writes a PropertySet object to an output stream
174 friend std::ostream& operator<< (std::ostream & os, const PropertySet & ps);
175
176 /// Reads a PropertySet object from an input stream, storing values as strings
177 friend std::istream& operator>> (std::istream& is, PropertySet & ps);
178 };
179
180
181 } // end of namespace dai
182
183
184 #endif