FST  openfst-1.8.3
OpenFst Library
sparse-tuple-weight.h
Go to the documentation of this file.
1 // Copyright 2005-2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the 'License');
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an 'AS IS' BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // See www.openfst.org for extensive documentation on this weighted
16 // finite-state transducer library.
17 //
18 // Sparse version of tuple-weight, based on tuple-weight.h.
19 // Internally stores sparse key, value pairs in linked list. The default value
20 // element is the assumed value of unset keys. Internal singleton
21 // implementation that stores first key, value pair as a initialized member
22 // variable to avoid unnecessary allocation on heap. Use
23 // SparseTupleWeightIterator to iterate through the key,value pairs. Note:
24 // this does NOT iterate through the default value.
25 //
26 // Sparse tuple weight set operation definitions.
27 
28 #ifndef FST_SPARSE_TUPLE_WEIGHT_H_
29 #define FST_SPARSE_TUPLE_WEIGHT_H_
30 
31 #include <algorithm>
32 #include <cstddef>
33 #include <functional>
34 #include <istream>
35 #include <list>
36 #include <ostream>
37 #include <stack>
38 #include <string>
39 #include <utility>
40 
41 #include <fst/util.h>
42 #include <fst/weight.h>
43 
44 namespace fst {
45 
46 template <class W, class K>
48 
49 // Arbitrary dimension tuple weight, stored as a sorted linked-list.
50 // W is any weight class, and K is the key value type. kNoKey (-1) is reserved
51 // for internal use.
52 template <class W, class K = int>
54  public:
56 
58  using Pair = std::pair<K, W>;
59  using Weight = W;
60  using Index = K;
61 
62  static constexpr K kNoKey = -1;
63 
65 
66  ~SparseTupleWeight() noexcept = default;
67 
68  template <class Iterator>
70  Init();
71  // Assumes input iterator is sorted.
72  for (auto it = begin; it != end; ++it) PushBack(*it);
73  }
74 
75  // Initialize component `key` to `weight`, with `default_weight` for all
76  // other components.
77  SparseTupleWeight(const K &key, const W &weight, const W &default_weight)
78  : default_(default_weight),
79  first_(weight == default_weight ? kNoKey : key, weight) {}
80 
81  explicit SparseTupleWeight(const W &weight) { Init(weight); }
82 
84  Init(weight.DefaultValue());
85  SetDefaultValue(weight.DefaultValue());
86  for (Iterator it(weight); !it.Done(); it.Next()) {
87  PushBack(it.Value());
88  }
89  }
90 
92  // Don't move the default, so weight.default_ is still valid.
93  : default_(weight.default_), // NOLINT
94  first_(std::move(weight.first_)),
95  rest_(std::move(weight.rest_)) {
96  // move leaves the source in a valid but unspecified state.
97  // Make sure the source weight is empty.
98  weight.first_ = Pair(kNoKey, W::NoWeight());
99  weight.rest_.clear();
100  }
101 
102  static const SparseTupleWeight &Zero() {
103  static const SparseTupleWeight zero(W::Zero());
104  return zero;
105  }
106 
107  static const SparseTupleWeight &One() {
108  static const SparseTupleWeight one(W::One());
109  return one;
110  }
111 
112  static const SparseTupleWeight &NoWeight() {
113  static const SparseTupleWeight no_weight(W::NoWeight());
114  return no_weight;
115  }
116 
117  std::istream &Read(std::istream &strm) {
118  ReadType(strm, &default_);
119  ReadType(strm, &first_);
120  return ReadType(strm, &rest_);
121  }
122 
123  std::ostream &Write(std::ostream &strm) const {
124  WriteType(strm, default_);
125  WriteType(strm, first_);
126  return WriteType(strm, rest_);
127  }
128 
130  if (this == &weight) return *this; // Checks for identity.
131  Init(weight.DefaultValue());
132  for (Iterator it(weight); !it.Done(); it.Next()) {
133  PushBack(it.Value());
134  }
135  return *this;
136  }
137 
139  if (this == &weight) return *this; // Checks for identity.
140  // Don't move the default, so weight.default_ is still valid.
141  default_ = weight.default_;
142  first_ = std::move(weight.first_);
143  rest_ = std::move(weight.rest_);
144  // move leaves the source in a valid but unspecified state.
145  // Make sure the source weight is empty.
146  weight.first_ = Pair(kNoKey, W::NoWeight());
147  weight.rest_.clear();
148  return *this;
149  }
150 
151  bool Member() const {
152  if (!DefaultValue().Member()) return false;
153  for (Iterator it(*this); !it.Done(); it.Next()) {
154  if (!it.Value().second.Member()) return false;
155  }
156  return true;
157  }
158 
159  // Assumes H() function exists for the hash of the key value.
160  size_t Hash() const {
161  size_t h = 0;
162  static const std::hash<K> H;
163  for (Iterator it(*this); !it.Done(); it.Next()) {
164  h = 5 * h + H(it.Value().first);
165  h = 13 * h + it.Value().second.Hash();
166  }
167  return h;
168  }
169 
170  SparseTupleWeight Quantize(float delta = kDelta) const {
171  SparseTupleWeight weight;
172  for (Iterator it(*this); !it.Done(); it.Next()) {
173  weight.PushBack(it.Value().first, it.Value().second.Quantize(delta));
174  }
175  return weight;
176  }
177 
179  ReverseWeight weight(DefaultValue().Reverse());
180  for (Iterator it(*this); !it.Done(); it.Next()) {
181  weight.PushBack(it.Value().first, it.Value().second.Reverse());
182  }
183  return weight;
184  }
185 
186  void Init(const W &default_value = W::Zero()) {
187  first_ = Pair(kNoKey, W::NoWeight());
188  // Initialized to the reserved key value.
189  default_ = default_value;
190  rest_.clear();
191  }
192 
193  size_t Size() const {
194  if (first_.first == kNoKey) {
195  return 0;
196  } else {
197  return rest_.size() + 1;
198  }
199  }
200 
201  inline void PushBack(const K &key, const W &weight,
202  bool default_value_check = true) {
203  PushBack(std::make_pair(key, weight), default_value_check);
204  }
205 
206  inline void PushBack(const Pair &pair, bool default_value_check = true) {
207  if (default_value_check && pair.second == default_) return;
208  if (first_.first == kNoKey) {
209  first_ = pair;
210  } else {
211  rest_.push_back(pair);
212  }
213  }
214 
215  // Returns the `key`-th component, or the default value if not set.
216  const W &Value(const K &key) const {
217  // TODO(rybach): Consider binary search.
218  Iterator iter(*this);
219  for (; !iter.Done() && iter.Value().first < key; iter.Next()) continue;
220  return !iter.Done() && iter.Value().first == key ? iter.Value().second
221  : DefaultValue();
222  }
223 
224  void SetValue(const K &key, const W &w) {
225  if (w == DefaultValue()) {
226  ClearValue(key);
227  } else {
228  SetValueToNonDefault(key, w);
229  }
230  }
231 
232  void SetDefaultValue(const W &value) { default_ = value; }
233 
234  const W &DefaultValue() const { return default_; }
235 
236  private:
237  void SetValueToNonDefault(const K &key, const W &w) {
238  // Don't use SparseTupleWeightIterator, since that's const.
239  if (first_.first == kNoKey) {
240  first_ = Pair(key, w);
241  } else if (key < first_.first) {
242  rest_.push_front(first_);
243  first_ = Pair(key, w);
244  } else if (key == first_.first) {
245  first_.second = w;
246  } else {
247  const auto i =
248  std::find_if(rest_.begin(), rest_.end(),
249  [key](const Pair &p) { return p.first >= key; });
250  if (i != rest_.end() && i->first == key) {
251  i->second = w;
252  } else {
253  rest_.insert(i, Pair(key, w));
254  }
255  }
256  }
257 
258  // Removes the weight value for `key`, having the effect of setting
259  // it to `DefaultValue()`.
260  void ClearValue(const K &key) {
261  if (key == first_.first) {
262  if (!rest_.empty()) {
263  first_ = rest_.front();
264  rest_.pop_front();
265  } else {
266  first_.first = kNoKey;
267  }
268  } else if (key > first_.first) {
269  const auto i =
270  std::find_if(rest_.begin(), rest_.end(),
271  [key](const Pair &p) { return p.first >= key; });
272  if (i != rest_.end() && i->first == key) {
273  rest_.erase(i);
274  }
275  }
276  }
277 
278  // Assumed default value of uninitialized keys, by default W::Zero().
279  W default_;
280 
281  // Key values pairs are first stored in first_, then fill rest_ this way we
282  // can avoid dynamic allocation in the common case where the weight is a
283  // single key/value pair.
284  Pair first_;
285  std::list<Pair> rest_;
286 
287  friend class SparseTupleWeightIterator<W, K>;
288 };
289 
290 template <class W, class K>
292  public:
294  using const_iterator = typename std::list<Pair>::const_iterator;
295  using iterator = typename std::list<Pair>::iterator;
296 
298  : first_(weight.first_),
299  rest_(weight.rest_),
300  init_(true),
301  iter_(rest_.begin()) {}
302 
303  bool Done() const {
304  if (init_) {
305  return first_.first == SparseTupleWeight<W, K>::kNoKey;
306  } else {
307  return iter_ == rest_.end();
308  }
309  }
310 
311  const Pair &Value() const { return init_ ? first_ : *iter_; }
312 
313  void Next() {
314  if (init_) {
315  init_ = false;
316  } else {
317  ++iter_;
318  }
319  }
320 
321  void Reset() {
322  init_ = true;
323  iter_ = rest_.begin();
324  }
325 
326  private:
327  const Pair &first_;
328  const std::list<Pair> &rest_;
329  bool init_; // In the initialized state?
330  const_iterator iter_;
331 };
332 
333 // M must be callable as a function W(K, W, W).
334 // K will be kNoKey when mapping the default value.
335 template <class W, class K, class M>
337  const SparseTupleWeight<W, K> &w1,
338  const SparseTupleWeight<W, K> &w2,
339  const M &operator_mapper) {
342  const auto &v1_def = w1.DefaultValue();
343  const auto &v2_def = w2.DefaultValue();
344  result->SetDefaultValue(
345  operator_mapper(SparseTupleWeight<W, K>::kNoKey, v1_def, v2_def));
346  while (!w1_it.Done() || !w2_it.Done()) {
347  const auto &k1 = (w1_it.Done()) ? w2_it.Value().first : w1_it.Value().first;
348  const auto &k2 = (w2_it.Done()) ? w1_it.Value().first : w2_it.Value().first;
349  const auto &v1 = (w1_it.Done()) ? v1_def : w1_it.Value().second;
350  const auto &v2 = (w2_it.Done()) ? v2_def : w2_it.Value().second;
351  if (k1 == k2) {
352  result->PushBack(k1, operator_mapper(k1, v1, v2));
353  if (!w1_it.Done()) w1_it.Next();
354  if (!w2_it.Done()) w2_it.Next();
355  } else if (k1 < k2) {
356  result->PushBack(k1, operator_mapper(k1, v1, v2_def));
357  w1_it.Next();
358  } else {
359  result->PushBack(k2, operator_mapper(k2, v1_def, v2));
360  w2_it.Next();
361  }
362  }
363 }
364 
365 template <class W, class K>
366 inline bool operator==(const SparseTupleWeight<W, K> &w1,
367  const SparseTupleWeight<W, K> &w2) {
368  const auto &v1_def = w1.DefaultValue();
369  const auto &v2_def = w2.DefaultValue();
370  if (v1_def != v2_def) return false;
373  while (!w1_it.Done() || !w2_it.Done()) {
374  const auto &k1 = (w1_it.Done()) ? w2_it.Value().first : w1_it.Value().first;
375  const auto &k2 = (w2_it.Done()) ? w1_it.Value().first : w2_it.Value().first;
376  const auto &v1 = (w1_it.Done()) ? v1_def : w1_it.Value().second;
377  const auto &v2 = (w2_it.Done()) ? v2_def : w2_it.Value().second;
378  if (k1 == k2) {
379  if (v1 != v2) return false;
380  if (!w1_it.Done()) w1_it.Next();
381  if (!w2_it.Done()) w2_it.Next();
382  } else if (k1 < k2) {
383  if (v1 != v2_def) return false;
384  w1_it.Next();
385  } else {
386  if (v1_def != v2) return false;
387  w2_it.Next();
388  }
389  }
390  return true;
391 }
392 
393 template <class W, class K>
394 inline bool operator!=(const SparseTupleWeight<W, K> &w1,
395  const SparseTupleWeight<W, K> &w2) {
396  return !(w1 == w2);
397 }
398 
399 template <class W, class K>
400 inline std::ostream &operator<<(std::ostream &strm,
401  const SparseTupleWeight<W, K> &weight) {
402  CompositeWeightWriter writer(strm);
403  writer.WriteBegin();
404  writer.WriteElement(weight.DefaultValue());
405  for (SparseTupleWeightIterator<W, K> it(weight); !it.Done(); it.Next()) {
406  writer.WriteElement(it.Value().first);
407  writer.WriteElement(it.Value().second);
408  }
409  writer.WriteEnd();
410  return strm;
411 }
412 
413 template <class W, class K>
414 inline std::istream &operator>>(std::istream &strm,
415  SparseTupleWeight<W, K> &weight) {
416  CompositeWeightReader reader(strm);
417  reader.ReadBegin();
418  W def;
419  bool more = reader.ReadElement(&def);
420  weight.Init(def);
421  while (more) {
422  K key;
423  reader.ReadElement(&key);
424  W v;
425  more = reader.ReadElement(&v);
426  weight.PushBack(key, v);
427  }
428  reader.ReadEnd();
429  return strm;
430 }
431 
432 } // namespace fst
433 
434 #endif // FST_SPARSE_TUPLE_WEIGHT_H_
void PushBack(const Pair &pair, bool default_value_check=true)
void PushBack(const K &key, const W &weight, bool default_value_check=true)
~SparseTupleWeight() noexcept=default
SparseTupleWeight & operator=(SparseTupleWeight &&weight) noexcept
void Init(const W &default_value=W::Zero())
std::ostream & Write(std::ostream &strm) const
void SparseTupleWeightMap(SparseTupleWeight< W, K > *result, const SparseTupleWeight< W, K > &w1, const SparseTupleWeight< W, K > &w2, const M &operator_mapper)
static const SparseTupleWeight & Zero()
static const SparseTupleWeight & One()
SparseTupleWeightIterator(const SparseTupleWeight< W, K > &weight)
static const SparseTupleWeight & NoWeight()
void SetValue(const K &key, const W &w)
std::ostream & WriteType(std::ostream &strm, const T t)
Definition: util.h:228
std::istream & operator>>(std::istream &strm, FloatWeightTpl< T > &w)
Definition: float-weight.h:185
SparseTupleWeight(Iterator begin, Iterator end)
bool operator!=(const ErrorWeight &, const ErrorWeight &)
Definition: error-weight.h:54
SparseTupleWeight(const K &key, const W &weight, const W &default_weight)
void SetDefaultValue(const W &value)
std::ostream & operator<<(std::ostream &strm, const ErrorWeight &)
Definition: error-weight.h:71
static constexpr K kNoKey
SparseTupleWeight(const W &weight)
typename SparseTupleWeight< W, K >::Pair Pair
const W & DefaultValue() const
SparseTupleWeight & operator=(const SparseTupleWeight &weight)
SparseTupleWeight(const SparseTupleWeight &weight)
typename std::list< Pair >::const_iterator const_iterator
std::istream & Read(std::istream &strm)
bool ReadElement(T *comp, bool last=false)
Definition: weight.h:367
const W & Value(const K &key) const
bool operator==(const ErrorWeight &, const ErrorWeight &)
Definition: error-weight.h:51
SparseTupleWeight Quantize(float delta=kDelta) const
typename std::list< Pair >::iterator iterator
std::istream & ReadType(std::istream &strm, T *t)
Definition: util.h:80
void WriteElement(const T &comp)
Definition: weight.h:317
SparseTupleWeight(SparseTupleWeight &&weight) noexcept
ReverseWeight Reverse() const
constexpr float kDelta
Definition: weight.h:133