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
243da1eb108d36da35333b2d655202791af854996bPrzemyslaw Szczepaniak#include <tr1/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
128dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin      Arc prev_arc;
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
135dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin      bool first_arc = true;
136f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      for (ArcIterator< Fst<Arc> > aiter(fst, s);
137f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson           !aiter.Done();
138f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson           aiter.Next()) {
139f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        const Arc &arc =aiter.Value();
140f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
141f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (ilabels && ilabels->find(arc.ilabel) != ilabels->end()) {
142f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNonIDeterministic;
143f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kIDeterministic;
144f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
145f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (olabels && olabels->find(arc.olabel) != olabels->end()) {
146f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNonODeterministic;
147f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kODeterministic;
148f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
149f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.ilabel != arc.olabel) {
150f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotAcceptor;
151f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kAcceptor;
152f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
153f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.ilabel == 0 && arc.olabel == 0) {
154f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kEpsilons;
155f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kNoEpsilons;
156f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
157f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.ilabel == 0) {
158f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kIEpsilons;
159f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kNoIEpsilons;
160f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
161f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.olabel == 0) {
162f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kOEpsilons;
163f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kNoOEpsilons;
164f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
165dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin        if (!first_arc) {
166dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin          if (arc.ilabel < prev_arc.ilabel) {
167dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin            comp_props |= kNotILabelSorted;
168dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin            comp_props &= ~kILabelSorted;
169dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin          }
170dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin          if (arc.olabel < prev_arc.olabel) {
171dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin            comp_props |= kNotOLabelSorted;
172dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin            comp_props &= ~kOLabelSorted;
173dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin          }
174f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
175f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.weight != Weight::One() && arc.weight != Weight::Zero()) {
176f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kWeighted;
177f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kUnweighted;
178f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
179f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.nextstate <= s) {
180f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotTopSorted;
181f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kTopSorted;
182f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
183f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (arc.nextstate != s + 1) {
184f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotString;
185f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kString;
186f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
187f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        prev_arc = arc;
188dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin        first_arc = false;
189f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (ilabels)
190f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          ilabels->insert(arc.ilabel);
191f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (olabels)
192f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          olabels->insert(arc.olabel);
193f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
194f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
195f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (nfinal > 0) {             // final state not last
196f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        comp_props |= kNotString;
197f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        comp_props &= ~kString;
198f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
199f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
200f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      Weight final = fst.Final(s);
201f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
202f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (final != Weight::Zero()) {  // final state
203f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (final != Weight::One()) {
204f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kWeighted;
205f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kUnweighted;
206f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
207f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        ++nfinal;
208f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      } else {                        // non-final state
209f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        if (fst.NumArcs(s) != 1) {
210f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props |= kNotString;
211f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          comp_props &= ~kString;
212f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        }
213f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
214f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
215f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      delete ilabels;
216f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      delete olabels;
217f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
218f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
219f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (fst.Start() != kNoStateId && fst.Start() != 0) {
220f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      comp_props |= kNotString;
221f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      comp_props &= ~kString;
222f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
223f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
224f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
225f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  *known = KnownProperties(comp_props);
226f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  return comp_props;
227f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}
228f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
229f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// This is a wrapper around ComputeProperties that will cause a fatal
230f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// error if the stored properties and the computed properties are
231f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// incompatible when 'FLAGS_fst_verify_properties' is true.  This
232f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// routine is seldom called directly; instead it is used to implement
233f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// fst.Properties(mask, true).
234f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate<class Arc>
235f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonuint64 TestProperties(const Fst<Arc> &fst, uint64 mask, uint64 *known) {
236f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  if (FLAGS_fst_verify_properties) {
237f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    uint64 stored_props = fst.Properties(kFstProperties, false);
238f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    uint64 computed_props = ComputeProperties(fst, mask, known, false);
239f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (!CompatProperties(stored_props, computed_props))
240f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      LOG(FATAL) << "TestProperties: stored Fst properties incorrect"
241f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                 << " (stored: props1, computed: props2)";
242f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return computed_props;
243f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  } else {
244f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return ComputeProperties(fst, mask, known, true);
245f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
246f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}
247f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
248f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}  // namespace fst
249f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
250f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#endif  // FST_LIB_TEST_PROPERTIES_H__
251