@Override
    public INDArray[] exec(CustomOp op) {

        Nd4j.getExecutioner().commit();

        //
        if (op.numOutputArguments() == 0 && !op.isInplaceCall()) {
            try {
                val list = this.calculateOutputShape(op);
                if (list.isEmpty())
                    throw new ND4JIllegalStateException("Op name " + op.opName() + " failed to execute. You can't execute non-inplace CustomOp without outputs being specified");

                for (val shape: list)
                    op.addOutputArgument(Nd4j.create(shape));

            } catch (Exception e) {
                throw new ND4JIllegalStateException("Op name " + op.opName() + " failed to execute. You can't execute non-inplace CustomOp without outputs being specified");
            }
        }

        if (op.opName().equalsIgnoreCase("im2col")) {
            val xArr = op.inputArguments()[0];
            val zArr = op.outputArguments()[0];

            CudaContext context = AtomicAllocator.getInstance().getFlowController().prepareAction(zArr, xArr);

            if (extraz.get() == null)
                extraz.set(new PointerPointer(32));

            PointerPointer xShapeHost =
                    extraz.get().put(AddressRetriever.retrieveHostPointer(xArr.shapeInfoDataBuffer()), // 0
                            context.getOldStream(), // 1
                            AtomicAllocator.getInstance().getDeviceIdPointer(), // 2
                            context.getBufferAllocation(), // 3
                            context.getBufferReduction(), // 4
                            context.getBufferScalar(), // 5
                            context.getBufferSpecial(),
                            null,
                            AddressRetriever.retrieveHostPointer(zArr.shapeInfoDataBuffer())
                    );


            val x = AtomicAllocator.getInstance().getPointer(xArr, context);
            val z = AtomicAllocator.getInstance().getPointer(zArr, context);

            val xShape = AtomicAllocator.getInstance().getPointer(xArr.shapeInfoDataBuffer(), context);
            val zShape = AtomicAllocator.getInstance().getPointer(zArr.shapeInfoDataBuffer(), context);

            val hxShape = AtomicAllocator.getInstance().getHostPointer(xArr.shapeInfoDataBuffer());
            val hzShape = AtomicAllocator.getInstance().getHostPointer(zArr.shapeInfoDataBuffer());

            double zeroPad = 0.0;
            if(op.tArgs() != null && op.tArgs().length > 0){
                zeroPad = op.tArgs()[0];
            }
            val extrass = new double[]{op.iArgs()[0], op.iArgs()[1], op.iArgs()[2], op.iArgs()[3], op.iArgs()[4], op.iArgs()[5], op.iArgs()[6], op.iArgs()[7], op.iArgs()[8], zeroPad};
            val extraArgsBuff = Nd4j.getConstantHandler().getConstantBuffer(extrass, xArr.dataType());
            val extraArgs = AtomicAllocator.getInstance().getPointer(extraArgsBuff, context);

            nativeOps.execTransformSame(xShapeHost, 9,
                    null, (LongPointer) hxShape, x, (LongPointer) xShape,
                    null, (LongPointer) hzShape, z, (LongPointer) zShape, extraArgs);

            //AtomicAllocator.getInstance().getAllocationPoint(zArr).tickDeviceWrite();
            AtomicAllocator.getInstance().getFlowController().registerAction(context, zArr, xArr);

            Nd4j.getExecutioner().commit();

            return op.outputArguments();
        } else if (op.opName().equalsIgnoreCase("col2im")) {
            val dtype = Nd4j.dataType();

            val xArr = op.inputArguments()[0];
            val zArr = op.outputArguments()[0];

            CudaContext context = AtomicAllocator.getInstance().getFlowController().prepareAction(zArr, xArr);

            if (extraz.get() == null)
                extraz.set(new PointerPointer(32));

            PointerPointer xShapeHost =
                    extraz.get().put(AddressRetriever.retrieveHostPointer(xArr.shapeInfoDataBuffer()), // 0
                            context.getOldStream(), // 1
                            AtomicAllocator.getInstance().getDeviceIdPointer(), // 2
                            context.getBufferAllocation(), // 3
                            context.getBufferReduction(), // 4
                            context.getBufferScalar(), // 5
                            context.getBufferSpecial(),
                            null,
                            AddressRetriever.retrieveHostPointer(zArr.shapeInfoDataBuffer())
                    );


            val x = AtomicAllocator.getInstance().getPointer(xArr, context);
            val z = AtomicAllocator.getInstance().getPointer(zArr, context);

            val xShape = AtomicAllocator.getInstance().getPointer(xArr.shapeInfoDataBuffer(), context);
            val zShape = AtomicAllocator.getInstance().getPointer(zArr.shapeInfoDataBuffer(), context);

            val hxShape = AtomicAllocator.getInstance().getHostPointer(xArr.shapeInfoDataBuffer());
            val hzShape = AtomicAllocator.getInstance().getHostPointer(zArr.shapeInfoDataBuffer());

            val extrass = new double[]{op.iArgs()[0], op.iArgs()[1], op.iArgs()[2], op.iArgs()[3], op.iArgs()[4], op.iArgs()[5], op.iArgs()[6], op.iArgs()[7]};
            val extraArgsBuff = Nd4j.getConstantHandler().getConstantBuffer(extrass, xArr.dataType());
            val extraArgs = AtomicAllocator.getInstance().getPointer(extraArgsBuff, context);


            nativeOps.execTransformSame(xShapeHost, 8,
                    null, (LongPointer) hxShape, x, (LongPointer) xShape,
                    null, (LongPointer) hzShape, z, (LongPointer) zShape, extraArgs);

            //AtomicAllocator.getInstance().getAllocationPoint(zArr).tickDeviceWrite();
            AtomicAllocator.getInstance().getFlowController().registerAction(context, zArr, xArr);

            //Nd4j.getExecutioner().commit();
            return op.outputArguments();
        } else if (op.opName().equalsIgnoreCase("pooling2d")) {
            val dtype = Nd4j.dataType();

            val xArr = op.inputArguments()[0];
            val zArr = op.outputArguments()[0];

            CudaContext context = AtomicAllocator.getInstance().getFlowController().prepareAction(zArr, xArr);

            if (extraz.get() == null)
                extraz.set(new PointerPointer(32));

            PointerPointer xShapeHost =
                    extraz.get().put(AddressRetriever.retrieveHostPointer(xArr.shapeInfoDataBuffer()), // 0
                            context.getOldStream(), // 1
                            AtomicAllocator.getInstance().getDeviceIdPointer(), // 2
                            context.getBufferAllocation(), // 3
                            context.getBufferReduction(), // 4
                            context.getBufferScalar(), // 5
                            context.getBufferSpecial(),
                            null,
                            AddressRetriever.retrieveHostPointer(zArr.shapeInfoDataBuffer())
                    );


            val x = AtomicAllocator.getInstance().getPointer(xArr, context);
            val z = AtomicAllocator.getInstance().getPointer(zArr, context);

            val xShape = AtomicAllocator.getInstance().getPointer(xArr.shapeInfoDataBuffer(), context);
            val zShape = AtomicAllocator.getInstance().getPointer(zArr.shapeInfoDataBuffer(), context);

            val hxShape = AtomicAllocator.getInstance().getHostPointer(xArr.shapeInfoDataBuffer());
            val hzShape = AtomicAllocator.getInstance().getHostPointer(zArr.shapeInfoDataBuffer());

            val extrass = new double[]{op.iArgs()[0], op.iArgs()[1], op.iArgs()[2], op.iArgs()[3], op.iArgs()[4], op.iArgs()[5], op.iArgs()[6], op.iArgs()[7], op.iArgs()[8]};
            val extraArgsBuff = Nd4j.getConstantHandler().getConstantBuffer(extrass, zArr.dataType());
            val extraArgs = AtomicAllocator.getInstance().getPointer(extraArgsBuff, context);


            nativeOps.execTransformFloat(xShapeHost, 23,
                    null, (LongPointer) hxShape, x, (LongPointer) xShape,
                    zArr.data().addressPointer(), (LongPointer) hzShape, z, (LongPointer) zShape,
                    extraArgs);

            // AtomicAllocator.getInstance().getAllocationPoint(zArr).tickDeviceWrite();
            AtomicAllocator.getInstance().getFlowController().registerAction(context, zArr, xArr);

            return op.outputArguments();
        }

        Nd4j.getExecutioner().commit();

        val context = buildContext();

        context.markInplace(op.isInplaceCall());

        // transferring rng state
        context.setRngStates(Nd4j.getRandom().rootState(), Nd4j.getRandom().nodeState());

        //transferring input/output arrays
        context.setInputArrays(op.inputArguments());
        context.setOutputArrays(op.outputArguments());

        // transferring static args
        context.setBArguments(op.bArgs());
        context.setIArguments(op.iArgs());
        context.setTArguments(op.tArgs());

        val result = exec(op, context);
        val states = context.getRngStates();

        // pulling states back
        Nd4j.getRandom().setStates(states.getFirst(), states.getSecond());

        return result;

        /*
        long st = profilingConfigurableHookIn(op);

        CudaContext context =(CudaContext) AtomicAllocator.getInstance().getDeviceContext().getContext();
        //AtomicAllocator.getInstance().getFlowController().prepareActionAllWrite(op.outputArguments());

        if (extraz.get() == null)
            extraz.set(new PointerPointer(32));


        PointerPointer extras = extraz.get().put(
                new CudaPointer(1),
                context.getOldStream(),
                context.getBufferScalar(),
                context.getBufferReduction());

        val outputArgs = op.outputArguments();
        val inputArgs = op.inputArguments();

        if (outputArgs.length == 0 && !op.isInplaceCall())
            throw new ND4JIllegalStateException("You can't execute non-inplace CustomOp without outputs being specified");

        val lc = op.opName().toLowerCase();
        val hash = op.opHash();


        val inputShapes = new PointerPointer<>(inputArgs.length * 2);
        val inputBuffers = new PointerPointer<>(inputArgs.length * 2);

        int cnt= 0;
        for (val in: inputArgs) {
            val hp = AtomicAllocator.getInstance().getHostPointer(in.shapeInfoDataBuffer());
            inputBuffers.put(cnt,  AtomicAllocator.getInstance().getHostPointer(in));
            inputShapes.put(cnt, hp);


            val dp = AtomicAllocator.getInstance().getPointer(in.shapeInfoDataBuffer(), context);

            inputBuffers.put(cnt + inputArgs.length, AtomicAllocator.getInstance().getPointer(in, context));
            inputShapes.put(cnt+ inputArgs.length, dp);

            if (op.isInplaceCall()) {
                val ap = AtomicAllocator.getInstance().getAllocationPoint(in);
                if (ap != null)
                    ap.tickHostWrite();
            }

            cnt++;
        }


        val outputShapes = new PointerPointer<>(outputArgs.length * 2);
        val outputBuffers = new PointerPointer<>(outputArgs.length * 2);

        cnt= 0;
        for (val out: outputArgs) {
            outputBuffers.put(cnt,  AtomicAllocator.getInstance().getHostPointer(out));
            outputShapes.put(cnt,  AtomicAllocator.getInstance().getHostPointer(out.shapeInfoDataBuffer()));

            outputBuffers.put(cnt + outputArgs.length,  AtomicAllocator.getInstance().getPointer(out, context));
            outputShapes.put(cnt + outputArgs.length,  AtomicAllocator.getInstance().getPointer(out.shapeInfoDataBuffer(), context));

            val ap = AtomicAllocator.getInstance().getAllocationPoint(out);

            if (ap != null)
                ap.tickHostWrite();

            cnt++;
        }

        val iArgs = op.iArgs().length > 0 ? new LongPointer(op.iArgs().length) : null;

        cnt = 0;
        for (val i: op.iArgs())
            iArgs.put(cnt++, i);


        val tArgs = op.tArgs().length > 0 ? new DoublePointer(op.tArgs().length) : null;

        val bArgs = op.bArgs().length > 0 ? new BooleanPointer(op.numBArguments()) : null;

        cnt = 0;
        for (val t: op.tArgs())
            tArgs.put(cnt++, t);

        cnt = 0;
        for (val b: op.bArgs())
            bArgs.put(cnt++, b);

        try {
            val status = OpStatus.byNumber(nativeOps.execCustomOp(extras, hash, inputBuffers, inputShapes, inputArgs.length, outputBuffers, outputShapes, outputArgs.length, tArgs, op.tArgs().length, iArgs, op.iArgs().length, bArgs, op.numBArguments(), op.isInplaceCall()));
            if (status != OpStatus.ND4J_STATUS_OK)
                throw new ND4JIllegalStateException("Op execution failed: " + status);
        } catch (Exception e) {
            throw new RuntimeException("Op [" + op.opName() + "] execution failed");
        }

        //AtomicAllocator.getInstance().getFlowController().prepareActionAllWrite(op.outputArguments());

        profilingConfigurableHookOut(op, st);
        return op.outputArguments();
         */
    }
@ Override public INDArray [ ] exec ( CustomOp op ) { Nd4j . getExecutioner ( ) . commit ( ) ; if ( op . numOutputArguments ( ) == 0 && ! op . isInplaceCall ( ) ) { try { val list = this . calculateOutputShape ( op ) ; if ( list . isEmpty ( ) ) throw new ND4JIllegalStateException ( "Op name " + op . opName ( ) + " failed to execute. You can't execute non-inplace CustomOp without outputs being specified" ) ; for ( val shape : list ) op . addOutputArgument ( Nd4j . create ( shape ) ) ; } catch ( Exception e ) { throw new ND4JIllegalStateException ( "Op name " + op . opName ( ) + " failed to execute. You can't execute non-inplace CustomOp without outputs being specified" ) ; } } if ( op . opName ( ) . equalsIgnoreCase ( "im2col" ) ) { val xArr = op . inputArguments ( ) [ 0 ] ; val zArr = op . outputArguments ( ) [ 0 ] ; CudaContext context = AtomicAllocator . getInstance ( ) . getFlowController ( ) . prepareAction ( zArr , xArr ) ; if ( extraz . get ( ) == null ) extraz . set ( new PointerPointer ( 32 ) ) ; PointerPointer xShapeHost = extraz . get ( ) . put ( AddressRetriever . retrieveHostPointer ( xArr . shapeInfoDataBuffer ( ) ) , context . getOldStream ( ) , AtomicAllocator . getInstance ( ) . getDeviceIdPointer ( ) , context . getBufferAllocation ( ) , context . getBufferReduction ( ) , context . getBufferScalar ( ) , context . getBufferSpecial ( ) , null , AddressRetriever . retrieveHostPointer ( zArr . shapeInfoDataBuffer ( ) ) ) ; val x = AtomicAllocator . getInstance ( ) . getPointer ( xArr , context ) ; val z = AtomicAllocator . getInstance ( ) . getPointer ( zArr , context ) ; val xShape = AtomicAllocator . getInstance ( ) . getPointer ( xArr . shapeInfoDataBuffer ( ) , context ) ; val zShape = AtomicAllocator . getInstance ( ) . getPointer ( zArr . shapeInfoDataBuffer ( ) , context ) ; val hxShape = AtomicAllocator . getInstance ( ) . getHostPointer ( xArr . shapeInfoDataBuffer ( ) ) ; val hzShape = AtomicAllocator . getInstance ( ) . getHostPointer ( zArr . shapeInfoDataBuffer ( ) ) ; double zeroPad = 0.0 ; if ( op . tArgs ( ) != null && op . tArgs ( ) . length > 0 ) { zeroPad = op . tArgs ( ) [ 0 ] ; } val extrass = new double [ ] { op . iArgs ( ) [ 0 ] , op . iArgs ( ) [ 1 ] , op . iArgs ( ) [ 2 ] , op . iArgs ( ) [ 3 ] , op . iArgs ( ) [ 4 ] , op . iArgs ( ) [ 5 ] , op . iArgs ( ) [ 6 ] , op . iArgs ( ) [ 7 ] , op . iArgs ( ) [ 8 ] , zeroPad } ; val extraArgsBuff = Nd4j . getConstantHandler ( ) . getConstantBuffer ( extrass , xArr . dataType ( ) ) ; val extraArgs = AtomicAllocator . getInstance ( ) . getPointer ( extraArgsBuff , context ) ; nativeOps . execTransformSame ( xShapeHost , 9 , null , ( LongPointer ) hxShape , x , ( LongPointer ) xShape , null , ( LongPointer ) hzShape , z , ( LongPointer ) zShape , extraArgs ) ; AtomicAllocator . getInstance ( ) . getFlowController ( ) . registerAction ( context , zArr , xArr ) ; Nd4j . getExecutioner ( ) . commit ( ) ; return op . outputArguments ( ) ; } else if ( op . opName ( ) . equalsIgnoreCase ( "col2im" ) ) { val dtype = Nd4j . dataType ( ) ; val xArr = op . inputArguments ( ) [ 0 ] ; val zArr = op . outputArguments ( ) [ 0 ] ; CudaContext context = AtomicAllocator . getInstance ( ) . getFlowController ( ) . prepareAction ( zArr , xArr ) ; if ( extraz . get ( ) == null ) extraz . set ( new PointerPointer ( 32 ) ) ; PointerPointer xShapeHost = extraz . get ( ) . put ( AddressRetriever . retrieveHostPointer ( xArr . shapeInfoDataBuffer ( ) ) , context . getOldStream ( ) , AtomicAllocator . getInstance ( ) . getDeviceIdPointer ( ) , context . getBufferAllocation ( ) , context . getBufferReduction ( ) , context . getBufferScalar ( ) , context . getBufferSpecial ( ) , null , AddressRetriever . retrieveHostPointer ( zArr . shapeInfoDataBuffer ( ) ) ) ; val x = AtomicAllocator . getInstance ( ) . getPointer ( xArr , context ) ; val z = AtomicAllocator . getInstance ( ) . getPointer ( zArr , context ) ; val xShape = AtomicAllocator . getInstance ( ) . getPointer ( xArr . shapeInfoDataBuffer ( ) , context ) ; val zShape = AtomicAllocator . getInstance ( ) . getPointer ( zArr . shapeInfoDataBuffer ( ) , context ) ; val hxShape = AtomicAllocator . getInstance ( ) . getHostPointer ( xArr . shapeInfoDataBuffer ( ) ) ; val hzShape = AtomicAllocator . getInstance ( ) . getHostPointer ( zArr . shapeInfoDataBuffer ( ) ) ; val extrass = new double [ ] { op . iArgs ( ) [ 0 ] , op . iArgs ( ) [ 1 ] , op . iArgs ( ) [ 2 ] , op . iArgs ( ) [ 3 ] , op . iArgs ( ) [ 4 ] , op . iArgs ( ) [ 5 ] , op . iArgs ( ) [ 6 ] , op . iArgs ( ) [ 7 ] } ; val extraArgsBuff = Nd4j . getConstantHandler ( ) . getConstantBuffer ( extrass , xArr . dataType ( ) ) ; val extraArgs = AtomicAllocator . getInstance ( ) . getPointer ( extraArgsBuff , context ) ; nativeOps . execTransformSame ( xShapeHost , 8 , null , ( LongPointer ) hxShape , x , ( LongPointer ) xShape , null , ( LongPointer ) hzShape , z , ( LongPointer ) zShape , extraArgs ) ; AtomicAllocator . getInstance ( ) . getFlowController ( ) . registerAction ( context , zArr , xArr ) ; return op . outputArguments ( ) ; } else if ( op . opName ( ) . equalsIgnoreCase ( "pooling2d" ) ) { val dtype = Nd4j . dataType ( ) ; val xArr = op . inputArguments ( ) [ 0 ] ; val zArr = op . outputArguments ( ) [ 0 ] ; CudaContext context = AtomicAllocator . getInstance ( ) . getFlowController ( ) . prepareAction ( zArr , xArr ) ; if ( extraz . get ( ) == null ) extraz . set ( new PointerPointer ( 32 ) ) ; PointerPointer xShapeHost = extraz . get ( ) . put ( AddressRetriever . retrieveHostPointer ( xArr . shapeInfoDataBuffer ( ) ) , context . getOldStream ( ) , AtomicAllocator . getInstance ( ) . getDeviceIdPointer ( ) , context . getBufferAllocation ( ) , context . getBufferReduction ( ) , context . getBufferScalar ( ) , context . getBufferSpecial ( ) , null , AddressRetriever . retrieveHostPointer ( zArr . shapeInfoDataBuffer ( ) ) ) ; val x = AtomicAllocator . getInstance ( ) . getPointer ( xArr , context ) ; val z = AtomicAllocator . getInstance ( ) . getPointer ( zArr , context ) ; val xShape = AtomicAllocator . getInstance ( ) . getPointer ( xArr . shapeInfoDataBuffer ( ) , context ) ; val zShape = AtomicAllocator . getInstance ( ) . getPointer ( zArr . shapeInfoDataBuffer ( ) , context ) ; val hxShape = AtomicAllocator . getInstance ( ) . getHostPointer ( xArr . shapeInfoDataBuffer ( ) ) ; val hzShape = AtomicAllocator . getInstance ( ) . getHostPointer ( zArr . shapeInfoDataBuffer ( ) ) ; val extrass = new double [ ] { op . iArgs ( ) [ 0 ] , op . iArgs ( ) [ 1 ] , op . iArgs ( ) [ 2 ] , op . iArgs ( ) [ 3 ] , op . iArgs ( ) [ 4 ] , op . iArgs ( ) [ 5 ] , op . iArgs ( ) [ 6 ] , op . iArgs ( ) [ 7 ] , op . iArgs ( ) [ 8 ] } ; val extraArgsBuff = Nd4j . getConstantHandler ( ) . getConstantBuffer ( extrass , zArr . dataType ( ) ) ; val extraArgs = AtomicAllocator . getInstance ( ) . getPointer ( extraArgsBuff , context ) ; nativeOps . execTransformFloat ( xShapeHost , 23 , null , ( LongPointer ) hxShape , x , ( LongPointer ) xShape , zArr . data ( ) . addressPointer ( ) , ( LongPointer ) hzShape , z , ( LongPointer ) zShape , extraArgs ) ; AtomicAllocator . getInstance ( ) . getFlowController ( ) . registerAction ( context , zArr , xArr ) ; return op . outputArguments ( ) ; } Nd4j . getExecutioner ( ) . commit ( ) ; val context = buildContext ( ) ; context . markInplace ( op . isInplaceCall ( ) ) ; context . setRngStates ( Nd4j . getRandom ( ) . rootState ( ) , Nd4j . getRandom ( ) . nodeState ( ) ) ; context . setInputArrays ( op . inputArguments ( ) ) ; context . setOutputArrays ( op . outputArguments ( ) ) ; context . setBArguments ( op . bArgs ( ) ) ; context . setIArguments ( op . iArgs ( ) ) ; context . setTArguments ( op . tArgs ( ) ) ; val result = exec ( op , context ) ; val states = context . getRngStates ( ) ; Nd4j . getRandom ( ) . setStates ( states . getFirst ( ) , states . getSecond ( ) ) ; return result ; }
This method executes given CustomOp

PLEASE NOTE: You're responsible for input/output validation
PLEASE NOTE: right now this operations are executing on CPU
@param op