mirror of https://github.com/curusarn/resh
enrich: add 'command' on top of 'firstWord' - first word is not always command strategies: add 'random' strategy, add markov chain based strategies evaluate: add plot with average recalled characters including prefix matchespull/15/head
parent
1bc5ef53f1
commit
ff878a9d79
@ -0,0 +1,91 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"sort" |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/curusarn/resh/common" |
||||||
|
"github.com/mb-14/gomarkov" |
||||||
|
) |
||||||
|
|
||||||
|
type strategyMarkovChainCmd struct { |
||||||
|
order int |
||||||
|
history []strMarkCmdHistoryEntry |
||||||
|
historyCmds []string |
||||||
|
} |
||||||
|
|
||||||
|
type strMarkCmdHistoryEntry struct { |
||||||
|
cmd string |
||||||
|
cmdLine string |
||||||
|
} |
||||||
|
|
||||||
|
type strMarkCmdEntry struct { |
||||||
|
cmd string |
||||||
|
transProb float64 |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChainCmd) init() { |
||||||
|
s.history = nil |
||||||
|
s.historyCmds = nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChainCmd) GetTitleAndDescription() (string, string) { |
||||||
|
return "command-based markov chain (order " + strconv.Itoa(s.order) + ")", "Use command-based markov chain to recommend commands" |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChainCmd) GetCandidates() []string { |
||||||
|
if len(s.history) < s.order { |
||||||
|
var hist []string |
||||||
|
for _, item := range s.history { |
||||||
|
hist = append(hist, item.cmdLine) |
||||||
|
} |
||||||
|
return hist |
||||||
|
} |
||||||
|
chain := gomarkov.NewChain(s.order) |
||||||
|
|
||||||
|
chain.Add(s.historyCmds) |
||||||
|
|
||||||
|
cmdsSet := map[string]bool{} |
||||||
|
var entries []strMarkCmdEntry |
||||||
|
for _, cmd := range s.historyCmds { |
||||||
|
if cmdsSet[cmd] { |
||||||
|
continue |
||||||
|
} |
||||||
|
cmdsSet[cmd] = true |
||||||
|
prob, _ := chain.TransitionProbability(cmd, s.historyCmds[len(s.historyCmds)-s.order:]) |
||||||
|
entries = append(entries, strMarkCmdEntry{cmd: cmd, transProb: prob}) |
||||||
|
} |
||||||
|
sort.Slice(entries, func(i int, j int) bool { return entries[i].transProb > entries[j].transProb }) |
||||||
|
var hist []string |
||||||
|
histSet := map[string]bool{} |
||||||
|
for i := len(s.history) - 1; i >= 0; i-- { |
||||||
|
if histSet[s.history[i].cmdLine] { |
||||||
|
continue |
||||||
|
} |
||||||
|
histSet[s.history[i].cmdLine] = true |
||||||
|
if s.history[i].cmd == entries[0].cmd { |
||||||
|
hist = append(hist, s.history[i].cmdLine) |
||||||
|
} |
||||||
|
} |
||||||
|
// log.Println("################")
|
||||||
|
// log.Println(s.history[len(s.history)-s.order:])
|
||||||
|
// log.Println(" -> ")
|
||||||
|
// x := math.Min(float64(len(hist)), 3)
|
||||||
|
// log.Println(entries[:int(x)])
|
||||||
|
// x = math.Min(float64(len(hist)), 5)
|
||||||
|
// log.Println(hist[:int(x)])
|
||||||
|
// log.Println("################")
|
||||||
|
return hist |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChainCmd) AddHistoryRecord(record *common.EnrichedRecord) error { |
||||||
|
s.history = append(s.history, strMarkCmdHistoryEntry{cmdLine: record.CmdLine, cmd: record.Command}) |
||||||
|
s.historyCmds = append(s.historyCmds, record.Command) |
||||||
|
// s.historySet[record.CmdLine] = true
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChainCmd) ResetHistory() error { |
||||||
|
s.init() |
||||||
|
return nil |
||||||
|
} |
||||||
@ -0,0 +1,70 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"sort" |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/curusarn/resh/common" |
||||||
|
"github.com/mb-14/gomarkov" |
||||||
|
) |
||||||
|
|
||||||
|
type strategyMarkovChain struct { |
||||||
|
order int |
||||||
|
history []string |
||||||
|
} |
||||||
|
|
||||||
|
type strMarkEntry struct { |
||||||
|
cmdLine string |
||||||
|
transProb float64 |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChain) init() { |
||||||
|
s.history = nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChain) GetTitleAndDescription() (string, string) { |
||||||
|
return "markov chain (order " + strconv.Itoa(s.order) + ")", "Use markov chain to recommend commands" |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChain) GetCandidates() []string { |
||||||
|
if len(s.history) < s.order { |
||||||
|
return s.history |
||||||
|
} |
||||||
|
chain := gomarkov.NewChain(s.order) |
||||||
|
|
||||||
|
chain.Add(s.history) |
||||||
|
|
||||||
|
cmdLinesSet := map[string]bool{} |
||||||
|
var entries []strMarkEntry |
||||||
|
for _, cmdLine := range s.history { |
||||||
|
if cmdLinesSet[cmdLine] { |
||||||
|
continue |
||||||
|
} |
||||||
|
cmdLinesSet[cmdLine] = true |
||||||
|
prob, _ := chain.TransitionProbability(cmdLine, s.history[len(s.history)-s.order:]) |
||||||
|
entries = append(entries, strMarkEntry{cmdLine: cmdLine, transProb: prob}) |
||||||
|
} |
||||||
|
sort.Slice(entries, func(i int, j int) bool { return entries[i].transProb > entries[j].transProb }) |
||||||
|
var hist []string |
||||||
|
for _, item := range entries { |
||||||
|
hist = append(hist, item.cmdLine) |
||||||
|
} |
||||||
|
// log.Println("################")
|
||||||
|
// log.Println(s.history[len(s.history)-s.order:])
|
||||||
|
// log.Println(" -> ")
|
||||||
|
// x := math.Min(float64(len(hist)), 5)
|
||||||
|
// log.Println(hist[:int(x)])
|
||||||
|
// log.Println("################")
|
||||||
|
return hist |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChain) AddHistoryRecord(record *common.EnrichedRecord) error { |
||||||
|
s.history = append(s.history, record.CmdLine) |
||||||
|
// s.historySet[record.CmdLine] = true
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyMarkovChain) ResetHistory() error { |
||||||
|
s.init() |
||||||
|
return nil |
||||||
|
} |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"math/rand" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/curusarn/resh/common" |
||||||
|
) |
||||||
|
|
||||||
|
type strategyRandom struct { |
||||||
|
candidatesSize int |
||||||
|
history []string |
||||||
|
historySet map[string]bool |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyRandom) init() { |
||||||
|
s.history = nil |
||||||
|
s.historySet = map[string]bool{} |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyRandom) GetTitleAndDescription() (string, string) { |
||||||
|
return "random", "Use random commands" |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyRandom) GetCandidates() []string { |
||||||
|
seed := time.Now().UnixNano() |
||||||
|
rand.Seed(seed) |
||||||
|
var candidates []string |
||||||
|
candidateSet := map[string]bool{} |
||||||
|
for len(candidates) < s.candidatesSize && len(candidates)*2 < len(s.historySet) { |
||||||
|
x := rand.Intn(len(s.history)) |
||||||
|
candidate := s.history[x] |
||||||
|
if candidateSet[candidate] == false { |
||||||
|
candidateSet[candidate] = true |
||||||
|
candidates = append(candidates, candidate) |
||||||
|
continue |
||||||
|
} |
||||||
|
} |
||||||
|
return candidates |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyRandom) AddHistoryRecord(record *common.EnrichedRecord) error { |
||||||
|
s.history = append([]string{record.CmdLine}, s.history...) |
||||||
|
s.historySet[record.CmdLine] = true |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *strategyRandom) ResetHistory() error { |
||||||
|
s.init() |
||||||
|
return nil |
||||||
|
} |
||||||
Loading…
Reference in new issue