aGrUM  0.18.1
a C++ library for (probabilistic) graphical models
PRMSystem_tpl.h
Go to the documentation of this file.
1 
31 
33 
38 
39 namespace gum {
40  namespace prm {
41  template < typename GUM_SCALAR >
42  PRMSystem< GUM_SCALAR >::PRMSystem(const std::string& name) : PRMObject(name) {
43  GUM_CONSTRUCTOR(PRMSystem);
44  }
45 
46  template < typename GUM_SCALAR >
48  GUM_DESTRUCTOR(PRMSystem);
49 
50  for (const auto& elt: *this)
51  delete elt.second;
52 
53  for (const auto& elt: instanceMap_)
54  delete elt.second;
55 
56  for (const auto& elt: arrayMap_)
57  delete elt.second.second;
58  }
59 
60  template < typename GUM_SCALAR >
62  PRMObject(from), skeleton_(from.skeleton_), nodeIdMap_(from.nodeIdMap_),
63  nameMap_(from.nameMap_), instanceMap_(from.instanceMap_),
64  arrayMap_(from.arrayMap_) {
65  GUM_CONS_CPY(PRMSystem);
66  }
67 
68  template < typename GUM_SCALAR >
70  if (nameMap_.exists(i->name())) {
71  GUM_ERROR(
73  "an Instance<GUM_SCALAR> with the same is already in this System");
74  }
75 
76  NodeId id = skeleton_.addNode();
77  nodeIdMap_.insert(id, i);
78  nameMap_.insert(i->name(), i);
79 
80  try {
81  instanceMap_[&(i->type())]->insert(i);
82  } catch (NotFound&) {
83  instanceMap_.insert(&(i->type()), new Set< PRMInstance< GUM_SCALAR >* >());
84  instanceMap_[&(i->type())]->insert(i);
85  }
86 
87  return id;
88  }
89 
90  template < typename GUM_SCALAR >
92  BayesNetFactory< GUM_SCALAR >& factory) const {
93  factory.startNetworkDeclaration();
94  factory.addNetworkProperty("name", name());
95  factory.endNetworkDeclaration();
96 
97  // Adding nodes
98  for (PRMSystem< GUM_SCALAR >::const_iterator iter = begin(); iter != end();
99  ++iter) {
100  groundAttr__(*(iter.val()), factory);
101  }
102 
103  // Adding arcs and filling CPTs
104  for (PRMSystem< GUM_SCALAR >::const_iterator iter = begin(); iter != end();
105  ++iter) {
106  groundRef__(*(iter.val()), factory);
107  }
108  }
109 
110  template < typename GUM_SCALAR >
112  const PRMInstance< GUM_SCALAR >& instance,
113  BayesNetFactory< GUM_SCALAR >& factory) const {
114  for (const auto node: instance.type().containerDag()) {
115  // Working a Class<GUM_SCALAR> level because PRMAggregate<GUM_SCALAR>
116  // are
117  // instantiated as PRMAttribute<GUM_SCALAR> in an
118  // PRMInstance<GUM_SCALAR>
119  switch (instance.type().get(node).elt_type()) {
121  // TODO: make a special case for noisy-or
122  std::stringstream elt_name;
123  elt_name << instance.name() << "."
124  << instance.type().get(node).safeName();
125  DiscreteVariable* var = instance.get(node).type().variable().clone();
126  var->setName(elt_name.str());
127  factory.setVariable(*var); // var is copied by the factory
128  delete var;
129  break;
130  }
131 
133  std::stringstream elt_name;
134  elt_name << instance.name() << "."
135  << instance.type().get(node).safeName();
136  groundAgg__(instance.type().get(node), elt_name.str(), factory);
137  break;
138  }
139 
140  default:
141  break;
142  /* Do nothing */;
143  }
144  }
145  }
146 
147  template < typename GUM_SCALAR >
150  const std::string& name,
151  BayesNetFactory< GUM_SCALAR >& factory) const {
152  factory.startVariableDeclaration();
153  factory.variableName(name);
154 
155  const DiscreteVariable& agg_var = elt.type().variable();
156 
157  VarType var_type = agg_var.varType();
158 
159  factory.variableType(var_type);
160 
161  switch (var_type) {
162  case VarType::Labelized: {
163  const auto l = static_cast< const LabelizedVariable& >(agg_var);
164  for (Idx i = 0; i < l.domainSize(); ++i) {
165  factory.addModality(l.label(i));
166  }
167  break;
168  }
169  case VarType::Discretized: {
170  const auto d =
171  static_cast< const DiscretizedVariable< GUM_SCALAR >& >(agg_var);
172  for (Idx i = 0; i < d.domainSize(); ++i) {
173  factory.addTick(d.tick(i));
174  }
175  break;
176  }
177  case VarType::Range: {
178  const auto r = static_cast< const RangeVariable& >(agg_var);
179  factory.addMin(r.minVal());
180  factory.addMax(r.maxVal());
181  break;
182  }
183  case VarType::Continuous:
184  // Todo Error
185  break;
186  }
187 
188  const PRMAggregate< GUM_SCALAR >& agg =
189  static_cast< const PRMAggregate< GUM_SCALAR >& >(elt);
190 
191  switch (agg.agg_type()) {
195  break;
196  }
197 
201  break;
202  }
203 
207  break;
208  }
209 
213  break;
214  }
215 
219  break;
220  }
221 
225  break;
226  }
227 
231  break;
232  }
233 
236  break;
237  }
238 
242  break;
243  }
244 
248  break;
249  }
250 
251  default: {
252  GUM_ERROR(OperationNotAllowed, "Aggregator not handled yet");
253  break;
254  }
255  }
256 
257  factory.endVariableDeclaration();
258  }
259 
260  template < typename GUM_SCALAR >
262  const PRMInstance< GUM_SCALAR >& instance,
263  BayesNetFactory< GUM_SCALAR >& factory) const {
264  for (const auto& elt: instance) {
265  std::stringstream elt_name;
266  elt_name << instance.name() << "." << elt.second->safeName();
267  factory.startParentsDeclaration(elt_name.str());
268 
269  for (const auto par:
270  instance.type().containerDag().parents(elt.second->id())) {
271  switch (instance.type().get(par).elt_type()) {
274  std::stringstream parent_name;
275  parent_name << instance.name() << "."
276  << instance.get(par).safeName();
277  factory.addParent(parent_name.str());
278  break;
279  }
280 
282  std::string parent_name =
283  static_cast< const PRMSlotChain< GUM_SCALAR >& >(
284  instance.type().get(par))
285  .lastElt()
286  .safeName();
287 
288  try {
289  for (const auto ref: instance.getInstances(par)) {
290  std::stringstream sBuff;
291  sBuff << ref->name() << "." << parent_name;
292  factory.addParent(sBuff.str());
293  }
294  } catch (NotFound&) {
295  // No instances for this slotchain
296  }
297 
298  break;
299  }
300 
301  default:
302  break;
303  /* nothing to do by default */
304  }
305  }
306 
307  factory.endParentsDeclaration();
308 
309  // Checking if we need to ground the Potential (only for class level
310  // attributes since
311  // aggregates Potentials are generated)
313  instance.type().get(elt.second->safeName())))
314  groundPotential__(instance, *elt.second, factory);
315  }
316  }
317 
318  template < typename GUM_SCALAR >
320  const PRMInstance< GUM_SCALAR >& instance,
321  const PRMAttribute< GUM_SCALAR >& attr,
322  BayesNetFactory< GUM_SCALAR >& factory) const {
324  std::stringstream var_name;
325  var_name << instance.name() << "." << attr.safeName();
326  bijection.insert(&(attr.type().variable()),
327  &(factory.variable(var_name.str())));
328 
329  for (const auto parent: instance.type().containerDag().parents(attr.id())) {
330  switch (instance.type().get(parent).elt_type()) {
333  std::stringstream parent_name;
334  parent_name << instance.name() << "."
335  << instance.get(parent).safeName();
336  bijection.insert(&(instance.get(parent).type().variable()),
337  &(factory.variable(parent_name.str())));
338  break;
339  }
340 
342  std::stringstream parent_name;
343  const PRMSlotChain< GUM_SCALAR >& sc =
344  static_cast< const PRMSlotChain< GUM_SCALAR >& >(
345  instance.type().get(parent));
346  parent_name << instance.getInstance(sc.id()).name() << "."
347  << sc.lastElt().safeName();
348  bijection.insert(&(instance.getInstance(sc.id())
349  .get(sc.lastElt().safeName())
350  .type()
351  .variable()),
352  &(factory.variable(parent_name.str())));
353  break;
354  }
355 
356  default: {
358  "invalid ClassElement<GUM_SCALAR> type as parent.");
359  break;
360  }
361  }
362  }
363 
364  // Copy Potential
365  // DO NOT USE MultiDimBijArray as they will wreck havok if you delete
366  // the prm befor its grounded BN (happens a lot in pyAgrum)
368  for (auto var: attr.cpf().variablesSequence()) {
369  p->add(*(bijection.second(var)));
370  }
371  Instantiation inst(attr.cpf()), jnst(*p);
372  for (inst.setFirst(), jnst.setFirst(); !(inst.end() || jnst.end());
373  inst.inc(), jnst.inc()) {
374  p->set(jnst, attr.cpf().get(inst));
375  }
376  GUM_ASSERT(inst.end() && jnst.end());
377  factory.setVariableCPT(var_name.str(), p, false);
378  }
379 
380  template < typename GUM_SCALAR >
381  INLINE NodeId PRMSystem< GUM_SCALAR >::add(const std::string& array,
383  return add(array, &i);
384  }
385 
386  template < typename GUM_SCALAR >
388  return skeleton_;
389  }
390 
391  template < typename GUM_SCALAR >
393  try {
394  return *(nodeIdMap_[id]);
395  } catch (NotFound&) {
396  GUM_ERROR(NotFound, "found no Instance<GUM_SCALAR> matching the given id");
397  }
398  }
399 
400  template < typename GUM_SCALAR >
401  INLINE const PRMInstance< GUM_SCALAR >&
403  try {
404  return *(nodeIdMap_[id]);
405  } catch (NotFound&) {
406  GUM_ERROR(NotFound, "found no Instance<GUM_SCALAR> matching the given id");
407  }
408  }
409 
410  template < typename GUM_SCALAR >
411  INLINE NodeId
413  try {
414  return nodeIdMap_.keyByVal(const_cast< PRMInstance< GUM_SCALAR >* >(&i));
415  } catch (NotFound&) {
416  GUM_ERROR(NotFound, "found no Instance<GUM_SCALAR> matching the given id");
417  }
418  }
419 
420  template < typename GUM_SCALAR >
422  return PRMObject::prm_type::SYSTEM;
423  }
424 
425  template < typename GUM_SCALAR >
427  return nodeIdMap_.size();
428  }
429 
430  template < typename GUM_SCALAR >
432  const PRMClass< GUM_SCALAR >& c) const {
433  return instanceMap_.exists(const_cast< PRMClass< GUM_SCALAR >* >(&c));
434  }
435 
436  template < typename GUM_SCALAR >
437  INLINE bool
438  PRMSystem< GUM_SCALAR >::isInstance(const std::string& name) const {
439  return nameMap_.exists(name);
440  }
441 
442  template < typename GUM_SCALAR >
443  INLINE bool PRMSystem< GUM_SCALAR >::isArray(const std::string& name) const {
444  return arrayMap_.exists(name);
445  }
446 
447  template < typename GUM_SCALAR >
449  for (auto iter = begin(); iter != end(); ++iter) {
450  (*(iter.val())).instantiate();
451  }
452  }
453 
454  template < typename GUM_SCALAR >
456  PRMSystem< GUM_SCALAR >::get(const std::string& name) {
457  try {
458  return *(nameMap_[name]);
459  } catch (NotFound&) {
461  "found no Instance<GUM_SCALAR> matching the given name");
462  }
463  }
464 
465  template < typename GUM_SCALAR >
466  INLINE const PRMInstance< GUM_SCALAR >&
467  PRMSystem< GUM_SCALAR >::get(const std::string& name) const {
468  try {
469  return *(nameMap_[name]);
470  } catch (NotFound&) {
472  "found no Instance<GUM_SCALAR> matching the given name");
473  }
474  }
475 
476  template < typename GUM_SCALAR >
477  INLINE const Set< PRMInstance< GUM_SCALAR >* >&
478 
480  try {
481  return *(instanceMap_[const_cast< PRMClass< GUM_SCALAR >* >(&type)]);
482  } catch (NotFound&) {
483  GUM_ERROR(
484  NotFound,
485  "the given Class<GUM_SCALAR> has no instantiation in this System");
486  }
487  }
488 
489  template < typename GUM_SCALAR >
490  INLINE const Sequence< PRMInstance< GUM_SCALAR >* >&
491 
492  PRMSystem< GUM_SCALAR >::getArray(const std::string& name) const {
493  try {
494  return *(arrayMap_[name].second);
495  } catch (NotFound&) {
496  GUM_ERROR(NotFound, "found no array matching the given name");
497  }
498  }
499 
500  template < typename GUM_SCALAR >
502  PRMSystem< GUM_SCALAR >::getArrayType(const std::string& name) {
503  try {
504  return *(arrayMap_[name].first);
505  } catch (NotFound&) {
506  GUM_ERROR(NotFound, "found no array matching the given name");
507  }
508  }
509 
510  template < typename GUM_SCALAR >
512  PRMSystem< GUM_SCALAR >::getArrayType(const std::string& name) const {
513  try {
514  return *(arrayMap_[name].first);
515  } catch (NotFound&) {
516  GUM_ERROR(NotFound, "found no array matching the given name");
517  }
518  }
519 
520  template < typename GUM_SCALAR >
521  INLINE NodeId PRMSystem< GUM_SCALAR >::add(const std::string& array,
523  try {
524  if (i->type().isSubTypeOf(*(arrayMap_[array].first))) {
525  NodeId id = add(i);
526  arrayMap_[array].second->insert(i);
527  return id;
528  } else {
530  "the given Instance<GUM_SCALAR> is of an incorrect "
531  "Class<GUM_SCALAR> type");
532  }
533  } catch (NotFound&) {
534  GUM_ERROR(NotFound, "found no array matching the given name");
535  }
536  }
537 
538  template < typename GUM_SCALAR >
540  const std::string& array, PRMClassElementContainer< GUM_SCALAR >& type) {
541  if (arrayMap_.exists(array)) {
543  "an array '" << array << "' is already in this System");
544  }
545 
546  arrayMap_.insert(array,
548  &type, new Sequence< PRMInstance< GUM_SCALAR >* >()));
549  }
550 
551  template < typename GUM_SCALAR >
552  INLINE typename PRMSystem< GUM_SCALAR >::iterator
554  return nodeIdMap_.begin();
555  }
556 
557  template < typename GUM_SCALAR >
558  INLINE const typename PRMSystem< GUM_SCALAR >::iterator&
560  return nodeIdMap_.end();
561  }
562 
563  template < typename GUM_SCALAR >
566  return nodeIdMap_.begin();
567  }
568 
569  template < typename GUM_SCALAR >
570  INLINE const typename PRMSystem< GUM_SCALAR >::const_iterator&
572  return nodeIdMap_.end();
573  }
574 
575  template < typename GUM_SCALAR >
577  PRMSystem< GUM_SCALAR >::begin(const std::string& a) {
578  try {
579  return arrayMap_[a].second->begin();
580  } catch (NotFound&) {
581  GUM_ERROR(NotFound, "found no array matching the given name");
582  }
583  }
584 
585  template < typename GUM_SCALAR >
586  INLINE const typename PRMSystem< GUM_SCALAR >::array_iterator&
587  PRMSystem< GUM_SCALAR >::end(const std::string& a) {
588  try {
589  return arrayMap_[a].second->end();
590  } catch (NotFound&) {
591  GUM_ERROR(NotFound, "found no array matching the given name");
592  }
593  }
594 
595  template < typename GUM_SCALAR >
597  PRMSystem< GUM_SCALAR >::begin(const std::string& a) const {
598  try {
599  return arrayMap_[a].second->begin();
600  } catch (NotFound&) {
601  GUM_ERROR(NotFound, "found no array matching the given name");
602  }
603  }
604 
605  template < typename GUM_SCALAR >
606  INLINE const typename PRMSystem< GUM_SCALAR >::const_array_iterator&
607  PRMSystem< GUM_SCALAR >::end(const std::string& a) const {
608  try {
609  return arrayMap_[a].second->end();
610  } catch (NotFound&) {
611  GUM_ERROR(NotFound, "found no array matching the given name");
612  }
613  }
614 
615  template < typename GUM_SCALAR >
616  INLINE bool PRMSystem< GUM_SCALAR >::exists(const std::string& name) const {
617  return nameMap_.exists(name) || arrayMap_.exists(name);
618  }
619 
620  } /* namespace prm */
621 } /* namespace gum */
void insert(const T1 &first, const T2 &second)
Inserts a new association in the gum::Bijection.
aGrUM&#39;s Potential is a multi-dimensional array with tensor operators.
Definition: potential.h:60
const T2 & second(const T1 &first) const
Returns the second value of a pair given its first value.
Sum aggregator.
Definition: sum.h:52
void setName(const std::string &theValue)
sets the name of the variable
const PRMInstance< GUM_SCALAR > & getInstance(NodeId id) const
Fast access to the first instance in a PRMReferenceSlot or PRMSlotChain<GUM_SCALAR>.
void variableName(const std::string &name) final
Tells the factory the current variable&#39;s name.
Unsafe Const Iterators for hashtablesHashTableConstIterator provides a fast but unsafe way to parse H...
Definition: hashTable.h:2465
class LabelizedVariable
PRMAttribute< GUM_SCALAR > & get(NodeId id)
Getter on an PRMAttribute<GUM_SCALAR> of this PRMInstance<GUM_SCALAR>.
void setVariableCPTImplementation(MultiDimAdressable *adressable) final
Defines the implementation to use for var&#39;s Potential.
const std::string & name() const
Returns the name of this object.
Definition: PRMObject_inl.h:35
iterator begin()
Returns an iterator over the instances in this system.
void addParent(const std::string &var) final
Tells the factory for which variable we&#39;re declaring parents.
virtual PRMType & type()=0
See gum::PRMClassElement::type().
An PRMInstance is a Bayesian Network fragment defined by a Class and used in a PRMSystem.
Definition: PRMInstance.h:63
void setVariable(const DiscreteVariable &var) final
Define a variable.
or aggregator
Definition: or.h:56
Unsafe Iterators for hashtablesHashTableIterator provides a fast but unsafe way to parse HashTables...
Definition: hashTable.h:2750
The generic class for storing (ordered) sequences of objects.
Definition: sequence.h:1022
PRMClass< GUM_SCALAR > & type()
Returns the type of this instance.
Class for discretized random variable.
void addNetworkProperty(const std::string &propName, const std::string &propValue) final
Tells the factory to add a property to the current network.
void startParentsDeclaration(const std::string &var) final
Tells the factory that we&#39;re declaring parents for some variable.
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
virtual VarType varType() const =0
returns the varType of variable
Abstract class representing an element of PRM class.
void endParentsDeclaration() final
Tells the factory that we&#39;ve finished declaring parents for some variable.
Base class for discrete random variable.
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
Definition: agrum.h:25
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
void variableType(const VarType &type)
Tells the factory the current variable&#39;s type.
PRMSystem(const std::string &name)
Default constructor.
Definition: PRMSystem_tpl.h:42
forall aggregator
Definition: forall.h:55
Representation of a setA Set is a structure that contains arbitrary elements.
Definition: set.h:165
const std::string & safeName() const
Returns the safe name of this PRMClassElement, if any.
prm_type
Enumeration of the different types of objects handled by a PRM.
Definition: PRMObject.h:69
And aggregator.
Definition: and.h:55
void inc()
Operator increment.
exists aggregator
Definition: exists.h:54
void startNetworkDeclaration() final
Tells the factory that we&#39;re in a network declaration.
AggregateType agg_type() const
Returns the aggregate of *this.
virtual const Potential< GUM_SCALAR > & cpf() const =0
See gum::PRMClassElement::cpf().
void startVariableDeclaration() final
Tells the factory that we&#39;re in a variable declaration.
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
Base class for all oriented graphs.
Definition: diGraph.h:111
VarType
Definition: variable.h:41
A PRMSystem is a container of PRMInstance and describe a relational skeleton.
Definition: PRMObject.h:229
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
Sequence< PRMInstance< GUM_SCALAR > *>::iterator array_iterator
Iterator over the PRMInstance in an array in this PRMSystem.
Definition: PRMSystem.h:231
void instantiate()
Instantiate all the PRMInstance in this PRMSystem.
Set of pairs of elements with fast search for both elements.
Definition: bijection.h:1805
void addMax(const long &max)
Adds the max value of the current range variable.
NodeId endVariableDeclaration() final
Tells the factory that we&#39;re out of a variable declaration.
Defines a discrete random variable over an integer interval.
Definition: rangeVariable.h:54
virtual PRMType & type()=0
Return a reference over the gum::PRMType of this class element.
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
A PRMSlotChain represents a sequence of gum::prm::PRMClassElement<GUM_SCALAR> where the n-1 first gum...
Definition: PRMObject.h:221
std::pair< PRMClassElementContainer< GUM_SCALAR > *, Sequence< PRMInstance< GUM_SCALAR > *> *> model_pair
Typedef of the pair of a Class<GUM_SCALAR> and the sequence of it&#39;s instantiation.
Definition: PRMSystem.h:289
Abstract base class for any element defined in a PRM.
Definition: PRMObject.h:56
Class for assigning/browsing values to tuples of discrete variables.
Definition: instantiation.h:83
void setVariableCPT(const std::string &varName, MultiDimAdressable *table, bool redefineParents) final
Define a variable&#39;s CPT.
virtual void add(const DiscreteVariable &v) final
Adds a new var to the variables of the multidimensional matrix.
Sequence< PRMInstance< GUM_SCALAR > *>::const_iterator const_array_iterator
Iterator over the PRMInstance in an array in this PRMSystem.
Definition: PRMSystem.h:245
<agrum/PRM/classElementContainer.h>
NodeId id() const
Returns the NodeId of this element in it&#39;s class DAG.
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
bool exists(const std::string &name) const
Retruns true either if name is an instance or an array in this PRMSystem.
A PRMClass is an object of a PRM representing a fragment of a Bayesian Network which can be instantia...
Definition: PRMClass.h:66
void addMin(const long &min)
Adds the min value of the current range variable.
Size size() const
Returns the number of PRMInstance in this PRMSystem.
virtual void set(const Instantiation &i, const GUM_SCALAR &value) const final
Default implementation of MultiDimContainer::set().
void setFirst()
Assign the first values to the tuple of the Instantiation.
void addTick(const GUM_SCALAR &tick)
Adds a tick to the current Discretized variable.
Size Idx
Type for indexes.
Definition: types.h:53
void endNetworkDeclaration() final
Tells the factory that we&#39;re out of a network declaration.
max aggregator
Definition: max.h:54
const DiscreteVariable & variable(const std::string &name) const
Returns a constant reference on a variable given it&#39;s name.
void addModality(const std::string &name) final
Adds a modality to the current labelized variable.
PRMAttribute is a member of a Class in a PRM.
Definition: PRMAttribute.h:61
median aggregator
Definition: median.h:60
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
const iterator & end()
Returns a iterator at the end of the set of PRMInstance in this PRMSystem.
PRMClassElement< GUM_SCALAR > & lastElt()
Returns the last element of the slot chain, typically this is an gum::PRMAttribute or a gum::PRMAggre...
amplitude aggregator
Definition: amplitude.h:55
Idx label() const
Returns the label&#39;s index on which this aggregate applies.
Size NodeId
Type for node ids.
Definition: graphElements.h:98
min aggregator
Definition: min.h:53
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
A factory class to ease BayesNet construction.
Definition: BayesNet.h:45
bool end() const
Returns true if the Instantiation reached the end.
count aggregator
Definition: count.h:57