mirror of
https://github.com/moses-smt/mosesdecoder.git
synced 2024-09-11 19:27:11 +03:00
Grid search for lattice mbr
git-svn-id: https://mosesdecoder.svn.sourceforge.net/svnroot/mosesdecoder/trunk@2913 1f5c12ca-751b-0410-a591-d2e778427230
This commit is contained in:
parent
ad3b032ebf
commit
b2201e765d
@ -492,7 +492,7 @@ vector<Word> calcMBRSol(const TrellisPathList& nBestList, map<Phrase, float>& f
|
||||
return argmaxTranslation;
|
||||
}
|
||||
|
||||
vector<Word> doLatticeMBR(Manager& manager) {
|
||||
vector<Word> doLatticeMBR(Manager& manager, TrellisPathList& nBestList) {
|
||||
const StaticData& staticData = StaticData::Instance();
|
||||
std::map < int, bool > connected;
|
||||
std::vector< const Hypothesis *> connectedList;
|
||||
@ -503,28 +503,8 @@ vector<Word> doLatticeMBR(Manager& manager) {
|
||||
manager.GetForwardBackwardSearchGraph(&connected, &connectedList, &outgoingHyps, &estimatedScores);
|
||||
pruneLatticeFB(connectedList, outgoingHyps, incomingEdges, estimatedScores, staticData.GetLatticeMBRPruningFactor());
|
||||
calcNgramPosteriors(connectedList, incomingEdges, staticData.GetMBRScale(), ngramPosteriors);
|
||||
vector<Word> mbrBestHypo;
|
||||
if (!staticData.UseLatticeHypSetForLatticeMBR()) {
|
||||
size_t nBestSize = staticData.GetMBRSize();
|
||||
if (nBestSize <= 0)
|
||||
{
|
||||
cerr << "ERROR: negative size for number of MBR candidate translations not allowed (option mbr-size)" << endl;
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
TrellisPathList nBestList;
|
||||
manager.CalcNBest(nBestSize, nBestList,true);
|
||||
VERBOSE(2,"size of n-best: " << nBestList.GetSize() << " (" << nBestSize << ")" << endl);
|
||||
IFVERBOSE(2) { PrintUserTime("calculated n-best list for MBR decoding"); }
|
||||
mbrBestHypo = calcMBRSol(nBestList, ngramPosteriors, staticData.GetLatticeMBRThetas(),
|
||||
staticData.GetLatticeMBRPrecision(), staticData.GetLatticeMBRPRatio());
|
||||
}
|
||||
}
|
||||
else {
|
||||
cerr << "Using Lattice for Hypothesis set not yet implemented" << endl;
|
||||
exit(1);
|
||||
}
|
||||
vector<Word> mbrBestHypo = calcMBRSol(nBestList, ngramPosteriors, staticData.GetLatticeMBRThetas(),
|
||||
staticData.GetLatticeMBRPrecision(), staticData.GetLatticeMBRPRatio());
|
||||
return mbrBestHypo;
|
||||
}
|
||||
|
||||
|
@ -113,4 +113,4 @@ void calcNgramPosteriors(Lattice & connectedHyp, map<const Hypothesis*, vector<E
|
||||
void GetOutputFactors(const TrellisPath &path, vector <Word> &translation);
|
||||
void extract_ngrams(const vector<Word >& sentence, map < Phrase, int > & allngrams);
|
||||
bool ascendingCoverageCmp(const Hypothesis* a, const Hypothesis* b);
|
||||
vector<Word> doLatticeMBR(Manager& manager);
|
||||
vector<Word> doLatticeMBR(Manager& manager, TrellisPathList& nBestList);
|
||||
|
203
moses-cmd/src/LatticeMBRGrid.cpp
Normal file
203
moses-cmd/src/LatticeMBRGrid.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
// $Id: $
|
||||
|
||||
/***********************************************************************
|
||||
Moses - factored phrase-based language decoder
|
||||
Copyright (c) 2010 University of Edinburgh
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the University of Edinburgh nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
***********************************************************************/
|
||||
/**
|
||||
* Lattice MBR grid search. Enables a grid search through the four parameters (p,r,scale and prune) used in lattice MBR.
|
||||
See 'Lattice Minimum Bayes-Risk Decoding for Statistical Machine Translation by Tromble, Kumar, Och and Macherey,
|
||||
EMNLP 2008 for details of the parameters.
|
||||
|
||||
The grid search is controlled by specifying comma separated lists for the lmbr parameters (-lmbr-p, -lmbr-r,
|
||||
-lmbr-pruning-factor and -mbr-size). All other parameters are passed through to moses. If any of the lattice mbr
|
||||
parameters are missing, then they are set to their default values. Output is of the form:
|
||||
sentence-id ||| p r prune size ||| translation-hypothesis
|
||||
**/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
|
||||
#include "IOWrapper.h"
|
||||
#include "LatticeMBR.h"
|
||||
#include "Manager.h"
|
||||
#include "StaticData.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace Moses;
|
||||
|
||||
//keys
|
||||
enum gridkey {lmbr_p,lmbr_r,lmbr_prune,lmbr_scale};
|
||||
|
||||
class Grid {
|
||||
public:
|
||||
/** Add a parameter with key, command line argument, and default value */
|
||||
void addParam(gridkey key, const string& arg, float defaultValue) {
|
||||
m_args[arg] = key;
|
||||
assert(m_grid.find(key) == m_grid.end());
|
||||
m_grid[key].push_back(defaultValue);
|
||||
}
|
||||
|
||||
/** Parse the arguments, removing those that define the grid and returning a copy of the rest */
|
||||
void parseArgs(int& argc, char**& argv) {
|
||||
char** newargv = new char*[argc];
|
||||
int newargc = 0;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
bool consumed = false;
|
||||
for (map<string,gridkey>::const_iterator argi = m_args.begin(); argi != m_args.end(); ++argi) {
|
||||
if (!strcmp(argv[i], argi->first.c_str())) {
|
||||
++i;
|
||||
if (i >= argc) {
|
||||
cerr << "Error: missing parameter for " << argi->first << endl;
|
||||
throw runtime_error("Missing parameter");
|
||||
} else {
|
||||
string value = argv[i];
|
||||
gridkey key = argi->second;
|
||||
if (m_grid[key].size() != 1) {
|
||||
throw runtime_error("Duplicate grid argument");
|
||||
}
|
||||
m_grid[key].clear();
|
||||
char delim = ',';
|
||||
string::size_type lastpos = value.find_first_not_of(delim);
|
||||
string::size_type pos = value.find_first_of(delim,lastpos);
|
||||
while (string::npos != pos || string::npos != lastpos) {
|
||||
float param = atof(value.substr(lastpos, pos-lastpos).c_str());
|
||||
if (!param) {
|
||||
cerr << "Error: Illegal grid parameter for " << argi->first << endl;
|
||||
throw runtime_error("Illegal grid parameter");
|
||||
}
|
||||
m_grid[key].push_back(param);
|
||||
lastpos = value.find_first_not_of(delim,pos);
|
||||
pos = value.find_first_of(delim,lastpos);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
if (consumed) break;
|
||||
}
|
||||
}
|
||||
if (!consumed) {
|
||||
newargv[newargc] = new char[strlen(argv[i]) + 1];
|
||||
strcpy(newargv[newargc],argv[i]);
|
||||
++newargc;
|
||||
}
|
||||
}
|
||||
argc = newargc;
|
||||
argv = newargv;
|
||||
}
|
||||
|
||||
/** Get the grid for a particular key.*/
|
||||
const vector<float>& getGrid(gridkey key) const {
|
||||
map<gridkey,vector<float> >::const_iterator iter = m_grid.find(key);
|
||||
assert (iter != m_grid.end());
|
||||
return iter->second;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
map<gridkey,vector<float> > m_grid;
|
||||
map<string,gridkey> m_args;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
cerr << "Lattice MBR Grid search" << endl;
|
||||
|
||||
Grid grid;
|
||||
grid.addParam(lmbr_p, "-lmbr-p", 0.5);
|
||||
grid.addParam(lmbr_r, "-lmbr-r", 0.5);
|
||||
grid.addParam(lmbr_prune, "-lmbr-pruning-factor",30.0);
|
||||
grid.addParam(lmbr_scale, "-mbr-scale",1.0);
|
||||
|
||||
grid.parseArgs(argc,argv);
|
||||
|
||||
Parameter* params = new Parameter();
|
||||
if (!params->LoadParam(argc,argv)) {
|
||||
params->Explain();
|
||||
exit(1);
|
||||
}
|
||||
if (!StaticData::LoadDataStatic(params)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
StaticData& staticData = const_cast<StaticData&>(StaticData::Instance());
|
||||
IOWrapper* ioWrapper = GetIODevice(staticData);
|
||||
|
||||
if (!ioWrapper) {
|
||||
throw runtime_error("Failed to initialise IOWrapper");
|
||||
}
|
||||
size_t nBestSize = staticData.GetMBRSize();
|
||||
|
||||
if (nBestSize <= 0){
|
||||
throw new runtime_error("Non-positive size specified for n-best list");
|
||||
}
|
||||
|
||||
size_t lineCount = 0;
|
||||
InputType* source = NULL;
|
||||
|
||||
const vector<float>& pgrid = grid.getGrid(lmbr_p);
|
||||
const vector<float>& rgrid = grid.getGrid(lmbr_r);
|
||||
const vector<float>& prune_grid = grid.getGrid(lmbr_prune);
|
||||
const vector<float>& scale_grid = grid.getGrid(lmbr_scale);
|
||||
|
||||
while(ReadInput(*ioWrapper,staticData.GetInputType(),source)) {
|
||||
++lineCount;
|
||||
Sentence sentence(Input);
|
||||
Manager manager(*source,staticData.GetSearchAlgorithm());
|
||||
manager.ProcessSentence();
|
||||
TrellisPathList nBestList;
|
||||
manager.CalcNBest(nBestSize, nBestList,true);
|
||||
//grid search
|
||||
for (vector<float>::const_iterator pi = pgrid.begin(); pi != pgrid.end(); ++pi) {
|
||||
float p = *pi;
|
||||
staticData.SetLatticeMBRPrecision(p);
|
||||
for (vector<float>::const_iterator ri = rgrid.begin(); ri != rgrid.end(); ++ri) {
|
||||
float r = *ri;
|
||||
staticData.SetLatticeMBRPRatio(r);
|
||||
for (vector<float>::const_iterator prune_i = prune_grid.begin(); prune_i != prune_grid.end(); ++prune_i) {
|
||||
size_t prune = (size_t)(*prune_i);
|
||||
staticData.SetLatticeMBRPruningFactor(prune);
|
||||
for (vector<float>::const_iterator scale_i = scale_grid.begin(); scale_i != scale_grid.end(); ++scale_i) {
|
||||
float scale = *scale_i;
|
||||
staticData.SetMBRScale(scale);
|
||||
cout << lineCount << " ||| " << p << " " << r << " " << prune << " " << scale << " ||| ";
|
||||
vector<Word> mbrBestHypo = doLatticeMBR(manager,nBestList);
|
||||
OutputBestHypo(mbrBestHypo, lineCount, staticData.GetReportSegmentation(),
|
||||
staticData.GetReportAllFactors(),cout);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -167,48 +167,49 @@ int main(int argc, char* argv[])
|
||||
IFVERBOSE(2) { PrintUserTime("N-Best Hypotheses Generation Time:"); }
|
||||
}
|
||||
}
|
||||
else if (staticData.UseLatticeMBR()) {
|
||||
vector<Word> mbrBestHypo = doLatticeMBR(manager);
|
||||
OutputBestHypo(mbrBestHypo, source->GetTranslationId(), staticData.GetReportSegmentation(),
|
||||
staticData.GetReportAllFactors(),cout);
|
||||
IFVERBOSE(2) { PrintUserTime("finished Lattice MBR decoding"); }
|
||||
}
|
||||
// consider top candidate translations to find minimum Bayes risk translation
|
||||
else {
|
||||
size_t nBestSize = staticData.GetMBRSize();
|
||||
else {
|
||||
size_t nBestSize = staticData.GetMBRSize();
|
||||
|
||||
if (nBestSize <= 0)
|
||||
{
|
||||
cerr << "ERROR: negative size for number of MBR candidate translations not allowed (option mbr-size)" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
TrellisPathList nBestList;
|
||||
manager.CalcNBest(nBestSize, nBestList,true);
|
||||
VERBOSE(2,"size of n-best: " << nBestList.GetSize() << " (" << nBestSize << ")" << endl);
|
||||
IFVERBOSE(2) { PrintUserTime("calculated n-best list for MBR decoding"); }
|
||||
std::vector<const Factor*> mbrBestHypo = doMBR(nBestList);
|
||||
OutputBestHypo(mbrBestHypo, source->GetTranslationId(),
|
||||
staticData.GetReportSegmentation(),
|
||||
staticData.GetReportAllFactors(),cout);
|
||||
IFVERBOSE(2) { PrintUserTime("finished MBR decoding"); }
|
||||
if (!staticData.GetNBestFilePath().empty()){
|
||||
//print the all nbest used for MBR (and not the amount passed through the parameter
|
||||
VERBOSE(2,"WRITING " << nBestSize << " TRANSLATION ALTERNATIVES TO " << staticData.GetNBestFilePath() << endl);
|
||||
ioWrapper->OutputNBestList(nBestList, source->GetTranslationId());
|
||||
IFVERBOSE(2) { PrintUserTime("N-Best Hypotheses Generation Time:"); }
|
||||
if (nBestSize <= 0)
|
||||
{
|
||||
cerr << "ERROR: negative size for number of MBR candidate translations not allowed (option mbr-size)" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
TrellisPathList nBestList;
|
||||
manager.CalcNBest(nBestSize, nBestList,true);
|
||||
VERBOSE(2,"size of n-best: " << nBestList.GetSize() << " (" << nBestSize << ")" << endl);
|
||||
IFVERBOSE(2) { PrintUserTime("calculated n-best list for (L)MBR decoding"); }
|
||||
if (staticData.UseLatticeMBR()) {
|
||||
vector<Word> mbrBestHypo = doLatticeMBR(manager,nBestList);
|
||||
OutputBestHypo(mbrBestHypo, source->GetTranslationId(), staticData.GetReportSegmentation(),
|
||||
staticData.GetReportAllFactors(),cout);
|
||||
IFVERBOSE(2) { PrintUserTime("finished Lattice MBR decoding"); }
|
||||
} else {
|
||||
std::vector<const Factor*> mbrBestHypo = doMBR(nBestList);
|
||||
OutputBestHypo(mbrBestHypo, source->GetTranslationId(),
|
||||
staticData.GetReportSegmentation(),
|
||||
staticData.GetReportAllFactors(),cout);
|
||||
IFVERBOSE(2) { PrintUserTime("finished MBR decoding"); }
|
||||
}
|
||||
|
||||
if (!staticData.GetNBestFilePath().empty()){
|
||||
//print the all nbest used for MBR (and not the amount passed through the parameter
|
||||
VERBOSE(2,"WRITING " << nBestSize << " TRANSLATION ALTERNATIVES TO " << staticData.GetNBestFilePath() << endl);
|
||||
ioWrapper->OutputNBestList(nBestList, source->GetTranslationId());
|
||||
IFVERBOSE(2) { PrintUserTime("N-Best Hypotheses Generation Time:"); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (staticData.IsDetailedTranslationReportingEnabled()) {
|
||||
TranslationAnalysis::PrintTranslationAnalysis(std::cerr, manager.GetBestHypothesis());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (staticData.IsDetailedTranslationReportingEnabled()) {
|
||||
TranslationAnalysis::PrintTranslationAnalysis(std::cerr, manager.GetBestHypothesis());
|
||||
}
|
||||
IFVERBOSE(2) { PrintUserTime("Sentence Decoding Time:"); }
|
||||
|
||||
IFVERBOSE(2) { PrintUserTime("Sentence Decoding Time:"); }
|
||||
manager.CalcDecoderStatistics();
|
||||
|
||||
manager.CalcDecoderStatistics();
|
||||
}
|
||||
|
||||
delete ioWrapper;
|
||||
|
@ -137,20 +137,20 @@ class TranslationTask : public Task {
|
||||
if (nBestSize <= 0) {
|
||||
cerr << "ERROR: negative size for number of MBR candidate translations not allowed (option mbr-size)" << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
TrellisPathList nBestList;
|
||||
manager.CalcNBest(nBestSize, nBestList,true);
|
||||
VERBOSE(2,"size of n-best: " << nBestList.GetSize() << " (" << nBestSize << ")" << endl);
|
||||
IFVERBOSE(2) { PrintUserTime("calculated n-best list for (L)MBR decoding"); }
|
||||
|
||||
if (staticData.UseLatticeMBR()) {
|
||||
//Lattice MBR decoding
|
||||
vector<Word> mbrBestHypo = doLatticeMBR(manager);
|
||||
vector<Word> mbrBestHypo = doLatticeMBR(manager,nBestList);
|
||||
OutputBestHypo(mbrBestHypo, m_lineNumber, staticData.GetReportSegmentation(),
|
||||
staticData.GetReportAllFactors(),out);
|
||||
IFVERBOSE(2) { PrintUserTime("finished Lattice MBR decoding"); }
|
||||
} else {
|
||||
//MBR decoding
|
||||
TrellisPathList nBestList;
|
||||
manager.CalcNBest(nBestSize, nBestList,true);
|
||||
VERBOSE(2,"size of n-best: " << nBestList.GetSize() << " (" << nBestSize << ")" << endl);
|
||||
IFVERBOSE(2) { PrintUserTime("calculated n-best list for MBR decoding"); }
|
||||
std::vector<const Factor*> mbrBestHypo = doMBR(nBestList);
|
||||
OutputBestHypo(mbrBestHypo, m_lineNumber,
|
||||
staticData.GetReportSegmentation(),
|
||||
|
@ -1,7 +1,7 @@
|
||||
if WITH_THREADS
|
||||
bin_PROGRAMS = moses mosesmt
|
||||
bin_PROGRAMS = moses mosesmt lmbrgrid
|
||||
else
|
||||
bin_PROGRAMS = moses
|
||||
bin_PROGRAMS = moses lmbrgrid
|
||||
endif
|
||||
AM_CPPFLAGS = -W -Wall -ffor-scope -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -DUSE_HYPO_POOL -I$(top_srcdir)/moses/src $(BOOST_CPPFLAGS)
|
||||
moses_SOURCES = Main.cpp mbr.cpp IOWrapper.cpp TranslationAnalysis.cpp LatticeMBR.cpp
|
||||
@ -13,4 +13,7 @@ mosesmt_LDADD = -L$(top_srcdir)/moses/src $(BOOST_LDFLAGS) -lmoses $(BOOST_THREA
|
||||
mosesmt_DEPENDENCIES = $(top_srcdir)/moses/src/libmoses.a
|
||||
|
||||
|
||||
lmbrgrid_SOURCES = LatticeMBRGrid.cpp LatticeMBR.cpp IOWrapper.cpp
|
||||
lmbrgrid_LDADD = -L$(top_srcdir)/moses/src $(BOOST_LDFLAGS) -lmoses $(BOOST_THREAD_LIB)
|
||||
lmbrgrid_DEPENDENCIES = $(top_srcdir)/moses/src/libmoses.a
|
||||
|
||||
|
@ -146,7 +146,7 @@ protected:
|
||||
size_t m_mbrSize; //! number of translation candidates considered
|
||||
float m_mbrScale; //! scaling factor for computing marginal probability of candidate translation
|
||||
size_t m_lmbrPruning; //! average number of nodes per word wanted in pruned lattice
|
||||
vector<float> m_lmbrThetas; //! theta(s) for lattice mbr calculation
|
||||
std::vector<float> m_lmbrThetas; //! theta(s) for lattice mbr calculation
|
||||
bool m_useLatticeHypSetForLatticeMBR; //! to use nbest as hypothesis set during lattice MBR
|
||||
float m_lmbrPrecision; //! unigram precision theta - see Tromble et al 08 for more details
|
||||
float m_lmbrPRatio; //! decaying factor for ngram thetas - see Tromble et al 08 for more details
|
||||
@ -467,15 +467,27 @@ public:
|
||||
bool UseLatticeMBR() const { return m_useLatticeMBR ;}
|
||||
size_t GetMBRSize() const { return m_mbrSize; }
|
||||
float GetMBRScale() const { return m_mbrScale; }
|
||||
void SetMBRScale(float scale) {
|
||||
m_mbrScale = scale;
|
||||
}
|
||||
size_t GetLatticeMBRPruningFactor() const { return m_lmbrPruning; }
|
||||
const vector<float>& GetLatticeMBRThetas() const {return m_lmbrThetas;}
|
||||
void SetLatticeMBRPruningFactor(size_t prune) {
|
||||
prune = m_lmbrPruning;
|
||||
}
|
||||
const std::vector<float>& GetLatticeMBRThetas() const {return m_lmbrThetas;}
|
||||
bool UseLatticeHypSetForLatticeMBR() const { return m_useLatticeHypSetForLatticeMBR;}
|
||||
float GetLatticeMBRPrecision() const {
|
||||
return m_lmbrPrecision;
|
||||
}
|
||||
void SetLatticeMBRPrecision(float p) {
|
||||
m_lmbrPrecision = p;
|
||||
}
|
||||
float GetLatticeMBRPRatio() const {
|
||||
return m_lmbrPRatio;
|
||||
}
|
||||
void SetLatticeMBRPRatio(float r) {
|
||||
m_lmbrPRatio = r;
|
||||
}
|
||||
|
||||
bool UseTimeout() const { return m_timeout; }
|
||||
size_t GetTimeoutThreshold() const { return m_timeout_threshold; }
|
||||
|
Loading…
Reference in New Issue
Block a user