1f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// test-properties.h
2f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
3f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Licensed under the Apache License, Version 2.0 (the "License");
4f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// you may not use this file except in compliance with the License.
5f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// You may obtain a copy of the License at
6f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
7f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//     http://www.apache.org/licenses/LICENSE-2.0
8f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
9f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Unless required by applicable law or agreed to in writing, software
10f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// distributed under the License is distributed on an "AS IS" BASIS,
11f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// See the License for the specific language governing permissions and
13f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// limitations under the License.
14f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
15f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Copyright 2005-2010 Google, Inc.
16f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Author: riley@google.com (Michael Riley)
17f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
18f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// \file
19f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Functions to manipulate and test property bits
20f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
21f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#ifndef FST_LIB_TEST_PROPERTIES_H__
22f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#define FST_LIB_TEST_PROPERTIES_H__
23f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
24f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#include <unordered_set>
25f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonusing std::tr1::unordered_set;
26f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonusing std::tr1::unordered_multiset;
27f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
28f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#include <fst/dfs-visit.h>
29f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#include <fst/connect.h>
30f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
31f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
32f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian HodsonDECLARE_bool(fst_verify_properties);
33f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
34f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonnamespace fst {
35f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
36f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// For a binary property, the bit is always returned set.
37f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// For a trinary (i.e. two-bit) property, both bits are
38f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// returned set iff either corresponding input bit is set.
39f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsoninline uint64 KnownProperties(uint64 props) {
40f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  return kBinaryProperties | (props & kTrinaryProperties) |
41f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    ((props & kPosTrinaryProperties) << 1) |
42f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    ((props & kNegTrinaryProperties) >> 1);
43f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}
44f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
45f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Tests compatibility between two sets of properties
46f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsoninline bool CompatProperties(uint64 props1, uint64 props2) {
47f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint64 known_props1 = KnownProperties(props1);
48f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint64 known_props2 = KnownProperties(props2);
49f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint64 known_props = known_props1 & known_props2;
50f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint64 incompat_props = (props1 & known_props) ^ (props2 & known_props);
51f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  if (incompat_props) {
52f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    uint64 prop = 1;
53f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    for (int i = 0; i < 64; ++i, prop <<= 1)
54f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (prop & incompat_props)
55f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        LOG(ERROR) << "CompatProperties: mismatch: " << PropertyNames[i]
56f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                   << ": props1 = " << (props1 & prop ? "true" : "false")
57f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                   << ", props2 = " << (props2 & prop ? "true" : "false");
58f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return false;
59f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  } else {
60f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return true;
61f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
62f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}
63f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
64f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Computes FST property values defined in properties.h.  The value of
65f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// each property indicated in the mask will be determined and returned
66f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// (these will never be unknown here). In the course of determining
67f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// the properties specifically requested in the mask, certain other
68f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// properties may be determined (those with little additional expense)
69f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// and their values will be returned as well. The complete set of
70f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// known properties (whether true or false) determined by this
71f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// operation will be assigned to the the value pointed to by KNOWN.
72f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// If 'use_stored' is true, pre-computed FST properties may be used
73f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// when possible. This routine is seldom called directly; instead it
74f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// is used to implement fst.Properties(mask, true).
75f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate<class Arc>
76f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonuint64 ComputeProperties(const Fst<Arc> &fst, uint64 mask, uint64 *known,
77f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                         bool use_stored) {
78f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::Label Label;
79f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::Weight Weight;
80f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::StateId StateId;
81f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
82f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint64 fst_props = fst.Properties(kFstProperties, false);  // Fst-stored
83f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
84f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Check stored FST properties first if allowed.
85f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  if (use_stored) {
86f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    uint64 known_props = KnownProperties(fst_props);
87f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    // If FST contains required info, return it.
88f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if ((known_props & mask) == mask) {
89f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      *known = known_props;
90f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return fst_props;
91f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
92f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
93f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
94f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Compute (trinary) properties explicitly.
95f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
96f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Initialize with binary properties (already known).
97f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint64 comp_props = fst_props & kBinaryProperties;
98f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
99f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Compute these trinary properties with a DFS. We compute only those
100f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // that need a DFS here, since we otherwise would like to avoid a DFS
101f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // since its stack could grow large.
102f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint64 dfs_props = kCyclic | kAcyclic | kInitialCyclic | kInitialAcyclic |
103f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                     kAccessible | kNotAccessible |
104f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                     kCoAccessible | kNotCoAccessible;
105f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  if (mask & dfs_props) {
106f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    SccVisitor<Arc> scc_visitor(&comp_props);
107f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    DfsVisit(fst, &scc_visitor);
108f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
109f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
110f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Compute any remaining trinary properties via a state and arcs iterations
111f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  if (mask & ~(kBinaryProperties | dfs_props)) {
112f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    comp_props |= kAcceptor | kNoEpsilons | kNoIEpsilons | kNoOEpsilons |
113f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        kILabelSorted | kOLabelSorted | kUnweighted | kTopSorted | kString;
114f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (mask & (kIDeterministic | kNonIDeterministic))
115f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      comp_props |= kIDeterministic;
116f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (mask & (kODeterministic | kNonODeterministic))
117f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      comp_props |= kODeterministic;
118f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
119f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    unordered_set<Label> *ilabels = 0;
120f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    unordered_set<Label> *olabels = 0;
121f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
122f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    StateId nfinal = 0;
123f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    for (StateIterator< Fst<Arc> > siter(fst);
124f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson         !siter.Done();
125f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson         siter.Next()) {
126f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      StateId s = siter.Value();
127f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
128f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      Arc prev_arc(kNoLabel, kNoLabel, Weight::One(), 0);
129f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      // Create these only if we need to
130f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (mask & (kIDeterministic | kNonIDeterministic))
131f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        ilabels = new unordered_set<Label>;
132f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (mask & (kODeterministic | kNonODeterministic))
133f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        olabels = new unordered_set<Label>;
134f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
135f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      for (ArcIterator< Fst<Arc> > aiter(fst, s);
136f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson           !aiter.Done();
137f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson           aiter.Next()) {
138f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        const Arc &arc =aiter.Value();
139f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
140f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (ilabels && ilabels->find(arc.ilabel) != ilabels->end()) {
141f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNonIDeterministic;
142f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kIDeterministic;
143f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
144f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (olabels && olabels->find(arc.olabel) != olabels->end()) {
145f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNonODeterministic;
146f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kODeterministic;
147f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
148f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.ilabel != arc.olabel) {
149f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotAcceptor;
150f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kAcceptor;
151f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
152f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.ilabel == 0 && arc.olabel == 0) {
153f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kEpsilons;
154f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kNoEpsilons;
155f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
156f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.ilabel == 0) {
157f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kIEpsilons;
158f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kNoIEpsilons;
159f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
160f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.olabel == 0) {
161f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kOEpsilons;
162f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kNoOEpsilons;
163f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
164f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (prev_arc.ilabel != kNoLabel && arc.ilabel < prev_arc.ilabel) {
165f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotILabelSorted;
166f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kILabelSorted;
167f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
168f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (prev_arc.olabel != kNoLabel && arc.olabel < prev_arc.olabel) {
169f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotOLabelSorted;
170f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kOLabelSorted;
171f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
172f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.weight != Weight::One() && arc.weight != Weight::Zero()) {
173f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kWeighted;
174f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kUnweighted;
175f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
176f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.nextstate <= s) {
177f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotTopSorted;
178f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kTopSorted;
179f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
180f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.nextstate != s + 1) {
181f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotString;
182f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kString;
183f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
184f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        prev_arc = arc;
185f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (ilabels)
186f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          ilabels->insert(arc.ilabel);
187f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (olabels)
188f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          olabels->insert(arc.olabel);
189f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
190f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
191f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (nfinal > 0) {             // final state not last
192f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        comp_props |= kNotString;
193f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        comp_props &= ~kString;
194f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
195f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
196f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      Weight final = fst.Final(s);
197f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
198f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (final != Weight::Zero()) {  // final state
199f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (final != Weight::One()) {
200f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kWeighted;
201f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kUnweighted;
202f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
203f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        ++nfinal;
204f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      } else {                        // non-final state
205f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (fst.NumArcs(s) != 1) {
206f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotString;
207f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kString;
208f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
209f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
210f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
211f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      delete ilabels;
212f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      delete olabels;
213f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
214f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
215f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (fst.Start() != kNoStateId && fst.Start() != 0) {
216f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      comp_props |= kNotString;
217f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      comp_props &= ~kString;
218f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
219f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
220f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
221f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  *known = KnownProperties(comp_props);
222f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  return comp_props;
223f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}
224f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
225f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// This is a wrapper around ComputeProperties that will cause a fatal
226f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// error if the stored properties and the computed properties are
227f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// incompatible when 'FLAGS_fst_verify_properties' is true.  This
228f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// routine is seldom called directly; instead it is used to implement
229f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// fst.Properties(mask, true).
230f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate<class Arc>
231f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonuint64 TestProperties(const Fst<Arc> &fst, uint64 mask, uint64 *known) {
232f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  if (FLAGS_fst_verify_properties) {
233f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    uint64 stored_props = fst.Properties(kFstProperties, false);
234f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    uint64 computed_props = ComputeProperties(fst, mask, known, false);
235f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (!CompatProperties(stored_props, computed_props))
236f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      LOG(FATAL) << "TestProperties: stored Fst properties incorrect"
237f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                 << " (stored: props1, computed: props2)";
238f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return computed_props;
239f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  } else {
240f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return ComputeProperties(fst, mask, known, true);
241f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
242f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}
243f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
244f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}  // namespace fst
245f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
246f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#endif  // FST_LIB_TEST_PROPERTIES_H__
247