7 #ifndef JADE_AGI_READER_HPP__
8 #define JADE_AGI_READER_HPP__
10 #include "jade.shunting_yard.hpp"
41 template <
typename TValue>
67 , _branch_names (_read_names(in))
68 , _proportion_names (_read_names(in))
70 , _entries (_read_entries(in, _k))
74 throw jade::error() <<
"unexpected token: " << token;
80 std::set<std::string> defined;
81 const auto vectors = { &_branch_names, &_proportion_names };
82 for (
const auto vector : vectors)
83 for (
const auto & name : *vector)
84 if (!defined.insert(name).second)
86 <<
"duplicate variable name '" << name <<
"'";
92 for (
const auto & entry : _entries)
93 for (
const auto & pair : entry.get_args())
94 if (defined.insert(pair.first).second)
96 <<
"undefined variable name '"
97 << pair.first <<
"' in expression";
102 std::set<std::string> used;
103 for (
const auto & entry : _entries)
104 for (
const auto & pair : entry.get_args())
105 used.insert(pair.first);
111 const auto remove = [&used](std::vector<std::string> & names)
113 const auto end = std::remove_if(
116 [&used](
const std::string & name)
118 return used.find(name) == used.end();
121 names.erase(end, names.end());
124 remove(_branch_names);
125 remove(_proportion_names);
134 for (
const auto & name : used)
146 , _proportion_names ()
152 std::ifstream in (path);
155 catch (
const std::exception & e)
158 <<
"error reading admixture graph input from file '"
182 return _branch_names;
191 return _proportion_names;
214 static std::vector<shunting_yard_type> _read_entries(
218 const auto n = k * (k - 1) / 2;
219 std::vector<shunting_yard_type> entries;
222 for (
size_t i = 0; i < n; i++)
223 entries.emplace_back(_read_line(in));
229 static std::string _read_line(std::istream & in)
234 if (!std::getline(in, line))
237 if (!line.empty() && line[0] !=
'#')
243 static std::vector<std::string> _read_names(std::istream & in)
245 std::vector<std::string> names;
247 std::istringstream line (_read_line(in));
255 names.push_back(_validate_name(name));
260 static size_t _read_size(std::istream & in)
262 const auto line = _read_line(in);
263 std::istringstream line_in (line);
266 if (!(line_in >> size) || size < 2)
270 if (!(line_in >> token))
273 throw jade::error() <<
"unexpected token: " << token;
277 static const std::string & _validate_name(
const std::string & name)
279 static const auto fn = [](
const char ch)
281 return std::isalnum(ch) || ch ==
'_';
284 if (!name.empty() && std::isalpha(name[0]))
285 if (std::all_of(name.begin() + 1, name.end(), fn))
288 throw jade::error() <<
"invalid name: '" << name <<
"'";
292 std::vector<std::string> _branch_names;
293 std::vector<std::string> _proportion_names;
295 std::vector<shunting_yard_type> _entries;
299 #endif // JADE_AGI_READER_HPP__