aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/vespa/searchlib/fef/functiontablefactory.cpp
blob: 0030641f8dae1964ea9e463cb1c33b2035c61e88 (plain) (blame)
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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "functiontablefactory.h"
#include <vespa/vespalib/locale/c.h>
#include <vespa/vespalib/text/stringtokenizer.h>
#include <cmath>
#include <vespa/log/log.h>
LOG_SETUP(".fef.functiontablefactory");

namespace {

void logArgumentWarning(const vespalib::string & name, size_t exp, size_t act)
{
    LOG(warning, "Cannot create table for function '%s'. Wrong number of arguments: expected %zu to %zu, but got %zu",
        name.c_str(), exp, exp + 1, act);
}

}

namespace search::fef {

bool
FunctionTableFactory::checkArgs(const std::vector<vespalib::string> & args, size_t exp, size_t & tableSize) const
{
    if (exp <= args.size() && args.size() <= (exp + 1)) {
        if (args.size() == (exp + 1)) {
            tableSize = atoi(args.back().c_str());
        } else {
            tableSize = _defaultTableSize;
        }
        return true;
    }
    return false;
}

bool
FunctionTableFactory::isSupported(const vespalib::string & type) const
{
    return (isExpDecay(type) || isLogGrowth(type) || isLinear(type));
}

Table::SP
FunctionTableFactory::createExpDecay(double w, double t, size_t len) const
{
    Table::SP table(new Table());
    for (size_t x = 0; x < len; ++x) {
        table->add(w * std::exp(-(x / t)));
    }
    return table;
}

Table::SP
FunctionTableFactory::createLogGrowth(double w, double t, double s, size_t len) const
{
    auto table = std::make_shared<Table>();
    for (size_t x = 0; x < len; ++x) {
        table->add(w * (std::log(1 + (x / s))) + t);
    }
    return table;
}

Table::SP
FunctionTableFactory::createLinear(double w, double t, size_t len) const
{
    Table::SP table(new Table());
    for (size_t x = 0; x < len; ++x) {
        table->add(w * x + t);
    }
    return table;
}

FunctionTableFactory::FunctionTableFactory(size_t defaultTableSize) :
    _defaultTableSize(defaultTableSize)
{
}

Table::SP
FunctionTableFactory::createTable(const vespalib::string & name) const
{
    ParsedName p;
    if (parseFunctionName(name, p)) {
        if (isSupported(p.type)) {
            size_t tableSize = _defaultTableSize;
            if (isExpDecay(p.type)) {
                if (checkArgs(p.args, 2, tableSize)) {
                    return createExpDecay(vespalib::locale::c::atof(p.args[0].c_str()), vespalib::locale::c::atof(p.args[1].c_str()), tableSize);
                }
                logArgumentWarning(name, 2, p.args.size());
            } else if (isLogGrowth(p.type)) {
                if (checkArgs(p.args, 3, tableSize)) {
                    return createLogGrowth(vespalib::locale::c::atof(p.args[0].c_str()), vespalib::locale::c::atof(p.args[1].c_str()), vespalib::locale::c::atof(p.args[2].c_str()), tableSize);
                }
                logArgumentWarning(name, 3, p.args.size());
            } else if (isLinear(p.type)) {
                if (checkArgs(p.args, 2, tableSize)) {
                    return createLinear(vespalib::locale::c::atof(p.args[0].c_str()), vespalib::locale::c::atof(p.args[1].c_str()), tableSize);
                }
                logArgumentWarning(name, 2, p.args.size());
            }
        } else {
            LOG(warning, "Cannot create table for function '%s'. Function type '%s' is not supported",
                name.c_str(), p.type.c_str());
        }
    } else {
        LOG(warning, "Cannot create table for function '%s'. Could not be parsed.", name.c_str());
    }
    return {};
}

bool
FunctionTableFactory::parseFunctionName(const vespalib::string & name, ParsedName & parsed)
{
    size_t ps = name.find('(');
    size_t pe = name.find(')');
    if (ps == vespalib::string::npos || pe == vespalib::string::npos) {
        LOG(warning, "Parse error: Did not find '(' and ')' in function name '%s'", name.c_str());
        return false;
    }
    if (ps >= pe) {
        LOG(warning, "Parse error: Found ')' before '(' in function name '%s'", name.c_str());
        return false;
    }
    parsed.type = name.substr(0, ps);
    vespalib::string args = name.substr(ps + 1, pe - ps - 1);
    if (!args.empty()) {
        vespalib::StringTokenizer tokenizer(args);
        for (const auto & token : tokenizer) {
            parsed.args.emplace_back(token);
        }
    }
    return true;
}

}