#include "lemfst.h" LemFST::LemFST(const char* plik_fst) { fst = StdFst::Read(plik_fst); } LemFST::~LemFST(void) { delete fst; path.clear(); } /** Zwraca true jezeli s jest koncowym */ bool LemFST::accept(State s) { if (s == fst::kNoStateId) return false; return fst->Final(s)!=StdFst::Weight::Zero(); } LemFST::State LemFST::start() { return fst->Start(); } /** Przechodzi do nastepnego stanu po jednym znaku */ LemFST::State LemFST::next(State s, Char c) { if (s==fst::kNoStateId) return fst::kNoStateId; ArcsIt aiter(*fst, s); for (; !aiter.Done(); aiter.Next()) { StdArc arc = aiter.Value(); if (arc.ilabel==c) return arc.nextstate; } return fst::kNoStateId; } /** Konsumuje slowo W zaczynajac w stanie s. * Zwraca: * State (int64) - w jakim sie znajdzie * kNoStateId (-1) - gdy nie moze dokonac takiego przejscia. */ LemFST::State LemFST::next(State s, Word w) { if (s==fst::kNoStateId) return fst::kNoStateId; LemFST::WordIt it; State ns = s; for(it=w.begin(); it!=w.end(); ++it) { ns = next(ns, *it); if (ns==fst::kNoStateId) { return fst::kNoStateId; } } return ns; } /** Funkcja zwraca kolejne sciezki z automatu w formie generatora. * Ustawienie s na kNoStateId (lub -1) restartuje generator. * Dopoki s!=-1 metoda zwraca przy kolejnych wywolaniach kolejne sciezki od stanu s * do stanow konczacych. * Sciezke mozna odzyskac poprzez metode getPath(); */ long LemFST::cont(State s, Word *result, int maxPath) { // Restart generatora po podaniu -1 // Lub przekroczeniu dlugosci sciezki if (s==fst::kNoStateId || path.size() > maxPath) { path.clear(); return 0; } // Stos jest pusty. Mozemy dodac do niego wierzcholek poczatkowy. if (path.empty()) { path.push_back(getStateInfo(s, fst::kNoStateId, 0)); } while(!path.empty()) { // Zdejmujemy ze stosu stan i jego iterator: StateInfo *state = &path.back(); ArcsIt *ait = state->it; // Jezeli stan jest koncowy to zwracamy sciezke do stanu "s" // Dodatkowo sprawdzamy czy juz nie startowalismy z tego stanu, aby nie wyswietlac wielokrotnie tego samego if (!state->checked && accept(state->id)) { state->checked = true; StateInfo tState; PathRevIt pit=path.rbegin(); State prevId = pit->id; result->clear(); for(; pit!=path.rend(); ++pit) { tState = (*pit); if (tState.id == prevId && tState.prev!=fst::kNoStateId && tState.id !=s) { ArcsIt *tArcIt = tState.it; result->push_front(tState.symbol); } if (tState.prev==fst::kNoStateId) break; prevId = tState.prev; } ait->Next(); return path.size(); } // Skonczylismy sprawdzac dany iterator (stan). // Dlatego mozemy go usunac ze stosu. if (ait->Done()) { path.pop_back(); // Jezeli jakies wierzcholki sa jeszcze na stosie to kontynuuj: if (path.size() > 0) continue; // w.p.p zakoncz. else return 0; } // Odwiedzamy stan. // Dodajemy jego nastepnikow: for(; !ait->Done(); ait->Next()) { State next = ait->Value().nextstate; Char isymbol = ait->Value().ilabel; path.push_back(getStateInfo(next, state->id, isymbol)); } } // Koniec (while(!path.empty()) return 0; } /** Zwraca strukture StateInfo uzupelniajac ja o dane * Parametry: * s - ktory stan opisujemy * prev - poprzednik stanu w automacie * isymbol - symbol po jakim dostalismy sie z 'prev' do 's' */ inline const LemFST::StateInfo LemFST::getStateInfo(State s, State prev, Char isymbol) { StateInfo sInfo; sInfo.id = s; sInfo.it = new ArcsIt(*fst, s); //Wyciagamy iterator z automatu sInfo.symbol = isymbol; sInfo.prev = prev; sInfo.checked = false; // Czy stan byl juz sprawdzany jako koncowy return sInfo; }