Skip to content
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

Confusion regarding mask types #77

Closed
arpit15 opened this issue Apr 5, 2020 · 10 comments
Closed

Confusion regarding mask types #77

arpit15 opened this issue Apr 5, 2020 · 10 comments

Comments

@arpit15
Copy link

arpit15 commented Apr 5, 2020

I wrote a simple test to try enoki. However, I am unable to perform simple comparison operations due to type differences. Documentation states that return type of operator< and neq is mask_t<Array>. However, types of result1 and result2 variable in the following code are different.

import enoki as ek

def myfunc(arr1, arr2):
  result1 = ek.dot(arr1, arr1) < 0
  result2 = ek.neq(arr2, 0)
  print(type(result1), type(result2))
  return result1, result2

def test_scalar():
  from enoki import scalar
  arr1 = scalar.Vector1f([1])
  arr2 = scalar.Vector1f([2])
  res = myfunc(arr1, arr2)


def test_cuda():
  from enoki import cuda
  arr1 = cuda.Vector1f([1])
  arr2 = cuda.Vector1f([2])
  res = myfunc(arr1, arr2)


if __name__ == '__main__':
  test_scalar()
  test_cuda()

Output in scalar mode gives below. According to my understanding this is because the output of dot operation is converted to py::float. Is there a way to perform comparison without explicitly casting to bool in this case?

<class 'bool'> <class 'enoki.scalar.Vector1m'>

Output in cuda mode gives below. The difference between these types is unclear to me. Can you kindly give more details?

class 'enoki.cuda.Mask'> <class 'enoki.cuda.Vector1m'>
@Speierers
Copy link
Member

Speierers commented Apr 6, 2020

Hi @arpit15 ,

Regarding the test_scalar, you are right, the dot function will return a float for which the comparison op will yield a bool value. On the other hand, Vector1m is equivalent to mask_t<Array<float, 1>> in C++. Arrays with 1 dimension are pretty much the same as scalar values like float. Therefore you should be able to seamlessly do arithmetic between bool, Mask, and Vector1m in python, so no need for explicit cast.

The same applies to the test_cuda. However this time, the dot function return a CUDAArray<float> value (that lives on the GPU), to the operator< returns a Mask and not a bool.

Please let me know if this answered you questions.

@arpit15
Copy link
Author

arpit15 commented Apr 6, 2020

I asked the difference in types because I am unable to perform operations between these types. For ex: I tried res = result1 & result2 in test_scalar and test_gpu both give me errors.
Error in scalar
TypeError: unsupported operand type(s) for &: 'bool' and 'enoki.scalar.Vector1m'
Error in gpu
TypeError: unsupported operand type(s) for &: 'enoki.cuda.Mask' and 'enoki.cuda.Vector1m

Please let me know the correct way to perform element-wise operations in enoki, if this is not the correct way.

@Speierers Speierers reopened this Apr 6, 2020
@Speierers
Copy link
Member

Currently enoki.cuda.Mask can be implicitly casted to enoki.cuda.Vector1m but not the other way around. Somehow Python also tries to cast from right to left with the & operator, which causes your issue. I will try to fix this in the future.
In the meantime, you should be able to do res = result2 & result1.

Also, could you tell me why using cuda.Vector1f and not cuda.Float32? This should solve you issue as well.

@arpit15
Copy link
Author

arpit15 commented Apr 8, 2020

Thanks! This issue is solved by using res = result2 & result1.
I am trying to write custom area emitter in python. My idea was to create a Vector1m for both scalar and cuda, to write logic like here. I presumed that comparing Vector1f in both variants would give me Vector1m which is the type I am observing on the python side when using arguments of sample_direction function.
Is there a reason to not have implicit converters from scalar.Vector1m to bool?

@Speierers
Copy link
Member

Is there a reason to not have implicit converters from scalar.Vector1m to bool?

No specific reason, we might add it in the future.

In this code

dot(ds.d, ds.n) < 0.f && neq(ds.pdf, 0.f)

both comparisons should return a Mask. I don't see where the Vector1f comes in?

@arpit15
Copy link
Author

arpit15 commented Apr 8, 2020

I don't really care about using Vector1f. I am just using it to create Vector1m. Using neq in python yields Vector1m for neq(ds.pdf, 0). Therefore using
dot(ds.d, ds.n) < 0.f & neq(ds.pdf, 0.f) doesn't work. However,
neq(ds.pdf, 0.f) & dot(ds.d, ds.n) < 0.f works fine, as you suggested.
Is there a way to create Mask type var from Vector1m type var without explicitly knowing, if the variant is scalar or cuda?
The main source of my problems is friction between Vector1m and Mask types.

@arpit15
Copy link
Author

arpit15 commented Apr 8, 2020

I see problems due to no implicit conversion from Vector1m to Mask when calling m_radiance->eval in scalar variant as the function requires Mask aka bool type. However, processing using neq(ds.pdf, 0.f) & dot(ds.d, ds.n) < 0.f & active gives me Vector1m

@Speierers
Copy link
Member

I see your problem now. There was indeed some missing bindings for the scalar mode causing the following issue:

ek.neq(0.0, 0.0) # -> return Vector1m instead of bool

This should be fixed now (486ddb0)

In the other modes (dynamic, cuda), I would be surprise if you ever encounter a Vector1m. This would indicate that there is another bug. Let me know in that case.

@arpit15
Copy link
Author

arpit15 commented Apr 9, 2020

Thanks for resolving this error. I tripped over another bug. I don't know if I should make another issue for this.
ek.select(True, 0.1, 0.2) returns enoki.scalar.Vector1m with value [1] which is wrong type and value.

@Speierers
Copy link
Member

Speierers commented Apr 14, 2020

Another one, thanks!

Just fixed in 1cc24d0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants