TEST_F(TestDFA, MinimizationStress) { auto fn = [](unsigned i) -> std::string { return std::to_string(i); }; unsigned limit = 999; instance.reserve(limit); for (unsigned i = 0; i < limit; i++) { instance << ("q" + fn(i)); } instance.accept("q" + fn(limit - 2)); instance.accept("q" + fn(limit - 1)); instance.addTransition("q0", "q1", 'a'); instance.addTransition("q0", "q2", 'b'); for (unsigned i = 1; i < limit - 2; i += 2) { unsigned next = (i + 1) % limit; instance.addTransition("q" + fn(i), "q" + fn(next), 'a'); instance.addTransition("q" + fn(next), "q" + fn(i), 'a'); instance.addTransition("q" + fn(i), "q" + fn((i + 2) % limit), 'b'); instance.addTransition("q" + fn(next), "q" + fn((i + 3) % limit), 'b'); } DFA other; ASSERT_NO_THROW(other = instance.minimized()); EXPECT_EQ((limit + 1)/2, other.size()); }
bool DFAMerger::add(const DFA& dfa) { if (_start == -1) { _start = new_state(); } assert(_start >= 0); size_t size = dfa.size(); size_t base = _trans.size(); _trans.resize(base + size); for (size_t i = 0; i < size; i++) { const DFATran& tran = dfa[i]; for (DFATran::const_iterator it = tran.begin(); it != tran.end(); ++it) { _trans[base + i][it->first].insert(base + it->second); } const Tag& tag = dfa.tags(i); if (!tag.empty()) { Tag& to = _tags[base + i]; to.insert(tag.begin(), tag.end()); } } _trans[_start][EPSILON].insert(base + dfa.start()); const States& last = dfa.last(); for (States::const_iterator it = last.begin(); it != last.end(); ++it) { _last.insert(base + *it); } return true; }
TEST_F(TestDFA, Containment) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q0", "q1", 'b'); instance.addTransition("q1", "q2", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q3", 'a'); instance.addTransition("q2", "q3", 'b'); instance.addTransition("q3", "q0", 'a'); instance.addTransition("q3", "q0", 'b'); instance.accept("q0"); instance.accept("q2"); DFA second; second << "q0"; second << "q1"; second.addTransition("q0", "q1", 'a'); second.addTransition("q1", "q0", 'a'); second.accept("q0"); bool r1, r2; ASSERT_NO_THROW(r1 = instance.contains(second)); ASSERT_NO_THROW(r2 = second.contains(instance)); EXPECT_TRUE(r1); EXPECT_FALSE(r2); EXPECT_EQ(4, instance.size()); EXPECT_EQ(2, second.size()); }
Ref<CompiledContentExtension> compileRuleList(const String& ruleList) { auto parsedRuleList = parseRuleList(ruleList); #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING double nfaBuildTimeStart = monotonicallyIncreasingTime(); #endif Vector<SerializedActionByte> actions; Vector<unsigned> actionLocations = serializeActions(parsedRuleList, actions); NFA nfa; URLFilterParser urlFilterParser(nfa); for (unsigned ruleIndex = 0; ruleIndex < parsedRuleList.size(); ++ruleIndex) { const ContentExtensionRule& contentExtensionRule = parsedRuleList[ruleIndex]; const Trigger& trigger = contentExtensionRule.trigger(); ASSERT(trigger.urlFilter.length()); String error = urlFilterParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, actionLocations[ruleIndex]); if (!error.isNull()) { dataLogF("Error while parsing %s: %s\n", trigger.urlFilter.utf8().data(), error.utf8().data()); continue; } } #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING double nfaBuildTimeEnd = monotonicallyIncreasingTime(); dataLogF(" Time spent building the NFA: %f\n", (nfaBuildTimeEnd - nfaBuildTimeStart)); #endif #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING nfa.debugPrintDot(); #endif #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING double dfaBuildTimeStart = monotonicallyIncreasingTime(); #endif const DFA dfa = NFAToDFA::convert(nfa); #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING double dfaBuildTimeEnd = monotonicallyIncreasingTime(); dataLogF(" Time spent building the DFA: %f\n", (dfaBuildTimeEnd - dfaBuildTimeStart)); #endif // FIXME: never add a DFA that only matches the empty set. #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING dfa.debugPrintDot(); #endif Vector<DFABytecode> bytecode; DFABytecodeCompiler compiler(dfa, bytecode); compiler.compile(); return CompiledContentExtension::create(WTF::move(bytecode), WTF::move(actions)); }
TEST_F(TestDFA, DeadStateRemoval) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q2", 'c'); instance.addTransition("q3", "q3", 'd'); EXPECT_EQ(4, instance.size()); DFA other = instance.withoutDeadStates(); EXPECT_EQ(0, other.size()); instance.accept("q1"); other = instance.withoutDeadStates(); EXPECT_EQ(2, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); instance.accept("q3"); other = instance.withoutDeadStates(); EXPECT_EQ(3, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); DFA empty; ASSERT_NO_THROW(empty.withoutDeadStates()); EXPECT_EQ(0, empty.withoutDeadStates().size()); }
TEST_F(TestDFA, Complement) { instance << "q0"; instance << "q1"; instance << "q2"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'a'); instance.addTransition("q2", "q0", 'a'); instance.accept("q0"); DFA complement; ASSERT_NO_THROW(complement = ~instance); EXPECT_EQ(3, instance.size()); EXPECT_EQ(3, complement.size()); EXPECT_TRUE(instance.accepts()); EXPECT_FALSE(complement.accepts()); instance.read("a"); complement.read("a"); EXPECT_FALSE(instance.accepts()); EXPECT_TRUE(complement.accepts()); instance.read("a"); complement.read("a"); EXPECT_FALSE(instance.accepts()); EXPECT_TRUE(complement.accepts()); instance.read("a"); complement.read("a"); EXPECT_TRUE(instance.accepts()); EXPECT_FALSE(complement.accepts()); }
void Regex::buildDFA(const std::string& regexStr) { using namespace std; unique_ptr<Exp> exp = parse(regexStr); cout << exp->toString() << endl; unique_ptr<NFA> nfa = exp->buildNFA(); cout << nfa->toString() << endl; DFA* dfa = new DFA(*nfa); cout << dfa->toString() << endl; m_dfa.reset(dfa); }
/// convert a NFA to a DFA vector<DFA*>* convertNFAToDFA(NFA *start, NFA *end) { // from the start state, find all unlabeled state vector<NFA*> baseNFAs; start->findUnlabeldState(baseNFAs); // allocate a stack, and push the unlabeled state into stack vector<DFA*> *stack = new vector<DFA *>(); stack->push_back(new DFA(baseNFAs, end)); // iterate the stack vector<DFA*>::iterator it = stack->begin(); for (; it != stack->end(); it++) { DFA *state = *it; // get all NFAs for the current DFA vector<NFA *> &nfas = state->m_nfas; // holder for arcs that start with DFA start state vector<pair<string, vector<NFA*>*> > arcs;; // iterate current DFA vector<NFA *>::iterator ite = nfas.begin(); for (; ite < nfas.end(); ite++) { NFA * nfa = *ite; // for each NFA,iterate all arcs to find unlabed state for (int arcIndex = 0; arcIndex < nfa->m_arcs.size(); arcIndex++) { pair<string, NFA *> ip = nfa->m_arcs[arcIndex]; if (!ip.first.empty()) { vector<NFA *> *nfaset = new vector<NFA *>(); ip.second->findUnlabeldState(*nfaset); arcs.push_back(make_pair(ip.first, nfaset)); } } } // for all arcs vector<pair<string, vector<NFA*>*> >::iterator it; for (it = arcs.begin(); it != arcs.end(); it++) { string label = (*it).first; vector<NFA*> *nfaset = (*it).second; // check to see wether the state is in stack vector<DFA*>::iterator i = stack->begin(); for (; i != stack->end(); i++) { if (isSameNFASet((*i)->m_nfas, *nfaset)) break; } // if not found, generate a new DFA state, and arc them if (i == stack->end()) { DFA * newState = new DFA(*nfaset, end); stack->push_back(newState); state->arc(newState, label); } } } return stack; }
unsigned long regex_parser::parse_regex_group(FILE *file, int group[]){ unsigned long size = _INFINITY; do { NFA *nfa = group_regex(file, group); nfa->remove_epsilon(); nfa->reduce(); DFA *dfa = nfa->nfa2dfa(); delete nfa; size = dfa->size(); delete dfa; } while (0); return size; }
DFA RegexParser::parse(RegexNode *root) { std::vector<pos_set> states; states.push_back(*root->first); int first_unmarked = 0; DFA dfa; dfa.add_state(); /* TODO: destroy the tree data structure */ while (first_unmarked < states.size()) { pos_set t = states[first_unmarked]; /* TODO: adapt this to work with Unicode */ for (int c = 0; c < 256; c++) { pos_set u; for (Leaf *l : t) if (l->value == c) merge_into(&u, l->follow); if (u.size() > 0) { int pos = std::find(states.begin(), states.end(), u) - states.begin(); if (pos == states.size()) { states.push_back(u); int state = dfa.add_state(); int accept = DFA_OK; for (Leaf* l : u) if (l->end) accept = MAX(accept, l->value); dfa.set_accept(state, accept); } dfa.set_trans(first_unmarked, c, pos); } } first_unmarked++; } return dfa; }
Status Translate(int cmd, const DFA &dfa) const { Status s = MakeInvalid(dfa); for (int i = 0; i < by_state.size(); i++) { if (by_state[i].score == NEG_INF) continue; for (int ch = cmd * 6; ch < (cmd + 1) * 6; ch++) { int j = dfa.transitions[i][ch]; unsigned novelty_mask = (unsigned)dfa.mask_increments[j] & ~by_state[i].first_seen_mask; int novelty_score = 300 * __builtin_popcount(novelty_mask); int new_score = by_state[i].score + dfa.score_from_mask_increments(dfa.mask_increments[j]) + novelty_score; if (new_score > s.by_state[j].score) { s.by_state[j].score = new_score; s.by_state[j].first_seen_mask = (unsigned)dfa.mask_increments[j] | by_state[i].first_seen_mask; s.by_state[j].best = AppendToChain(by_state[i].best, ch); } } } return s; }
DFA::DFA(const DFA & dfa){ this->transitionFunction = new TransitionFunction(*(dfa.transitionFunction)); this->alphabet = new std::vector<int>(dfa.getSymbolCount()); const std::vector<int>* oldAlphabet = dfa.getAlphabet(); for(unsigned int i = 0; i < dfa.getSymbolCount(); i++){ (*this->alphabet)[i] = (*oldAlphabet)[i]; } this->initialState = dfa.getInitialState(); this->acceptingStates = new std::vector<unsigned int>(*(dfa.getAcceptingStates())); }
TEST_F(TestDFA, UselessStateRemoval) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance.accept("q1"); instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q2", 'c'); instance.addTransition("q3", "q3", 'd'); EXPECT_EQ(4, instance.size()); DFA other = instance.withoutUselessStates(); EXPECT_EQ(2, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); }
void GenerateDFA(const string &patten, DFA &target) { target.resize(10); for (DFA::iterator e = target.begin(); e != target.end(); e++) { e->resize(patten.size()); } // foreach in target target[ToNumber(patten[0])][0] = 1U; for (unsigned x = 0U, j = 1U; j < patten.size(); j++) { for (unsigned c = 0U; c < 10U; c++) { target[c][j] = target[c][x]; } // for target[ToNumber(patten[j])][j] = j + 1; x = target[ToNumber(patten[j])][x]; } // for }
TEST_F(TestDFA, Acceptance) { instance << "q0"; instance << "q1"; instance << "q2"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q1", 'b'); instance.accept("q2"); instance.read("ab"); EXPECT_TRUE(instance.accepts()); instance.reset(); instance.read("abb"); EXPECT_FALSE(instance.accepts()); DFA other; other << "q0"; other.accept("q0"); EXPECT_TRUE(other.accepts()); other.read("a"); EXPECT_FALSE(other.accepts()); other.reset(); EXPECT_TRUE(other.accepts()); }
TEST_F(TestDFA, Equivalence) { instance << "q0"; instance << "q1"; instance.addTransition("q0", "q1", 'a'); instance.accept("q1"); DFA copy; ASSERT_NO_THROW(copy = ~~instance); ASSERT_EQ(instance.size(), copy.size()); DFA almostEqual; almostEqual << "q0"; almostEqual << "q1"; almostEqual.addTransition("q0", "q1", 'b'); almostEqual.accept("q1"); bool r; ASSERT_NO_THROW(r = (copy == instance)); EXPECT_TRUE(r); EXPECT_EQ(2, instance.size()); EXPECT_EQ(2, copy.size()); ASSERT_NO_THROW(r = (almostEqual == instance)); EXPECT_FALSE(r); EXPECT_EQ(2, instance.size()); EXPECT_EQ(2, almostEqual.size()); }
long trie_recurse( DFA<N_AMINOACIDS> &A, IDFA<int> &Apep, IDFAState<int> *pep, vector<int> &pre, const double thr_pos, int i ){ //cerr << i << " " << pre.size() << endl; if( i == pre.size() ){ IDFA<int> A2; vector<int> pre2( pre ); long snew = add_strings_near( A2, A, 0, A.pureAccepting(), pre, pre2, thr_pos, max_energy(pre), min_energy(pre), 0 ); if( snew > 0 ){ /*cout << "1st guy: " << endl; A.printDebug(); cout << "2nd guy: " << endl; DFA<N_AMINOACIDS>(A2).printDebug();*/ A = A.join( DFA<N_AMINOACIDS>(A2) ).minimize(); } //cerr << snew << endl; return snew; } long r = 0; float max_of_minima = 0.0; vector<int> dominated(N_AMINOACIDS,0); for( int j = 0 ; j < N_AMINOACIDS ; j ++ ){ if( IDFAState<int> * tgt = pep->next(aa_by_min_energy[j]) ){ pre[i] = aa_by_min_energy[j]; if( pep -> fanOut() > 1 ){ if( dominated[pre[i]] ){ continue; } for( int k = 0 ; k < N_AMINOACIDS ; k ++ ){ if( pre[i] != k && mj_domination[pre[i]][k] && ( tgt == pep->next(k) ) ){ /*cerr << aminoacids[pre[i]] << " (" << pre[i] << ") dom. " << aminoacids[k] << " (" << k << ")" << endl;*/ dominated[k]=1; } } } r += trie_recurse( A, Apep, tgt, pre, thr_pos, i+1 ); } } return r; }
TEST_F(TestDFA, EquivalentStateRemoval) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance << "q4"; instance << "q5"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q2", 'c'); instance.addTransition("q3", "q3", 'd'); instance.addTransition("q3", "q4", 'a'); instance.addTransition("q4", "q5", 'a'); instance.addTransition("q5", "q3", 'a'); instance.accept("q2"); EXPECT_EQ(6, instance.size()); instance.read("abc"); EXPECT_TRUE(instance.accepts()); instance.read("d"); EXPECT_FALSE(instance.accepts()); DFA other = instance.withoutDeadStates(); EXPECT_EQ(3, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); other.read("abc"); EXPECT_TRUE(other.accepts()); other.read("d"); EXPECT_FALSE(other.accepts()); }
// Ö÷º¯Êý void main() { DFA dfa; dfa.GetRegExp(); dfa.InsertCatNode(); dfa.RegExpToPost(); dfa.GetEdgeNumber(); dfa.ThompsonConstruction(); dfa.SubsetConstruction(); dfa.check(); }
forceinline DFA::Symbols::Symbols(const DFA& d) { const DFAI* o = static_cast<DFAI*>(d.object()); if (o != NULL) { c_trans = &o->trans[0]; e_trans = c_trans+o->n_trans; } else { c_trans = e_trans = NULL; } }
void main(void) { DFA myDfa; myDfa.AddString("hello",1); myDfa.AddString("howdy",2); myDfa.AddString("hell",3); string result; stringstream ss("howdy hello hell howdy hello help"); int id; while (true) { id=myDfa.GetString(result,ss); if (id != 0) cout << result << endl; else { cout << result << (char)ss.get() <<endl; break; } } }
TEST(DFAParticleDecoder, ParticleDecodedIntoDFA_SmallWord_ProperComputeState) { unsigned int stateCount = 4; unsigned int symbolCount = 2; double encodingDelta = 0.5; DFAParticleDecoder decoder(stateCount, symbolCount, encodingDelta); Particle p = createParticle_s4_r2(); DFA* dfa = (DFA*)decoder.decodeCurrent(p); std::vector<int> word_entries2{0}; Word w2(word_entries2); int expectedState = 1; int actualState = dfa->compute(w2); EXPECT_EQ(expectedState, actualState); delete dfa; }
size_t minimize(const DFA& dfa, const vector<size_t>& terminalStates) { for (int stateA_ = dfa.statesCount() - 1; stateA_ >= 0; --stateA_) { size_t stateA = stateA_; if (!dfa.isReachable(stateA)) { continue; } for (int stateB_ = 0; stateB_ <= stateA_; ++stateB_) { size_t stateB = stateB_; if (!dfa.isReachable(stateB)) { continue; } if (stateA < stateB) { std::swap(stateA, stateB); } for (size_t index = 0; index < dfa.alphaberSize(); ++index) { char symbol = 'a' + index; size_t newStateA = dfa.adjcencyState(symbol, stateA); size_t newStateB = dfa.adjcencyState(symbol, stateB); if (newStateA < newStateB) { std::swap(newStateA, newStateB); } pairGraph[newStateA][newStateB].push_back(make_pair(stateA, stateB)); } } } return countNonEquivalentStates(dfa, terminalStates); }
TEST_F(TestDFA, Minimization) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance << "q4"; instance << "q5"; instance.accept("q3"); instance.addTransition("q0", "q1", 'a'); instance.addTransition("q0", "q2", 'b'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q1", 'b'); instance.addTransition("q1", "q3", 'c'); instance.addTransition("q2", "q3", 'c'); instance.addTransition("q3", "q4", 'a'); instance.addTransition("q4", "q4", 'b'); instance.addTransition("q5", "q2", 'a'); DFA minimized; ASSERT_NO_THROW(minimized = instance.minimized()); EXPECT_EQ(3, minimized.size()); EXPECT_EQ(minimized.initialState().getName(), instance.initialState().getName()); }
forceinline DFA::Transitions::Transitions(const DFA& d, int n) { const DFAI* o = static_cast<DFAI*>(d.object()); if (o != NULL) { int mask = (1<<o->n_log)-1; int p = n & mask; while ((o->table[p].fst != NULL) && (o->table[p].symbol != n)) p = (p+1) & mask; c_trans = o->table[p].fst; e_trans = o->table[p].lst; } else { c_trans = e_trans = NULL; } }
void dfa_test() { DFA dfa; dfa.set_states_count(5); //ui initial_states[3] = {1, 0, 2}; dfa.set_initial_state(0); ui final_states[2] = {4, 3}; dfa.set_final_states(final_states, 2); dfa.add_transition(0, 'a', 1); dfa.add_transition(0, 'b', 2); dfa.add_transition(1, 'b', 2); dfa.add_transition(1, 'c', 3); dfa.add_transition(2, 'c', 3); dfa.add_transition(3, 'd', 4); dfa.add_transition(4, 'd', 4); printf("%s\n", dfa.check_word("bcddd") ? "true" : "false"); }
TEST_F(TestDFA, RValueOperations) { DFA first; first << "q0" << "q1" << "q2"; first.addTransition("q0", "q1", 'a'); first.addTransition("q1", "q2", 'a'); first.addTransition("q2", "q0", 'a'); first.accept("q0"); DFA second; second << "q0" << "q1"; second.addTransition("q0", "q1", 'a'); second.addTransition("q1", "q0", 'a'); second.accept("q1"); EXPECT_NO_THROW(first & ~second); EXPECT_NO_THROW(first | ~second); EXPECT_NO_THROW(first == ~second); EXPECT_NO_THROW(first.contains(~second)); EXPECT_NO_THROW(second.contains(~first)); }
int main( int argc, char * argv[] ) { if( argc < 3 ){ cerr << "Usage : " << argv[0] << " [n] [thr_pos] " << endl; exit(1); } int n = atoi( argv[1] ); double thr_pos = atof( argv[2] )*n; string line; /** new method with trie/trie interaction */ IDFA<int> Apep; DFA<N_AMINOACIDS> TCR; while( cin ){ getline( cin, line ); if( line.length() >= n ){ Apep.addString( pep2intseq( line.substr( 0, n ) ) ); } } vector<int> pre(n); trie_recurse( TCR, Apep, Apep.initialState(), pre, thr_pos, 0 ); TCR.print(); }
void print_dfa(const DFA& dfa) { cout << "start : " << dfa.start() << endl; cout << "last : "; const ::mpl::lexer::detail::States& last = dfa.last(); print_set(last); cout << endl; for (size_t i = 0; i < dfa.size(); i++) { const ::mpl::lexer::detail::DFATran& tran = dfa[i]; for (::mpl::lexer::detail::DFATran::const_iterator it = tran.begin(); it != tran.end(); ++it) { cout << i << "("; if (it->first == ::mpl::lexer::detail::EPSILON) { cout << "\\0"; } else if (it->first == ::mpl::lexer::detail::OTHER) { cout << "-1"; } else { //cout << it->first; cout << "0x" << hex << (int)(it->first & 0xFF) << dec; } cout << ")"; cout << "\t->\t"; cout << it->second; cout << endl; } } for (::mpl::lexer::detail::States::const_iterator it = last.begin(); it != last.end(); ++it) { const ::mpl::lexer::detail::Tag& tag = dfa.tags(*it); cout << *it << ": "; print_set(tag); cout << endl; } }
long add_strings_near( IDFA<T> &A, DFA<N_AMINOACIDS> &Aacc, long qacc, const unordered_set<long> &acc, const vector<int>& pep, vector<int> &pre, double thr_pos, const vector<double>& emin, const vector<double>& emax, int i ){ if( thr_pos < emin[i] ){ //cerr << "breaking " << thr_pos << " " << emin[i] << endl; return 0; } if( i == pep.size() ){ if( thr_pos >= 0 && acc.find( qacc ) == acc.end() ){ //cerr << "adding single string" << endl; A.addString( pre ); return 1; } else { return 0; } } if( acc.find( qacc ) != acc.end() ){ /*if( i < 4 ){ cerr << "branch off at " << i << endl; }*/ return 0; } if( thr_pos >= emax[i] ){ if( i < 4 ){ //DFA<N_AMINOACIDS>(A).printDebug(); //cerr << intseq2pep(pre) << " to insert complete subtree at " << i << endl; } A.addTree( pre, pep.size()-i, N_AMINOACIDS ); return pow( N_AMINOACIDS, pep.size()-i ); } long r = 0; for( int j = 0 ; j < N_AMINOACIDS ; j ++ ){ pre[i] = j; double eij = mj_matrix[pep[i]][j]; r += add_strings_near( A, Aacc, Aacc.nextState( qacc, j ), acc, pep, pre, thr_pos-eij, emin, emax, i+1 ); } return r; }