5#ifndef LINE_API_SN_SN_VALIDATE_CONTRACT_H
6#define LINE_API_SN_SN_VALIDATE_CONTRACT_H
47inline std::vector<std::string> contract_split(
const std::string& s,
char sep) {
48 std::vector<std::string> out;
62inline std::string contract_join(
const std::vector<std::string>& v,
const std::string& sep) {
64 for (std::size_t i = 0; i < v.size(); ++i) {
65 out += (i ? sep :
"") + v[i];
71inline bool contract_extent_admits(std::string tok,
long n,
const std::map<char, double>& dims) {
75 bool upper = !tok.empty() && tok.back() ==
'?';
82 static const std::regex term_re(
"^([0-9]*)([A-Z]*)$");
84 for (
const auto& term : contract_split(tok,
'+')) {
86 if (!std::regex_match(term, m, term_re) || (m[1].length() == 0 && m[2].length() == 0)) {
89 double f = m[1].length() ? std::stod(m[1].str()) : 1.0;
90 for (
char ch : m[2].str()) {
91 auto it = dims.find(ch);
92 f *= (it == dims.end()) ? std::nan(
"") : it->second;
96 return upper ? n <= total : static_cast<double>(n) == total;
99inline bool contract_shape_admits(
const SnFieldView& v,
const std::string& shape,
100 const std::map<char, double>& dims) {
101 auto parts = contract_split(shape,
'x');
102 if (parts.size() == 1) {
105 if (parts.size() != 2) {
109 return contract_extent_admits(parts[0], v.rows, dims) && contract_extent_admits(parts[1], v.cols, dims);
111 if (v.ndim != 1 || !contract_extent_admits(parts[0], v.rows, dims)) {
114 for (
long e : v.elems) {
115 if (e !=
kEmptyExtent && !contract_extent_admits(parts[1], e, dims)) {
122inline std::string contract_describe(
const SnFieldView& v) {
124 return "[" + std::to_string(v.rows) +
" " + std::to_string(v.cols) +
"]";
127 std::set<long> inner(v.elems.begin(), v.elems.end());
128 std::vector<std::string> s;
129 for (
long e : inner) {
132 return "of size " + std::to_string(v.rows) +
" (element extents " + contract_join(s,
",") +
")";
134 return "a " + v.kind;
141 const char*
env = std::getenv(
"LINE_VALIDATE_SN");
150 std::vector<std::string> v;
151 std::map<std::string, const SnContractField*> by_name;
153 by_name[f.name] = &f;
154 if (std::string(f.group) ==
"required" && std::string(f.via) !=
"" && !views.
fields.count(f.name)) {
155 v.push_back(std::string(
"required field sn.") + f.name +
" is missing");
158 for (
const auto& kv : views.
fields) {
159 const std::string& name = kv.first;
161 auto it = by_name.find(name);
162 if (it == by_name.end() || std::string(it->second->via).empty()) {
163 v.push_back(
"sn." + name +
" is not in sn_contract: misspelled, or a new field that was never declared");
167 auto kinds = detail::contract_split(c.
kinds,
',');
168 bool kind_ok = std::string(c.
kinds).empty();
169 for (
const auto& k : kinds) {
170 kind_ok = kind_ok || k == fv.
kind;
173 v.push_back(
"sn." + name +
" is a " + fv.
kind +
", but the contract admits " +
174 detail::contract_join(kinds,
" or "));
180 auto shapes = detail::contract_split(c.
shapes,
',');
182 for (
const auto& s : shapes) {
183 ok = ok || detail::contract_shape_admits(fv, s, views.
dims);
186 v.push_back(
"sn." + name +
" is " + detail::contract_describe(fv) +
", but the contract admits " +
187 detail::contract_join(shapes,
" or "));
190 if (error && !v.empty()) {
192 detail::contract_join(v,
"\n "));
InternalError(const std::string &what)
A network plus its refreshed NetworkStruct.
static VerboseLevel get_verbose()
The session verbosity.
The exception types the port throws.
Running progress log of a LINE solver run (the "solver console").
std::vector< std::string > sn_validate_contract(const SnFieldViews &views, bool error=false)
The contract violations of a field view; with error true, throws InternalError with id LINE:internal:...
SnFieldViews sn_contract_view(const qn::NetworkStruct< T > &sn)
The field view of a struct: one entry per contract field this port stores, keyed by the MATLAB name,...
bool sn_validate_requested()
True when get_struct should validate: debug verbosity, or LINE_VALIDATE_SN=1.
constexpr long kEmptyExtent
long sn_view_extent(const SnFieldView &v)
The 1-D extent of a field view: a container's size, a vector Matrix's length.
const std::array< SnContractField, 127 > & sn_contract()
std::string upper(std::string s)
Conservation laws of a layered queueing network, enumerated from its structure.
The NetworkStruct contract: every field a NetworkStruct may carry, keyed by its MATLAB name,...
The FIELD VIEW the NetworkStruct contract is checked on: for each value, its kind (Matrix,...
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
One NetworkStruct field; kinds and shapes are comma-separated.
const char * shapes
admissible shapes of a non-empty value
const char * kinds
admissible sn_field_kind() values
The view of a whole struct: its dimensions and one view per contract field, by MATLAB name.
std::map< char, double > dims
std::map< std::string, SnFieldView > fields