25 #include "graph_builder_internal.hpp"
26 #include "onnx_function_impl.hpp"
35 stream <<
io <<
" " <<
name <<
": " <<
dtype <<
"[";
36 for (
size_t k = 0; k <
dimension.size(); ++k) {
43 if (
baked) stream <<
" (baked)";
54 auto dot =
path.find_last_of(
'.');
55 std::string suffix =
dot == std::string::npos ?
"" :
path.substr(
dot + 1);
56 if (suffix ==
"onnx")
return "onnx";
57 casadi_error(
"GraphBuilder: cannot infer format from '" +
path +
"'");
66 std::ifstream file(model_path, std::ios::binary | std::ios::ate);
67 casadi_assert(file.is_open(),
"Cannot open model file: " + model_path);
68 std::streamsize size = file.tellg();
69 file.seekg(0, std::ios::beg);
70 std::vector<uint8_t> data(
static_cast<size_t>(size));
71 casadi_assert(file.read(
reinterpret_cast<char*
>(data.data()), size),
72 "Cannot read model file: " + model_path);
81 const std::string& format,
const Dict& opts) {
96 static std::string
null =
"null";
97 return is_null() ? null : (*this)->name_;
105 return (*this)->node(
name).dimension;
108 return (*this)->node(
name).dtype;
111 return (*this)->node(
name).dim_params;
114 return (*this)->dynamic_params();
118 (*this)->bind_dim(param, value);
121 const std::vector<casadi_int>& shape) {
122 (*this)->bind_shape(input_name, shape);
125 (*this)->set_value(input_name, value);
128 (*this)->set_value(input_name, std::vector<double>(1, value));
132 const std::vector<std::string>& name_in,
133 const std::vector<std::string>& name_out,
134 const Dict& opts)
const {
138 return (*this)->create_function(
name, {}, {}, opts);
141 (*this)->export_onnx(
filename, opts);
147 const std::vector<uint8_t>& model_data,
148 const std::string& format,
const Dict& opts)
149 : name_(name), format_(format), model_data_(model_data) {
156 : name_(name), format_(
"onnx"), fun_(f) {
157 populate_from_function();
163 void GraphBuilderInternal::populate_from_function() {
165 for (casadi_int i = 0; i <
fun_.
n_in(); ++i) {
173 for (casadi_int i = 0; i <
fun_.
n_out(); ++i) {
178 n.dim_params = {
"",
""};
184 if (n.
io ==
"input") {
188 std::vector<casadi_int> shape;
189 for (
size_t k = 0; k < n.
dimension.size(); ++k) {
201 for (
const Node& n :
nodes_)
if (n.io == io && n.name == name)
return n;
202 casadi_error(
"Graph tensor '" + name +
"' (" + io +
") not found in model '" +
name_ +
"'");
207 for (
const Node& n :
nodes_)
if (n.io ==
"input") ++c;
212 for (
const Node& n :
nodes_)
if (n.io ==
"output") ++c;
216 std::vector<std::string> r;
217 for (
const Node& n :
nodes_)
if (n.io ==
"input") r.push_back(n.name);
221 std::vector<std::string> r;
222 for (
const Node& n :
nodes_)
if (n.io ==
"output") r.push_back(n.name);
233 std::vector<std::string> r;
235 for (
size_t k = 0; k < n.dimension.size(); ++k) {
236 if (n.dimension[k] < 0 && !n.dim_params[k].empty() &&
237 std::find(r.begin(), r.end(), n.dim_params[k]) == r.end()) {
238 r.push_back(n.dim_params[k]);
246 for (
const Node& n :
nodes_)
if (n.name == name)
return n;
247 casadi_error(
"Graph tensor '" + name +
"' not found in model '" +
name_ +
"'");
251 const std::vector<double>& value) {
252 find(input_name,
"input");
254 for (
Node& n :
nodes_)
if (n.io ==
"input" && n.name == input_name) {
261 const std::vector<casadi_int>& shape) {
262 const Node& t =
find(input_name,
"input");
263 casadi_assert(shape.size() == t.
dimension.size(),
264 "bind_shape: rank mismatch for '" + input_name +
"'");
267 for (
size_t k = 0; k < t.
dimension.size(); ++k) {
273 const std::vector<std::string>& inputs,
274 const std::vector<std::string>& outputs,
275 const Dict& opts)
const {
276 bool symbolic =
false;
277 std::string backend =
"ort";
279 for (
auto&& op : opts) {
280 if (op.first ==
"symbolic") symbolic = op.second;
281 else if (op.first ==
"backend") backend = op.second.to_string();
283 o[op.first] = op.second;
288 "GraphBuilder: symbolic create requires a parsed model (build from a file)");
293 casadi_assert(!
model_data_.empty(),
"GraphBuilder: numeric create requires model bytes");
298 std::vector<uint8_t> bytes;
303 casadi_assert(!
model_data_.empty(),
"GraphBuilder: nothing to export");
306 std::ofstream out(
filename, std::ios::binary);
307 casadi_assert(out.good(),
"Cannot open output file: " +
filename);
308 out.write(
reinterpret_cast<const char*
>(bytes.data()), bytes.size());
312 stream <<
"GraphBuilder '" <<
name_ <<
"': " <<
n_in() <<
" input(s), "
313 <<
n_out() <<
" output(s)";
315 stream <<
"\nInputs:";
316 for (
const Node& n :
nodes_)
if (n.io ==
"input") stream <<
"\n " << n.get_str();
317 stream <<
"\nOutputs:";
318 for (
const Node& n :
nodes_)
if (n.io ==
"output") stream <<
"\n " << n.get_str();
321 stream <<
"\nDynamic dimensions:";
322 for (
const std::string& p : dp) stream <<
" " << p;
casadi_int size2_out(casadi_int ind) const
Get output dimension.
casadi_int size1_in(casadi_int ind) const
Get input dimension.
const std::vector< std::string > & name_in() const
Get input scheme.
const std::string & name() const
Name of the function.
casadi_int n_out() const
Get the number of function outputs.
casadi_int n_in() const
Get the number of function inputs.
casadi_int size1_out(casadi_int ind) const
Get output dimension.
casadi_int size2_in(casadi_int ind) const
Get input dimension.
const std::vector< std::string > & name_out() const
Get output scheme.
SharedObjectInternal * get() const
Get a const pointer to the node.
bool is_null() const
Is a null pointer?
void own(SharedObjectInternal *node)
SharedObjectInternal * operator->() const
Access a member function or object.
Internal class for GraphBuilder.
void export_onnx(const std::string &filename, const Dict &opts)
void bind_shape(const std::string &input_name, const std::vector< casadi_int > &shape)
~GraphBuilderInternal() override
std::map< std::string, std::vector< double > > input_values_
std::vector< Node > nodes_
Tensor metadata (inputs followed by outputs)
Function fun_
Source Function (export lifecycle); null when built from a model.
const Node & find(const std::string &name, const std::string &io) const
Locate a node by name in a given I/O role (throws if absent)
Node node(const std::string &name) const
std::vector< casadi_int > resolved_shape(const Node &n) const
std::vector< std::string > name_out() const
void set_value(const std::string &input_name, const std::vector< double > &value)
std::map< std::string, casadi_int > dim_bindings_
Pending configuration carried into create()
std::map< std::string, std::vector< casadi_int > > input_shapes_
GraphModel model_
Parsed model backend (import lifecycle); null when built from a Function.
GraphBuilderInternal(const std::string &name, const std::vector< uint8_t > &model_data, const std::string &format, const Dict &opts)
Construct from parsed model bytes of a given format.
std::vector< casadi_int > input_shape(const std::string &name) const
std::vector< casadi_int > output_shape(const std::string &name) const
std::vector< std::string > dynamic_params() const
std::vector< std::string > name_in() const
void disp(std::ostream &stream, bool more) const override
Print a description of the object.
std::vector< uint8_t > model_data_
Function create_function(const std::string &name, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out, const Dict &opts) const
GraphBuilder()
Default constructor.
std::vector< std::string > dynamic_params() const
Names of the symbolic/dynamic dimensions in the model.
std::string dtype(const std::string &name) const
Element type name of a tensor (input or output) by name (FLOAT, INT64, ...)
GraphBuilderInternal * operator->()
void bind_dim(const std::string ¶m, casadi_int value)
Bind a symbolic/dynamic dimension to a concrete size.
casadi_int n_in() const
Declared shape of a tensor (input or output) by name; -1 for dynamic dimensions.
std::vector< std::string > name_in() const
Declared shape of a tensor (input or output) by name; -1 for dynamic dimensions.
Function create() const
Freeze into an evaluable Function, default naming.
std::vector< casadi_int > dimension(const std::string &name) const
Declared shape of a tensor (input or output) by name; -1 for dynamic dimensions.
void set(const std::string &input_name, const std::vector< double > &value)
Bake a fixed value into an input; it is fed at create() and not exposed as a Function input.
void bind_shape(const std::string &input_name, const std::vector< casadi_int > &shape)
Pin the full shape of an input.
GraphBuilderInternal * get() const
const std::string & name() const
Name of the model.
casadi_int n_out() const
Declared shape of a tensor (input or output) by name; -1 for dynamic dimensions.
void export_onnx(const std::string &filename, const Dict &opts=Dict())
Export to an ONNX model file.
std::vector< std::string > name_out() const
Declared shape of a tensor (input or output) by name; -1 for dynamic dimensions.
std::vector< std::string > dimension_param(const std::string &name) const
Per-axis symbolic dimension name of a tensor by name ("" for static axes)
Format-agnostic handle to a parsed computational-graph model.
std::vector< uint8_t > export_symbolic(const Function &f, const Dict &opts=Dict())
Symbolic export: serialize a CasADi Function to model bytes.
void fill_metadata(GraphBuilderInternal &gb) const
Populate a builder's Node metadata from the parsed model.
Function import_symbolic(const GraphBuilderInternal &gb, const std::string &name) const
Symbolic import: rebuild the graph as a CasADi Function.
static Function create(const std::string &solver, const std::string &name, const GraphBuilderInternal *gb, const std::vector< std::string > &inputs, const std::vector< std::string > &outputs, const Dict &opts)
Plugin factory.
static std::string format_from_path(const std::string &path)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T dot(const std::vector< T > &a, const std::vector< T > &b)
std::vector< casadi_int > path(const std::vector< casadi_int > &map, casadi_int i_start)
std::string filename(const std::string &path)
Metadata for one graph tensor (graph input or output)
void disp(std::ostream &stream, bool more=false) const
std::string get_str(bool more=false) const
std::vector< casadi_int > dimension
Declared shape, -1 for dynamic dimensions.
std::string name
Tensor name.
std::string io
"input" or "output"
std::string dtype
Element type name (FLOAT, INT64, ...)
std::vector< std::string > dim_params
Symbolic name per axis ("" if static)
bool baked
True if a fixed value was set() for this input.