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__