| 158 | } |
| 159 | |
| 160 | std::string Subgraph::repr() const { |
| 161 | std::ostringstream buf; |
| 162 | buf << "("; |
| 163 | for (size_t i = 0; i < inputs.size(); ++i) { |
| 164 | if (i > 0) |
| 165 | buf << ", "; |
| 166 | buf << "%" << inputs[i]; |
| 167 | } |
| 168 | buf << ") => {\n"; |
| 169 | auto fmt_const = [](size_t i, const TensorPtr& t) { |
| 170 | if (t->shape().ndim == 1 && t->shape()[0] == 1) { |
| 171 | auto&& v = t->get_value(); |
| 172 | if (v.dtype() == dtype::Float32{}) { |
| 173 | return std::to_string(*v.ptr<dt_float32>()); |
| 174 | } else if (v.dtype() == dtype::Int32{}) { |
| 175 | return std::to_string(*v.ptr<int32_t>()); |
| 176 | } |
| 177 | } |
| 178 | return std::string("%c") + std::to_string(i); |
| 179 | }; |
| 180 | std::unordered_map<size_t, std::string> const_reps; |
| 181 | for (auto&& [i, t] : constants) { |
| 182 | const_reps.emplace(i, fmt_const(i, t)); |
| 183 | } |
| 184 | for (auto& [op, ins, outs] : exprs) { |
| 185 | buf << " "; |
| 186 | if (outs.size()) { |
| 187 | for (size_t i = 0; i < outs.size(); ++i) { |
| 188 | if (i > 0) |
| 189 | buf << ", "; |
| 190 | buf << "%" << outs[i]; |
| 191 | } |
| 192 | buf << " = "; |
| 193 | } |
| 194 | if (auto* p = op->try_cast_final<OprAttr>()) { |
| 195 | buf << p->type; |
| 196 | } else { |
| 197 | buf << op->to_string(); |
| 198 | } |
| 199 | for (size_t i : ins) { |
| 200 | buf << " "; |
| 201 | auto&& it = const_reps.find(i); |
| 202 | if (it != const_reps.end()) { |
| 203 | buf << it->second; |
| 204 | } else { |
| 205 | buf << "%" << i; |
| 206 | } |
| 207 | } |
| 208 | buf << "\n"; |
| 209 | } |
| 210 | buf << " "; |
| 211 | if (outputs.size()) { |
| 212 | for (size_t i = 0; i < outputs.size(); ++i) { |
| 213 | if (i > 0) |
| 214 | buf << ", "; |
| 215 | buf << "%" << outputs[i]; |
| 216 | } |
| 217 | } else { |