-
Notifications
You must be signed in to change notification settings - Fork 22.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add list methods: copy,extend #17092
Conversation
Tackles #16662 |
I'll close this one, then. |
@Krovatkin you could reopen it with just extends and copy, those are still missing. |
@TheCodez ah, thanks for letting me know! Will do! |
df873cc
to
a62e894
Compare
torch/csrc/jit/register_prim_ops.cpp
Outdated
@@ -1286,6 +1314,15 @@ RegisterOperators reg2({ | |||
"aten::append( " decl_type "[](a!) self, " decl_type \ | |||
"(c) el) -> " decl_type "[](a!)", \ | |||
listAppend<Shared<c_type>, c_type::ElemType>), \ | |||
Operator( \ | |||
"aten::extend(" decl_type "[](a!) self, " decl_type \ | |||
" [](b) other) -> ()", \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The b
annotation here is unnecessary, since you're not doing a write or creating an alias. So it's fine to leave it blank (which is sugar for "this is a read-only, unique value")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addresssed
torch/csrc/jit/register_prim_ops.cpp
Outdated
Operator( \ | ||
"aten::copy(" decl_type \ | ||
"[](a) self)" \ | ||
" -> " decl_type "[](b!)", \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The !
annotation is only necessary to denote mutations to existing values. So you don't (b!)
on the return type, since it's a new value returned by the op. The rules are this way so that pure ops (the common case) don't need annotations, e.g. (add(Tensor a, Tensor b) -> Tensor
).
I know this is confusing! I am doing a writeup of all the aliasing/mutation semantics to help clarify
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed
test/test_jit.py
Outdated
for l in [[], [torch.rand(2)], [torch.rand(2), torch.rand(2), torch.rand(2)]]: | ||
for r in [[], [torch.rand(2)], [torch.rand(2), torch.rand(2), torch.rand(2)]]: | ||
rl = l[:] # side effects due to extend | ||
self.assertEqual(extend_list(l, r), rl + r) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also verify that rl
has been mutated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe, rl
(it should be a copy of l
) would change, but rl + r
would give us the correct answer to compare against l
that does change. Why do we want rl
to be mutated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, I could switch the order of args in assertEqual
that we shouldn't need a copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@apaszke scratch that. JIT makes a copy of every list
argument meaning we never modify l
.
TList list; | ||
pop(stack, list); | ||
|
||
const auto& vec = list->elements(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does actually perform a copy?
a = [1, 2, 3]
b = a.copy()
Won't creating an IValue from a reference to a
result in it b
sharing the same underlying data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will indeed perform a shallow copy.
const auto& vec = list->elements();
auto out = vec;
auto out
is deduced to be std::vector<decl(vec)::value_type>
, which isn't a reference type, so vec
gets copied via an assignment operator into out
. I believe this is an IValue
c-tor that gets invoked in our case: IValue::IValue(std::vector<int64_t> v)
(or a similar one corresponding to a given element type). We could explicitly pass a const reference (i.e. const auto& vec
) into the c-tor and we should still get a shallow copy. I do prefer explicit copies and let a compiler elide them (even lvalue ones), even though passing a const reference should (in theory) prevent us from going to the wrong c-tor even if IValue::IValue(std::vector<int64_t> &v)
gets added.
torch/csrc/jit/register_prim_ops.cpp
Outdated
@@ -17,6 +17,7 @@ | |||
#include <ATen/core/thread_pool.h> | |||
#include <c10/util/SmallVector.h> | |||
|
|||
#include <algorithm> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this header for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I'll remove it. I needed it for std::reverse
. Thank you!
@@ -1003,6 +1004,33 @@ Operation listAppend(const Node* node) { | |||
}; | |||
} | |||
|
|||
template <typename TList> | |||
Operation listExtend(const Node* node) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Operator()
can take the std::function<int(Stack& stack)
directly and this doesn't need node
, so you can declare the op directly (e.g. int listExtend(Stack& stack) { ... }
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of the list
operations seems to need a node
and they all use the same c-tor. Maybe we should stick to that c-tor in order to be consistent here and follow up with another PR to update all the list
ops wholesale?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alrightie, created a separate task to track this one.
remove reverse,pop,clear put back accidentally removed tests revert some extra changes address feedback; fix test cases address David's feedback
8c0d7ff
to
8f09d09
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Krovatkin has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
This PR adds the following methods to python's list.
and tests