// See www.openfst.org for extensive documentation on this weighted // finite-state transducer library. // // Functions to manipulate and test property bits. #ifndef FST_TEST_PROPERTIES_H_ #define FST_TEST_PROPERTIES_H_ #include #include #include #include #include DECLARE_bool(fst_verify_properties); namespace fst { // namespace internal { // For a binary property, the bit is always returned set. For a trinary (i.e., // two-bit) property, both bits are returned set iff either corresponding input // bit is set. inline uint64 KnownProperties(uint64 props) { return kBinaryProperties | (props & kTrinaryProperties) | ((props & kPosTrinaryProperties) << 1) | ((props & kNegTrinaryProperties) >> 1); } // Tests compatibility between two sets of properties. inline bool CompatProperties(uint64 props1, uint64 props2) { const auto known_props1 = KnownProperties(props1); const auto known_props2 = KnownProperties(props2); const auto known_props = known_props1 & known_props2; const auto incompat_props = (props1 & known_props) ^ (props2 & known_props); if (incompat_props) { uint64 prop = 1; for (int i = 0; i < 64; ++i, prop <<= 1) { if (prop & incompat_props) { LOG(ERROR) << "CompatProperties: Mismatch: " << PropertyNames[i] << ": props1 = " << (props1 & prop ? "true" : "false") << ", props2 = " << (props2 & prop ? "true" : "false"); } } return false; } else { return true; } } // Computes FST property values defined in properties.h. The value of each // property indicated in the mask will be determined and returned (these will // never be unknown here). In the course of determining the properties // specifically requested in the mask, certain other properties may be // determined (those with little additional expense) and their values will be // returned as well. The complete set of known properties (whether true or // false) determined by this operation will be assigned to the the value pointed // to by KNOWN. If 'use_stored' is true, pre-computed FST properties may be used // when possible. 'mask & required_mask' is used to determine whether the stored // propertoes can be used. This routine is seldom called directly; instead it is // used to implement fst.Properties(mask, true). template uint64 ComputeProperties(const Fst &fst, uint64 mask, uint64 *known, bool use_stored) { using Label = typename Arc::Label; using StateId = typename Arc::StateId; using Weight = typename Arc::Weight; const auto fst_props = fst.Properties(kFstProperties, false); // FST-stored. // Check stored FST properties first if allowed. if (use_stored) { const auto known_props = KnownProperties(fst_props); // If FST contains required info, return it. if ((known_props & mask) == mask) { if (known) *known = known_props; return fst_props; } } // Computes (trinary) properties explicitly. // Initialize with binary properties (already known). uint64 comp_props = fst_props & kBinaryProperties; // Computes these trinary properties with a DFS. We compute only those that // need a DFS here, since we otherwise would like to avoid a DFS since its // stack could grow large. uint64 dfs_props = kCyclic | kAcyclic | kInitialCyclic | kInitialAcyclic | kAccessible | kNotAccessible | kCoAccessible | kNotCoAccessible; std::vector scc; if (mask & (dfs_props | kWeightedCycles | kUnweightedCycles)) { SccVisitor scc_visitor(&scc, nullptr, nullptr, &comp_props); DfsVisit(fst, &scc_visitor); } // Computes any remaining trinary properties via a state and arcs iterations if (mask & ~(kBinaryProperties | dfs_props)) { comp_props |= kAcceptor | kNoEpsilons | kNoIEpsilons | kNoOEpsilons | kILabelSorted | kOLabelSorted | kUnweighted | kTopSorted | kString; if (mask & (kIDeterministic | kNonIDeterministic)) { comp_props |= kIDeterministic; } if (mask & (kODeterministic | kNonODeterministic)) { comp_props |= kODeterministic; } if (mask & (dfs_props | kWeightedCycles | kUnweightedCycles)) { comp_props |= kUnweightedCycles; } std::unique_ptr> ilabels; std::unique_ptr> olabels; StateId nfinal = 0; for (StateIterator> siter(fst); !siter.Done(); siter.Next()) { StateId s = siter.Value(); Arc prev_arc; // Creates these only if we need to. if (mask & (kIDeterministic | kNonIDeterministic)) { ilabels.reset(new std::unordered_set