diff --git a/include/clad/Differentiator/Array.h b/include/clad/Differentiator/Array.h index 5be12ff3f..7bd7ab5e1 100644 --- a/include/clad/Differentiator/Array.h +++ b/include/clad/Differentiator/Array.h @@ -154,7 +154,7 @@ template class array { return *this; } /// Initializes the clad::array to the given clad::array_ref - CUDA_HOST_DEVICE array& operator=(array_ref& arr) { + CUDA_HOST_DEVICE array& operator=(const array_ref& arr) { assert(arr.size() == m_size); for (std::size_t i = 0; i < m_size; i++) m_arr[i] = arr[i]; @@ -162,7 +162,7 @@ template class array { } template - CUDA_HOST_DEVICE array& operator=(array_ref& arr) { + CUDA_HOST_DEVICE array& operator=(const array_ref& arr) { assert(arr.size() == m_size); for (std::size_t i = 0; i < m_size; i++) m_arr[i] = arr[i]; @@ -170,28 +170,28 @@ template class array { } /// Performs element wise addition - CUDA_HOST_DEVICE array& operator+=(array_ref& arr) { + CUDA_HOST_DEVICE array& operator+=(const array_ref& arr) { assert(arr.size() == m_size); for (std::size_t i = 0; i < m_size; i++) m_arr[i] += arr[i]; return *this; } /// Performs element wise subtraction - CUDA_HOST_DEVICE array& operator-=(array_ref& arr) { + CUDA_HOST_DEVICE array& operator-=(const array_ref& arr) { assert(arr.size() == m_size); for (std::size_t i = 0; i < m_size; i++) m_arr[i] -= arr[i]; return *this; } /// Performs element wise multiplication - CUDA_HOST_DEVICE array& operator*=(array_ref& arr) { + CUDA_HOST_DEVICE array& operator*=(const array_ref& arr) { assert(arr.size() == m_size); for (std::size_t i = 0; i < m_size; i++) m_arr[i] *= arr[i]; return *this; } /// Performs element wise division - CUDA_HOST_DEVICE array& operator/=(array_ref& arr) { + CUDA_HOST_DEVICE array& operator/=(const array_ref& arr) { assert(arr.size() == m_size); for (std::size_t i = 0; i < m_size; i++) m_arr[i] /= arr[i]; diff --git a/include/clad/Differentiator/ArrayRef.h b/include/clad/Differentiator/ArrayRef.h index 042d0cb82..8a4aa4988 100644 --- a/include/clad/Differentiator/ArrayRef.h +++ b/include/clad/Differentiator/ArrayRef.h @@ -33,7 +33,8 @@ template class array_ref { /// Constructor for clad::array types CUDA_HOST_DEVICE array_ref(array& a) : m_arr(a.ptr()), m_size(a.size()) {} - template CUDA_HOST_DEVICE array_ref& operator=(array& a) { + template + CUDA_HOST_DEVICE array_ref& operator=(const array& a) { assert(m_size == a.size()); for (std::size_t i = 0; i < m_size; ++i) m_arr[i] = a[i]; @@ -53,6 +54,7 @@ template class array_ref { /// Returns the reference to the location at the index of the underlying /// array CUDA_HOST_DEVICE T& operator[](std::size_t i) { return m_arr[i]; } + CUDA_HOST_DEVICE const T& operator[](std::size_t i) const { return m_arr[i]; } /// Returns the reference to the underlying array CUDA_HOST_DEVICE T& operator*() { return *m_arr; } @@ -156,6 +158,116 @@ template class array_ref { } }; +/// Overloaded operators for clad::array_ref which returns a new clad::array +/// object. + +/// Multiplies the arrays element wise +template +CUDA_HOST_DEVICE array operator*(const array_ref& Ar, + const array_ref& Br) { + assert(Ar.size() == Br.size() && + "Size of both the array_refs must be equal for carrying out addition " + "assignment"); + array C(Ar); + C *= Br; + return C; +} + +/// Adds the arrays element wise +template +CUDA_HOST_DEVICE array operator+(const array_ref& Ar, + const array_ref& Br) { + assert(Ar.size() == Br.size() && + "Size of both the array_refs must be equal for carrying out addition " + "assignment"); + array C(Ar); + C += Br; + return C; +} + +/// Subtracts the arrays element wise +template +CUDA_HOST_DEVICE array operator-(const array_ref& Ar, + const array_ref& Br) { + assert(Ar.size() == Br.size() && + "Size of both the array_refs must be equal for carrying out addition " + "assignment"); + array C(Ar); + C -= Br; + return C; +} + +/// Divides the arrays element wise +template +CUDA_HOST_DEVICE array operator/(const array_ref& Ar, + const array_ref& Br) { + assert(Ar.size() == Br.size() && + "Size of both the array_refs must be equal for carrying out addition " + "assignment"); + array C(Ar); + C /= Br; + return C; +} + +/// Multiplies array_ref by a scalar +template ::value, int>::type = 0> +CUDA_HOST_DEVICE array operator*(const array_ref& Ar, U a) { + array C(Ar); + C *= a; + return C; +} + +/// Multiplies array_ref by a scalar (reverse order) +template ::value, int>::type = 0> +CUDA_HOST_DEVICE array operator*(U a, const array_ref& Ar) { + return Ar * a; +} + +/// Divides array_ref by a scalar +template ::value, int>::type = 0> +CUDA_HOST_DEVICE array operator/(const array_ref& Ar, U a) { + array C(Ar); + C /= a; + return C; +} + +/// Adds array_ref by a scalar +template ::value, int>::type = 0> +CUDA_HOST_DEVICE array operator+(const array_ref& Ar, U a) { + array C(Ar); + C += a; + return C; +} + +/// Adds array_ref by a scalar (reverse order) +template ::value, int>::type = 0> +CUDA_HOST_DEVICE array operator+(U a, const array_ref& Ar) { + return Ar + a; +} + +/// Subtracts array_ref by a scalar +template ::value, int>::type = 0> +CUDA_HOST_DEVICE array operator-(const array_ref& Ar, U a) { + array C(Ar); + C -= a; + return C; +} + +/// Subtracts array_ref by a scalar (reverse order) +template ::value, int>::type = 0> +CUDA_HOST_DEVICE array operator-(U a, const array_ref& Ar) { + array C(Ar.size(), a); + C -= Ar; + return C; +} + /// `array_ref` specialisation is created to be used as a placeholder /// type in the overloaded derived function. All `array_ref` types are /// implicitly convertible to `array_ref` type. diff --git a/include/clad/Differentiator/BaseForwardModeVisitor.h b/include/clad/Differentiator/BaseForwardModeVisitor.h index 1331beee6..068d2170d 100644 --- a/include/clad/Differentiator/BaseForwardModeVisitor.h +++ b/include/clad/Differentiator/BaseForwardModeVisitor.h @@ -39,7 +39,8 @@ class BaseForwardModeVisitor static bool IsDifferentiableType(clang::QualType T); - StmtDiff VisitArraySubscriptExpr(const clang::ArraySubscriptExpr* ASE); + virtual StmtDiff + VisitArraySubscriptExpr(const clang::ArraySubscriptExpr* ASE); StmtDiff VisitBinaryOperator(const clang::BinaryOperator* BinOp); StmtDiff VisitCallExpr(const clang::CallExpr* CE); StmtDiff VisitCompoundStmt(const clang::CompoundStmt* CS); diff --git a/include/clad/Differentiator/Differentiator.h b/include/clad/Differentiator/Differentiator.h index ac59cfbd3..b59f77189 100644 --- a/include/clad/Differentiator/Differentiator.h +++ b/include/clad/Differentiator/Differentiator.h @@ -206,7 +206,6 @@ namespace clad { else return ""; } - void dump() const { printf("The code is: \n%s\n", getCode()); } diff --git a/include/clad/Differentiator/FunctionTraits.h b/include/clad/Differentiator/FunctionTraits.h index fbb57f882..72cab7438 100644 --- a/include/clad/Differentiator/FunctionTraits.h +++ b/include/clad/Differentiator/FunctionTraits.h @@ -719,8 +719,10 @@ namespace clad { using ExtractDerivedFnTraitsForwMode_t = typename ExtractDerivedFnTraitsForwMode::type; + // OutputVecParamType is used to deduce the type of derivative arguments + // for vector forward mode. template struct OutputVecParamType { - using type = typename std::add_pointer::type; + using type = array_ref::type>; }; template diff --git a/include/clad/Differentiator/VectorForwardModeVisitor.h b/include/clad/Differentiator/VectorForwardModeVisitor.h index b0456e4f1..a5a21d13a 100644 --- a/include/clad/Differentiator/VectorForwardModeVisitor.h +++ b/include/clad/Differentiator/VectorForwardModeVisitor.h @@ -16,6 +16,11 @@ class VectorForwardModeVisitor : public BaseForwardModeVisitor { /// m_Variables map because all other intermediate variables will have /// derivatives as vectors. std::unordered_map m_ParamVariables; + /// Expression for total number of independent variables. This also includes + /// the size of array independent variables which will be inferred from the + /// size of the corresponding clad array they provide at runtime for storing + /// the derivatives. + clang::Expr* m_IndVarCountExpr; public: VectorForwardModeVisitor(DerivativeBuilder& builder); @@ -68,6 +73,8 @@ class VectorForwardModeVisitor : public BaseForwardModeVisitor { /// For example: for size = 4, the returned expression is: {0, 0, 0, 0} clang::Expr* getZeroInitListExpr(size_t size, clang::QualType type); + StmtDiff + VisitArraySubscriptExpr(const clang::ArraySubscriptExpr* ASE) override; StmtDiff VisitReturnStmt(const clang::ReturnStmt* RS) override; // Decl is not Stmt, so it cannot be visited directly. VarDeclDiff DifferentiateVarDecl(const clang::VarDecl* VD) override; diff --git a/include/clad/Differentiator/VisitorBase.h b/include/clad/Differentiator/VisitorBase.h index e9118481f..ef609f395 100644 --- a/include/clad/Differentiator/VisitorBase.h +++ b/include/clad/Differentiator/VisitorBase.h @@ -483,6 +483,16 @@ namespace clad { clang::TemplateDecl* GetCladArrayDecl(); /// Create clad::array type. clang::QualType GetCladArrayOfType(clang::QualType T); + /// Find declaration of clad::matrix templated type. + clang::TemplateDecl* GetCladMatrixDecl(); + /// Create clad::matrix type. + clang::QualType GetCladMatrixOfType(clang::QualType T); + /// Creates the expression clad::matrix::identity(Args) for the given + /// type and args. + clang::Expr* + BuildIdentityMatrixExpr(clang::QualType T, + llvm::MutableArrayRef Args, + clang::SourceLocation Loc); /// Creates the expression Base.size() for the given Base expr. The Base /// expr must be of clad::array_ref type clang::Expr* BuildArrayRefSizeExpr(clang::Expr* Base); diff --git a/lib/Differentiator/VectorForwardModeVisitor.cpp b/lib/Differentiator/VectorForwardModeVisitor.cpp index e05a83463..039c6c083 100644 --- a/lib/Differentiator/VectorForwardModeVisitor.cpp +++ b/lib/Differentiator/VectorForwardModeVisitor.cpp @@ -11,7 +11,7 @@ using namespace clang; namespace clad { VectorForwardModeVisitor::VectorForwardModeVisitor(DerivativeBuilder& builder) - : BaseForwardModeVisitor(builder) {} + : BaseForwardModeVisitor(builder), m_IndVarCountExpr(nullptr) {} VectorForwardModeVisitor::~VectorForwardModeVisitor() {} @@ -51,10 +51,16 @@ VectorForwardModeVisitor::DeriveVectorMode(const FunctionDecl* FD, if (it == std::end(args)) continue; // This parameter is not in the diff list. - QualType ValueType = utils::GetValueType(PVD->getType()); - ValueType.removeLocalConst(); - // Generate pointer type for the derivative. - QualType dParamType = m_Context.getPointerType(ValueType); + QualType valueType = utils::GetValueType(PVD->getType()); + valueType.removeLocalConst(); + QualType dParamType; + if (utils::isArrayOrPointerType(PVD->getType())) { + // Generate array reference type for the derivative. + dParamType = GetCladArrayRefOfType(valueType); + } else { + // Generate pointer type for the derivative. + dParamType = m_Context.getPointerType(valueType); + } paramTypes.push_back(dParamType); } @@ -91,23 +97,84 @@ VectorForwardModeVisitor::DeriveVectorMode(const FunctionDecl* FD, beginScope(Scope::FnScope | Scope::DeclScope); m_DerivativeFnScope = getCurrentScope(); beginBlock(); + + // Instantiate a variable indepVarCount to store the total number of + // independent variables requested. + // size_t indepVarCount = m_IndVarCountExpr; + auto* totalIndVars = BuildVarDecl(m_Context.UnsignedLongTy, "indepVarCount", + m_IndVarCountExpr); + addToCurrentBlock(BuildDeclStmt(totalIndVars)); + m_IndVarCountExpr = BuildDeclRef(totalIndVars); + + // Expression for maintaining the number of independent variables processed + // till now present as array elements. This will be sum of sizes of all such + // arrays. + Expr* arrayIndVarCountExpr = nullptr; + + // Number of non-array independent variables processed till now. + size_t nonArrayIndVarCount = 0; + + // Current Index of independent variable in the param list of the function. size_t independentVarIndex = 0; + for (size_t i = 0; i < m_Function->getNumParams(); ++i) { + bool is_array = + utils::isArrayOrPointerType(m_Function->getParamDecl(i)->getType()); auto param = params[i]; QualType dParamType = clad::utils::GetValueType(param->getType()); Expr* dVectorParam = nullptr; if (m_IndependentVars.size() > independentVarIndex && m_IndependentVars[independentVarIndex] == m_Function->getParamDecl(i)) { - // This parameter is an independent variable. - // Create a one hot vector for the parameter. - dVectorParam = getOneHotInitExpr(independentVarIndex, - m_IndependentVars.size(), dParamType); + + // Current offset for independent variable. + Expr* offsetExpr = arrayIndVarCountExpr; + Expr* nonArrayIndVarCountExpr = ConstantFolder::synthesizeLiteral( + m_Context.UnsignedLongTy, m_Context, nonArrayIndVarCount); + if (!offsetExpr) { + offsetExpr = nonArrayIndVarCountExpr; + } else if (nonArrayIndVarCount != 0) { + offsetExpr = BuildOp(BinaryOperatorKind::BO_Add, offsetExpr, + nonArrayIndVarCountExpr); + } + + if (is_array) { + // Get size of the array. + Expr* getSize = BuildArrayRefSizeExpr( + m_ParamVariables[m_Function->getParamDecl(i)]); + + // Create an identity matrix for the parameter, + // with number of rows equal to the size of the array, + // and number of columns equal to the number of independent variables + llvm::SmallVector args = {getSize, m_IndVarCountExpr, + offsetExpr}; + dVectorParam = BuildCallExprToCladFunction("identity_matrix", args, + {dParamType}, loc); + + // Update the array independent expression. + if (!arrayIndVarCountExpr) { + arrayIndVarCountExpr = getSize; + } else { + arrayIndVarCountExpr = BuildOp(BinaryOperatorKind::BO_Add, + arrayIndVarCountExpr, getSize); + } + } else { + // Create a one hot vector for the parameter. + llvm::SmallVector args = {m_IndVarCountExpr, offsetExpr}; + dVectorParam = BuildCallExprToCladFunction("one_hot_vector", args, + {dParamType}, loc); + ++nonArrayIndVarCount; + } ++independentVarIndex; } else { + // We cannot initialize derived variable for pointer types because + // we do not know the correct size. + if (is_array) + continue; // This parameter is not an independent variable. // Initialize by all zeros. - dVectorParam = getZeroInitListExpr(m_IndependentVars.size(), dParamType); + dVectorParam = BuildCallExprToCladFunction( + "zero_vector", {m_IndVarCountExpr}, {dParamType}, loc); } // For each function arg to be differentiated, create a variable @@ -117,9 +184,15 @@ VectorForwardModeVisitor::DeriveVectorMode(const FunctionDecl* FD, // -> clad::array _d_vector_x = {1, 0}; // -> clad::array _d_vector_y = {0, 0}; // -> clad::array _d_vector_z = {0, 1}; + QualType dVectorParamType; + if (is_array) { + dVectorParamType = GetCladMatrixOfType(dParamType); + } else { + dVectorParamType = GetCladArrayOfType(dParamType); + } auto dVectorParamDecl = - BuildVarDecl(GetCladArrayOfType(dParamType), - "_d_vector_" + param->getNameAsString(), dVectorParam); + BuildVarDecl(dVectorParamType, "_d_vector_" + param->getNameAsString(), + dVectorParam); addToCurrentBlock(BuildDeclStmt(dVectorParamDecl)); dVectorParam = BuildDeclRef(dVectorParamDecl); // Memorize the derivative vector for the parameter. @@ -164,11 +237,12 @@ clang::FunctionDecl* VectorForwardModeVisitor::CreateVectorModeOverload() { } // instantiate output parameter type as void* - QualType outputParamType = m_Context.getPointerType(m_Context.VoidTy); + QualType outputParamType = GetCladArrayRefOfType(m_Context.VoidTy); // Push param types for derived params. - for (std::size_t i = 0; i < m_Function->getNumParams(); ++i) + for (std::size_t i = 0; i < m_Function->getNumParams(); ++i) { paramTypes.push_back(outputParamType); + } auto vectorModeFuncOverloadEPI = dyn_cast(m_Function->getType())->getExtProtoInfo(); @@ -250,16 +324,21 @@ clang::FunctionDecl* VectorForwardModeVisitor::CreateVectorModeOverload() { // Create a cast expression to cast the derivative parameter to the correct // type. - auto* castExpr = + Expr* toCastExpr = BuildDeclRef(overloadParam); + if (!isCladArrayType(vectorModeParam->getType())) { + toCastExpr = + BuildCallExprToMemFn(toCastExpr, /*MemberFunctionName=*/"ptr", {}); + } + auto* castedExpr = m_Sema .BuildCXXNamedCast( noLoc, tok::TokenKind::kw_static_cast, m_Context.getTrivialTypeSourceInfo(vectorModeParam->getType()), - BuildDeclRef(overloadParam), noLoc, noLoc) + toCastExpr, noLoc, noLoc) .get(); auto* vectorModeVD = BuildVarDecl(vectorModeParam->getType(), - vectorModeParam->getNameAsString(), castExpr); + vectorModeParam->getNameAsString(), castedExpr); callArgs.push_back(BuildDeclRef(vectorModeVD)); addToCurrentBlock(BuildDeclStmt(vectorModeVD)); } @@ -279,30 +358,6 @@ clang::FunctionDecl* VectorForwardModeVisitor::CreateVectorModeOverload() { return vectorModeOverloadFD; } -clang::Expr* VectorForwardModeVisitor::getOneHotInitExpr(size_t index, - size_t size, - clang::QualType type) { - // Build call expression for one_hot - llvm::SmallVector args = { - ConstantFolder::synthesizeLiteral(m_Context.UnsignedLongTy, m_Context, - size), - ConstantFolder::synthesizeLiteral(m_Context.UnsignedLongTy, m_Context, - index)}; - return BuildCallExprToCladFunction("one_hot_vector", args, {type}, - m_Function->getLocation()); -} - -clang::Expr* -VectorForwardModeVisitor::getZeroInitListExpr(size_t size, - clang::QualType type) { - // define a vector of size `size` with all elements set to 0. - // Build call expression for zero_vector - llvm::SmallVector args = {ConstantFolder::synthesizeLiteral( - m_Context.UnsignedLongTy, m_Context, size)}; - return BuildCallExprToCladFunction("zero_vector", args, {type}, - m_Function->getLocation()); -} - llvm::SmallVector VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams) { llvm::SmallVector params, paramDerivatives; @@ -310,6 +365,10 @@ VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams) { auto derivativeFnType = cast(m_Derivative->getType()); std::size_t dParamTypesIdx = m_Function->getNumParams(); + // Count the number of non-array independent variables requested for + // differentiation. + size_t nonArrayIndVarCount = 0; + for (auto PVD : m_Function->parameters()) { auto newPVD = utils::BuildParmVarDecl( m_Sema, m_Derivative, PVD->getIdentifier(), PVD->getType(), @@ -336,8 +395,36 @@ VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams) { m_Sema.PushOnScopeChains(dPVD, getCurrentScope(), /*AddToContext=*/false); - m_ParamVariables[*it] = BuildOp(UO_Deref, BuildDeclRef(dPVD), noLoc); + if (utils::isArrayOrPointerType(PVD->getType())) { + m_ParamVariables[*it] = (Expr*)BuildDeclRef(dPVD); + // dPVD will be a clad::array or clad::array_ref, both have size() method. + // If m_IndVarCountExpr is null, initialize it with dPVD.size(). + // Otherwise, increment it by dPVD.size(). + Expr* getSize = BuildArrayRefSizeExpr(m_ParamVariables[*it]); + if (!m_IndVarCountExpr) { + m_IndVarCountExpr = getSize; + } else { + m_IndVarCountExpr = + BuildOp(BinaryOperatorKind::BO_Add, m_IndVarCountExpr, getSize); + } + } else { + m_ParamVariables[*it] = BuildOp(UO_Deref, BuildDeclRef(dPVD), noLoc); + nonArrayIndVarCount += 1; + } } + + // Process the expression for the number independent variables. + // This will be the sum of the sizes of all array parameters and the number + // of non-array parameters. + Expr* nonArrayIndVarCountExpr = ConstantFolder::synthesizeLiteral( + m_Context.UnsignedLongTy, m_Context, nonArrayIndVarCount); + if (!m_IndVarCountExpr) { + m_IndVarCountExpr = nonArrayIndVarCountExpr; + } else if (nonArrayIndVarCount != 0) { + m_IndVarCountExpr = BuildOp(BinaryOperatorKind::BO_Add, m_IndVarCountExpr, + nonArrayIndVarCountExpr); + } + // insert the derivative parameters at the end of the parameter list. params.insert(params.end(), paramDerivatives.begin(), paramDerivatives.end()); // store the independent variables for later use. @@ -346,15 +433,52 @@ VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams) { return params; } +StmtDiff VectorForwardModeVisitor::VisitArraySubscriptExpr( + const ArraySubscriptExpr* ASE) { + auto ASI = SplitArraySubscript(ASE); + const Expr* Base = ASI.first; + StmtDiff BaseDiff = Visit(Base); + const auto& Indices = ASI.second; + Expr* clonedBase = BaseDiff.getExpr(); + llvm::SmallVector clonedIndices(Indices.size()); + std::transform(std::begin(Indices), std::end(Indices), + std::begin(clonedIndices), + [this](const Expr* E) { return Clone(E); }); + auto cloned = BuildArraySubscript(clonedBase, clonedIndices); + + QualType ExprTy = ASE->getType(); + if (ExprTy->isPointerType()) + ExprTy = ExprTy->getPointeeType(); + auto zero = ConstantFolder::synthesizeLiteral(ExprTy, m_Context, 0); + Expr* diffExpr = zero; + + Expr* target = BaseDiff.getExpr_dx(); + if (target) { + diffExpr = + m_Sema + .ActOnArraySubscriptExpr(getCurrentScope(), target, + target->getExprLoc(), clonedIndices, noLoc) + .get(); + } + return StmtDiff(cloned, diffExpr); +} + StmtDiff VectorForwardModeVisitor::VisitReturnStmt(const ReturnStmt* RS) { - StmtDiff retValDiff = Visit(RS->getRetValue()); + const Expr* retVal = RS->getRetValue(); + QualType retType = retVal->getType(); + StmtDiff retValDiff = Visit(retVal); Expr* derivedRetValE = retValDiff.getExpr_dx(); // If we are in vector mode, we need to wrap the return value in a // vector. + SourceLocation loc{m_Function->getLocation()}; + llvm::SmallVector args = {m_IndVarCountExpr, derivedRetValE}; + QualType cladArrayType = GetCladArrayOfType(utils::GetValueType(retType)); + TypeSourceInfo* TSI = m_Context.getTrivialTypeSourceInfo(cladArrayType, loc); + Expr* constructorCallExpr = + m_Sema.BuildCXXTypeConstructExpr(TSI, loc, args, loc, false).get(); auto dVectorParamDecl = - BuildVarDecl(GetCladArrayOfType( - clad::utils::GetValueType(RS->getRetValue()->getType())), - "_d_vector_return", derivedRetValE); + BuildVarDecl(cladArrayType, "_d_vector_return", constructorCallExpr, + false, nullptr, VarDecl::InitializationStyle::CallInit); // Create an array of statements to hold the return statement and the // assignments to the derivatives of the parameters. Stmts returnStmts; @@ -362,17 +486,53 @@ StmtDiff VectorForwardModeVisitor::VisitReturnStmt(const ReturnStmt* RS) { // Assign values from return vector to the derivatives of the // parameters. auto dVectorRef = BuildDeclRef(dVectorParamDecl); + + // Expression for maintaining the number of independent variables processed + // till now present as array elements. This will be sum of sizes of all such + // arrays. + Expr* arrayIndVarCountExpr = nullptr; + // Number of non-array independent variables processed till now. + size_t nonArrayIndVarCount = 0; + for (size_t i = 0; i < m_IndependentVars.size(); ++i) { // Get the derivative of the ith parameter. auto dParam = m_ParamVariables[m_IndependentVars[i]]; - // Create an array subscript expression to access the ith element - auto indexExpr = - ConstantFolder::synthesizeLiteral(m_Context.IntTy, m_Context, i); - auto dParamValue = - m_Sema - .ActOnArraySubscriptExpr(getCurrentScope(), dVectorRef, - dVectorRef->getExprLoc(), indexExpr, noLoc) - .get(); + Expr* dParamValue = nullptr; + + // Current offset for independent variable. + Expr* offsetExpr = arrayIndVarCountExpr; + Expr* nonArrayIndVarCountExpr = ConstantFolder::synthesizeLiteral( + m_Context.UnsignedLongTy, m_Context, nonArrayIndVarCount); + if (!offsetExpr) { + offsetExpr = nonArrayIndVarCountExpr; + } else if (nonArrayIndVarCount != 0) { + offsetExpr = BuildOp(BinaryOperatorKind::BO_Add, offsetExpr, + nonArrayIndVarCountExpr); + } + + if (isCladArrayType(dParam->getType())) { + // Get the size of the array. + Expr* getSize = BuildArrayRefSizeExpr(dParam); + + // Create an expression to fetch slice of the return vector. + llvm::SmallVector args = {offsetExpr, getSize}; + dParamValue = BuildArrayRefSliceExpr(dVectorRef, args); + + // Update the array independent expression. + if (!arrayIndVarCountExpr) { + arrayIndVarCountExpr = getSize; + } else { + arrayIndVarCountExpr = + BuildOp(BinaryOperatorKind::BO_Add, arrayIndVarCountExpr, getSize); + } + } else { + dParamValue = m_Sema + .ActOnArraySubscriptExpr(getCurrentScope(), dVectorRef, + dVectorRef->getExprLoc(), + offsetExpr, noLoc) + .get(); + ++nonArrayIndVarCount; + } // Create an assignment expression to assign the ith element of the // return vector to the derivative of the ith parameter. auto dParamAssign = BuildOp(BO_Assign, dParam, dParamValue); @@ -408,16 +568,13 @@ VarDeclDiff VectorForwardModeVisitor::DifferentiateVarDecl(const VarDecl* VD) { // clad::array _d_vector_y(2, 1); // this means that we have to initialize the derivative vector of // size 2 with all elements equal to 1. - Expr* size = ConstantFolder::synthesizeLiteral( - m_Context.UnsignedLongTy, m_Context, m_IndependentVars.size()); - llvm::SmallVector args = {size, initDiff.getExpr_dx()}; + SourceLocation loc{m_Function->getLocation()}; + llvm::SmallVector args = {m_IndVarCountExpr, initDiff.getExpr_dx()}; + QualType cladArrayType = + GetCladArrayOfType(utils::GetValueType(VD->getType())); + TypeSourceInfo* TSI = m_Context.getTrivialTypeSourceInfo(cladArrayType, loc); Expr* constructorCallExpr = - m_Sema - .ActOnCXXTypeConstructExpr( - OpaquePtr::make( - GetCladArrayOfType(utils::GetValueType(VD->getType()))), - noLoc, args, noLoc, false) - .get(); + m_Sema.BuildCXXTypeConstructExpr(TSI, loc, args, loc, false).get(); VarDecl* VDDerived = BuildVarDecl(GetCladArrayOfType(utils::GetValueType(VD->getType())), diff --git a/lib/Differentiator/VisitorBase.cpp b/lib/Differentiator/VisitorBase.cpp index 541b72990..c9652f943 100644 --- a/lib/Differentiator/VisitorBase.cpp +++ b/lib/Differentiator/VisitorBase.cpp @@ -611,6 +611,25 @@ namespace clad { return InstantiateTemplate(GetCladArrayDecl(), {T}); } + TemplateDecl* VisitorBase::GetCladMatrixDecl() { + static TemplateDecl* Result = nullptr; + if (!Result) + Result = LookupTemplateDeclInCladNamespace(/*ClassName=*/"matrix"); + return Result; + } + + QualType VisitorBase::GetCladMatrixOfType(clang::QualType T) { + return InstantiateTemplate(GetCladMatrixDecl(), {T}); + } + + Expr* VisitorBase::BuildIdentityMatrixExpr(clang::QualType T, + MutableArrayRef Args, + clang::SourceLocation Loc) { + auto* M = + BuildCallExprToCladFunction(/*name=*/"identity_matrix", Args, {T}, Loc); + return M; + } + Expr* VisitorBase::BuildArrayRefSizeExpr(Expr* Base) { return BuildCallExprToMemFn(Base, /*MemberFunctionName=*/"size", {}); } diff --git a/test/Arrays/ArrayInputsVectorForwardMode.C b/test/Arrays/ArrayInputsVectorForwardMode.C new file mode 100644 index 000000000..bbc681684 --- /dev/null +++ b/test/Arrays/ArrayInputsVectorForwardMode.C @@ -0,0 +1,90 @@ +// RUN: %cladclang %s -I%S/../../include -oArrayInputsVectorForwardMode.out 2>&1 | FileCheck %s +// RUN: ./ArrayInputsVectorForwardMode.out | FileCheck -check-prefix=CHECK-EXEC %s + +// CHECK-NOT: {{.*error|warning|note:.*}} + +#include "clad/Differentiator/Differentiator.h" + +double multiply(double *arr) { + return arr[0] * arr[1]; +} + +// CHECK: void multiply_dvec(double *arr, clad::array_ref _d_arr) { +// CHECK-NEXT: unsigned long indepVarCount = _d_arr.size(); +// CHECK-NEXT: clad::matrix _d_vector_arr = clad::identity_matrix(_d_arr.size(), indepVarCount, 0UL); +// CHECK-NEXT: { +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, (_d_vector_arr[0]) * arr[1] + arr[0] * (_d_vector_arr[1]))); +// CHECK-NEXT: _d_arr = _d_vector_return.slice(0UL, _d_arr.size()); +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-NEXT: } + +double divide(double *arr) { + return arr[0] / arr[1]; +} + +// CHECK: void divide_dvec(double *arr, clad::array_ref _d_arr) { +// CHECK-NEXT: unsigned long indepVarCount = _d_arr.size(); +// CHECK-NEXT: clad::matrix _d_vector_arr = clad::identity_matrix(_d_arr.size(), indepVarCount, 0UL); +// CHECK-NEXT: { +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, ((_d_vector_arr[0]) * arr[1] - arr[0] * (_d_vector_arr[1])) / (arr[1] * arr[1]))); +// CHECK-NEXT: _d_arr = _d_vector_return.slice(0UL, _d_arr.size()); +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-NEXT: } + +double addArr(double *arr, int n) { + double ret = 0; + for (int i = 0; i < n; i++) { + ret += arr[i]; + } + return ret; +} + +// CHECK: void addArr_dvec_0(double *arr, int n, clad::array_ref _d_arr) { +// CHECK-NEXT: unsigned long indepVarCount = _d_arr.size(); +// CHECK-NEXT: clad::matrix _d_vector_arr = clad::identity_matrix(_d_arr.size(), indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_n = clad::zero_vector(indepVarCount); +// CHECK-NEXT: clad::array _d_vector_ret(clad::array(indepVarCount, 0)); +// CHECK-NEXT: double ret = 0; +// CHECK-NEXT: { +// CHECK-NEXT: clad::array _d_vector_i(clad::array(indepVarCount, 0)); +// CHECK-NEXT: for (int i = 0; i < n; i++) { +// CHECK-NEXT: _d_vector_ret += _d_vector_arr[i]; +// CHECK-NEXT: ret += arr[i]; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, _d_vector_ret)); +// CHECK-NEXT: _d_arr = _d_vector_return.slice(0UL, _d_arr.size()); +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-NEXT: } + +int main() { + // multiply + double a1[] = {1, 2, 3}; + double da1[3] = {0}; + clad::array_ref da1_ref(da1, 3); + auto multiply_darr = clad::differentiate(multiply, "arr"); + multiply_darr.execute(a1, da1_ref); + printf("Result = {%.2f, %.2f, %.2f}\n", da1[0], da1[1], da1[2]); // CHECK-EXEC: Result = {2.00, 1.00, 0.00} + + // divide + double a2[] = {1, 2, 3}; + double da2[3] = {0}; + clad::array_ref da2_ref(da2, 3); + auto divide_darr = clad::differentiate(divide, "arr"); + divide_darr.execute(a2, da2_ref); + printf("Result = {%.2f, %.2f, %.2f}\n", da2[0], da2[1], da2[2]); // CHECK-EXEC: Result = {0.50, -0.25, 0.00} + + // addArr + double a3[] = {1, 2, 3}; + double da3[3] = {0}; + clad::array_ref da3_ref(da3, 3); + auto addArr_darr = clad::differentiate(addArr, "arr"); + addArr_darr.execute(a3, 3, da3_ref); + printf("Result = {%.2f, %.2f, %.2f}\n", da3[0], da3[1], da3[2]); // CHECK-EXEC: Result = {1.00, 1.00, 1.00} + + return 0; +} \ No newline at end of file diff --git a/test/ForwardMode/VectorMode.C b/test/ForwardMode/VectorMode.C index 9dfef8e98..08fdfad2b 100644 --- a/test/ForwardMode/VectorMode.C +++ b/test/ForwardMode/VectorMode.C @@ -12,14 +12,15 @@ double f1(double x, double y) { void f1_dvec(double x, double y, double *_d_x, double *_d_y); // CHECK: void f1_dvec(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 1UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); // CHECK-NEXT: double _t0 = x * y; // CHECK-NEXT: double _t1 = (x + y + 1); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = (_d_vector_x * y + x * _d_vector_y) * _t1 + _t0 * (_d_vector_x + _d_vector_y + 0); -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_y = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, (_d_vector_x * y + x * _d_vector_y) * _t1 + _t0 * (_d_vector_x + _d_vector_y + 0))); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_y = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // CHECK-NEXT: } @@ -34,16 +35,17 @@ double f2(double x, double y) { void f2_dvec(double x, double y, double *_d_x, double *_d_y); // CHECK: void f2_dvec(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 1UL); -// CHECK-NEXT: clad::array _d_vector_temp1(clad::array(2UL, _d_vector_x * y + x * _d_vector_y)); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); +// CHECK-NEXT: clad::array _d_vector_temp1(clad::array(indepVarCount, _d_vector_x * y + x * _d_vector_y)); // CHECK-NEXT: double temp1 = x * y; -// CHECK-NEXT: clad::array _d_vector_temp2(clad::array(2UL, _d_vector_x + _d_vector_y + 0)); +// CHECK-NEXT: clad::array _d_vector_temp2(clad::array(indepVarCount, _d_vector_x + _d_vector_y + 0)); // CHECK-NEXT: double temp2 = x + y + 1; // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = _d_vector_temp1 * temp2 + temp1 * _d_vector_temp2; -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_y = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, _d_vector_temp1 * temp2 + temp1 * _d_vector_temp2)); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_y = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // CHECK-NEXT: } @@ -59,8 +61,9 @@ double f3(double x, double y) { void f3_dvec(double x, double y, double *_d_x, double *_d_y); // CHECK: void f3_dvec(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 1UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); // CHECK-NEXT: if (y < 0) { // CHECK-NEXT: _d_vector_y = - _d_vector_y; // CHECK-NEXT: y = -y; @@ -68,9 +71,9 @@ void f3_dvec(double x, double y, double *_d_x, double *_d_y); // CHECK-NEXT: _d_vector_y += 0; // CHECK-NEXT: y += 1; // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = _d_vector_x * y + x * _d_vector_y; -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_y = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, _d_vector_x * y + x * _d_vector_y)); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_y = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // CHECK-NEXT: } @@ -89,17 +92,18 @@ double f4(double lower, double upper) { void f4_dvec(double lower, double upper, double *_d_lower, double *_d_upper); // CHECK: void f4_dvec(double lower, double upper, double *_d_lower, double *_d_upper) { -// CHECK-NEXT: clad::array _d_vector_lower = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_upper = clad::one_hot_vector(2UL, 1UL); -// CHECK-NEXT: clad::array _d_vector_sum(clad::array(2UL, 0)); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_lower = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_upper = clad::one_hot_vector(indepVarCount, 1UL); +// CHECK-NEXT: clad::array _d_vector_sum(clad::array(indepVarCount, 0)); // CHECK-NEXT: double sum = 0; -// CHECK-NEXT: clad::array _d_vector_num_points(clad::array(2UL, 0)); +// CHECK-NEXT: clad::array _d_vector_num_points(clad::array(indepVarCount, 0)); // CHECK-NEXT: double num_points = 10000; // CHECK-NEXT: double _t0 = (upper - lower); -// CHECK-NEXT: clad::array _d_vector_interval(clad::array(2UL, ((_d_vector_upper - _d_vector_lower) * num_points - _t0 * _d_vector_num_points) / (num_points * num_points))); +// CHECK-NEXT: clad::array _d_vector_interval(clad::array(indepVarCount, ((_d_vector_upper - _d_vector_lower) * num_points - _t0 * _d_vector_num_points) / (num_points * num_points))); // CHECK-NEXT: double interval = _t0 / num_points; // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_x(clad::array(2UL, _d_vector_lower)); +// CHECK-NEXT: clad::array _d_vector_x(clad::array(indepVarCount, _d_vector_lower)); // CHECK-NEXT: for (double x = lower; x <= upper; (_d_vector_x += _d_vector_interval) , (x += interval)) { // CHECK-NEXT: double _t1 = x * x; // CHECK-NEXT: _d_vector_sum += (_d_vector_x * x + x * _d_vector_x) * interval + _t1 * _d_vector_interval; @@ -107,9 +111,9 @@ void f4_dvec(double lower, double upper, double *_d_lower, double *_d_upper); // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = _d_vector_sum; -// CHECK-NEXT: *_d_lower = _d_vector_return[0]; -// CHECK-NEXT: *_d_upper = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, _d_vector_sum)); +// CHECK-NEXT: *_d_lower = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_upper = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // CHECK-NEXT: } @@ -120,61 +124,66 @@ double f5(double x, double y, double z) { // all // CHECK: void f5_dvec(double x, double y, double z, double *_d_x, double *_d_y, double *_d_z) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(3UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(3UL, 1UL); -// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(3UL, 2UL); +// CHECK-NEXT: unsigned long indepVarCount = 3UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); +// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(indepVarCount, 2UL); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z; -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_y = _d_vector_return[1]; -// CHECK-NEXT: *_d_z = _d_vector_return[2]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z)); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_y = _d_vector_return[1UL]; +// CHECK-NEXT: *_d_z = _d_vector_return[2UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // x, y // CHECK: void f5_dvec_0_1(double x, double y, double z, double *_d_x, double *_d_y) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 1UL); -// CHECK-NEXT: clad::array _d_vector_z = clad::zero_vector(2UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); +// CHECK-NEXT: clad::array _d_vector_z = clad::zero_vector(indepVarCount); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z; -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_y = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z)); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_y = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // x, z // CHECK: void f5_dvec_0_2(double x, double y, double z, double *_d_x, double *_d_z) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::zero_vector(2UL); -// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(2UL, 1UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::zero_vector(indepVarCount); +// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(indepVarCount, 1UL); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z; -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_z = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z)); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_z = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // y, z // CHECK: void f5_dvec_1_2(double x, double y, double z, double *_d_y, double *_d_z) { -// CHECK-NEXT: clad::array _d_vector_x = clad::zero_vector(2UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(2UL, 1UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::zero_vector(indepVarCount); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(indepVarCount, 1UL); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z; -// CHECK-NEXT: *_d_y = _d_vector_return[0]; -// CHECK-NEXT: *_d_z = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z)); +// CHECK-NEXT: *_d_y = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_z = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // z // CHECK: void f5_dvec_2(double x, double y, double z, double *_d_z) { -// CHECK-NEXT: clad::array _d_vector_x = clad::zero_vector(1UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::zero_vector(1UL); -// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(1UL, 0UL); +// CHECK-NEXT: unsigned long indepVarCount = 1UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::zero_vector(indepVarCount); +// CHECK-NEXT: clad::array _d_vector_y = clad::zero_vector(indepVarCount); +// CHECK-NEXT: clad::array _d_vector_z = clad::one_hot_vector(indepVarCount, 0UL); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z; -// CHECK-NEXT: *_d_z = _d_vector_return[0]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, 0. * x + 1. * _d_vector_x + 0. * y + 2. * _d_vector_y + 0. * z + 3. * _d_vector_z)); +// CHECK-NEXT: *_d_z = _d_vector_return[0UL]; // CHECK-NEXT: return; // CHECK-NEXT: } diff --git a/test/ForwardMode/VectorModeInterface.C b/test/ForwardMode/VectorModeInterface.C index a550f0468..3c809ab67 100644 --- a/test/ForwardMode/VectorModeInterface.C +++ b/test/ForwardMode/VectorModeInterface.C @@ -9,12 +9,13 @@ double f1(double x, double y) { } // CHECK: void f1_dvec(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 1UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = _d_vector_x * y + x * _d_vector_y; -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_y = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, _d_vector_x * y + x * _d_vector_y)); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_y = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // CHECK-NEXT: } @@ -26,12 +27,13 @@ double f2(double x, double y) { void f2_dvec(double x, double y, double *_d_x, double *_d_y); // CHECK: void f2_dvec(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 1UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); // CHECK-NEXT: { -// CHECK-NEXT: clad::array _d_vector_return = _d_vector_x + _d_vector_y; -// CHECK-NEXT: *_d_x = _d_vector_return[0]; -// CHECK-NEXT: *_d_y = _d_vector_return[1]; +// CHECK-NEXT: clad::array _d_vector_return(clad::array(indepVarCount, _d_vector_x + _d_vector_y)); +// CHECK-NEXT: *_d_x = _d_vector_return[0UL]; +// CHECK-NEXT: *_d_y = _d_vector_return[1UL]; // CHECK-NEXT: return; // CHECK-NEXT: } // CHECK-NEXT: } @@ -45,8 +47,9 @@ double f_try_catch(double x, double y) } // CHECK: void f_try_catch_dvec(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(2UL, 0UL); -// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(2UL, 1UL); +// CHECK-NEXT: unsigned long indepVarCount = 2UL; +// CHECK-NEXT: clad::array _d_vector_x = clad::one_hot_vector(indepVarCount, 0UL); +// CHECK-NEXT: clad::array _d_vector_y = clad::one_hot_vector(indepVarCount, 1UL); // CHECK-NEXT: try { // CHECK-NEXT: return x; // CHECK-NEXT: } catch (int) {