Skip to content

Support for MaxPool1D and RQSConv1D for PULPOpen#146

Open
marchioa wants to merge 7 commits intopulp-platform:develfrom
marchioa:titancfi
Open

Support for MaxPool1D and RQSConv1D for PULPOpen#146
marchioa wants to merge 7 commits intopulp-platform:develfrom
marchioa:titancfi

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

Walkthrough

Adds 1D MaxPool and RQSConv1D support across Generic and PULPOpen: kernels, templates, bindings, tiler/tiling constraints, parsers, platform mappings, and test config updates; also adjusts Conv1D im2col sizing and MaxPool header consolidation.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Recorded MaxPool1D and RQSConv1D additions and im2col buffer fix.
Generic templates & bindings
Deeploy/Targets/Generic/Templates/MaxPoolTemplate.py, Deeploy/Targets/Generic/Bindings.py
Renamed base MaxPool template, added a 1D reference template and an explicit int8_t MaxPool1D binding.
Generic kernels & headers
TargetLibraries/Generic/inc/kernel/MaxPool.h, TargetLibraries/Generic/inc/kernel/MaxPool1d.h (removed), TargetLibraries/Generic/src/MaxPool_fp32.c, TargetLibraries/Generic/src/MaxPool_s8.c, TargetLibraries/Generic/src/MaxPool1D_fp32.c (moved/removed), TargetLibraries/Generic/inc/DeeployBasicMath.h
Consolidated 1D declarations into MaxPool.h, removed standalone MaxPool1d.h, added/relocated FP32 and s8 1D implementations (s8 added, fp32 relocated), and removed the MaxPool1d.h include from DeeployBasicMath.h; added 2D guards.
PULPOpen templates & bindings
Deeploy/Targets/PULPOpen/Templates/MaxPoolTemplate.py, Deeploy/Targets/PULPOpen/Bindings.py
Added PULPMaxPool1D_8_Template, created PULP 1D maxpool bindings for int8/uint8, and updated existing 2D bindings to use the new MaxPoolTemplate.
PULPOpen Conv1D templates
Deeploy/Targets/PULPOpen/Templates/ConvTemplate.py
Changed im2col transient size computation for 1D to be channel-aware and removed conditional pointwise path—1D now emits conv variant unconditionally.
PULPOpen tiler & tile constraints
Deeploy/Targets/PULPOpen/TileConstraints/ConvTileConstraint.py, Deeploy/Targets/PULPOpen/Tiler.py
Added RQConv1DTileConstraint with 1D-specific tiling, added PULPRQSConv1DTilingReadyBindings and PULPMaxPool1DTilingReadyBindings, and exposed 1D tiling readiness bindings.
PULPOpen platform mapping
Deeploy/Targets/PULPOpen/Platform.py
Added MaxPool1DParser/Mapper, included 1D tiling bindings in Conv1DMapper, and updated PULPMapping to expose both MaxPool1D and MaxPool2D mappers.
Generic parser
Deeploy/Targets/Generic/Parsers.py
MaxPoolParser now enforces positive stride (stride > 0) validation.
Tests / configs
DeeployTest/*_config.py, DeeployTest/test_deeploy_internal.py
Updated kernel test paths to explicitly reference Regular_1D and/or Regular_2D MaxPool kernel variants instead of generic entries.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant ONNX as ONNX Node
participant Parser as Generic Parser
participant Mapper as NodeMapper
participant Tiler as Tiler / TileConstraint
participant Bindings as Bindings/Templates
participant Kernel as Target Kernel
ONNX->>Parser: parse MaxPool/Conv1D (validate stride, attrs)
Parser->>Mapper: produce parseDict
Mapper->>Tiler: select tiling-ready bindings (1D/2D)
Tiler->>Tiler: RQConv1DTileConstraint / serialize tiling solution
Tiler->>Bindings: select template & binding (PULP/Generic, 1D)
Bindings->>Kernel: emit kernel call (pulp_nn_maxpool/_conv 1D variant)
Kernel-->>Bindings: compiled kernel implementation

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Possibly related PRs

Suggested labels

Bug

Suggested reviewers

  • Xeratec
  • Victor-Jung
🚥 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 directly summarizes the main changes: adding MaxPool1D and RQSConv1D support for the PULPOpen platform, which aligns with the primary objectives of the PR.
Description check ✅ Passed The PR description clearly outlines the changes made: adding MaxPool1D and RQSConv1D support, renaming MaxPool2D tests, and fixing an im2col buffer size issue. It directly relates to the changeset.

✏️ 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

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.

@Victor-Jung Victor-Jung moved this from In review to Ready for Merge in Deeploy Feb 5, 2026
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: Ready for Merge

Development

Successfully merging this pull request may close these issues.

3 participants