Caffe2 - C++ API
A deep learning, cross platform ML framework
utils.cpp
1 #include <torch/csrc/python_headers.h>
2 #include <cstdarg>
3 #include <string>
4 #include <vector>
5 #include <sstream>
6 #include <algorithm>
7 #include <unordered_map>
8 #include <torch/csrc/THP.h>
9 #include <torch/csrc/utils/python_strings.h>
10 #include <torch/csrc/utils/invalid_arguments.h>
11 #include <torch/csrc/autograd/variable.h>
12 #include <torch/csrc/DynamicTypes.h>
13 
14 #include <torch/csrc/generic/utils.cpp>
15 #include <TH/THGenerateAllTypes.h>
16 
17 #include <torch/csrc/generic/utils.cpp>
18 #include <TH/THGenerateHalfType.h>
19 
20 #include <torch/csrc/generic/utils.cpp>
21 #include <TH/THGenerateBoolType.h>
22 
23 int THPUtils_getCallable(PyObject *arg, PyObject **result) {
24  if (!PyCallable_Check(arg))
25  return 0;
26  *result = arg;
27  return 1;
28 }
29 
30 THLongStoragePtr THPUtils_unpackSize(PyObject *arg) {
31  THLongStoragePtr result;
32  if (!THPUtils_tryUnpackLongs(arg, result)) {
33  std::string msg = "THPUtils_unpackSize() expects a torch.Size (got '";
34  msg += Py_TYPE(arg)->tp_name;
35  msg += "')";
36  throw std::runtime_error(msg);
37  }
38  return result;
39 }
40 
41 bool THPUtils_tryUnpackLongs(PyObject *arg, THLongStoragePtr& result) {
42  bool tuple = PyTuple_Check(arg);
43  bool list = PyList_Check(arg);
44  if (tuple || list) {
45  int nDim = tuple ? PyTuple_GET_SIZE(arg) : PyList_GET_SIZE(arg);
46  THLongStoragePtr storage(THLongStorage_newWithSize(nDim));
47  for (int i = 0; i != nDim; ++i) {
48  PyObject* item = tuple ? PyTuple_GET_ITEM(arg, i) : PyList_GET_ITEM(arg, i);
49  if (!THPUtils_checkLong(item)) {
50  return false;
51  }
52  THLongStorage_set(storage, i, THPUtils_unpackLong(item));
53  }
54  result = std::move(storage);
55  return true;
56  }
57  return false;
58 }
59 
60 std::vector<int64_t> THPUtils_unpackLongs(PyObject *arg) {
61  bool tuple = PyTuple_Check(arg);
62  bool list = PyList_Check(arg);
63  if (tuple || list) {
64  int nDim = tuple ? PyTuple_GET_SIZE(arg) : PyList_GET_SIZE(arg);
65  std::vector<int64_t> sizes(nDim);
66  for (int i = 0; i != nDim; ++i) {
67  PyObject* item = tuple ? PyTuple_GET_ITEM(arg, i) : PyList_GET_ITEM(arg, i);
68  if (!THPUtils_checkLong(item)) {
69  std::ostringstream oss;
70  oss << "expected int at position " << i << ", but got: " << THPUtils_typename(item);
71  throw std::runtime_error(oss.str());
72  }
73  sizes[i] = THPUtils_unpackLong(item);
74  }
75  return sizes;
76  }
77  throw std::runtime_error("Expected tuple or list");
78 }
79 
80 bool THPUtils_tryUnpackLongVarArgs(PyObject *args, int ignore_first, THLongStoragePtr& result) {
81  Py_ssize_t length = PyTuple_Size(args) - ignore_first;
82  if (length < 1) {
83  return false;
84  }
85 
86  PyObject *first_arg = PyTuple_GET_ITEM(args, ignore_first);
87  if (length == 1 && THPUtils_tryUnpackLongs(first_arg, result)) {
88  return true;
89  }
90 
91  // Try to parse the numbers
92  result = THLongStorage_newWithSize(length);
93  for (Py_ssize_t i = 0; i < length; ++i) {
94  PyObject *arg = PyTuple_GET_ITEM(args, i + ignore_first);
95  if (!THPUtils_checkLong(arg)) {
96  return false;
97  }
98  THLongStorage_set(result, i, THPUtils_unpackLong(arg));
99  }
100  return true;
101 }
102 
103 bool THPUtils_checkIntTuple(PyObject *arg)
104 {
105  if (!PyTuple_Check(arg)) {
106  return false;
107  }
108  for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(arg); ++i) {
109  if (!THPUtils_checkLong(PyTuple_GET_ITEM(arg, i))) {
110  return false;
111  }
112  }
113  return true;
114 }
115 
116 std::vector<int> THPUtils_unpackIntTuple(PyObject *arg)
117 {
118  if (!THPUtils_checkIntTuple(arg)) {
119  throw std::runtime_error("Couldn't unpack int tuple");
120  }
121  std::vector<int> values(PyTuple_GET_SIZE(arg));
122  for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(arg); ++i) {
123  values[i] = (int)THPUtils_unpackLong(PyTuple_GET_ITEM(arg, i));
124  }
125  return values;
126 }
127 
128 void THPUtils_setError(const char *format, ...)
129 {
130  static const size_t ERROR_BUFFER_SIZE = 1000;
131  char buffer[ERROR_BUFFER_SIZE];
132  va_list fmt_args;
133 
134  va_start(fmt_args, format);
135  vsnprintf(buffer, ERROR_BUFFER_SIZE, format, fmt_args);
136  va_end(fmt_args);
137  PyErr_SetString(PyExc_RuntimeError, buffer);
138 }
139 
140 void THPUtils_addPyMethodDefs(std::vector<PyMethodDef>& vector, PyMethodDef* methods)
141 {
142  if (!vector.empty()) {
143  // remove nullptr terminator
144  vector.pop_back();
145  }
146  while (true) {
147  vector.push_back(*methods);
148  if (!methods->ml_name) {
149  break;
150  }
151  methods++;
152  }
153 }
154 
155 static const char* classOrTypename(PyObject* obj) {
156  if (PyType_Check(obj)) {
157  return ((PyTypeObject*)obj)->tp_name;
158  }
159  return Py_TYPE(obj)->tp_name;
160 }
161 
162 PyObject * THPUtils_dispatchStateless(
163  PyObject *tensor, const char *name, PyObject *args, PyObject *kwargs)
164 {
165  THPObjectPtr methods(PyObject_GetAttrString(tensor, THP_STATELESS_ATTRIBUTE_NAME));
166  if (!methods) {
167  return PyErr_Format(
168  PyExc_TypeError,
169  "Type %s doesn't implement stateless methods",
170  classOrTypename(tensor));
171  }
172  THPObjectPtr method(PyObject_GetAttrString(methods, name));
173  if (!method) {
174  return PyErr_Format(
175  PyExc_TypeError,
176  "Type %s doesn't implement stateless method %s",
177  classOrTypename(tensor),
178  name);
179  }
180  return PyObject_Call(method.get(), args, kwargs);
181 }
182 
183 void THPUtils_invalidArguments(PyObject *given_args, PyObject *given_kwargs,
184  const char *function_name, size_t num_options, ...) {
185  std::vector<std::string> option_strings;
186  va_list option_list;
187  va_start(option_list, num_options);
188  for (size_t i = 0; i < num_options; i++)
189  option_strings.emplace_back(va_arg(option_list, const char*));
190  va_end(option_list);
191 
192  PyErr_SetString(PyExc_TypeError, torch::format_invalid_args(
193  given_args, given_kwargs, function_name, option_strings).c_str());
194 }
195 
196 template<>
198  if (ptr)
199  Py_DECREF(ptr);
200 }
201 
202 template class THPPointer<THPGenerator>;
203 
204 static bool backCompatBroadcastWarn = false;
205 
206 void setBackCompatBroadcastWarn(bool warn) {
207  backCompatBroadcastWarn = warn;
208 }
209 
210 bool getBackCompatBroadcastWarn() {
211  return backCompatBroadcastWarn;
212 }
213 
214 static bool backCompatKeepdimWarn = false;
215 
216 void setBackCompatKeepdimWarn(bool warn) {
217  backCompatKeepdimWarn = warn;
218 }
219 
220 bool getBackCompatKeepdimWarn() {
221  return backCompatKeepdimWarn;
222 }
223 
224 bool maybeThrowBackCompatKeepdimWarn(char *func) {
225  if(getBackCompatKeepdimWarn()) {
226  std::ostringstream ss;
227  ss << "backwards compatibility: call to \"" << func
228  << "\" uses default value for keepdim which has changed default to False. Consider passing as kwarg.",
229  PyErr_WarnEx(PyExc_UserWarning, ss.str().c_str(), 1);
230  }
231  return true;
232 }
233 
234 template<>
236  if (ptr) {
237  THTensor_free(LIBRARY_STATE ptr);
238  }
239 }
240 
241 template<>
243  if (ptr)
244  Py_DECREF(ptr);
245 }
246 
247 template class THPPointer<THPStorage>;