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

Fix for Parenthesis issue in gradients #1180

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

toshit3q34
Copy link

This resolves the issue with two or more consecutive negative signs while dumping the code.
While copying the code to m_Code, changes include iterating the loop and checking when there are two or more consecutive negative signs and resolves them to be either '-' or ' ' depending on the parity.

Eg.
-(-(-1))*(x)
Before : _d_x += - - -1 * 1;
After : _d_x += -1 * 1;

The differentiate remains intact.
Fixes : #1098

// Fixes consecutive negative signs
// (-1)*(-x) gives *_d_x += 1 * 1; instead of
// *_d_x += --1 * 1;
CUDA_HOST_DEVICE void ResolveParenthesis(char* temp, const char* code) {
Copy link
Owner

Choose a reason for hiding this comment

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

We do not do textual parsing and transformations. The solution must be on AST level in one of our Visitor classes. You should check our documentation for more details.

to.emplace_back(val);
return val;
}
/// Add value to the end of the tape, return the same value.
Copy link
Owner

Choose a reason for hiding this comment

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

Running clang-format on the entire file is not a good idea. We should run it only on the changes with git-clang-format HEAD~.

@toshit3q34
Copy link
Author

@vgvassilev Thanks! I went through the documentation and have fixed the issue in the BuildParens function of VisitorBase class. The tests compile without a problem but CHECK-NEXT shows error in 5 tests due to mistmaching body statements.
Example :
Expected : -_d_x * x + -x * _d_x
After the changes : (-_d_x) * x + (-x) * _d_x

What should be done to deal with such instances or those 5 tests need to be changed ?

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 83. Check the log or trigger a new build to see more.

#include <cstring>
#include <stddef.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead [modernize-deprecated-headers]

Suggested change
#include <stddef.h>
#include <cstddef>

// Fixes consecutive negative signs
// (-1)*(-x) gives *_d_x += 1 * 1; instead of
// *_d_x += --1 * 1;
CUDA_HOST_DEVICE void ResolveParenthesis(char* temp, const char* code) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: function 'ResolveParenthesis' defined in a header file; function definitions in header files can lead to ODR violations [misc-definitions-in-headers]

CUDA_HOST_DEVICE void ResolveParenthesis(char* temp, const char* code) {
                      ^
Additional context

include/clad/Differentiator/Differentiator.h:46: make as 'inline'

CUDA_HOST_DEVICE void ResolveParenthesis(char* temp, const char* code) {
                      ^

if (*code == '-') {
current_block = 1;
negative_sign_count ^= 1;
code++;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

      code++;
          ^

}
if (current_block && *code != ' ') {
if (negative_sign_count == 1) {
*temp++ = '-';
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

        *temp++ = '-';
             ^

if (negative_sign_count == 1) {
*temp++ = '-';
if (*code == '(')
*temp++ = ' ';
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

          *temp++ = ' ';
               ^

negative_sign_count = 0;
}
if (current_block && *code == ' ') {
code++;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

      code++;
          ^

code++;
continue;
}
*temp++ = *code++;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

    *temp++ = *code++;
                   ^

code++;
continue;
}
*temp++ = *code++;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

    *temp++ = *code++;
         ^

/// N.
template <typename T> CUDA_HOST_DEVICE void zero_init(T* x, std::size_t N) {
for (std::size_t i = 0; i < N; ++i)
zero_init(x[i]);
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

    zero_init(x[i]);
              ^

/// Initialize a const sized array.
// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays)
template <typename T, std::size_t N>
CUDA_HOST_DEVICE void zero_init(T (&arr)[N]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]

CUDA_HOST_DEVICE void zero_init(T (&arr)[N]) {
                                ^

@toshit3q34 toshit3q34 marked this pull request as draft December 21, 2024 22:20
@toshit3q34 toshit3q34 force-pushed the Fix_parenthesis_in_gradient branch from 7b900b8 to 9461931 Compare December 22, 2024 17:24
@toshit3q34 toshit3q34 marked this pull request as ready for review December 22, 2024 17:25
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

return m_Sema.BuildUnaryOp(nullptr, OpLoc, OpCode, E).get();
}
Expr* VisitorBase::RemoveFirstUnaryMinus(Expr* E, SourceLocation OpLoc) {
if (auto* UO = llvm::dyn_cast<UnaryOperator>(E)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "llvm::dyn_cast" is directly included [misc-include-cleaner]

    if (auto* UO = llvm::dyn_cast<UnaryOperator>(E)) {
                         ^

return UO->getSubExpr();
}
if (auto* BO = llvm::dyn_cast<BinaryOperator>(E)) {
if (BO->getOpcode() == BO_Mul || BO->getOpcode() == BO_Div) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "clang::BO_Div" is directly included [misc-include-cleaner]

      if (BO->getOpcode() == BO_Mul || BO->getOpcode() == BO_Div) {
                                                          ^

return UO->getSubExpr();
}
if (auto* BO = llvm::dyn_cast<BinaryOperator>(E)) {
if (BO->getOpcode() == BO_Mul || BO->getOpcode() == BO_Div) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "clang::BO_Mul" is directly included [misc-include-cleaner]

      if (BO->getOpcode() == BO_Mul || BO->getOpcode() == BO_Div) {
                             ^

Copy link

codecov bot commented Dec 22, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 94.57%. Comparing base (3e50707) to head (f26b5bf).
Report is 31 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           master    #1180    +/-   ##
========================================
  Coverage   94.56%   94.57%            
========================================
  Files          51       51            
  Lines        8960     8845   -115     
========================================
- Hits         8473     8365   -108     
+ Misses        487      480     -7     
Files with missing lines Coverage Δ
include/clad/Differentiator/VisitorBase.h 100.00% <ø> (ø)
lib/Differentiator/VisitorBase.cpp 97.73% <100.00%> (+0.04%) ⬆️

... and 20 files with indirect coverage changes

Files with missing lines Coverage Δ
include/clad/Differentiator/VisitorBase.h 100.00% <ø> (ø)
lib/Differentiator/VisitorBase.cpp 97.73% <100.00%> (+0.04%) ⬆️

... and 20 files with indirect coverage changes

@toshit3q34
Copy link
Author

toshit3q34 commented Dec 22, 2024

@vgvassilev Codecov test is failing because there is no test to check those lines.
Example : f(x) = (-1) * (-x)
So should I add a file for such tests ?

return m_Sema.BuildUnaryOp(nullptr, OpLoc, OpCode, E).get();
}
Expr* VisitorBase::RemoveFirstUnaryMinus(Expr* E, SourceLocation OpLoc) {
Copy link
Owner

Choose a reason for hiding this comment

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

Rather than removing the minus we should figure out where we synthesize the minus and we need parens.

Copy link
Author

Choose a reason for hiding this comment

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

I tried to do that at first and was able to do it as well. However for some cases like :
f(x) = (-(-1)) * (-(-(x))) if we try to parenthesize, the output becomes (-(-(-(-1))*1)) which looks quite cluttered and redundant. Similar thing also happens when we try for higher powers like
f(x) = (-1) * (-x) * (-x) * (-x)
Would you recommend continuing to parenthesize in such cases, or would it be acceptable to simplify the representation for clarity?

Copy link
Owner

Choose a reason for hiding this comment

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

It's better to add parenthesis only at the places where it is necessary.

Copy link
Author

Choose a reason for hiding this comment

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

Okay sure. Can you please specify the expected output of f_grad() for f(x) = (-(-1)) * (-(-(x))) so that I have a basis to work with and can modify accordingly. Thanks.

@toshit3q34 toshit3q34 force-pushed the Fix_parenthesis_in_gradient branch from 9461931 to f086371 Compare December 25, 2024 15:55
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@toshit3q34
Copy link
Author

@vgvassilev I hope you have reviewed the code. I have done the following two things :

  1. Reduce unary minus when done on the same operand to avoid clutter. example : ---2 becomes -2
  2. Add parenthesis when unary minus is added in front of compound statement as asked before.
    example : --1*x becomes -(-1*x)

The codecov tests fail because there are no tests which check either of the above conditions.
Is there anything else that I need to change ?

@vgvassilev
Copy link
Owner

Can you add a few tests demonstrating this pull request works?

@toshit3q34 toshit3q34 force-pushed the Fix_parenthesis_in_gradient branch from f086371 to f26b5bf Compare January 10, 2025 18:25
@toshit3q34
Copy link
Author

@vgvassilev I have added a test file containing two tests which covers the above stated scenarios. You may review it now.

Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

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.

Incorrect gradient differentiating parenthesis
2 participants