Change:
On recent PyTorch master (built from source; 0.4.0a0+) on a P100, CUDA 9:
I think the results on CPU meets the defination of triu (upper triangular part of the matrix). It is really hard to handle with a tensor from expand operation with multi-thread not only on GPU but also on CPU. The unexpected result will also happen on CPU if we apply openmp to it. I think it is necessary to eleminate the difference between the implementation and defination.
It doesn’t matter if it’s cpu or not. triu doesn’t have an underscore which means it doesn’t operate in-place and should always give the same result (in new memory)

Discussion:
TensorTriOp(T *start_, int64_t stride0_, int64_t stride1_, int64_t k_) : start(start_), stride0(stride0_), stride1(stride1_), k(k_) {} <del> __device__ __forceinline__ int mask(T *in) { ptrdiff_t n = in - start; </del> <ins> __device__ __forceinline__ int mask(T *out) { ptrdiff_t n = out - start; </ins> int64_t row, col; if (stride0 > stride1) {

} __device__ __forceinline__ void operator()(T* out, T* in) { <del> *out = mask(in) ? *in : ScalarConvert<int, T>::to(0); </del> <ins> *out = mask(out) ? *in : ScalarConvert<int, T>::to(0); </ins> } __device__ __forceinline__ void operator()(T* v) {

THCAssertSameGPU(THCTensor_(checkGPU)(state, 2, self_, src_)); THArgCheck(src_->nDimension == 2, 1, "expected a matrix"); <del> THCTensor *src = src_; if (self_ == src_) src = THCTensor_(newContiguous)(state, src_); </del> <ins> if (self_ != src_) THCTensor_(resizeAs)(state, self_, src_); </ins> <del> int64_t stride0 = src->stride[0]; int64_t stride1 = src->stride[1]; real *start = THCTensor_(data)(state, src); </del> <ins> int64_t stride0 = self_->stride[0]; int64_t stride1 = self_->stride[1]; real *start = THCTensor_(data)(state, self_); </ins> TensorTriOp<real, 0> op(start, stride0, stride1, k); if (self_ == src_) { <del> if (!THC_pointwiseApply1(state, src, op)) { </del> <ins> if (!THC_pointwiseApply1(state, src_, op)) { </ins> THArgCheck(false, 2, CUTORCH_DIM_WARNING); } } else { <del> THCTensor_(resizeAs)(state, self_, src); </del> <ins> THCTensor_(resizeAs)(state, self_, src_); </ins> <del> if (!THC_pointwiseApply2(state, self_, src, op)) { </del> <ins> if (!THC_pointwiseApply2(state, self_, src_, op)) { </ins> THArgCheck(false, 2, CUTORCH_DIM_WARNING); } } <del> if (self_ == src_) THCTensor_(freeCopyTo)(state, src, src_); </del> THCudaCheck(cudaGetLastError()); }

THCAssertSameGPU(THCTensor_(checkGPU)(state, 2, self_, src_)); THArgCheck(src_->nDimension == 2, 1, "expected a matrix"); <del> THCTensor *src = src_; if (self_ == src_) src = THCTensor_(newContiguous)(state, src_); </del> <ins> if (self_ != src_) THCTensor_(resizeAs)(state, self_, src_); </ins> <del> int64_t stride0 = src->stride[0]; int64_t stride1 = src->stride[1]; real *start = THCTensor_(data)(state, src); </del> <ins> int64_t stride0 = self_->stride[0]; int64_t stride1 = self_->stride[1]; real *start = THCTensor_(data)(state, self_); </ins> TensorTriOp<real, 1> op(start, stride0, stride1, k); if (self_ == src_) { <del> if (!THC_pointwiseApply1(state, src, op)) { </del> <ins> if (!THC_pointwiseApply1(state, src_, op)) { </ins> THArgCheck(false, 2, CUTORCH_DIM_WARNING); } } else { <del> THCTensor_(resizeAs)(state, self_, src); if (!THC_pointwiseApply2(state, self_, src, op)) { </del> <ins> if (!THC_pointwiseApply2(state, self_, src_, op)) { </ins> THArgCheck(false, 2, CUTORCH_DIM_WARNING); } } <del> if (self_ == src_) THCTensor_(freeCopyTo)(state, src, src_); </del> THCudaCheck(cudaGetLastError()); }

return make_tensor(t, M, M) <ins> def medium_2d_expanded(t): return t(1).expand(M, M) </ins> def medium_2d_scaled(t, scale=10): return make_tensor(t, M, M).mul(scale)

return t(*sizes).copy_(torch.randn(*sizes)) return tmp <ins> # Content of each tuple: # - function name # - constructor for the tensor,    signature: fn(tensor_type) -> tensor # - constructor for the arguments, signature: fn(tensor_type) -> list # - postfix name for the test (must be unique for a given function) (default='') # - tensor types to use (default=types) # - disable inplace test, if set to True, no inplace test will be done (default=False) </ins> tests = [ ('add', small_3d, lambda t: [number(3.14, 3, t)]), ('add', small_3d, lambda t: [small_3d_positive(t)], 'tensor'),

('topk', small_3d_unique, lambda t: [2, 1, True, True], 'dim_desc_sort'), ('trace', medium_2d, lambda t: [],), ('tril', medium_2d, lambda t: [],), <ins> ('tril', medium_2d_expanded, lambda t: [], 'zero_stride', types, True), </ins> ('tril', medium_2d, lambda t: [2], 'positive'), ('tril', medium_2d, lambda t: [-2], 'negative'), ('triu', medium_2d, lambda t: [],), <ins> ('triu', medium_2d_expanded, lambda t: [], 'zero_stride', types, True), </ins> ('triu', medium_2d, lambda t: [2], 'positive'), ('triu', medium_2d, lambda t: [-2], 'negative'), ('unsqueeze', new_t(2, 3, 4), lambda t: [2],),

for t in types: tensor = t() gpu_tensor = get_gpu_type(t)() <ins> # Default values desc = '' type_subset = types no_inplace = False </ins> if len(decl) == 3: name, constr, arg_constr = decl <del> desc = '' </del> elif len(decl) == 4: name, constr, arg_constr, desc = decl elif len(decl) == 5: name, constr, arg_constr, desc, type_subset = decl <del> if t not in type_subset: continue </del> <ins> elif len(decl) == 6: name, constr, arg_constr, desc, type_subset, no_inplace = decl if t not in type_subset: continue </ins> precision = custom_precision.get(name, TestCuda.precision) for inplace in (True, False): <ins> if inplace and no_inplace: continue </ins> if inplace: name_inner = name + '_' else: