Skip to content

Conversation

@marchioa
Copy link
Contributor

@marchioa marchioa commented Jan 10, 2026

Add integer MaxPool1D for Generic platform and RQSConv1D support for PULPOpen, with corresponding kernel tests.

Added

  • MaxPool1D fp32 kernel and template for Generic platform
  • Test for MaxPool1D fp32 and int8
  • RQSConv1 template and tiling contraints for PULP Platform
  • Test for RQSConv1D int8

Changed

  • renamed MaxPool2D test from MaxPool to MaxPool/Regular_2D for both Integer and FP32

Fixed

  • im2col buffer size in Conv1d template

PR Merge Checklist

  1. The PR is rebased on the latest devel commit and pointing to devel.
  2. Your PR reviewed and approved.
  3. All checks are passing.
  4. The CHANGELOG.md file has been updated.
  5. If the docker was modified, change back its link after review.

@marchioa marchioa changed the title Titancfi Support for MaxPool1D and RQSConv1D for PULPOpen Jan 19, 2026
@marchioa marchioa marked this pull request as ready for review January 19, 2026 07:59
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 19, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added 1D MaxPool support for Generic and PULPOpen platforms with FP32 and int8 data types
    • Added RQSConv1D support for PULPOpen platform
  • Bug Fixes

    • Fixed im2col buffer size calculation in Conv1d template
  • Tests

    • Expanded kernel test coverage to explicitly include 1D MaxPool variants alongside existing 2D tests

Walkthrough

This PR adds 1D MaxPool and RQSConv1D support for both Generic and PULPOpen platforms, including kernel implementations, templates, bindings, tiling constraints, and platform mappings.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Added entries for MaxPool1D and RQSConv1D support and im2col buffer fix in Conv1d template.
Generic MaxPool Support
Deeploy/Targets/Generic/Bindings.py, Deeploy/Targets/Generic/Templates/MaxPoolTemplate.py
Renamed base template class to _MaxPoolTemplate and introduced reference1DTemplate for 1D MaxPool; added int8_t MaxPool1D binding for Generic platform.
Generic MaxPool Kernels
TargetLibraries/Generic/inc/kernel/MaxPool.h, TargetLibraries/Generic/inc/kernel/MaxPool1d.h, TargetLibraries/Generic/src/MaxPool_fp32.c, TargetLibraries/Generic/src/MaxPool_s8.c
Added MaxPool1d_s8_s8 and MaxPool1d_fp32_fp32 kernel implementations; consolidated declarations into MaxPool.h; removed separate MaxPool1d.h and MaxPool1D_fp32.c files; added input validation guards to 2D variants.
Generic Headers Cleanup
TargetLibraries/Generic/inc/DeeployBasicMath.h
Removed inclusion of kernel/MaxPool1d.h.
PULPOpen MaxPool Templates & Bindings
Deeploy/Targets/PULPOpen/Templates/MaxPoolTemplate.py, Deeploy/Targets/PULPOpen/Bindings.py
Added PULPMaxPool1D_8_Template and PULPMaxPool1DBindings for int8_t and uint8_t; updated MaxPool2D bindings to reference new MaxPoolTemplate.
PULPOpen Conv1D Bindings
Deeploy/Targets/PULPOpen/Bindings.py
Replaced single PULPConv1DBinding with parameterized PULPRQSConv1DBindings list for int8_t and uint8_t; updated import from MaxPool2DTemplate to MaxPoolTemplate.
PULPOpen Conv1D Templates
Deeploy/Targets/PULPOpen/Templates/ConvTemplate.py
Updated im2col buffer size calculation and removed pointwise convolution path in PULPConv1D_8_Template, now unconditionally using conv variant.
PULPOpen 1D Tiling Constraints
Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py
Added new RQConv1DTileConstraint class with 1D-specific geometrical constraints, policy constraints, symbolic node representation, and tiling serialization logic for im2col-based 1D convolution tiling.
PULPOpen Platform Integration
Deeploy/Targets/PULPOpen/Platform.py, Deeploy/Targets/PULPOpen/Tiler.py
Added MaxPool1DMapper and PULPMaxPool1DTilingReadyBindings; updated Conv1DMapper to use PULPRQSConv1DTilingReadyBindings; added RQConv1DTileConstraint integration; updated PULPMapping to support both 1D and 2D MaxPool variants.
Parser Updates
Deeploy/Targets/Generic/Parsers.py
Added stride validation (stride > 0) to MaxPoolParser.
Test Configuration Updates
DeeployTest/test_cortexm_config.py, DeeployTest/test_deeploy_internal.py, DeeployTest/test_generic_config.py, DeeployTest/test_mempool_config.py, DeeployTest/test_siracusa_config.py, DeeployTest/test_siracusa_tiled_config.py
Updated MaxPool kernel test paths to explicitly reference Regular_1D and/or Regular_2D variants instead of generic MaxPool entries.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Possibly related PRs

Suggested reviewers

  • Victor-Jung
  • Xeratec
  • lukamac
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main additions in the PR: support for MaxPool1D and RQSConv1D for PULPOpen platform.
Description check ✅ Passed The description provides relevant details about what was added, changed, and fixed, directly relating to the changeset with clear organization by category.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Important

Action Needed: IP Allowlist Update

If your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:

  • 136.113.208.247/32 (new)
  • 34.170.211.100/32
  • 35.222.179.152/32

Reviews will stop working after February 8, 2026 if the new IP is not added to your allowlist.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@Deeploy/Targets/PULPOpen/Templates/MaxPoolTemplate.py`:
- Around line 34-46: The template PULPMaxPool1D_8_Template/PULPMaxPoolTemplate
currently passes ONNX 1D pads into the HEIGHT pad slots of pulp_nn_maxpool (so
padding_top/padding_bottom get ${padding_y}/${padding_y_right}); swap the pad
ordering so height pads are zeros and width pads receive the ONNX values: set
padding_top=0, padding_bottom=0 and padding_left=${padding_y},
padding_right=${padding_y_right} in the pulp_nn_maxpool${signatureString} call
(i.e. move the two zeros before the two ${padding_y} args).

In `@Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py`:
- Around line 840-844: The effectiveInputLengthVar calculation is wrong: it
subtracts (inputLengthVar - 1) for the tiled case but should subtract the kernel
span (weightLengthVar - 1); update the expression in ConvTileConstraint (the
effectiveInputLengthVar assignment) to replace the final term ((inputLengthVar -
1) * (inputLengthVar != inputBuffer.shape[1])) with ((weightLengthVar - 1) *
(inputLengthVar != inputBuffer.shape[1])) so the receptive field overlap uses
weightLengthVar consistently with the 2D implementation.
- Around line 871-873: The effectiveInputLength calculation in
addPolicyConstraint uses (inputLengthVar - 1) where it should subtract the
kernel length minus one (same bug as in addGeometricalConstraint); update the
ternary expression so the last term uses the kernel size (e.g., kernelLength or
kernelLengthVar) minus one instead of inputLengthVar - 1, i.e., change "-
(inputLengthVar - 1) * (inputLengthVar != inputBuffer.shape[1])" to "-
(kernelLength - 1) * (inputLengthVar != inputBuffer.shape[1])" in the
effectiveInputLength assignment inside addPolicyConstraint.

In `@TargetLibraries/Generic/src/MaxPool_s8.c`:
- Around line 52-69: The MaxPool1d_s8_s8 function currently computes L_out = (L
- K) / S + 1 which can underflow when K > L and divide-by-zero when S == 0;
before calculating L_out, add guards: if S == 0 return (or otherwise abort) and
if K > L set L_out = 0 (or return) to avoid the underflow/OOB behavior; update
the function entry (MaxPool1d_s8_s8) to validate S and the relationship of K and
L and bail out or produce zero-length output before any loops that use L_out.
🧹 Nitpick comments (5)
TargetLibraries/Generic/inc/kernel/MaxPool.h (1)

42-48: Consider aligning parameter naming between int8 and fp32 variants.

The MaxPool1d_s8_s8 function uses L for the spatial dimension while MaxPool1d_fp32_fp32 uses W. For consistency across the API, consider using the same parameter name (e.g., L for "Length" in 1D operations) in both declarations.

Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py (4)

618-618: Remove unused variable dilation.

The dilation variable is assigned but never used in addGeometricalConstraint. If dilation support is intended for future use, consider adding a TODO comment; otherwise, remove it.

♻️ Suggested fix
-        dilation = parseDict["dilations"][0]
+        # Note: dilation not currently used in 1D constraint; add if needed

651-658: Remove unused variable pads in addPolicyConstraint.

The pads variable is assigned on line 657 but never used in this method.

♻️ Suggested fix
         inputBuffer = ctxt.lookup(name = parseDict['data_in'])
         weightBuffer = ctxt.lookup(name = parseDict['weight'])

-        pads = parseDict["pads"]
         stride = parseDict["strides"][0]

768-769: Consider adding strict=True to zip() calls.

Using zip() without strict=True may silently truncate if the input lists have different lengths, potentially masking bugs.

♻️ Suggested fix
-        for a, b, add, mul in zip(inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes):
+        for a, b, add, mul in zip(inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes, strict=True):

1046-1056: Consider adding strict=True to zip() calls.

Same recommendation as in RQConv1DTileConstraint for defensive programming.

♻️ Suggested fix
         if varBias == "NULL":
-            for a, b in zip(inputInCubes, inputWeightCubes):
+            for a, b in zip(inputInCubes, inputWeightCubes, strict=True):
                 inputLoadSchedule.append({"data_in": a, "weight": b})
         else:
-            for a, b, c in zip(inputInCubes, inputWeightCubes, inputBiasCubes):
+            for a, b, c in zip(inputInCubes, inputWeightCubes, inputBiasCubes, strict=True):
                 inputLoadSchedule.append({"data_in": a, "weight": b, "bias": c})

Comment on lines +840 to +844
effectiveInputLengthVar = inputLengthVar \
+ (sum(pads) * (inputLengthVar == inputBuffer.shape[1])) \
- ((inputLengthVar - 1) * (inputLengthVar != inputBuffer.shape[1]))

_outputLengthVar = (effectiveInputLengthVar - dilation * (weightLengthVar - 1) - 1) // stride + 1
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential bug in effectiveInputLengthVar formula.

The formula subtracts (inputLengthVar - 1) when tiling, but comparing with Conv2DTileConstraint.addGeometricalConstraint (lines 305-308), the 2D version subtracts (weightHeightVar - 1). This appears to be a copy-paste error—it should likely be (weightLengthVar - 1) to account for the kernel receptive field overlap.

🐛 Suggested fix
         #   Assume worst case scenario (data padding on all sides) when tiling on a ceratin dimension.
         effectiveInputLengthVar = inputLengthVar \
             + (sum(pads) * (inputLengthVar == inputBuffer.shape[1])) \
-            - ((inputLengthVar - 1) * (inputLengthVar != inputBuffer.shape[1]))
+            - ((weightLengthVar - 1) * (inputLengthVar != inputBuffer.shape[1]))
🤖 Prompt for AI Agents
In `@Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py` around lines
840 - 844, The effectiveInputLengthVar calculation is wrong: it subtracts
(inputLengthVar - 1) for the tiled case but should subtract the kernel span
(weightLengthVar - 1); update the expression in ConvTileConstraint (the
effectiveInputLengthVar assignment) to replace the final term ((inputLengthVar -
1) * (inputLengthVar != inputBuffer.shape[1])) with ((weightLengthVar - 1) *
(inputLengthVar != inputBuffer.shape[1])) so the receptive field overlap uses
weightLengthVar consistently with the 2D implementation.

Comment on lines +871 to +873
effectiveInputLength = inputLengthVar \
+ (sum(pads) * (inputLengthVar == inputBuffer.shape[1])) \
- (inputLengthVar - 1) * (inputLengthVar != inputBuffer.shape[1])
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same formula issue in addPolicyConstraint.

This has the same issue as addGeometricalConstraint—it subtracts (inputLengthVar - 1) instead of the kernel length minus one.

🐛 Suggested fix
         effectiveInputLength = inputLengthVar \
             + (sum(pads) * (inputLengthVar == inputBuffer.shape[1])) \
-            - (inputLengthVar - 1) * (inputLengthVar != inputBuffer.shape[1])
+            - (weightLengthVar - 1) * (inputLengthVar != inputBuffer.shape[1])
🤖 Prompt for AI Agents
In `@Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py` around lines
871 - 873, The effectiveInputLength calculation in addPolicyConstraint uses
(inputLengthVar - 1) where it should subtract the kernel length minus one (same
bug as in addGeometricalConstraint); update the ternary expression so the last
term uses the kernel size (e.g., kernelLength or kernelLengthVar) minus one
instead of inputLengthVar - 1, i.e., change "- (inputLengthVar - 1) *
(inputLengthVar != inputBuffer.shape[1])" to "- (kernelLength - 1) *
(inputLengthVar != inputBuffer.shape[1])" in the effectiveInputLength assignment
inside addPolicyConstraint.

Copy link
Member

@Victor-Jung Victor-Jung left a comment

Choose a reason for hiding this comment

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

Ciao Alex, I have a few minor comments but overall it looks good.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Deeploy/Targets/Generic/Parsers.py (1)

193-200: Potential KeyError when strides attribute is missing.

The stride validation on line 199 accesses node.attrs['strides'] unconditionally. Since this is a list literal passed to all(), Python evaluates all elements before calling all() — no short-circuit evaluation occurs. If 'strides' not in node.attrs, this will raise a KeyError.

🐛 Proposed fix: move stride validation after the attribute existence check
 def parseNode(self, node: gs.Node) -> bool:

     ret = all([
         'ceil_mode' in node.attrs, 'kernel_shape' in node.attrs, 'pads' in node.attrs, 'strides' in node.attrs,
         len(node.inputs) == 1,
         len(node.outputs) >= 1,
-        all([stride > 0 for stride in node.attrs['strides']]),
     ])

+    if ret:
+        ret = all(stride > 0 for stride in node.attrs['strides'])
+
     if ret:
         self.operatorRepresentation['ceil_mode'] = node.attrs['ceil_mode']
🤖 Fix all issues with AI agents
In `@TargetLibraries/Generic/src/MaxPool_s8.c`:
- Around line 55-58: The code lacks a guard for K == 0 which allows a
zero-length kernel and produces invalid outputs; update the input validation in
MaxPool_s8 (the block checking L, K, S) to treat K == 0 as invalid—mirror the
existing stride guard (S == 0) by returning (or asserting) when K == 0 (e.g.,
add K == 0 to the condition that currently checks L < K || S == 0) so the
computation of L_out is never performed with a zero kernel.

@marchioa
Copy link
Contributor Author

I handled both conditions directly in the C kernel by early-returning when the parameters are invalid. I couldn’t find an existing pattern for this in other kernels, so this was a best-effort approach on my side — please let me know if there’s a preferred or more idiomatic way to handle it.

Should I apply the same kind of guard to MaxPool2d as well?

Additionally, since the stride value is available from ONNX, I added a guard in the parser to catch stride == 0.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Deeploy/Targets/Generic/Parsers.py (1)

195-211: KeyError when strides attribute is missing.

The stride validation on line 202 accesses node.attrs['strides'] unconditionally. Since all([...]) evaluates all list elements before calling all(), this will raise a KeyError if the 'strides' attribute is not present—even though the check 'strides' in node.attrs exists earlier in the list.

🐛 Proposed fix: Move stride validation after initial checks
     def parseNode(self, node: gs.Node) -> bool:

         ret = all([
             'ceil_mode' in node.attrs,
             'kernel_shape' in node.attrs,
             'pads' in node.attrs,
             'strides' in node.attrs,
             len(node.inputs) == 1,
             len(node.outputs) >= 1,
-            all([stride > 0 for stride in node.attrs['strides']]),
         ])

-        if ret:
+        if ret and not all(stride > 0 for stride in node.attrs['strides']):
+            return False
+
+        if ret:
             self.operatorRepresentation['ceil_mode'] = node.attrs['ceil_mode']
             self.operatorRepresentation['pads'] = node.attrs['pads']
             self.operatorRepresentation['kernel_shape'] = node.attrs['kernel_shape']
             self.operatorRepresentation['strides'] = node.attrs['strides']

         return ret
🤖 Fix all issues with AI agents
In `@TargetLibraries/Generic/src/MaxPool_fp32.c`:
- Around line 46-50: The guard that validates input parameters in MaxPool_fp32.c
should also treat a kernel size of zero as invalid; update the condition
currently checking "if (W < K || S == 0)" to include "K == 0" so the function
returns early for empty kernels (this affects the validation in the function
containing the W_out calculation and the loop "for (uint32_t c = 0; c < C;
++c)"). Ensure the check prevents proceeding when K == 0 to avoid leaving max
initialized at -inf and producing invalid outputs.
♻️ Duplicate comments (1)
TargetLibraries/Generic/src/MaxPool_s8.c (1)

55-58: Still missing guard for K == 0.

As flagged in a previous review, a zero-length kernel bypasses the current guard, causes the inner loop to never execute, and writes -128 + output_offset to all output positions. Add K == 0 to the validation.

Proposed fix
-  if (L < K || S == 0) {
+  if (K == 0 || S == 0 || L < K) {
     return;
   }

@Victor-Jung
Copy link
Member

I handled both conditions directly in the C kernel by early-returning when the parameters are invalid. I couldn’t find an existing pattern for this in other kernels, so this was a best-effort approach on my side — please let me know if there’s a preferred or more idiomatic way to handle it.

Should I apply the same kind of guard to MaxPool2d as well?

Additionally, since the stride value is available from ONNX, I added a guard in the parser to catch stride == 0.

Sorry, I missed the guard statement 😁 Sure, if you can add the guard to the other maxpool kernels, it would be amazing! Thanks for the contribution. I am approving this PR, and we can merge it soon.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@Deeploy/Targets/Generic/Parsers.py`:
- Around line 195-203: The current boolean expression assigned to ret eagerly
accesses node.attrs['strides'] and can raise KeyError; modify the condition so
the positivity check runs only when 'strides' is present (e.g., replace the
inner all([stride > 0 for stride in node.attrs['strides']]) with a
short-circuiting check like ('strides' in node.attrs and all(stride > 0 for
stride in node.attrs['strides'])) or restructure the overall predicate to use
generator expressions that only evaluate node.attrs['strides'] after confirming
'strides' in node.attrs); update the expression that sets ret (and reference
node.attrs, 'strides', and the ret assignment) accordingly so missing strides
yields False without an exception.

In `@TargetLibraries/Generic/src/MaxPool_fp32.c`:
- Around line 14-16: The early-return in MaxPool_fp32.c currently checks if (H <
P || W < Q || SP == 0 || SQ == 0) but misses guarding P == 0 || Q == 0, which
allows empty pooling windows to leave max as -inf; update the condition in the
MaxPool_fp32 function to also return when P == 0 or Q == 0 (i.e., include P == 0
|| Q == 0 alongside the existing H, W, SP, SQ checks) so no invalid -inf outputs
are written.
🧹 Nitpick comments (1)
TargetLibraries/Generic/src/MaxPool_s8.c (1)

13-15: Add guards for P == 0 and Q == 0.

For consistency with the 1D variant feedback, a zero kernel size (P == 0 or Q == 0) would cause the inner loops to never execute, leaving max = -128 and producing semantically incorrect output. Consider guarding these cases as well.

♻️ Proposed fix
-  if (H < P || W < Q || SP == 0 || SQ == 0) {
+  if (P == 0 || Q == 0 || SP == 0 || SQ == 0 || H < P || W < Q) {
     return;
   }

Comment on lines 195 to 203
ret = all([
'ceil_mode' in node.attrs, 'kernel_shape' in node.attrs, 'pads' in node.attrs, 'strides' in node.attrs,
'ceil_mode' in node.attrs,
'kernel_shape' in node.attrs,
'pads' in node.attrs,
'strides' in node.attrs,
len(node.inputs) == 1,
len(node.outputs) >= 1
len(node.outputs) >= 1,
all([stride > 0 for stride in node.attrs['strides']]),
])
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid KeyError when strides is absent (Line 195–203).
all([...]) eagerly evaluates the list, so node.attrs['strides'] will throw if the attribute is missing; previously this would just return False. Guard the access and run the positivity check only when strides is present.

🛠️ Proposed fix
-        ret = all([
-            'ceil_mode' in node.attrs,
-            'kernel_shape' in node.attrs,
-            'pads' in node.attrs,
-            'strides' in node.attrs,
-            len(node.inputs) == 1,
-            len(node.outputs) >= 1,
-            all([stride > 0 for stride in node.attrs['strides']]),
-        ])
+        strides = node.attrs.get('strides')
+        ret = all([
+            'ceil_mode' in node.attrs,
+            'kernel_shape' in node.attrs,
+            'pads' in node.attrs,
+            strides is not None,
+            len(node.inputs) == 1,
+            len(node.outputs) >= 1,
+        ])
+        if ret and not all(stride > 0 for stride in strides):
+            return False
🤖 Prompt for AI Agents
In `@Deeploy/Targets/Generic/Parsers.py` around lines 195 - 203, The current
boolean expression assigned to ret eagerly accesses node.attrs['strides'] and
can raise KeyError; modify the condition so the positivity check runs only when
'strides' is present (e.g., replace the inner all([stride > 0 for stride in
node.attrs['strides']]) with a short-circuiting check like ('strides' in
node.attrs and all(stride > 0 for stride in node.attrs['strides'])) or
restructure the overall predicate to use generator expressions that only
evaluate node.attrs['strides'] after confirming 'strides' in node.attrs); update
the expression that sets ret (and reference node.attrs, 'strides', and the ret
assignment) accordingly so missing strides yields False without an exception.

@Xeratec Xeratec added the Feature Addition of new features label Feb 3, 2026
@Xeratec Xeratec added this to Deeploy Feb 3, 2026
@Xeratec Xeratec moved this to In progress in Deeploy Feb 3, 2026
@Xeratec Xeratec moved this from In progress to Need Reviewer in Deeploy Feb 3, 2026
@Xeratec Xeratec added this to the Release 0.2.2 milestone Feb 3, 2026
@Xeratec Xeratec moved this from Need Reviewer to In review in Deeploy Feb 3, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py`:
- Around line 616-630: Remove or silence the three unused local variables to
satisfy Ruff F841: eliminate the unused assignments to dilation,
inputChannelVar, and weightInChannelVar (or rename them to _dilation,
_inputChannelVar, _weightInChannelVar) in the method that builds the tiler model
where tilerModel.addTensorDimToModel(...) and tilerModel.getTensorDimVar(...)
are called; ensure any remaining needed dimension variables (e.g.,
inputBatchVar, inputLengthVar, weightOutChannelVar, weightLengthVar) are left
intact and no other logic depends on the removed variables.
- Around line 657-658: Remove the unused variable assignment pads =
parseDict["pads"] in ConvTileConstraint.py to satisfy Ruff F841; locate the
occurrence where parseDict is read (the pads assignment near stride =
parseDict["strides"][0]) and either delete that pads line entirely or, if the
read is needed for side effects, replace it with an intentional discard like _ =
parseDict["pads"] so the parser intent remains clear.
- Around line 768-769: Update all zip() calls in ConvTileConstraint.py to pass
strict=True to satisfy B905: add strict=True to the zip used to build
inputLoadSchedule (the loop that zips inputInCubes, inputWeightCubes,
inputAddCubes, inputMulCubes producing inputLoadSchedule), and likewise add
strict=True to the zip calls in the other locations mentioned (the zip usages
around lines where input/weight/add/mul cube lists are zipped and the ones at
lines 221, 583, 586, 1048, and 1051). Locate the loops/functions that use zip
(e.g., the function/method that fills inputLoadSchedule and any helper functions
that iterate over cube lists) and change zip(...) to zip(..., strict=True) for
each occurrence so mismatched-length iterables raise immediately.

Comment on lines +616 to +630
pads = parseDict["pads"]
stride = parseDict["strides"][0]
dilation = parseDict["dilations"][0]

# Add I/O dimensions to the model as variables
for bufferName in [inputBufferName, weightBufferName, mulBufferName, addBufferName, outputBufferName]:
tilerModel.addTensorDimToModel(ctxt, bufferName)

inputBatchVar = tilerModel.getTensorDimVar(tensorName = inputBufferName, dimIdx = 0)
inputLengthVar = tilerModel.getTensorDimVar(tensorName = inputBufferName, dimIdx = 1)
inputChannelVar = tilerModel.getTensorDimVar(tensorName = inputBufferName, dimIdx = 2)

weightOutChannelVar = tilerModel.getTensorDimVar(tensorName = weightBufferName, dimIdx = 0)
weightLengthVar = tilerModel.getTensorDimVar(tensorName = weightBufferName, dimIdx = 1)
weightInChannelVar = tilerModel.getTensorDimVar(tensorName = weightBufferName, dimIdx = 2)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused locals to satisfy Ruff F841.
dilation, inputChannelVar, and weightInChannelVar are assigned but unused in this method.

🧹 Proposed fix
-        dilation = parseDict["dilations"][0]
-
         # Add I/O dimensions to the model as variables
         for bufferName in [inputBufferName, weightBufferName, mulBufferName, addBufferName, outputBufferName]:
             tilerModel.addTensorDimToModel(ctxt, bufferName)
@@
-        inputChannelVar = tilerModel.getTensorDimVar(tensorName = inputBufferName, dimIdx = 2)
-
         weightOutChannelVar = tilerModel.getTensorDimVar(tensorName = weightBufferName, dimIdx = 0)
         weightLengthVar = tilerModel.getTensorDimVar(tensorName = weightBufferName, dimIdx = 1)
-        weightInChannelVar = tilerModel.getTensorDimVar(tensorName = weightBufferName, dimIdx = 2)
🧰 Tools
🪛 Ruff (0.14.14)

[error] 618-618: Local variable dilation is assigned to but never used

Remove assignment to unused variable dilation

(F841)


[error] 626-626: Local variable inputChannelVar is assigned to but never used

Remove assignment to unused variable inputChannelVar

(F841)


[error] 630-630: Local variable weightInChannelVar is assigned to but never used

Remove assignment to unused variable weightInChannelVar

(F841)

🤖 Prompt for AI Agents
In `@Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py` around lines
616 - 630, Remove or silence the three unused local variables to satisfy Ruff
F841: eliminate the unused assignments to dilation, inputChannelVar, and
weightInChannelVar (or rename them to _dilation, _inputChannelVar,
_weightInChannelVar) in the method that builds the tiler model where
tilerModel.addTensorDimToModel(...) and tilerModel.getTensorDimVar(...) are
called; ensure any remaining needed dimension variables (e.g., inputBatchVar,
inputLengthVar, weightOutChannelVar, weightLengthVar) are left intact and no
other logic depends on the removed variables.

Comment on lines +657 to +658
pads = parseDict["pads"]
stride = parseDict["strides"][0]
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused pads to satisfy Ruff F841.

🧹 Proposed fix
-        pads = parseDict["pads"]
         stride = parseDict["strides"][0]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pads = parseDict["pads"]
stride = parseDict["strides"][0]
stride = parseDict["strides"][0]
🧰 Tools
🪛 Ruff (0.14.14)

[error] 657-657: Local variable pads is assigned to but never used

Remove assignment to unused variable pads

(F841)

🤖 Prompt for AI Agents
In `@Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py` around lines
657 - 658, Remove the unused variable assignment pads = parseDict["pads"] in
ConvTileConstraint.py to satisfy Ruff F841; locate the occurrence where
parseDict is read (the pads assignment near stride = parseDict["strides"][0])
and either delete that pads line entirely or, if the read is needed for side
effects, replace it with an intentional discard like _ = parseDict["pads"] so
the parser intent remains clear.

Comment on lines +768 to +769
for a, b, add, mul in zip(inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes):
inputLoadSchedule.append({"data_in": a, "weight": b, "add": add, "mul": mul})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find Python version requirements in the project
find . -type f \( -name "setup.py" -o -name "setup.cfg" -o -name "pyproject.toml" -o -name ".python-version" -o -name "tox.ini" -o -name "requirements*.txt" \) | head -20

Repository: pulp-platform/Deeploy

Length of output: 115


🏁 Script executed:

# Check the file and locate the code at the mentioned lines
wc -l Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py

Repository: pulp-platform/Deeploy

Length of output: 132


🏁 Script executed:

# Read the relevant sections of the file
sed -n '765,775p' Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py
sed -n '1045,1055p' Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py

Repository: pulp-platform/Deeploy

Length of output: 1084


🏁 Script executed:

# Check Python version requirement
cat setup.py | grep -A 5 "python_requires"

Repository: pulp-platform/Deeploy

Length of output: 47


🏁 Script executed:

# Also check pyproject.toml
cat pyproject.toml | grep -A 5 "python"

Repository: pulp-platform/Deeploy

Length of output: 166


🌐 Web query:

B905 flake8 rule zip strict parameter Python

💡 Result:

B905 (from flake8-bugbear) flags uses of zip() with 2+ iterables (or any starred *args) that don’t pass an explicit strict= keyword. The intent is to prevent subtle bugs from zip silently truncating to the shortest iterable. Set either:

  • strict=True to raise ValueError if lengths differ (safer), or
  • strict=False to keep truncation but make it explicit.

Notes:

  • strict= exists only in Python 3.10+, so don’t enable B905 if you need to support Python <3.10.
  • itertools.count, itertools.cycle, and itertools.repeat(times=None) are excluded as infinite iterators.

Sources: flake8-bugbear docs on PyPI [1] (also mirrored elsewhere [2]); Ruff’s equivalent rule description [3].


🏁 Script executed:

# Search for all zip() calls in the file to ensure the review comment covers all instances
grep -n "zip(" Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py

Repository: pulp-platform/Deeploy

Length of output: 566


Add explicit strict= to zip() calls to satisfy B905.

The project requires Python 3.10+, which natively supports the strict= parameter. Add strict=True to the following zip() calls:

  • Lines 768-769, 1048, and 1051 (as shown in the proposed fix)
  • Also lines 221, 583, and 586 have similar patterns that should be updated consistently
Proposed fix for lines 768-769, 1048, 1051
-        for a, b, add, mul in zip(inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes):
+        for a, b, add, mul in zip(inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes, strict=True):
             inputLoadSchedule.append({"data_in": a, "weight": b, "add": add, "mul": mul})
-            for a, b in zip(inputInCubes, inputWeightCubes):
+            for a, b in zip(inputInCubes, inputWeightCubes, strict=True):
                 inputLoadSchedule.append({"data_in": a, "weight": b})
-            for a, b, c in zip(inputInCubes, inputWeightCubes, inputBiasCubes):
+            for a, b, c in zip(inputInCubes, inputWeightCubes, inputBiasCubes, strict=True):
                 inputLoadSchedule.append({"data_in": a, "weight": b, "bias": c})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for a, b, add, mul in zip(inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes):
inputLoadSchedule.append({"data_in": a, "weight": b, "add": add, "mul": mul})
for a, b, add, mul in zip(inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes, strict=True):
inputLoadSchedule.append({"data_in": a, "weight": b, "add": add, "mul": mul})
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 768-768: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

🤖 Prompt for AI Agents
In `@Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py` around lines
768 - 769, Update all zip() calls in ConvTileConstraint.py to pass strict=True
to satisfy B905: add strict=True to the zip used to build inputLoadSchedule (the
loop that zips inputInCubes, inputWeightCubes, inputAddCubes, inputMulCubes
producing inputLoadSchedule), and likewise add strict=True to the zip calls in
the other locations mentioned (the zip usages around lines where
input/weight/add/mul cube lists are zipped and the ones at lines 221, 583, 586,
1048, and 1051). Locate the loops/functions that use zip (e.g., the
function/method that fills inputLoadSchedule and any helper functions that
iterate over cube lists) and change zip(...) to zip(..., strict=True) for each
occurrence so mismatched-length iterables raise immediately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Addition of new features

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

3 participants