| File: | nnc/ccv_nnc_symbolic_graph_chain_decomposition.c |
| Warning: | line 88, 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) | |||
| 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_ = (visit)->size - 1; _i_ >= 0; _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; { | |||
| ||||
| 19 | if (node->flags & CCV_NNC_GRAPH_EXEC_DEAD) | |||
| 20 | continue; | |||
| 21 | chain_ids[idx] = -1; | |||
| 22 | if (!node->outgoings || node->outgoings->rnum == 0) | |||
| 23 | { | |||
| 24 | reversed_depth[idx] = 0; | |||
| 25 | continue; | |||
| 26 | } | |||
| 27 | const int outgoing = *(int*)ccv_array_get(node->outgoings, 0)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(0))); | |||
| 28 | int depth = reversed_depth[outgoing]; | |||
| 29 | for (i = 1; i < node->outgoings->rnum; i++) | |||
| 30 | { | |||
| 31 | const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(i))); | |||
| 32 | depth = ccv_max(depth, reversed_depth[outgoing])({ typeof (depth) _a = (depth); typeof (reversed_depth[outgoing ]) _b = (reversed_depth[outgoing]); (_a > _b) ? _a : _b; } ); | |||
| 33 | } | |||
| 34 | reversed_depth[idx] = depth + 1; | |||
| 35 | } ccv_nnc_graph_visit_endfor} } | |||
| 36 | // Go in order to generate chain ids (if there are multiple exits, we use the reverse depth to break the tie). | |||
| 37 | // Note that we cannot use depth so-far because then multiple exit nodes are equally good to "inherit" the chain selection. | |||
| 38 | int chain_count = 0; | |||
| 39 | 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; { | |||
| 40 | if (node->flags & CCV_NNC_GRAPH_EXEC_DEAD) | |||
| 41 | continue; | |||
| 42 | int chain_id = chain_ids[idx]; | |||
| 43 | if (chain_ids[idx] < 0) | |||
| 44 | { | |||
| 45 | chain_id = chain_count; | |||
| 46 | chain_ids[idx] = chain_id; | |||
| 47 | chain_pos[idx] = 1; // The first one in this chain. 1-based index because in sparse matrix, 0 is the default value. | |||
| 48 | chain_count += 1; | |||
| 49 | } | |||
| 50 | if (!node->outgoings || node->outgoings->rnum == 0) | |||
| 51 | continue; | |||
| 52 | int depth = -1; | |||
| 53 | int next_idx = -1; | |||
| 54 | for (i = 0; i < node->outgoings->rnum; i++) | |||
| 55 | { | |||
| 56 | const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(i))); | |||
| 57 | if (chain_ids[outgoing] < 0 && reversed_depth[outgoing] > depth) | |||
| 58 | depth = reversed_depth[outgoing], next_idx = outgoing; | |||
| 59 | } | |||
| 60 | if (next_idx >= 0) | |||
| 61 | { | |||
| 62 | chain_ids[next_idx] = chain_id; | |||
| 63 | assert(reversed_depth[idx] - depth >= 1)((void) sizeof ((reversed_depth[idx] - depth >= 1) ? 1 : 0 ), __extension__ ({ if (reversed_depth[idx] - depth >= 1) ; else __assert_fail ("reversed_depth[idx] - depth >= 1", "ccv_nnc_symbolic_graph_chain_decomposition.c" , 63, __extension__ __PRETTY_FUNCTION__); })); | |||
| 64 | chain_pos[next_idx] = chain_pos[idx] + (reversed_depth[idx] - depth); | |||
| 65 | } | |||
| 66 | } ccv_nnc_graph_visit_endfor} } | |||
| 67 | if (exec_symbol_info_size < chain_count * 3) // Be more conservative on RAM usage. | |||
| 68 | buf = ccreallocrealloc(buf, sizeof(int) * chain_count * 3); | |||
| 69 | 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); | |||
| 70 | // 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. | |||
| 71 | #define for_block(x, val) \ | |||
| 72 | do { \ | |||
| 73 | if (((int32_t*)val)[0] > 0) \ | |||
| 74 | { \ | |||
| 75 | buf[buf_size * 3] = x; \ | |||
| 76 | buf[buf_size * 3 + 1] = ((int32_t*)val)[0]; \ | |||
| 77 | buf[buf_size * 3 + 2] = ((int32_t*)val)[1] + 1; \ | |||
| 78 | ++buf_size; \ | |||
| 79 | } \ | |||
| 80 | } while (0) | |||
| 81 | int buf_size; | |||
| 82 | 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; { | |||
| 83 | if (node->flags & CCV_NNC_GRAPH_EXEC_DEAD) | |||
| 84 | continue; | |||
| 85 | buf_size = 0; /* save all its parent deps to this buffer */ | |||
| 86 | ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(deps, idx); | |||
| 87 | if (vector) | |||
| 88 | 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); | |||
| ||||
| 89 | if (!node->outgoings) | |||
| 90 | continue; | |||
| 91 | const int chain_id = chain_ids[idx]; | |||
| 92 | const int pos = chain_pos[idx]; | |||
| 93 | for (i = 0; i < node->outgoings->rnum; i++) | |||
| 94 | { | |||
| 95 | const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)( node->outgoings)->rsize * (size_t)(i))); | |||
| 96 | const int outgoing_chain_id = chain_ids[outgoing]; | |||
| 97 | if (outgoing_chain_id != chain_id) | |||
| 98 | { | |||
| 99 | ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(deps, outgoing, chain_id); | |||
| 100 | /* If not found, set, if the current node is the destination node, no need | |||
| 101 | * set itself as parent of subsequent nodes because its terminal nature. */ | |||
| 102 | if (!cell.i32 || cell.i32[0] == 0 || cell.i32[0] < pos) | |||
| 103 | { | |||
| 104 | int p[2] = { pos, 1 }; | |||
| 105 | ccv_set_sparse_matrix_cell(deps, outgoing, chain_id, &p); | |||
| 106 | } | |||
| 107 | } | |||
| 108 | if (buf_size > 0) | |||
| 109 | { | |||
| 110 | ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(deps, outgoing); | |||
| 111 | for (j = 0; j < buf_size; j++) /* set with all idx's dependencies as well */ | |||
| 112 | { | |||
| 113 | if (outgoing_chain_id == buf[j * 3]) // We don't need to add as dependency for the same chain. | |||
| 114 | continue; | |||
| 115 | if (!vector) | |||
| 116 | { | |||
| 117 | ccv_set_sparse_matrix_cell(deps, outgoing, buf[j * 3], &buf[j * 3 + 1]); | |||
| 118 | vector = ccv_get_sparse_matrix_vector(deps, outgoing); | |||
| 119 | continue; | |||
| 120 | } | |||
| 121 | ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3]); | |||
| 122 | /* If not found, set. Otherwise, set to the latest one only if it is later. */ | |||
| 123 | if (!cell.i32) | |||
| 124 | ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &buf[j * 3 + 1]); | |||
| 125 | else if (cell.i32[0] == 0 || cell.i32[0] < buf[j * 3 + 1]) | |||
| 126 | ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &buf[j * 3 + 1]); | |||
| 127 | else if (cell.i32[0] == buf[j * 3 + 1]) { // If we point to the same one, use the longest. | |||
| 128 | 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; }) }; | |||
| 129 | ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &p); | |||
| 130 | } | |||
| 131 | } | |||
| 132 | } | |||
| 133 | } | |||
| 134 | } ccv_nnc_graph_visit_endfor} } | |||
| 135 | #undef for_block | |||
| 136 | ccfreefree(buf); | |||
| 137 | ccv_nnc_exec_dep_t exec_dep = { | |||
| 138 | .chain_ids = chain_ids, | |||
| 139 | .chain_pos = chain_pos, | |||
| 140 | .deps = deps | |||
| 141 | }; | |||
| 142 | return exec_dep; | |||
| 143 | } | |||
| 144 | ||||
| 145 | void ccv_nnc_exec_dep_free(const ccv_nnc_exec_dep_t exec_dep) | |||
| 146 | { | |||
| 147 | ccfreefree(exec_dep.chain_ids); | |||
| 148 | ccv_matrix_free(exec_dep.deps); | |||
| 149 | } |