This file is indexed.

/usr/include/fst/isomorphic.h is in libfst-dev 1.5.3+r3-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// See www.openfst.org for extensive documentation on this weighted
// finite-state transducer library.
//
// Function to test two FSTs are isomorphic, i.e., they are equal up to a state
// and arc re-ordering. FSTs should be deterministic when viewed as
// unweighted automata.

#ifndef FST_LIB_ISOMORPHIC_H_
#define FST_LIB_ISOMORPHIC_H_

#include <algorithm>

#include <fst/fst.h>


namespace fst {

template <class Arc>
class Isomorphism {
  typedef typename Arc::StateId StateId;
  typedef typename Arc::Weight Weight;

 public:
  Isomorphism(const Fst<Arc> &fst1, const Fst<Arc> &fst2, float delta)
      : fst1_(fst1.Copy()),
        fst2_(fst2.Copy()),
        delta_(delta),
        error_(false),
        comp_(delta, &error_) {}

  ~Isomorphism() {
    delete fst1_;
    delete fst2_;
  }

  // Checks if input FSTs are isomorphic
  bool IsIsomorphic() {
    if (fst1_->Start() == kNoStateId && fst2_->Start() == kNoStateId)
      return true;

    if (fst1_->Start() == kNoStateId || fst2_->Start() == kNoStateId)
      return false;

    PairState(fst1_->Start(), fst2_->Start());
    while (!queue_.empty()) {
      const std::pair<StateId, StateId> &pr = queue_.front();
      if (!IsIsomorphicState(pr.first, pr.second)) return false;
      queue_.pop_front();
    }
    return true;
  }

  bool Error() const { return error_; }

 private:
  // Orders arcs for equality checking.
  class ArcCompare {
   public:
    ArcCompare(float delta, bool *error) : delta_(delta), error_(error) {}

    bool operator()(const Arc &arc1, const Arc &arc2) const {
      if (arc1.ilabel < arc2.ilabel) return true;
      if (arc1.ilabel > arc2.ilabel) return false;

      if (arc1.olabel < arc2.olabel) return true;
      if (arc1.olabel > arc2.olabel) return false;

      return WeightCompare(arc1.weight, arc2.weight, delta_, error_);
    }

   private:
    float delta_;
    bool *error_;
  };

  // Orders weights for equality checking.
  static bool WeightCompare(Weight w1, Weight w2, float delta, bool *error);

  // Maintains state correspondences and queue.
  bool PairState(StateId s1, StateId s2) {
    if (state_pairs_.size() <= s1) state_pairs_.resize(s1 + 1, kNoStateId);
    if (state_pairs_[s1] == s2)
      return true;  // already seen this pair
    else if (state_pairs_[s1] != kNoStateId)
      return false;  // s1 already paired with another s2

    state_pairs_[s1] = s2;
    queue_.push_back(std::make_pair(s1, s2));
    return true;
  }

  // Checks if state pair is isomorphic
  bool IsIsomorphicState(StateId s1, StateId s2);

  Fst<Arc> *fst1_;
  Fst<Arc> *fst2_;
  float delta_;                          // Weight equality delta
  std::vector<Arc> arcs1_;               // for sorting arcs on FST1
  std::vector<Arc> arcs2_;               // for sorting arcs on FST2
  std::vector<StateId> state_pairs_;     // maintains state correspondences
  std::list<std::pair<StateId, StateId>> queue_;  // queue of states to process
  bool error_;                           // error flag
  ArcCompare comp_;

  DISALLOW_COPY_AND_ASSIGN(Isomorphism);
};

template <class Arc>
bool Isomorphism<Arc>::WeightCompare(Weight w1, Weight w2, float delta,
                                     bool *error) {
  if (Weight::Properties() & kIdempotent) {
    NaturalLess<Weight> less;
    return less(w1, w2);
  } else {  // No natural order; use hash
    Weight q1 = w1.Quantize(delta);
    Weight q2 = w2.Quantize(delta);
    size_t n1 = q1.Hash();
    size_t n2 = q2.Hash();

    // Hash not unique. Very unlikely to happen.
    if (n1 == n2 && q1 != q2) {
      FSTERROR() << "Isomorphic: Weight hash collision";
      *error = true;
    }
    return n1 < n2;
  }
}

template <class Arc>
bool Isomorphism<Arc>::IsIsomorphicState(StateId s1, StateId s2) {
  if (!ApproxEqual(fst1_->Final(s1), fst2_->Final(s2), delta_)) return false;
  if (fst1_->NumArcs(s1) != fst2_->NumArcs(s2)) return false;

  ArcIterator<Fst<Arc>> aiter1(*fst1_, s1);
  ArcIterator<Fst<Arc>> aiter2(*fst2_, s2);

  arcs1_.clear();
  arcs2_.clear();
  for (; !aiter1.Done(); aiter1.Next(), aiter2.Next()) {
    arcs1_.push_back(aiter1.Value());
    arcs2_.push_back(aiter2.Value());
  }

  std::sort(arcs1_.begin(), arcs1_.end(), comp_);
  std::sort(arcs2_.begin(), arcs2_.end(), comp_);

  Arc arc0;
  for (size_t i = 0; i < arcs1_.size(); ++i) {
    const Arc &arc1 = arcs1_[i];
    const Arc &arc2 = arcs2_[i];

    if (arc1.ilabel != arc2.ilabel) return false;
    if (arc1.olabel != arc2.olabel) return false;
    if (!ApproxEqual(arc1.weight, arc2.weight, delta_)) return false;
    if (!PairState(arc1.nextstate, arc2.nextstate)) return false;

    if (i > 0) {  // Checks for non-determinism
      const Arc &arc0 = arcs1_[i - 1];
      if (arc1.ilabel == arc0.ilabel && arc1.olabel == arc0.olabel &&
          ApproxEqual(arc1.weight, arc0.weight, delta_)) {
        FSTERROR() << "Isomorphic: Non-determinism as an unweighted automaton";
        error_ = true;
        return false;
      }
    }
  }
  return true;
}

// Tests if two Fsts have the same states and arcs up to a reordering.
// Inputs should be non-deterministic when viewed as unweighted automata
// (cf. Encode()).  Returns optional error value (useful when
// FLAGS_error_fatal = false).
template <class Arc>
bool Isomorphic(const Fst<Arc> &fst1, const Fst<Arc> &fst2,
                float delta = kDelta, bool *error = 0) {
  Isomorphism<Arc> iso(fst1, fst2, delta);
  bool ret = iso.IsIsomorphic();
  if (iso.Error()) {
    FSTERROR() << "Isomorphic: Can't determine if inputs are isomorphic";
    if (error) *error = true;
    return false;
  } else {
    if (error) *error = false;
    return ret;
  }
}

}  // namespace fst

#endif  // FST_LIB_ISOMORPHIC_H_