You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

595 lines
21 KiB

  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. // Functions and classes to disambiguate an FST.
  19. #ifndef FST_DISAMBIGUATE_H_
  20. #define FST_DISAMBIGUATE_H_
  21. #include <sys/types.h>
  22. #include <cstdint>
  23. #include <list>
  24. #include <map>
  25. #include <memory>
  26. #include <set>
  27. #include <utility>
  28. #include <vector>
  29. #include <fst/log.h>
  30. #include <fst/arcsort.h>
  31. #include <fst/cc-visitors.h>
  32. #include <fst/compose-filter.h>
  33. #include <fst/compose.h>
  34. #include <fst/connect.h>
  35. #include <fst/determinize.h>
  36. #include <fst/dfs-visit.h>
  37. #include <fst/expanded-fst.h>
  38. #include <fst/filter-state.h>
  39. #include <fst/fst.h>
  40. #include <fst/matcher.h>
  41. #include <fst/mutable-fst.h>
  42. #include <fst/project.h>
  43. #include <fst/properties.h>
  44. #include <fst/prune.h>
  45. #include <fst/state-map.h>
  46. #include <fst/state-table.h>
  47. #include <fst/union-find.h>
  48. #include <fst/util.h>
  49. #include <fst/vector-fst.h>
  50. #include <fst/verify.h>
  51. #include <fst/weight.h>
  52. namespace fst {
  53. template <class Arc>
  54. struct DisambiguateOptions : public DeterminizeOptions<Arc> {
  55. using Label = typename Arc::Label;
  56. using StateId = typename Arc::StateId;
  57. using Weight = typename Arc::Weight;
  58. explicit DisambiguateOptions(float delta = kDelta,
  59. Weight weight = Weight::Zero(),
  60. StateId n = kNoStateId, Label label = 0)
  61. : DeterminizeOptions<Arc>(delta, std::move(weight), n, label,
  62. DETERMINIZE_FUNCTIONAL) {}
  63. };
  64. namespace internal {
  65. // A determinization filter based on a subset element relation. The relation is
  66. // assumed to be reflexive and symmetric.
  67. template <class Arc, class Relation>
  68. class RelationDeterminizeFilter {
  69. public:
  70. using Label = typename Arc::Label;
  71. using StateId = typename Arc::StateId;
  72. using Weight = typename Arc::Weight;
  73. using FilterState = IntegerFilterState<StateId>;
  74. using StateTuple = DeterminizeStateTuple<Arc, FilterState>;
  75. using Subset = typename StateTuple::Subset;
  76. using Element = typename StateTuple::Element;
  77. using LabelMap = std::multimap<Label, DeterminizeArc<StateTuple>>;
  78. // This is needed (e.g.) to go into the gallic domain for transducers; there
  79. // is no need to rebind the relation since its use here only depends on the
  80. // state IDs.
  81. template <class A>
  82. struct rebind {
  83. using Other = RelationDeterminizeFilter<A, Relation>;
  84. };
  85. explicit RelationDeterminizeFilter(const Fst<Arc> &fst)
  86. : fst_(fst.Copy()),
  87. head_(nullptr),
  88. r_(std::make_unique<Relation>()),
  89. s_(kNoStateId) {}
  90. RelationDeterminizeFilter(const Fst<Arc> &fst, std::unique_ptr<Relation> r,
  91. std::vector<StateId> *head = nullptr)
  92. : fst_(fst.Copy()), head_(head), r_(std::move(r)), s_(kNoStateId) {}
  93. // This is needed, e.g., to go into the gallic domain for transducers.
  94. template <class Filter>
  95. RelationDeterminizeFilter(const Fst<Arc> &fst, std::unique_ptr<Filter> filter)
  96. : fst_(fst.Copy()),
  97. head_(filter->GetHeadStates()),
  98. r_(std::move(*filter).GetRelation()),
  99. s_(kNoStateId) {}
  100. // Copy constructor; the FST can be passed if it has been deep-copied.
  101. RelationDeterminizeFilter(const RelationDeterminizeFilter &filter,
  102. const Fst<Arc> *fst = nullptr)
  103. : fst_(fst ? fst->Copy() : filter.fst_->Copy()),
  104. head_(nullptr),
  105. r_(std::make_unique<Relation>(*filter.r_)),
  106. s_(kNoStateId) {}
  107. FilterState Start() const { return FilterState(fst_->Start()); }
  108. void SetState(StateId s, const StateTuple &tuple) {
  109. if (s_ != s) {
  110. s_ = s;
  111. tuple_ = &tuple;
  112. const auto head = tuple.filter_state.GetState();
  113. is_final_ = fst_->Final(head) != Weight::Zero();
  114. if (head_) {
  115. if (head_->size() <= s) head_->resize(s + 1, kNoStateId);
  116. (*head_)[s] = head;
  117. }
  118. }
  119. }
  120. // Filters transition, possibly modifying label map. Returns true if arc is
  121. // added to label map.
  122. bool FilterArc(const Arc &arc, const Element &src_element,
  123. const Element &dest_element, LabelMap *label_map) const;
  124. // Filters super-final transition, returning new final weight.
  125. Weight FilterFinal(const Weight final_weight, const Element &element) const {
  126. return is_final_ ? final_weight : Weight::Zero();
  127. }
  128. static uint64_t Properties(uint64_t props) {
  129. return props & ~(kIDeterministic | kODeterministic);
  130. }
  131. std::unique_ptr<Relation> GetRelation() && { return std::move(r_); }
  132. std::vector<StateId> *GetHeadStates() { return head_; }
  133. private:
  134. // Pairs arc labels with state tuples with possible heads and empty subsets.
  135. void InitLabelMap(LabelMap *label_map) const;
  136. std::unique_ptr<Fst<Arc>> fst_; // Input FST.
  137. std::vector<StateId> *head_; // Head state for a given state,
  138. // owned by the Disambiguator.
  139. std::unique_ptr<Relation> r_; // Relation compatible with inv. trans. fnc.
  140. StateId s_; // Current state.
  141. const StateTuple *tuple_; // Current tuple.
  142. bool is_final_; // Is the current head state final?
  143. };
  144. template <class Arc, class Relation>
  145. bool RelationDeterminizeFilter<Arc, Relation>::FilterArc(
  146. const Arc &arc, const Element &src_element, const Element &dest_element,
  147. LabelMap *label_map) const {
  148. bool added = false;
  149. if (label_map->empty()) InitLabelMap(label_map);
  150. // Adds element to state tuple if element state is related to tuple head.
  151. for (auto liter = label_map->lower_bound(arc.ilabel);
  152. liter != label_map->end() && liter->first == arc.ilabel; ++liter) {
  153. const auto &dest_tuple = liter->second.dest_tuple;
  154. const auto dest_head = dest_tuple->filter_state.GetState();
  155. if ((*r_)(dest_element.state_id, dest_head)) {
  156. dest_tuple->subset.push_front(dest_element);
  157. added = true;
  158. }
  159. }
  160. return added;
  161. }
  162. template <class Arc, class Relation>
  163. void RelationDeterminizeFilter<Arc, Relation>::InitLabelMap(
  164. LabelMap *label_map) const {
  165. const auto src_head = tuple_->filter_state.GetState();
  166. Label label = kNoLabel;
  167. StateId nextstate = kNoStateId;
  168. for (ArcIterator<Fst<Arc>> aiter(*fst_, src_head); !aiter.Done();
  169. aiter.Next()) {
  170. const auto &arc = aiter.Value();
  171. // Continues if multiarc.
  172. if (arc.ilabel == label && arc.nextstate == nextstate) continue;
  173. DeterminizeArc<StateTuple> det_arc(arc);
  174. det_arc.dest_tuple->filter_state = FilterState(arc.nextstate);
  175. label_map->emplace(arc.ilabel, std::move(det_arc));
  176. label = arc.ilabel;
  177. nextstate = arc.nextstate;
  178. }
  179. }
  180. // Helper class to disambiguate an FST via Disambiguate().
  181. template <class Arc>
  182. class Disambiguator {
  183. public:
  184. using Label = typename Arc::Label;
  185. using StateId = typename Arc::StateId;
  186. using Weight = typename Arc::Weight;
  187. // IDs arcs with state ID and arc position. Arc position -1 indicates final
  188. // (super-final transition).
  189. using ArcId = std::pair<StateId, ssize_t>;
  190. Disambiguator() : error_(false) {}
  191. void Disambiguate(
  192. const Fst<Arc> &ifst, MutableFst<Arc> *ofst,
  193. const DisambiguateOptions<Arc> &opts = DisambiguateOptions<Arc>()) {
  194. VectorFst<Arc> sfst(ifst);
  195. Connect(&sfst);
  196. ArcSort(&sfst, ArcCompare());
  197. PreDisambiguate(sfst, ofst, opts);
  198. ArcSort(ofst, ArcCompare());
  199. FindAmbiguities(*ofst);
  200. RemoveSplits(ofst);
  201. MarkAmbiguities();
  202. RemoveAmbiguities(ofst);
  203. if (error_) ofst->SetProperties(kError, kError);
  204. }
  205. private:
  206. // Comparison functor for comparing input labels and next states of arcs. This
  207. // sort order facilitates the predisambiguation.
  208. class ArcCompare {
  209. public:
  210. bool operator()(const Arc &arc1, const Arc &arc2) const {
  211. return arc1.ilabel < arc2.ilabel ||
  212. (arc1.ilabel == arc2.ilabel && arc1.nextstate < arc2.nextstate);
  213. }
  214. uint64_t Properties(uint64_t props) const {
  215. return (props & kArcSortProperties) | kILabelSorted |
  216. (props & kAcceptor ? kOLabelSorted : 0);
  217. }
  218. };
  219. // Comparison functor for comparing transitions represented by their arc ID.
  220. // This sort order facilitates ambiguity detection.
  221. class ArcIdCompare {
  222. public:
  223. explicit ArcIdCompare(const std::vector<StateId> &head) : head_(head) {}
  224. bool operator()(const ArcId &a1, const ArcId &a2) const {
  225. // Sort first by source head state...
  226. const auto src1 = a1.first;
  227. const auto src2 = a2.first;
  228. const auto head1 = head_[src1];
  229. const auto head2 = head_[src2];
  230. if (head1 < head2) return true;
  231. if (head2 < head1) return false;
  232. // ...then by source state...
  233. if (src1 < src2) return true;
  234. if (src2 < src1) return false;
  235. // ...then by position.
  236. return a1.second < a2.second;
  237. }
  238. private:
  239. const std::vector<StateId> &head_;
  240. };
  241. // A relation that determines if two states share a common future.
  242. class CommonFuture {
  243. public:
  244. using StateTable = GenericComposeStateTable<Arc, TrivialFilterState>;
  245. using StateTuple = typename StateTable::StateTuple;
  246. // Needed for compilation with DeterminizeRelationFilter.
  247. CommonFuture() {
  248. FSTERROR() << "Disambiguate::CommonFuture: FST not provided";
  249. }
  250. explicit CommonFuture(const Fst<Arc> &ifst) {
  251. using M = Matcher<Fst<Arc>>;
  252. ComposeFstOptions<Arc, M, NullComposeFilter<M>> opts;
  253. // Ensures composition is between acceptors.
  254. const bool trans = ifst.Properties(kNotAcceptor, true);
  255. const auto *fsa =
  256. trans ? new ProjectFst<Arc>(ifst, ProjectType::INPUT) : &ifst;
  257. opts.state_table = new StateTable(*fsa, *fsa);
  258. const ComposeFst<Arc> cfst(*fsa, *fsa, opts);
  259. std::vector<bool> coaccess;
  260. uint64_t props = 0;
  261. SccVisitor<Arc> scc_visitor(nullptr, nullptr, &coaccess, &props);
  262. DfsVisit(cfst, &scc_visitor);
  263. for (StateId s = 0; s < coaccess.size(); ++s) {
  264. if (coaccess[s]) {
  265. related_.insert(opts.state_table->Tuple(s).StatePair());
  266. }
  267. }
  268. if (trans) delete fsa;
  269. }
  270. bool operator()(const StateId s1, StateId s2) const {
  271. return related_.count(std::make_pair(s1, s2)) > 0;
  272. }
  273. private:
  274. // States s1 and s2 resp. are in this relation iff they there is a
  275. // path from s1 to a final state that has the same label as some
  276. // path from s2 to a final state.
  277. std::set<std::pair<StateId, StateId>> related_;
  278. };
  279. using ArcIdMap = std::multimap<ArcId, ArcId, ArcIdCompare>;
  280. // Inserts candidate into the arc ID map.
  281. inline void InsertCandidate(StateId s1, StateId s2, const ArcId &a1,
  282. const ArcId &a2) {
  283. candidates_->insert(head_[s1] > head_[s2] ? std::make_pair(a1, a2)
  284. : std::make_pair(a2, a1));
  285. }
  286. // Returns the arc corresponding to ArcId a.
  287. static Arc GetArc(const Fst<Arc> &fst, ArcId aid) {
  288. if (aid.second == -1) { // Returns super-final transition.
  289. return Arc(kNoLabel, kNoLabel, fst.Final(aid.first), kNoStateId);
  290. } else {
  291. ArcIterator<Fst<Arc>> aiter(fst, aid.first);
  292. aiter.Seek(aid.second);
  293. return aiter.Value();
  294. }
  295. }
  296. // Outputs an equivalent FST whose states are subsets of states that have a
  297. // future path in common.
  298. void PreDisambiguate(const ExpandedFst<Arc> &ifst, MutableFst<Arc> *ofst,
  299. const DisambiguateOptions<Arc> &opts);
  300. // Finds transitions that are ambiguous candidates in the result of
  301. // PreDisambiguate.
  302. void FindAmbiguities(const ExpandedFst<Arc> &fst);
  303. // Finds transition pairs that are ambiguous candidates from two specified
  304. // source states.
  305. void FindAmbiguousPairs(const ExpandedFst<Arc> &fst, StateId s1, StateId s2);
  306. // Marks ambiguous transitions to be removed.
  307. void MarkAmbiguities();
  308. // Deletes spurious ambiguous transitions (due to quantization).
  309. void RemoveSplits(MutableFst<Arc> *ofst);
  310. // Deletes actual ambiguous transitions.
  311. void RemoveAmbiguities(MutableFst<Arc> *ofst);
  312. // States s1 and s2 are in this relation iff there is a path from the initial
  313. // state to s1 that has the same label as some path from the initial state to
  314. // s2. We store only state pairs s1, s2 such that s1 <= s2.
  315. std::set<std::pair<StateId, StateId>> coreachable_;
  316. // Queue of disambiguation-related states to be processed. We store only
  317. // state pairs s1, s2 such that s1 <= s2.
  318. std::list<std::pair<StateId, StateId>> queue_;
  319. // Head state in the pre-disambiguation for a given state.
  320. std::vector<StateId> head_;
  321. // Maps from a candidate ambiguous arc A to each ambiguous candidate arc B
  322. // with the same label and destination state as A, whose source state s' is
  323. // coreachable with the source state s of A, and for which head(s') < head(s).
  324. std::unique_ptr<ArcIdMap> candidates_;
  325. // Set of ambiguous transitions to be removed.
  326. std::set<ArcId> ambiguous_;
  327. // States to merge due to quantization issues.
  328. std::unique_ptr<UnionFind<StateId>> merge_;
  329. // Marks error condition.
  330. bool error_;
  331. Disambiguator(const Disambiguator &) = delete;
  332. Disambiguator &operator=(const Disambiguator &) = delete;
  333. };
  334. template <class Arc>
  335. void Disambiguator<Arc>::PreDisambiguate(const ExpandedFst<Arc> &ifst,
  336. MutableFst<Arc> *ofst,
  337. const DisambiguateOptions<Arc> &opts) {
  338. using CommonDivisor = DefaultCommonDivisor<Weight>;
  339. using Filter = RelationDeterminizeFilter<Arc, CommonFuture>;
  340. // Subset elements with states s1 and s2 (resp.) are in this relation iff they
  341. // there is a path from s1 to a final state that has the same label as some
  342. // path from s2 to a final state.
  343. auto common_future = std::make_unique<CommonFuture>(ifst);
  344. DeterminizeFstOptions<Arc, CommonDivisor, Filter> nopts;
  345. nopts.delta = opts.delta;
  346. nopts.subsequential_label = opts.subsequential_label;
  347. nopts.filter = new Filter(ifst, std::move(common_future), &head_);
  348. // Determinization takes ownership of the filter itself.
  349. nopts.gc_limit = 0; // Cache only the last state for fastest copy.
  350. if (opts.weight_threshold != Weight::Zero() ||
  351. opts.state_threshold != kNoStateId) {
  352. if constexpr (IsPath<Weight>::value) {
  353. /* TODO(riley): fails regression test; understand why
  354. if (ifst.Properties(kAcceptor, true)) {
  355. std::vector<Weight> idistance, odistance;
  356. ShortestDistance(ifst, &idistance, true);
  357. DeterminizeFst<Arc> dfst(ifst, &idistance, &odistance, nopts);
  358. PruneOptions< Arc, AnyArcFilter<Arc>> popts(opts.weight_threshold,
  359. opts.state_threshold,
  360. AnyArcFilter<Arc>(),
  361. &odistance);
  362. Prune(dfst, ofst, popts);
  363. } else */
  364. {
  365. *ofst = DeterminizeFst<Arc>(ifst, nopts);
  366. Prune(ofst, opts.weight_threshold, opts.state_threshold);
  367. }
  368. } else {
  369. FSTERROR() << "Disambiguate: Weight must have path property to use "
  370. << "pruning options: " << Weight::Type();
  371. error_ = true;
  372. }
  373. } else {
  374. *ofst = DeterminizeFst<Arc>(ifst, nopts);
  375. }
  376. head_.resize(ofst->NumStates(), kNoStateId);
  377. }
  378. template <class Arc>
  379. void Disambiguator<Arc>::FindAmbiguities(const ExpandedFst<Arc> &fst) {
  380. if (fst.Start() == kNoStateId) return;
  381. candidates_ = std::make_unique<ArcIdMap>(ArcIdCompare(head_));
  382. const auto start_pr = std::make_pair(fst.Start(), fst.Start());
  383. coreachable_.insert(start_pr);
  384. queue_.push_back(start_pr);
  385. while (!queue_.empty()) {
  386. const auto &pr = queue_.front();
  387. const auto s1 = pr.first;
  388. const auto s2 = pr.second;
  389. queue_.pop_front();
  390. FindAmbiguousPairs(fst, s1, s2);
  391. }
  392. }
  393. template <class Arc>
  394. void Disambiguator<Arc>::FindAmbiguousPairs(const ExpandedFst<Arc> &fst,
  395. StateId s1, StateId s2) {
  396. if (fst.NumArcs(s2) > fst.NumArcs(s1)) FindAmbiguousPairs(fst, s2, s1);
  397. SortedMatcher<Fst<Arc>> matcher(fst, MATCH_INPUT);
  398. matcher.SetState(s2);
  399. for (ArcIterator<Fst<Arc>> aiter(fst, s1); !aiter.Done(); aiter.Next()) {
  400. const auto &arc1 = aiter.Value();
  401. const ArcId a1(s1, aiter.Position());
  402. if (matcher.Find(arc1.ilabel)) {
  403. for (; !matcher.Done(); matcher.Next()) {
  404. const auto &arc2 = matcher.Value();
  405. // Continues on implicit epsilon match.
  406. if (arc2.ilabel == kNoLabel) continue;
  407. const ArcId a2(s2, matcher.Position());
  408. // Actual transition is ambiguous.
  409. if (s1 != s2 && arc1.nextstate == arc2.nextstate) {
  410. InsertCandidate(s1, s2, a1, a2);
  411. }
  412. const auto spr = arc1.nextstate <= arc2.nextstate
  413. ? std::make_pair(arc1.nextstate, arc2.nextstate)
  414. : std::make_pair(arc2.nextstate, arc1.nextstate);
  415. // Not already marked as coreachable?
  416. if (coreachable_.insert(spr).second) {
  417. // Only possible if state split by quantization issues.
  418. if (spr.first != spr.second &&
  419. head_[spr.first] == head_[spr.second]) {
  420. if (!merge_) {
  421. merge_ = std::make_unique<UnionFind<StateId>>(fst.NumStates(),
  422. kNoStateId);
  423. merge_->MakeAllSet(fst.NumStates());
  424. }
  425. merge_->Union(spr.first, spr.second);
  426. } else {
  427. queue_.push_back(spr);
  428. }
  429. }
  430. }
  431. }
  432. }
  433. // Super-final transition is ambiguous.
  434. if (s1 != s2 && fst.Final(s1) != Weight::Zero() &&
  435. fst.Final(s2) != Weight::Zero()) {
  436. const ArcId a1(s1, -1);
  437. const ArcId a2(s2, -1);
  438. InsertCandidate(s1, s2, a1, a2);
  439. }
  440. }
  441. template <class Arc>
  442. void Disambiguator<Arc>::MarkAmbiguities() {
  443. if (!candidates_) return;
  444. for (auto it = candidates_->begin(); it != candidates_->end(); ++it) {
  445. const auto a = it->first;
  446. const auto b = it->second;
  447. // If b is not to be removed, then a is.
  448. if (ambiguous_.count(b) == 0) ambiguous_.insert(a);
  449. }
  450. coreachable_.clear();
  451. candidates_.reset();
  452. }
  453. template <class Arc>
  454. void Disambiguator<Arc>::RemoveSplits(MutableFst<Arc> *ofst) {
  455. if (!merge_) return;
  456. // Merges split states to remove spurious ambiguities.
  457. for (StateIterator<MutableFst<Arc>> siter(*ofst); !siter.Done();
  458. siter.Next()) {
  459. for (MutableArcIterator<MutableFst<Arc>> aiter(ofst, siter.Value());
  460. !aiter.Done(); aiter.Next()) {
  461. auto arc = aiter.Value();
  462. const auto nextstate = merge_->FindSet(arc.nextstate);
  463. if (nextstate != arc.nextstate) {
  464. arc.nextstate = nextstate;
  465. aiter.SetValue(arc);
  466. }
  467. }
  468. }
  469. // Repeats search for actual ambiguities on modified FST.
  470. coreachable_.clear();
  471. merge_.reset();
  472. candidates_.reset();
  473. FindAmbiguities(*ofst);
  474. if (merge_) { // Shouldn't get here; sanity test.
  475. FSTERROR() << "Disambiguate: Unable to remove spurious ambiguities";
  476. error_ = true;
  477. return;
  478. }
  479. }
  480. template <class Arc>
  481. void Disambiguator<Arc>::RemoveAmbiguities(MutableFst<Arc> *ofst) {
  482. if (ambiguous_.empty()) return;
  483. // Adds dead state to redirect ambiguous transitions to be removed.
  484. const auto dead = ofst->AddState();
  485. for (auto it = ambiguous_.begin(); it != ambiguous_.end(); ++it) {
  486. const auto pos = it->second;
  487. if (pos >= 0) { // Actual transition.
  488. MutableArcIterator<MutableFst<Arc>> aiter(ofst, it->first);
  489. aiter.Seek(pos);
  490. auto arc = aiter.Value();
  491. arc.nextstate = dead;
  492. aiter.SetValue(arc);
  493. } else { // Super-final transition.
  494. ofst->SetFinal(it->first, Weight::Zero());
  495. }
  496. }
  497. Connect(ofst);
  498. ambiguous_.clear();
  499. }
  500. } // namespace internal
  501. // Disambiguates a weighted FST. This version writes the disambiguated FST to an
  502. // output MutableFst. The result will be an equivalent FST that has the
  503. // property that there are not two distinct paths from the initial state to a
  504. // final state with the same input labeling.
  505. //
  506. // The weights must be (weakly) left divisible (valid for Tropical and
  507. // LogWeight).
  508. //
  509. // Complexity:
  510. //
  511. // Disambiguable: exponential (polynomial in the size of the output).
  512. // Non-disambiguable: does not terminate.
  513. //
  514. // The disambiguable transducers include all automata and functional transducers
  515. // that are unweighted or that are acyclic or that are unambiguous.
  516. //
  517. // For more information, see:
  518. //
  519. // Mohri, M. and Riley, M. 2015. On the disambiguation of weighted automata.
  520. // In CIAA, pages 263-278.
  521. template <class Arc>
  522. void Disambiguate(
  523. const Fst<Arc> &ifst, MutableFst<Arc> *ofst,
  524. const DisambiguateOptions<Arc> &opts = DisambiguateOptions<Arc>()) {
  525. internal::Disambiguator<Arc> disambiguator;
  526. disambiguator.Disambiguate(ifst, ofst, opts);
  527. }
  528. } // namespace fst
  529. #endif // FST_DISAMBIGUATE_H_