File: | nnc/ccv_nnc_symbolic_graph_chain_decomposition.c |
Warning: | line 81, column 4 Use of memory allocated with size zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include "ccv_nnc.h" | |||
2 | #include "ccv_nnc_easy.h" | |||
3 | #include "ccv_nnc_internal.h" | |||
4 | #include "ccv_internal.h" | |||
5 | #include "_ccv_nnc_symbolic_graph.h" | |||
6 | ||||
7 | // Implement the new method for exec_dep. We use chain decomposition such that each node only needs to log which chain and at which node to be dependent on. | |||
8 | ccv_nnc_exec_dep_t ccv_nnc_exec_dep_new(const ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_graph_visit_t* const visit, const ccv_nnc_graph_visit_t* const reversed_visit) | |||
9 | { | |||
10 | const int exec_symbol_info_size = graph->exec_symbol_info->rnum; | |||
11 | int* chain_ids = ccmallocmalloc(sizeof(int) * exec_symbol_info_size * 2); | |||
12 | int* chain_pos = chain_ids + exec_symbol_info_size; | |||
13 | int* buf = (int*)ccmallocmalloc(sizeof(int) * exec_symbol_info_size); | |||
14 | int* reversed_depth = buf; | |||
15 | const ccv_nnc_graph_exec_symbol_info_t* const exec_symbol_info = (ccv_nnc_graph_exec_symbol_info_t*)ccv_array_get(graph->exec_symbol_info, 0)((void*)(((char*)((graph->exec_symbol_info)->data)) + ( size_t)(graph->exec_symbol_info)->rsize * (size_t)(0))); | |||
16 | int i, j; | |||
17 | // Go reverse order to generate the distance from sink. | |||
18 | ccv_nnc_graph_visit_for(reversed_visit, exec_symbol_info, node, idx, term){ int _i_; for (_i_ = 0; _i_ < (reversed_visit)->size; _i_ ++) { const int idx __attribute__((unused)) = (reversed_visit )->node[_i_].index; const int term __attribute__((unused)) = (reversed_visit)->node[_i_].term; typeof ((exec_symbol_info )) const node __attribute__((unused)) = (exec_symbol_info) + idx ; { | |||
| ||||
19 | chain_ids[idx] = -1; | |||
20 | if (!node->outgoings || node->outgoings->rnum == 0) | |||
21 | { | |||
22 | reversed_depth[idx] = 0; | |||
23 | continue; | |||
24 | } | |||
25 | const int outgoing = *(int*)ccv_array_get(node->outgoings, 0)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(0))); | |||
26 | int depth = reversed_depth[outgoing]; | |||
27 | for (i = 1; i < node->outgoings->rnum; i++) | |||
28 | { | |||
29 | const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(i))); | |||
30 | depth = ccv_max(depth, reversed_depth[outgoing])({ typeof (depth) _a = (depth); typeof (reversed_depth[outgoing ]) _b = (reversed_depth[outgoing]); (_a > _b) ? _a : _b; } ); | |||
31 | } | |||
32 | reversed_depth[idx] = depth + 1; | |||
33 | } ccv_nnc_graph_visit_endfor} } | |||
34 | // Go in order to generate chain ids (if there are multiple exits, we use the reverse depth to break the tie). | |||
35 | // Note that we cannot use depth so-far because then multiple exit nodes are equally good to "inherit" the chain selection. | |||
36 | int chain_count = 0; | |||
37 | ccv_nnc_graph_visit_for(visit, exec_symbol_info, node, idx, term){ int _i_; for (_i_ = 0; _i_ < (visit)->size; _i_++) { const int idx __attribute__((unused)) = (visit)->node[_i_].index ; const int term __attribute__((unused)) = (visit)->node[_i_ ].term; typeof ((exec_symbol_info)) const node __attribute__( (unused)) = (exec_symbol_info) + idx; { | |||
38 | int chain_id = chain_ids[idx]; | |||
39 | if (chain_ids[idx] < 0) | |||
40 | { | |||
41 | chain_id = chain_count; | |||
42 | chain_ids[idx] = chain_id; | |||
43 | chain_pos[idx] = 1; // The first one in this chain. 1-based index because in sparse matrix, 0 is the default value. | |||
44 | chain_count += 1; | |||
45 | } | |||
46 | if (!node->outgoings || node->outgoings->rnum == 0) | |||
47 | continue; | |||
48 | int depth = 0; | |||
49 | int next_idx = -1; | |||
50 | for (i = 0; i < node->outgoings->rnum; i++) | |||
51 | { | |||
52 | const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(i))); | |||
53 | if (chain_ids[outgoing] < 0 && reversed_depth[outgoing] > depth) | |||
54 | depth = reversed_depth[outgoing], next_idx = outgoing; | |||
55 | } | |||
56 | if (next_idx >= 0) | |||
57 | { | |||
58 | chain_ids[next_idx] = chain_id; | |||
59 | chain_pos[next_idx] = chain_pos[idx] + 1; | |||
60 | } | |||
61 | } ccv_nnc_graph_visit_endfor} } | |||
62 | if (exec_symbol_info_size < chain_count * 3) // Be more conservative on RAM usage. | |||
63 | buf = ccreallocrealloc(buf, sizeof(int) * chain_count * 3); | |||
64 | ccv_sparse_matrix_t* deps = ccv_sparse_matrix_new(graph->exec_symbol_info->rnum, chain_count, CCV_32S | CCV_C2, CCV_SPARSE_ROW_MAJOR, 0); | |||
65 | // It logs which pos on that chain we depend on. We can simply compare that with the chain_pos for a node to know if they are ancestors. | |||
66 | #define for_block(x, val) \ | |||
67 | do { \ | |||
68 | if (((int32_t*)val)[0] > 0) \ | |||
69 | { \ | |||
70 | buf[buf_size * 3] = x; \ | |||
71 | buf[buf_size * 3 + 1] = ((int32_t*)val)[0]; \ | |||
72 | buf[buf_size * 3 + 2] = ((int32_t*)val)[1] + 1; \ | |||
73 | ++buf_size; \ | |||
74 | } \ | |||
75 | } while (0) | |||
76 | int buf_size; | |||
77 | ccv_nnc_graph_visit_for(visit, exec_symbol_info, node, idx, term){ int _i_; for (_i_ = 0; _i_ < (visit)->size; _i_++) { const int idx __attribute__((unused)) = (visit)->node[_i_].index ; const int term __attribute__((unused)) = (visit)->node[_i_ ].term; typeof ((exec_symbol_info)) const node __attribute__( (unused)) = (exec_symbol_info) + idx; { | |||
78 | buf_size = 0; /* save all its parent deps to this buffer */ | |||
79 | ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(deps, idx); | |||
80 | if (vector) | |||
81 | CCV_SPARSE_VECTOR_FOREACH(deps, vector, for_block)do { switch ((((deps)->type) & 0xFF000)) { case CCV_32S : { do { int _i_; __attribute__((unused)) const size_t _c_ = ( ((deps)->type) & 0xFFF); if ((deps)->type & CCV_DENSE_VECTOR ) { for (_i_ = 0; _i_ < (vector)->size; _i_++) { for_block ((_i_), ((vector)->data.i32 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof(ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size [(((deps)->type) & 0xFF000) >> 12] * (((deps)-> type) & 0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t *)(vector)->index; for (_i_ = 0; _i_ < (vector)->size ; _i_++) { ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t *)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1) continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_ + 1) }; for_block((_idx_i_->i), (_d_.i32 + (0))); } } } while (0); break; } case CCV_32F: { do { int _i_; __attribute__((unused )) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps )->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < ( vector)->size; _i_++) { for_block((_i_), ((vector)->data .f32 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof (ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps )->type) & 0xFF000) >> 12] * (((deps)->type) & 0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector )->index; for (_i_ = 0; _i_ < (vector)->size; _i_++) { ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t *)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1) continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_ + 1) }; for_block((_idx_i_->i), (_d_.f32 + (0))); } } } while (0); break; } case CCV_64S: { do { int _i_; __attribute__((unused )) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps )->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < ( vector)->size; _i_++) { for_block((_i_), ((vector)->data .i64 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof (ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps )->type) & 0xFF000) >> 12] * (((deps)->type) & 0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector )->index; for (_i_ = 0; _i_ < (vector)->size; _i_++) { ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t *)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1) continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_ + 1) }; for_block((_idx_i_->i), (_d_.i64 + (0))); } } } while (0); break; } case CCV_64F: { do { int _i_; __attribute__((unused )) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps )->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < ( vector)->size; _i_++) { for_block((_i_), ((vector)->data .f64 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof (ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps )->type) & 0xFF000) >> 12] * (((deps)->type) & 0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector )->index; for (_i_ = 0; _i_ < (vector)->size; _i_++) { ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t *)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1) continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_ + 1) }; for_block((_idx_i_->i), (_d_.f64 + (0))); } } } while (0); break; } default: { do { int _i_; __attribute__((unused )) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps )->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < ( vector)->size; _i_++) { for_block((_i_), ((vector)->data .u8 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof (ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps )->type) & 0xFF000) >> 12] * (((deps)->type) & 0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector )->index; for (_i_ = 0; _i_ < (vector)->size; _i_++) { ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t *)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1) continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_ + 1) }; for_block((_idx_i_->i), (_d_.u8 + (0))); } } } while (0); } } } while (0); | |||
| ||||
82 | if (!node->outgoings) | |||
83 | continue; | |||
84 | const int chain_id = chain_ids[idx]; | |||
85 | const int pos = chain_pos[idx]; | |||
86 | for (i = 0; i < node->outgoings->rnum; i++) | |||
87 | { | |||
88 | const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(i))); | |||
89 | const int outgoing_chain_id = chain_ids[outgoing]; | |||
90 | if (outgoing_chain_id != chain_id) | |||
91 | { | |||
92 | ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(deps, outgoing, chain_id); | |||
93 | /* If not found, set, if the current node is the destination node, no need | |||
94 | * set itself as parent of subsequent nodes because its terminal nature. */ | |||
95 | if (!cell.i32 || cell.i32[0] == 0 || cell.i32[0] < pos) | |||
96 | { | |||
97 | int p[2] = { pos, 1 }; | |||
98 | ccv_set_sparse_matrix_cell(deps, outgoing, chain_id, &p); | |||
99 | } | |||
100 | } | |||
101 | if (buf_size > 0) | |||
102 | { | |||
103 | ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(deps, outgoing); | |||
104 | for (j = 0; j < buf_size; j++) /* set with all idx's dependencies as well */ | |||
105 | { | |||
106 | if (outgoing_chain_id == buf[j * 3]) // We don't need to add as dependency for the same chain. | |||
107 | continue; | |||
108 | if (!vector) | |||
109 | { | |||
110 | ccv_set_sparse_matrix_cell(deps, outgoing, buf[j * 3], &buf[j * 3 + 1]); | |||
111 | vector = ccv_get_sparse_matrix_vector(deps, outgoing); | |||
112 | continue; | |||
113 | } | |||
114 | ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3]); | |||
115 | /* If not found, set. Otherwise, set to the latest one only if it is later. */ | |||
116 | if (!cell.i32) | |||
117 | ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &buf[j * 3 + 1]); | |||
118 | else if (cell.i32[0] == 0 || cell.i32[0] < buf[j * 3 + 1]) | |||
119 | ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &buf[j * 3 + 1]); | |||
120 | else if (cell.i32[0] == buf[j * 3 + 1]) { // If we point to the same one, use the longest. | |||
121 | int p[2] = { cell.i32[0], ccv_max(buf[j * 3 + 2], cell.i32[1])({ typeof (buf[j * 3 + 2]) _a = (buf[j * 3 + 2]); typeof (cell .i32[1]) _b = (cell.i32[1]); (_a > _b) ? _a : _b; }) }; | |||
122 | ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &p); | |||
123 | } | |||
124 | } | |||
125 | } | |||
126 | } | |||
127 | } ccv_nnc_graph_visit_endfor} } | |||
128 | #undef for_block | |||
129 | ccfreefree(buf); | |||
130 | ccv_nnc_exec_dep_t exec_dep = { | |||
131 | .chain_ids = chain_ids, | |||
132 | .chain_pos = chain_pos, | |||
133 | .deps = deps | |||
134 | }; | |||
135 | return exec_dep; | |||
136 | } | |||
137 | ||||
138 | int ccv_nnc_exec_dep_hop(const ccv_nnc_exec_dep_t exec_dep, const int d, ccv_sparse_matrix_vector_t* const vector, const int dd) | |||
139 | { | |||
140 | // Check if dd is d's ancestor. | |||
141 | const int dd_chain_id = exec_dep.chain_ids[dd]; | |||
142 | const int dd_chain_pos = exec_dep.chain_pos[dd]; | |||
143 | if (exec_dep.chain_ids[d] == dd_chain_id) | |||
144 | return exec_dep.chain_pos[d] - dd_chain_pos; | |||
145 | const ccv_numeric_data_t cell = vector ? ccv_get_sparse_matrix_cell_from_vector(exec_dep.deps, vector, dd_chain_id) : ccv_get_sparse_matrix_cell(exec_dep.deps, d, dd_chain_id); | |||
146 | if (cell.i32 && cell.i32[0] > 0 && cell.i32[0] >= dd_chain_pos) | |||
147 | { | |||
148 | // Check if the chain pos is greater than or equal to dd_chain_pos. If it is, it is an ancestor. | |||
149 | return cell.i32[0] - dd_chain_pos + cell.i32[1]; | |||
150 | } | |||
151 | return -1; | |||
152 | } | |||
153 | ||||
154 | int ccv_nnc_exec_dep_check(const ccv_nnc_exec_dep_t exec_dep, const int d, const int dd) | |||
155 | { | |||
156 | // Check if dd is d's ancestor. | |||
157 | const int dd_chain_id = exec_dep.chain_ids[dd]; | |||
158 | const int dd_chain_pos = exec_dep.chain_pos[dd]; | |||
159 | if (exec_dep.chain_ids[d] == dd_chain_id) | |||
160 | return exec_dep.chain_pos[d] > dd_chain_pos; | |||
161 | const ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(exec_dep.deps, d, dd_chain_id); | |||
162 | if (cell.i32 && cell.i32[0] > 0) | |||
163 | { | |||
164 | // Check if the chain pos is greater than or equal to dd_chain_pos. If it is, it is an ancestor. | |||
165 | return cell.i32[0] >= dd_chain_pos; | |||
166 | } | |||
167 | return 0; | |||
168 | } | |||
169 | ||||
170 | void ccv_nnc_exec_dep_free(const ccv_nnc_exec_dep_t exec_dep) | |||
171 | { | |||
172 | ccfreefree(exec_dep.chain_ids); | |||
173 | ccv_matrix_free(exec_dep.deps); | |||
174 | } |