1// Copyright 2016 ALRUX Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package levenshtein
16
17// Params represents a set of parameter values for the various formulas involved
18// in the calculation of the Levenshtein string metrics.
19type Params struct {
20	insCost        int
21	subCost        int
22	delCost        int
23	maxCost        int
24	minScore       float64
25	bonusPrefix    int
26	bonusScale     float64
27	bonusThreshold float64
28}
29
30var (
31	defaultParams = NewParams()
32)
33
34// NewParams creates a new set of parameters and initializes it with the default values.
35func NewParams() *Params {
36	return &Params{
37		insCost:        1,
38		subCost:        1,
39		delCost:        1,
40		maxCost:        0,
41		minScore:       0,
42		bonusPrefix:    4,
43		bonusScale:     .1,
44		bonusThreshold: .7,
45	}
46}
47
48// Clone returns a pointer to a copy of the receiver parameter set, or of a new
49// default parameter set if the receiver is nil.
50func (p *Params) Clone() *Params {
51	if p == nil {
52		return NewParams()
53	}
54	return &Params{
55		insCost:        p.insCost,
56		subCost:        p.subCost,
57		delCost:        p.delCost,
58		maxCost:        p.maxCost,
59		minScore:       p.minScore,
60		bonusPrefix:    p.bonusPrefix,
61		bonusScale:     p.bonusScale,
62		bonusThreshold: p.bonusThreshold,
63	}
64}
65
66// InsCost overrides the default value of 1 for the cost of insertion.
67// The new value must be zero or positive.
68func (p *Params) InsCost(v int) *Params {
69	if v >= 0 {
70		p.insCost = v
71	}
72	return p
73}
74
75// SubCost overrides the default value of 1 for the cost of substitution.
76// The new value must be zero or positive.
77func (p *Params) SubCost(v int) *Params {
78	if v >= 0 {
79		p.subCost = v
80	}
81	return p
82}
83
84// DelCost overrides the default value of 1 for the cost of deletion.
85// The new value must be zero or positive.
86func (p *Params) DelCost(v int) *Params {
87	if v >= 0 {
88		p.delCost = v
89	}
90	return p
91}
92
93// MaxCost overrides the default value of 0 (meaning unlimited) for the maximum cost.
94// The calculation of Distance() stops when the result is guaranteed to exceed
95// this maximum, returning a lower-bound rather than exact value.
96// The new value must be zero or positive.
97func (p *Params) MaxCost(v int) *Params {
98	if v >= 0 {
99		p.maxCost = v
100	}
101	return p
102}
103
104// MinScore overrides the default value of 0 for the minimum similarity score.
105// Scores below this threshold are returned as 0 by Similarity() and Match().
106// The new value must be zero or positive. Note that a minimum greater than 1
107// can never be satisfied, resulting in a score of 0 for any pair of strings.
108func (p *Params) MinScore(v float64) *Params {
109	if v >= 0 {
110		p.minScore = v
111	}
112	return p
113}
114
115// BonusPrefix overrides the default value for the maximum length of
116// common prefix to be considered for bonus by Match().
117// The new value must be zero or positive.
118func (p *Params) BonusPrefix(v int) *Params {
119	if v >= 0 {
120		p.bonusPrefix = v
121	}
122	return p
123}
124
125// BonusScale overrides the default value for the scaling factor used by Match()
126// in calculating the bonus.
127// The new value must be zero or positive. To guarantee that the similarity score
128// remains in the interval 0..1, this scaling factor is not allowed to exceed
129// 1 / BonusPrefix.
130func (p *Params) BonusScale(v float64) *Params {
131	if v >= 0 {
132		p.bonusScale = v
133	}
134
135	// the bonus cannot exceed (1-sim), or the score may become greater than 1.
136	if float64(p.bonusPrefix)*p.bonusScale > 1 {
137		p.bonusScale = 1 / float64(p.bonusPrefix)
138	}
139
140	return p
141}
142
143// BonusThreshold overrides the default value for the minimum similarity score
144// for which Match() can assign a bonus.
145// The new value must be zero or positive. Note that a threshold greater than 1
146// effectively makes Match() become the equivalent of Similarity().
147func (p *Params) BonusThreshold(v float64) *Params {
148	if v >= 0 {
149		p.bonusThreshold = v
150	}
151	return p
152}
153