daphne-eu / daphne

DAPHNE: An Open and Extensible System Infrastructure for Integrated Data Analysis Pipelines
Apache License 2.0
67 stars 62 forks source link

[DAPHNE-#768] isNan: elementwise check for NaN elements in a matrix - Draft PR #779

Closed StoeckOverflow closed 4 months ago

StoeckOverflow commented 4 months ago

This Draft PR introduces the isNan function to the Daphne project, enabling element-wise NaN checks on matrices (see issue #768) . The function has been implemented and successfully tested in C++ unit tests.

However, there is an issue with invoking the isNan function from a Daphne script, which needs to be resolved.

Implemented Features

Issues

The current implementation works in C++ unit tests but fails when invoked from a Daphne script with the following error:


bin/daphne test/api/cli/operations/isNan_1.daphne

[error]: Lowering pipeline error.RewriteToCallKernelOpPass failed with the following message [ no kernels registered for operation `ewIsNan` ]
    | Source file -> "/home/domin/daphne/test/api/cli/operations/isNan_1.daphne":1:6
    |
  1 | print(isNan(3));
    |       ^~~

PassManager failed module lowering, responsible IR written to module_fail.log.

This is the module_fail.log:

module {
  func.func @main() {
    %0 = "daphne.constant"() {value = 3 : si64} : () -> si64
    %1 = "daphne.constant"() {value = true} : () -> i1
    %2 = "daphne.constant"() {value = false} : () -> i1
    %3 = "daphne.constant"() {value = 0x7FF8000000000000 : f64} : () -> f64
    %4 = "daphne.constant"() {value = 94808314720080 : ui64} : () -> ui64
    %5 = "daphne.constant"() {value = 1 : index} : () -> index
    %6 = "daphne.constant"() {value = 6 : index} : () -> index
    %7 = "daphne.constant"() {value = 94808303431520 : ui64} : () -> ui64
    %8 = "daphne.constant"() {value = 94808303431392 : ui64} : () -> ui64
    %9 = "daphne.constant"() {value = 140725113146728 : ui64} : () -> ui64
    %c0_i32 = arith.constant 0 : i32
    %10 = "daphne.call_kernel"(%9, %8, %7, %c0_i32) {callee = "_createDaphneContext__DaphneContext__uint64_t__uint64_t__uint64_t"} : (ui64, ui64, ui64, i32) -> !daphne.DaphneContext
    %11 = "daphne.createDaphneContext"(%9, %8, %7) : (ui64, ui64, ui64) -> !daphne.DaphneContext
    %12 = "daphne.ewIsNan"(%0) : (si64) -> si64
    "daphne.print"(%12, %1, %2) : (si64, i1, i1) -> ()
    %13 = "daphne.ewIsNan"(%3) : (f64) -> f64
    "daphne.print"(%13, %1, %2) : (f64, i1, i1) -> ()
    %14 = "daphne.matrixConstant"(%4) : (ui64) -> !daphne.Matrix<6x1xf64>
    %15 = "daphne.reshape"(%14, %6, %5) : (!daphne.Matrix<6x1xf64>, index, index) -> !daphne.Matrix<6x1xf64>
    "daphne.decRef"(%14) : (!daphne.Matrix<6x1xf64>) -> ()
    %16 = "daphne.transpose"(%15) : (!daphne.Matrix<6x1xf64>) -> !daphne.Matrix<1x6xf64>
    "daphne.decRef"(%15) : (!daphne.Matrix<6x1xf64>) -> ()
    %17 = "daphne.ewIsNan"(%16) : (!daphne.Matrix<1x6xf64>) -> !daphne.Matrix<1x6xf64>
    "daphne.decRef"(%16) : (!daphne.Matrix<1x6xf64>) -> ()
    "daphne.print"(%17, %1, %2) : (!daphne.Matrix<1x6xf64>, i1, i1) -> ()
    "daphne.decRef"(%17) : (!daphne.Matrix<1x6xf64>) -> ()
    "daphne.destroyDaphneContext"() : () -> ()
    "daphne.return"() : () -> ()
  }
}

Next Steps and Feedback

I am currently investigating the kernel registration issue and ensuring proper integration. Any insights or suggestions on this matter would be greatly appreciated. Thank you for your time and assistance in reviewing this PR.

pdamme commented 4 months ago

Hi @StoeckOverflow, thanks for this pull request!

The error message [ no kernels registered for operation `ewIsNan` ] indicates that DAPHNE looks for a kernel that is registered for the operation ewIsNan (case-sensitive). However, the kernel catalog (materialized in lib/catalog.json) contains kernels for the operation ewIsnan. The simplest solution is to change the mnemonic of the DaphneIR operation to ewIsnan in src/ir/daphneir/DaphneOps.td.


For some background: The catalog file is generated automatically by src/runtime/local/kernels/genKernelInst.py from the information in src/runtime/local/kernels.json. In the latter file, we specify the op codes of the elementwise unary operations to pre-compile like they are spelled in the respective C++ enum, i.e., in upper case letters. When deriving the DaphneIR operation names, genKernelInst.py (line 153) takes the first letter in upper case and all remaining letter in lower case, which makes sense for virtually all op codes.

StoeckOverflow commented 4 months ago

Hi @pdamme, Thank you for your detailed explanation!

I have implemented the suggested change by modifying the mnemonic of the DaphneIR operation to ewIsnan in src/ir/daphneir/DaphneOps.td. I am pleased to report that this has resolved the issue. All tests have passed successfully, and the pull request is now ready for review.