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

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

Merged
merged 7 commits into from
Jul 11, 2024

Conversation

StoeckOverflow
Copy link
Contributor

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

  • Created an IsNanOp operation in DaphneIR as a subclass of EwUnaryOp (elementwise unary operation) (see src/ir/daphneir/DaphneOps.td).
  • Created a DaphneDSL built-in function isNan and documented it (see src/parser/daphnedsl/DaphneDSLBuiltins.cpp and doc/DaphneDSL/Builtins.md).
  • Created a DaphneLib function isNan for matrices and scalars and documented it (see src/api/python/daphne/operator/nodes/matrix.py, src/api/python/daphne/operator/nodes/scalar.py, and doc/DaphneLib/APIRef.md).
  • Created a runtime kernel for isNan by extending the existing ewUnaryMat and ewUnarySca kernel with a new op code (see src/runtime/local/kernels/EwUnaryMat.h).
  • Added unit test cases for the kernel and script-level test cases for DaphneDSL and DaphneLib.

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
Copy link
Collaborator

pdamme commented Jul 9, 2024

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 StoeckOverflow marked this pull request as ready for review July 9, 2024 22:06
@StoeckOverflow
Copy link
Contributor Author

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.

@pdamme pdamme self-requested a review July 11, 2024 20:53
- Renamed the new category of unary ops to "Comparison".
- Removed special floating-point values like nan and inf from test cases with integer value types.
- Removed comment on missing isNan() from guidelines on porting from Numpy to DaphneLib.
- Some more minor changes.
Copy link
Collaborator

@pdamme pdamme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating this PR, @StoeckOverflow. Your code looks very good to me. Well done! I applied just a few minor changes, e.g., renaming the new category of elementwise unary operations from "other utilities" to "comparison" (makes more sense and is consistent with the same class of binary ops). Please have a look at the commit I added to see the details.

This PR is ready to be merged. Congrats on your first (*) contribution to the DAPHNE code base! Looking forward to your future contributions.


(*) We will merge your earlier PR #608 later...

@pdamme pdamme merged commit 29fd7b9 into daphne-eu:main Jul 11, 2024
2 checks passed
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

Successfully merging this pull request may close these issues.

2 participants