midas-edge 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/NOTICE.txt +1 -1
- data/README.md +1 -1
- data/ext/midas/ext.cpp +80 -74
- data/lib/midas/detector.rb +30 -2
- data/lib/midas/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0d21103c3d31faae0c5a22a3909c2594b9d406ca6d971927b59955821517b477
|
|
4
|
+
data.tar.gz: 07450a43b2ad27bda97545b813cc0766c55802e2ef565d1387de0a5f7307c04c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0db11f6d7de5d528d81b180b5e759ec36e794ebce62ddcf748c2db9f502ac0c4b6f95673b197f30c48564baeb36a6089b4f3ef599249070088a4057f03b57b51
|
|
7
|
+
data.tar.gz: a7a886546d177686b173e8fe2b70af54c67ce265095304190442d5bb740386082f673c58d43a1416540d5c8e2fb31440b863fe9447be621e73e727debd2dd22d
|
data/CHANGELOG.md
CHANGED
data/NOTICE.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Copyright 2020 Rui Liu (liurui39660) and Siddharth Bhatia (bhatiasiddharth)
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Andrew Kane
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
data/README.md
CHANGED
|
@@ -32,7 +32,7 @@ midas = Midas.new
|
|
|
32
32
|
scores = midas.fit_predict(data)
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Higher scores are more anomalous. There is [not currently](https://github.com/
|
|
35
|
+
Higher scores are more anomalous. There is [not currently](https://github.com/Stream-AD/MIDAS/issues/4) a defined threshold for anomalies.
|
|
36
36
|
|
|
37
37
|
## Parameters
|
|
38
38
|
|
data/ext/midas/ext.cpp
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// stdlib
|
|
2
|
+
#include <cstdio>
|
|
2
3
|
#include <iostream>
|
|
3
4
|
#include <vector>
|
|
4
5
|
|
|
@@ -14,39 +15,42 @@
|
|
|
14
15
|
// numo
|
|
15
16
|
#include "numo.hpp"
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
template<typename T>
|
|
19
|
+
void load_array(T& midas, Rice::Array input, bool directed, std::vector<float>& result) {
|
|
20
|
+
for (auto r : input) {
|
|
21
|
+
Rice::Array row(r);
|
|
22
|
+
if (row.size() != 3) {
|
|
23
|
+
throw Rice::Exception(rb_eArgError, "Bad shape");
|
|
24
|
+
}
|
|
25
|
+
int s = Rice::detail::From_Ruby<int>().convert(row[0].value());
|
|
26
|
+
int d = Rice::detail::From_Ruby<int>().convert(row[1].value());
|
|
27
|
+
int t = Rice::detail::From_Ruby<int>().convert(row[2].value());
|
|
28
|
+
result.push_back(midas(s, d, t));
|
|
29
|
+
if (!directed) {
|
|
30
|
+
result.push_back(midas(d, s, t));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
template<typename T>
|
|
36
|
+
void load_numo_array(T& midas, numo::Int32 input, bool directed, std::vector<float>& result) {
|
|
18
37
|
auto shape = input.shape();
|
|
38
|
+
if (input.ndim() == 1 && shape[0] == 0) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
19
41
|
if (input.ndim() != 2 || shape[1] != 3) {
|
|
20
42
|
throw Rice::Exception(rb_eArgError, "Bad shape");
|
|
21
43
|
}
|
|
22
44
|
|
|
23
|
-
auto input_ptr = input.read_ptr();
|
|
24
|
-
auto n = shape[0];
|
|
25
45
|
auto sz = input.size();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
dst.push_back(input_ptr[i + 1]);
|
|
35
|
-
times.push_back(input_ptr[i + 2]);
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
src.reserve(n * 2);
|
|
39
|
-
dst.reserve(n * 2);
|
|
40
|
-
times.reserve(n * 2);
|
|
41
|
-
|
|
42
|
-
for (size_t i = 0; i < sz; i += 3) {
|
|
43
|
-
src.push_back(input_ptr[i]);
|
|
44
|
-
dst.push_back(input_ptr[i + 1]);
|
|
45
|
-
times.push_back(input_ptr[i + 2]);
|
|
46
|
-
|
|
47
|
-
src.push_back(input_ptr[i + 1]);
|
|
48
|
-
dst.push_back(input_ptr[i]);
|
|
49
|
-
times.push_back(input_ptr[i + 2]);
|
|
46
|
+
auto input_ptr = input.read_ptr();
|
|
47
|
+
for (size_t i = 0; i < sz; i += 3) {
|
|
48
|
+
int s = input_ptr[i];
|
|
49
|
+
int d = input_ptr[i + 1];
|
|
50
|
+
int t = input_ptr[i + 2];
|
|
51
|
+
result.push_back(midas(s, d, t));
|
|
52
|
+
if (!directed) {
|
|
53
|
+
result.push_back(midas(d, s, t));
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
}
|
|
@@ -54,59 +58,42 @@ void load_array(std::vector<int>& src, std::vector<int>& dst, std::vector<int>&
|
|
|
54
58
|
// load_data from main.cpp
|
|
55
59
|
// modified to throw std::runtime_error when cannot find file
|
|
56
60
|
// instead of exiting
|
|
57
|
-
|
|
61
|
+
template<typename T>
|
|
62
|
+
void load_file(T& midas, Rice::String input_file, bool directed, std::vector<float>& result) {
|
|
58
63
|
FILE* infile = fopen(input_file.c_str(), "r");
|
|
59
64
|
if (infile == NULL) {
|
|
60
65
|
throw std::runtime_error("Could not read file: " + input_file.str());
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
int s, d, t;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
dst.push_back(d);
|
|
69
|
-
times.push_back(t);
|
|
70
|
-
}
|
|
71
|
-
} else {
|
|
72
|
-
while (fscanf(infile, "%d,%d,%d", &s, &d, &t) == 3) {
|
|
73
|
-
src.push_back(s);
|
|
74
|
-
dst.push_back(d);
|
|
75
|
-
times.push_back(t);
|
|
76
|
-
|
|
77
|
-
src.push_back(d);
|
|
78
|
-
dst.push_back(s);
|
|
79
|
-
times.push_back(t);
|
|
69
|
+
while (fscanf(infile, "%d,%d,%d", &s, &d, &t) == 3) {
|
|
70
|
+
result.push_back(midas(s, d, t));
|
|
71
|
+
if (!directed) {
|
|
72
|
+
result.push_back(midas(d, s, t));
|
|
80
73
|
}
|
|
81
74
|
}
|
|
82
75
|
|
|
83
76
|
fclose(infile);
|
|
84
77
|
}
|
|
85
78
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
MIDAS::FilteringCore midas(num_rows, num_buckets, threshold, factor);
|
|
95
|
-
for (size_t i = 0; i < n; i++) {
|
|
96
|
-
result[i] = midas(src[i], dst[i], times[i]);
|
|
97
|
-
}
|
|
98
|
-
} else if (relations) {
|
|
99
|
-
MIDAS::RelationalCore midas(num_rows, num_buckets, factor);
|
|
100
|
-
for (size_t i = 0; i < n; i++) {
|
|
101
|
-
result[i] = midas(src[i], dst[i], times[i]);
|
|
102
|
-
}
|
|
79
|
+
template<typename T>
|
|
80
|
+
Rice::Object fit_predict(T& midas, Rice::Object input, bool directed) {
|
|
81
|
+
std::vector<float> result;
|
|
82
|
+
if (input.is_a(rb_cString)) {
|
|
83
|
+
load_file(midas, input, directed, result);
|
|
84
|
+
// TODO uncomment in 0.6.0
|
|
85
|
+
// } else if (input.is_instance_of(rb_cArray)) {
|
|
86
|
+
// load_array(midas, input, directed, result);
|
|
103
87
|
} else {
|
|
104
|
-
|
|
105
|
-
for (size_t i = 0; i < n; i++) {
|
|
106
|
-
result[i] = midas(src[i], dst[i], times[i]);
|
|
107
|
-
}
|
|
88
|
+
load_numo_array(midas, input, directed, result);
|
|
108
89
|
}
|
|
109
90
|
|
|
91
|
+
size_t n = result.size();
|
|
92
|
+
auto ary = numo::SFloat({n});
|
|
93
|
+
auto out = ary.write_ptr();
|
|
94
|
+
for (size_t i = 0; i < n; i++) {
|
|
95
|
+
out[i] = result[i];
|
|
96
|
+
}
|
|
110
97
|
return ary;
|
|
111
98
|
}
|
|
112
99
|
|
|
@@ -114,16 +101,35 @@ extern "C"
|
|
|
114
101
|
void Init_ext() {
|
|
115
102
|
auto rb_mMidas = Rice::define_module("Midas");
|
|
116
103
|
|
|
104
|
+
// TODO make seed part of Core classes
|
|
117
105
|
Rice::define_class_under(rb_mMidas, "Detector")
|
|
118
106
|
.define_function(
|
|
119
|
-
"
|
|
120
|
-
[](
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
107
|
+
"_set_seed",
|
|
108
|
+
[](int seed) {
|
|
109
|
+
srand(seed);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
Rice::define_class_under<MIDAS::NormalCore>(rb_mMidas, "NormalCore")
|
|
113
|
+
.define_constructor(Rice::Constructor<MIDAS::NormalCore, int, int>())
|
|
114
|
+
.define_method(
|
|
115
|
+
"fit_predict",
|
|
116
|
+
[](MIDAS::NormalCore& self, Rice::Object input, bool directed) {
|
|
117
|
+
return fit_predict(self, input, directed);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
Rice::define_class_under<MIDAS::RelationalCore>(rb_mMidas, "RelationalCore")
|
|
121
|
+
.define_constructor(Rice::Constructor<MIDAS::RelationalCore, int, int, float>())
|
|
122
|
+
.define_method(
|
|
123
|
+
"fit_predict",
|
|
124
|
+
[](MIDAS::RelationalCore& self, Rice::Object input, bool directed) {
|
|
125
|
+
return fit_predict(self, input, directed);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
Rice::define_class_under<MIDAS::FilteringCore>(rb_mMidas, "FilteringCore")
|
|
129
|
+
.define_constructor(Rice::Constructor<MIDAS::FilteringCore, int, int, float, float>())
|
|
130
|
+
.define_method(
|
|
131
|
+
"fit_predict",
|
|
132
|
+
[](MIDAS::FilteringCore& self, Rice::Object input, bool directed) {
|
|
133
|
+
return fit_predict(self, input, directed);
|
|
128
134
|
});
|
|
129
135
|
}
|
data/lib/midas/detector.rb
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
module Midas
|
|
2
2
|
class Detector
|
|
3
|
-
def initialize(
|
|
3
|
+
def initialize(
|
|
4
|
+
rows: 2,
|
|
5
|
+
buckets: 769,
|
|
6
|
+
alpha: 0.5,
|
|
7
|
+
threshold: nil,
|
|
8
|
+
relations: true,
|
|
9
|
+
directed: true,
|
|
10
|
+
seed: 0
|
|
11
|
+
)
|
|
4
12
|
@rows = rows
|
|
5
13
|
@buckets = buckets
|
|
6
14
|
@alpha = alpha
|
|
@@ -11,7 +19,27 @@ module Midas
|
|
|
11
19
|
end
|
|
12
20
|
|
|
13
21
|
def fit_predict(x)
|
|
14
|
-
|
|
22
|
+
@core = nil # reset core
|
|
23
|
+
partial_fit_predict(x)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# TODO better name
|
|
27
|
+
def partial_fit_predict(x)
|
|
28
|
+
@core ||= core
|
|
29
|
+
@core.fit_predict(x, @directed)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def core
|
|
35
|
+
_set_seed(@seed)
|
|
36
|
+
if @threshold && !@threshold.to_f.nan?
|
|
37
|
+
FilteringCore.new(@rows, @buckets, @threshold, @alpha)
|
|
38
|
+
elsif @relations
|
|
39
|
+
RelationalCore.new(@rows, @buckets, @alpha)
|
|
40
|
+
else
|
|
41
|
+
NormalCore.new(@rows, @buckets)
|
|
42
|
+
end
|
|
15
43
|
end
|
|
16
44
|
end
|
|
17
45
|
end
|
data/lib/midas/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: midas-edge
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Kane
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rice
|
|
@@ -77,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
77
77
|
- !ruby/object:Gem::Version
|
|
78
78
|
version: '0'
|
|
79
79
|
requirements: []
|
|
80
|
-
rubygems_version:
|
|
80
|
+
rubygems_version: 4.0.3
|
|
81
81
|
specification_version: 4
|
|
82
82
|
summary: Edge stream anomaly detection for Ruby
|
|
83
83
|
test_files: []
|