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

Struct member function can not be called #7370

Open
Enigmatisms opened this issue Feb 15, 2023 · 9 comments
Open

Struct member function can not be called #7370

Enigmatisms opened this issue Feb 15, 2023 · 9 comments
Assignees

Comments

@Enigmatisms
Copy link

Calling nested struct member function
Calling the function of a struct from the parent struct will fail and lead to "AttributeError: 'Structxx' object has no attribute 'xxx'"

To Reproduce
First, I know this issue looks like #6917 or #6737 but it's different. I saw there was a pr in #6917. I ran through the code, and also found the updated version of struct initialization. Yet I got a exception.
I create a small example snippet to reproduce:

import taichi as ti

ti.init()

@ti.dataclass
class Core:
    foo:  ti.i32

    @ti.func
    def positive(self):
        return self.foo >= 0

@ti.dataclass
class InnerWrapper:
    core: Core

    @ti.func
    def is_positive(self):
        return self.core.positive()

@ti.dataclass
class OuterWrapper:
    inner: InnerWrapper

test_field = OuterWrapper.field()
ti.root.bitmasked(ti.i, 16).place(test_field)

random_num = ti.field(ti.i32, 16)

for i in range(16):
    test_field[i] = OuterWrapper(inner = InnerWrapper(core = Core(foo = -1 if i & 1 else 1)))

@ti.kernel
def test():
    for i in test_field:
        # this call would fail
        random_num[i] = test_field[i].inner.is_positive()

test()

for i in range(16):
    print(random_num[i], end = ', ')

The code is run by (say we create a file called test.py): python3 test.py

Log/Screenshots
The exception thrown:

[Taichi] version 1.4.1, llvm 15.0.1, commit e67c674e, win, python 3.7.1
[Taichi] Starting on arch=x64
Traceback (most recent call last):
  File ".\test.py", line 38, in <module>
    test()
  File "user\AppData\Local\Programs\Python\Python37\lib\site-packages\taichi\lang\kernel_impl.py", line 976, in wrapped
    raise type(e)('\n' + str(e)) from None
taichi.lang.exception.TaichiCompilationError:
File ".\test.py", line 36, in test:
        random_num[i] = test_field[i].inner.is_positive()
File ".\test.py", line 19, in is_positive:
        return self.core.positive()
Traceback (most recent call last):
  File "user\AppData\Local\Programs\Python\Python37\lib\site-packages\taichi\lang\ast\ast_transformer_utils.py", line 25, in __call__  
    return method(ctx, node)
  File "user\AppData\Local\Programs\Python\Python37\lib\site-packages\taichi\lang\ast\ast_transformer.py", line 862, in build_Attribute
    node.ptr = getattr(node.value.ptr, node.attr)
  File "user\AppData\Local\Programs\Python\Python37\lib\site-packages\taichi\lang\common_ops.py", line 27, in __getattr__
    f"'{type(self).__name__}' object has no attribute '{item}'")
AttributeError: 'Struct193' object has no attribute 'positive'

I have tested this behavior on Win11 / Ubuntu 20.04, with python 3.7.1 and 3.7.5, taichi 1.3.0 (after that fixing PR) and 1.4.1. It looks like on win11, llvm version is 15.0.1 while on linux it is 15.0.4. They all throw the same exception. I tried to print the __struct_method field when initializing the struct, everything seems fine to me. I just got no clue why this would happen.

Additional comments

  • Python 3.7.9 & 3.8.16 do not throw this exception, everything seems fine
@Enigmatisms Enigmatisms changed the title Struct member function can not be called (Taichi v1.4.1) Struct member function can not be called Feb 15, 2023
@chen-erqi
Copy link
Contributor

I meet this problem too T_T.
May I ask if there are any ways to bypass this issue now?
Can we write the member function outter and pass the struct into this function?

@bobcao3
Copy link
Collaborator

bobcao3 commented May 7, 2023

I guess currently only way is to use procedural programming with first argument being the struct...

@chen-erqi
Copy link
Contributor

I guess currently only way is to use procedural programming with first argument being the struct...

May i ask if this is data oriented programming? The struct is considered as a group of data without function.

@Enigmatisms
Copy link
Author

It's been a long time. By the way I bypassed this issue by opting for newer python version.

So... what's the cause of this problem? As far as I can recall, it's caused by struct name aliasing? But I don't see anything related to this in my minimal reproduction code.

Judging from the discussion you have above, it seems that it is caused by struct nesting, and the member functions of the inner struct are stripped?

@chen-erqi
Copy link
Contributor

It's been a long time. By the way I bypassed this issue by opting for newer python version.

So... what's the cause of this problem? As far as I can recall, it's caused by struct name aliasing? But I don't see anything related to this in my minimal reproduction code.

Judging from the discussion you have above, it seems that it is caused by struct nesting, and the member functions of the inner struct are stripped?

Could you please explain how you can bypass this issue by newer python version? Because I think maybe taichi is not related to the version of python?
I think that it is caused by struct nesting, nesting in taichi and paralleling is complex.

@Enigmatisms
Copy link
Author

Enigmatisms commented May 8, 2023

Since I have two systems (one windows and one ubuntu) on my laptop, I found that the behavior of my code was different, even if I have the same version of Taichi. I did some experiments back then, and found that 3.8- (not all of them, 3.7.8 seemed fine, if I recall it correctly) would run into this issue. I tried again this code just now:

  • Python 3.7.5 with Taichi 1.4.1: Error

  • Python 3.9+ with Taichi 1.4.1: passed

And..., is struct nesting such a big problem? I used a lot in my project, like: BSDF.py. The outtermost struct is BSDF, containing a struct Medium, which contains, further, a dataclass struct called PhaseFunction. The code works fine.

@chen-erqi
Copy link
Contributor

thanks a lot!!
My code was run on python 3.8.10 and it was bad.
Could you please offer your exact python version?

@Enigmatisms
Copy link
Author

Mine is 3.9.13, but my ubuntu is 3.8+. This is weird...

@chen-erqi
Copy link
Contributor

Mine is 3.9.13, but my ubuntu is 3.8+. This is weird...

yes...
My code will be pushed into some projects which require other envrioment...
So i try to use procedural programming mentioned by @bobcao3.
Thanks a lot for ur explaination and @bobcao3 !

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

No branches or pull requests

4 participants