-
Notifications
You must be signed in to change notification settings - Fork 0
/
knnp.c
228 lines (151 loc) · 4.33 KB
/
knnp.c
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>
// tamanho do vetor rotulado
int N;
// tamanho do vetor a ser predito
int M;
// quantidade de dimensões
int DIM;
// quantidade de vizinhos a serem considerados
int K;
// quantidade de rotulos diferentes (na realidade o número do maior rotulo +1)
int NS;
#define INF (1e7)
#define TNUM (4)
// matriz NxDIM com os dados rotulados
double *data;
// vetor de tamanho N com os rótulos de cada linha da tabela
int *rotulos_data;
// matriz MxDIM com os dados que devem ser preditos
double *test;
// rotulos da matriz test geradas pelo scikit-learn (para conferir o resultado)
int *rotulos_test;
// rotulos da matriz test que devem ser preenchidos na sua implementação
// da função Calc_DisS
int *rotulos_tests;
// rotulos da matriz test que devem ser preenchidos na sua implementação
// da função Calc_DisP
int *rotulos_testp;
void le_arquivo(char *name, char *predict) {
FILE *f;
int *p;
char buffer[50];
p = (int*)buffer;
f = fopen(name, "rb");
fread(buffer, 4, 4, f);
N = p[0];
M = p[1];
DIM = p[2];
NS = p[3];
data = aligned_alloc(64, N*DIM*sizeof(double));
test = aligned_alloc(64, M*DIM*sizeof(double));
rotulos_data = aligned_alloc(64, N*sizeof(int));
rotulos_test = aligned_alloc(64, M*sizeof(int));
rotulos_tests = aligned_alloc(64, M*sizeof(int));
rotulos_testp = aligned_alloc(64, M*sizeof(int));
if (!data || !test || !rotulos_data || !rotulos_test ||
!rotulos_tests || !rotulos_testp) {
perror("não alocou as estruturas\n");
exit(1);
}
fread(data, N*DIM, sizeof(double), f);
//printf("%lf %lf %lf %lf\n", data[0], data[1], data[2], data[3]);
fread(rotulos_data, N, sizeof(int), f);
//printf("%d %d %d %d\n", rotulos_data[0], rotulos_data[1],
// rotulos_data[2], rotulos_data[3]);
fread(test, M*DIM, sizeof(double), f);
//printf("%lf %lf %lf %lf\n", test[0], test[1], test[2], test[3]);
fclose(f);
f = fopen(predict, "rb");
fread(buffer, 4, 1, f);
if (p[0] != M) {
perror("os arquivos tem vetores de tamanhos diferentes");
exit(2);
}
fread(rotulos_test, M, sizeof(int), f);
fclose(f);
}
void Calc_DisP() {
int i, j, k, aux;
// percorre os valores do test
#pragma omp parallel for private(j,k,aux) num_threads(TNUM)
for(i = 0; i < M; i++){
double dist, aux2;
// lista dos k vizinhos mais proximos
int viz[K+1];
// distancias para os respectivos vizinhos do vetor acima
double distancias[K+1];
// quantidade de vizinhos já descoberto
// para quando i ainda é menor k
int quant = 0;
int votos[NS];
for(j = 0; j < K+1; j++) {
distancias[j] = INF;
}
// percorre os valores base para comparação (data)
for(j = 0; j < N; j++){
dist = 0;
for(k = 0; k < DIM; k++){
aux2 = data[j*DIM+k] - test[i*DIM+k];
dist += aux2 * aux2;
}
// atualiza o vetor dos K mais próximos
if(quant == 0) {
viz[0] = j; // j == 0
distancias[0] = dist;
quant = 1;
} else {
// o vetor de vizinhos é mantido ordenado
// arrasta os valores pro lado pra abrir o espaço do novo
for(k = quant-1; k >= 0 && dist < distancias[k]; k--) {
distancias[k] = distancias[k-1];
viz[k] = viz[k-1];
}
distancias[k+1] = dist;
viz[k+1] = j;
if(quant < K) quant++;
}
}
// votação dos rótulos de vizinhos
memset(votos, 0, sizeof(votos));
for(j = 0; j < K; j++) {
votos[rotulos_data[viz[j]]]++;
}
aux = 0;
for(j = 1; j < NS; j++){
if(votos[j] > votos[aux]){
aux = j;
}
}
rotulos_testp[i] = aux;
}
}
int main(int argc, char **argv) {
int i, missmatches = 0;
if(argc != 4){
perror("exemplo de entrada: ./knn data.knn 5 data-k5.knn");
exit(4);
}
le_arquivo(argv[1], argv[3]);
K = atoi(argv[2]);
start = omp_get_wtime(); //Calcula o tempo
Calc_DisP();
end = omp_get_wtime(); //Calcula o tempo
printf("paralelo: %f\n", end-start);
for (i = 0; i < M; i++) {
if (rotulos_test[i] != rotulos_testp[i] || rotulos_testp[i] != rotulos_tests[i]) {
missmatches++;
printf("%d: %d %d\n", i, rotulos_testp[i], rotulos_test[i]);
}
}
printf("%d of %d missmatches\n", missmatches, M);
free(data);
free(test);
free(rotulos_data);
free(rotulos_test);
free(rotulos_tests);
free(rotulos_testp);
return 0;
}