How to Use Functions of Complex Numbers In Pyopencl?

142 Views Asked by At

Ive been trying to implement newton fractals using pyopencl's element wise kernel, from what i can tell it essentially compiles a section of C code then runs it for each element in parallel on a GPU. Ive been running into issues getting it to work with complex numbers. Pyopencl documentation on this ( https://documen.tician.de/pyopencl/array.html ) seems unclear to me, though I have tried adding the define and include statements mentioned here to the preamble. But I still am unsure on how do simple things such as find the absolute value of a complex number. This is: https://github.com/inducer/pyopencl/blob/main/pyopencl/cl/pyopencl-complex.h linked in the pyopencl documentation. I think it contains the .h file for Complex stuff for pyopencl, but im not to sure as i have very little experience outside of Python. The way it was linked to me implies i was meant to be able to read through the code to ascertain what funcs are implemented and how to what there called. However i cannot work out how to use any of these functions. I do not know if it is because i have not imported/included them correctly, or if theirs some part of the call signature im missing.

mapclstr="""
int C = 0;
cdouble_t fval;
cdouble_t fpval;
fval.real=100;
fpval.real=100;
fval.imag=100;
fpval.imag=100;

while ((fval.real*fval.real+fval.imag*fval.imag)>precision && C<N) 
{
    
  fval=_add(_pow( X[i] , 3 ) + _pow( X[i] , 2 ) + X[i],- 1.0);
  fpval=_add(_mul(3,_pow( X[i] , 2 ))  + _mul(2,X[i]),1);
  
  X[i] =_add(X[i],-_divide(fval,fpval));
  C+=1;


} 
"""
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

A=np.linspace(3,6,1,dtype=np.complex128)#1val for easy testing
res_g = cl.array.to_device(queue, A)
mapcl = ElementwiseKernel(ctx,"cdouble_t *X,int N,double precision",mapclstr,"mapcl",preamble="#define PYOPENCL_DEFINE_CDOUBLE //#include <pyopencl-complex.h>  ")
mapcl(res_g,np.intc(500),np.float64(0.00001)) 
print(res_g.get())  

i get this error for all of the _ functions, ive tried without the "_" and a few other variations but i get the same error.

Traceback (most recent call last):
  File "c:/Users/kieran/Documents/Coding projects/Fractal-Viewer/pyopencltest6.py", line 37, in <module>
    mapcl(res_g,np.intc(500),np.float64(0.00001))
  File "C:\ProgramData\Anaconda3\envs\FractalStuff\lib\site-packages\pyopencl\elementwise.py", line 249, in __call__
    kernel, arg_descrs = self.get_kernel(use_range)
  File "C:\ProgramData\Anaconda3\envs\FractalStuff\lib\site-packages\pytools\__init__.py", line 766, in wrapper
    result = function(obj, *args, **kwargs)
  File "C:\ProgramData\Anaconda3\envs\FractalStuff\lib\site-packages\pyopencl\elementwise.py", line 222, in get_kernel
    use_range=use_range, **self.kwargs)
  File "C:\ProgramData\Anaconda3\envs\FractalStuff\lib\site-packages\pyopencl\elementwise.py", line 159, in get_elwise_kernel_and_types
    use_range=use_range, loop_prep=loop_prep, **kwargs)
  File "C:\ProgramData\Anaconda3\envs\FractalStuff\lib\site-packages\pyopencl\elementwise.py", line 109, in get_elwise_program
    return Program(context, source).build(options)
  File "C:\ProgramData\Anaconda3\envs\FractalStuff\lib\site-packages\pyopencl\__init__.py", line 539, in build
    options_bytes=options_bytes, source=self._source)
  File "C:\ProgramData\Anaconda3\envs\FractalStuff\lib\site-packages\pyopencl\__init__.py", line 583, in _build_and_catch_errors
    raise err
pyopencl._cl.RuntimeError: clBuildProgram failed: BUILD_PROGRAM_FAILURE - clBuildProgram failed: BUILD_PROGRAM_FAILURE - clBuildProgram failed: BUILD_PROGRAM_FAILURE

Build on <pyopencl.Device 'gfx1010:xnack-' on 'AMD Accelerated Parallel Processing' at 0x271b4693a60>:

C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:37:8: error: implicit declaration of function '_add' is invalid in OpenCL
  fval=_add(_pow( X[i] , 3 ) + _pow( X[i] , 2 ) + X[i],- 1.0);
       ^
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:37:8: note: did you mean 'hadd'?
C:\constructicon\builds\gfx\two\21.50\stream\opencl\compiler\llvm\build\wNow64a\B_rel\tools\comgr\<stdin>:9854:23: note: 'hadd' declared here
ulong16 __ovld __cnfn hadd(ulong16 x, ulong16 y);
                      ^
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:37:13: error: implicit declaration of function '_pow' is invalid in OpenCL
  fval=_add(_pow( X[i] , 3 ) + _pow( X[i] , 2 ) + X[i],- 1.0);
            ^
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:37:13: note: did you mean 'pow'?
C:\constructicon\builds\gfx\two\21.50\stream\opencl\compiler\llvm\build\wNow64a\B_rel\tools\comgr\<stdin>:8733:22: note: 'pow' declared here
half16 __ovld __cnfn pow(half16 x, half16 y);
                     ^
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:37:49: error: invalid operands to binary expression ('int' and '__global cdouble_t')
  fval=_add(_pow( X[i] , 3 ) + _pow( X[i] , 2 ) + X[i],- 1.0);
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:38:14: error: implicit declaration of function '_mul' is invalid in OpenCL
  fpval=_add(_mul(3,_pow( X[i] , 2 ))  + _mul(2,X[i]),1);
             ^
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:38:8: error: assigning to '__private cdouble_t' from incompatible type 'int'
  fpval=_add(_mul(3,_pow( X[i] , 2 ))  + _mul(2,X[i]),1);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:40:20: error: implicit declaration of function '_divide' is invalid in OpenCL
  X[i] =_add(X[i],-_divide(fval,fpval));
                   ^
C:\Users\kieran\AppData\Local\Temp\comgr-26ac13\input\CompileSource:40:8: error: assigning to '__global cdouble_t' from incompatible type 'int'
  X[i] =_add(X[i],-_divide(fval,fpval));
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 errors generated.
Error: Failed to compile source (from CL or HIP source to LLVM IR).

Im struggling with the PyopenCl documentation, the opencl documentation seems to assume good knowledge of C which i dont have.

My actual request is for someone to tell me what im doing wrong with pyopencl's complex module and how i can do things such as find a modulus, or raise a complex number to a power. An alternative way to manipulate complex numbers in a opencl kernel would also be appreciated. Bonus points for explaining whats going on in here: https://github.com/inducer/pyopencl/blob/main/pyopencl/cl/pyopencl-complex.h why each func is defined inline and has this TP TPROOT##.

1

There are 1 best solutions below

0
Kieran Clarke On

I think i worked it out the TPROOT## is like a general data type, so if you want multiplication of complex doubles: cdouble you use cdouble_mul replacing the TPROOT## with the data type you want it to take.

  { \
    return TPROOT##_new( \
        a.real*b.real - a.imag*b.imag, \
        a.real*b.imag + a.imag*b.real); \
  } \```

I spent ages trying to work this out and there was not help anywhere i could find on what `TPROOT##` meant. Gonna leave this here in hopes it saves someone time.