Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Nov 12, 2025

📄 33% (0.33x) speedup for IPAdapterField.validate_ip_adapter_weight in invokeai/app/invocations/ip_adapter.py

⏱️ Runtime : 319 microseconds 240 microseconds (best of 130 runs)

📝 Explanation and details

The optimization replaces the original any() function with generator expression approach with a more direct conditional logic that eliminates intermediate data structure creation and function call overhead.

Key Changes:

  1. Eliminated list creation for single floats: Instead of always converting single floats to [weights], the optimized version handles single floats directly with a simple range check, avoiding list allocation entirely.

  2. Replaced any() with explicit loop: The original code used any(i < -1 or i > 2 for i in to_validate) which creates a generator object and involves function call overhead. The optimized version uses a direct for loop that short-circuits immediately when an invalid value is found.

  3. Branch specialization: By using separate if/else branches for lists vs single values, each code path is optimized for its specific data type without unnecessary conversions.

Why This is Faster:

  • Memory allocation reduction: Single float validation no longer creates a temporary list
  • Function call overhead elimination: Removes the any() function call and generator creation
  • Early termination: The explicit loop can return immediately upon finding the first invalid value
  • Better CPU cache behavior: Direct comparisons are more cache-friendly than generator-based iterations

Performance Impact:
The test results show consistent 30-77% speedups across all scenarios, with particularly strong gains for single float validation (up to 77% faster). Even large lists with 1000 elements see ~30% improvement, demonstrating the optimization scales well. The validation is commonly called during model parameter setup, making these microsecond savings meaningful in aggregate.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 46 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime

from typing import Union

imports

import pytest
from invokeai.app.invocations.ip_adapter import IPAdapterField

-------------------------------

Unit tests for validate_ip_adapter_weight

-------------------------------

1. Basic Test Cases

def test_single_valid_weight_middle():
# Test a single valid weight in the middle of the range
codeflash_output = IPAdapterField.validate_ip_adapter_weight(1.0) # 1.99μs -> 1.13μs (75.8% faster)

def test_single_valid_weight_lower_bound():
# Test a single valid weight at the lower bound
codeflash_output = IPAdapterField.validate_ip_adapter_weight(-1.0) # 1.76μs -> 1.07μs (65.3% faster)

def test_single_valid_weight_upper_bound():
# Test a single valid weight at the upper bound
codeflash_output = IPAdapterField.validate_ip_adapter_weight(2.0) # 1.71μs -> 997ns (71.5% faster)

def test_list_valid_weights():
# Test a list of valid weights
weights = [0.0, 1.5, -0.5, 2.0, -1.0]
codeflash_output = IPAdapterField.validate_ip_adapter_weight(weights) # 2.10μs -> 1.41μs (49.0% faster)

def test_list_valid_weights_bounds():
# Test a list with weights at the bounds
weights = [-1.0, 2.0]
codeflash_output = IPAdapterField.validate_ip_adapter_weight(weights) # 1.67μs -> 1.17μs (43.3% faster)

2. Edge Test Cases

def test_single_weight_below_lower_bound():
# Test a single weight just below the lower bound
with pytest.raises(ValueError) as excinfo:
IPAdapterField.validate_ip_adapter_weight(-1.00001) # 2.30μs -> 1.45μs (58.6% faster)

def test_single_weight_above_upper_bound():
# Test a single weight just above the upper bound
with pytest.raises(ValueError) as excinfo:
IPAdapterField.validate_ip_adapter_weight(2.00001) # 2.29μs -> 1.52μs (50.2% faster)

def test_list_with_one_invalid_weight_below():
# Test a list with one invalid weight below the lower bound
weights = [0.0, -1.1, 1.0]
with pytest.raises(ValueError) as excinfo:
IPAdapterField.validate_ip_adapter_weight(weights) # 2.47μs -> 1.70μs (45.6% faster)

def test_list_with_one_invalid_weight_above():
# Test a list with one invalid weight above the upper bound
weights = [2.1, 1.0, 0.0]
with pytest.raises(ValueError) as excinfo:
IPAdapterField.validate_ip_adapter_weight(weights) # 2.20μs -> 1.53μs (44.0% faster)

def test_list_with_multiple_invalid_weights():
# Test a list with multiple invalid weights
weights = [-1.2, 2.3, 0.5]
with pytest.raises(ValueError) as excinfo:
IPAdapterField.validate_ip_adapter_weight(weights) # 2.07μs -> 1.39μs (48.7% faster)

def test_list_with_valid_and_invalid_weights():
# Test a list with both valid and invalid weights
weights = [-1.0, 0.0, 2.1]
with pytest.raises(ValueError) as excinfo:
IPAdapterField.validate_ip_adapter_weight(weights) # 2.78μs -> 1.96μs (42.2% faster)

def test_empty_list():
# Test an empty list (should be valid as there are no invalid weights)
weights = []
codeflash_output = IPAdapterField.validate_ip_adapter_weight(weights) # 1.31μs -> 770ns (70.1% faster)

def test_single_weight_at_float_precision_limit():
# Test a single weight at float precision boundary
codeflash_output = IPAdapterField.validate_ip_adapter_weight(-1.0 + 1e-15) # 1.79μs -> 1.01μs (77.3% faster)
codeflash_output = IPAdapterField.validate_ip_adapter_weight(2.0 - 1e-15) # 754ns -> 484ns (55.8% faster)

def test_list_with_float_precision_limits():
# Test a list with weights at float precision boundaries
weights = [-1.0, 2.0, 1.9999999999999998, -0.9999999999999998]
codeflash_output = IPAdapterField.validate_ip_adapter_weight(weights) # 1.92μs -> 1.28μs (50.0% faster)

def test_weight_as_integer():
# Test integer values for weights
codeflash_output = IPAdapterField.validate_ip_adapter_weight(0) # 1.52μs -> 761ns (99.5% faster)
codeflash_output = IPAdapterField.validate_ip_adapter_weight(2) # 653ns -> 389ns (67.9% faster)
codeflash_output = IPAdapterField.validate_ip_adapter_weight(-1) # 556ns -> 329ns (69.0% faster)
codeflash_output = IPAdapterField.validate_ip_adapter_weight([0, 1, 2, -1]) # 898ns -> 737ns (21.8% faster)

def test_weight_as_large_negative_integer():
# Test a large negative integer
with pytest.raises(ValueError):
IPAdapterField.validate_ip_adapter_weight(-100) # 2.21μs -> 1.37μs (61.7% faster)

def test_weight_as_large_positive_integer():
# Test a large positive integer
with pytest.raises(ValueError):
IPAdapterField.validate_ip_adapter_weight(100) # 2.22μs -> 1.29μs (71.5% faster)

def test_weight_as_non_numeric_type():
# Test passing a string instead of a float/list
with pytest.raises(TypeError):
IPAdapterField.validate_ip_adapter_weight("not_a_number") # 2.92μs -> 2.17μs (34.7% faster)

def test_weight_as_list_with_non_numeric():
# Test passing a list with a non-numeric value
weights = [1.0, "bad", 0.0]
with pytest.raises(TypeError):
IPAdapterField.validate_ip_adapter_weight(weights) # 3.02μs -> 2.31μs (30.7% faster)

def test_weight_as_none():
# Test passing None as weight
with pytest.raises(TypeError):
IPAdapterField.validate_ip_adapter_weight(None) # 2.50μs -> 1.86μs (34.0% faster)

3. Large Scale Test Cases

def test_large_list_all_valid():
# Test a large list of valid weights
weights = [1.0 for _ in range(1000)]
codeflash_output = IPAdapterField.validate_ip_adapter_weight(weights) # 44.3μs -> 34.2μs (29.4% faster)

def test_large_list_with_one_invalid_at_start():
# Test a large list with one invalid value at the start
weights = [-1.1] + [1.0 for _ in range(999)]
with pytest.raises(ValueError):
IPAdapterField.validate_ip_adapter_weight(weights) # 2.26μs -> 1.45μs (55.5% faster)

def test_large_list_with_one_invalid_at_end():
# Test a large list with one invalid value at the end
weights = [1.0 for _ in range(999)] + [2.1]
with pytest.raises(ValueError):
IPAdapterField.validate_ip_adapter_weight(weights) # 45.1μs -> 34.6μs (30.3% faster)

def test_large_list_with_one_invalid_in_middle():
# Test a large list with one invalid value in the middle
weights = [1.0 for _ in range(500)] + [-1.2] + [1.0 for _ in range(499)]
with pytest.raises(ValueError):
IPAdapterField.validate_ip_adapter_weight(weights) # 23.8μs -> 18.3μs (30.4% faster)

def test_large_list_with_multiple_invalid():
# Test a large list with multiple invalid values
weights = [1.0 for _ in range(495)] + [-2.0, 3.0, -1.1, 2.5, 1.0, 0.5, 2.0, -1.0, 1.0, 2.0]
with pytest.raises(ValueError):
IPAdapterField.validate_ip_adapter_weight(weights) # 23.7μs -> 18.1μs (30.9% faster)

def test_large_list_with_all_valid_and_edge_values():
# Test a large list with valid and edge values
weights = [-1.0, 2.0] * 500
codeflash_output = IPAdapterField.validate_ip_adapter_weight(weights) # 44.5μs -> 34.6μs (28.7% faster)

def test_large_list_empty():
# Test a large empty list (should be valid)
weights = []
codeflash_output = IPAdapterField.validate_ip_adapter_weight(weights) # 1.28μs -> 780ns (64.0% faster)

codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

#------------------------------------------------
from typing import List, Optional, Union

imports

import pytest
from invokeai.app.invocations.ip_adapter import IPAdapterField
from pydantic import BaseModel, Field, field_validator

unit tests

---------------------------

Basic Test Cases

---------------------------

def test_single_weight_below_lower_bound():
"""Test a single weight just below the lower bound."""
with pytest.raises(ValueError) as excinfo:
IPAdapterField(weight=-1.0001)

def test_single_weight_above_upper_bound():
"""Test a single weight just above the upper bound."""
with pytest.raises(ValueError) as excinfo:
IPAdapterField(weight=2.0001)

def test_list_of_weights_one_below_bound():
"""Test a list with one weight below the lower bound."""
weights = [0.5, -1.1, 1.0]
with pytest.raises(ValueError) as excinfo:
IPAdapterField(weight=weights)

def test_list_of_weights_one_above_bound():
"""Test a list with one weight above the upper bound."""
weights = [0.5, 2.1, 1.0]
with pytest.raises(ValueError) as excinfo:
IPAdapterField(weight=weights)

def test_list_of_weights_multiple_out_of_bounds():
"""Test a list with multiple out-of-bounds weights."""
weights = [-1.5, 2.5, 0.0]
with pytest.raises(ValueError) as excinfo:
IPAdapterField(weight=weights)

def test_weight_is_string_should_fail():
"""Test that a string weight raises a validation error."""
with pytest.raises(Exception):
IPAdapterField(weight="1.0")

def test_list_with_non_numeric_should_fail():
"""Test that a list with a non-numeric value raises a validation error."""
with pytest.raises(Exception):
IPAdapterField(weight=[1.0, "bad", 0.0])

def test_nan_weight_should_fail():
"""Test that a NaN weight raises a validation error."""
import math
with pytest.raises(ValueError):
IPAdapterField(weight=math.nan)

def test_list_with_nan_weight_should_fail():
"""Test that a list containing NaN raises a validation error."""
import math
with pytest.raises(ValueError):
IPAdapterField(weight=[0.0, math.nan, 1.0])

def test_inf_weight_should_fail():
"""Test that an infinite weight raises a validation error."""
with pytest.raises(ValueError):
IPAdapterField(weight=float('inf'))

def test_list_with_inf_weight_should_fail():
"""Test that a list containing infinity raises a validation error."""
with pytest.raises(ValueError):
IPAdapterField(weight=[0.0, float('-inf'), 1.0])

---------------------------

Large Scale Test Cases

---------------------------

def test_large_list_one_invalid_weight():
"""Test a large list (1000 elements) with one invalid weight."""
weights = [1.0 for _ in range(999)] + [2.1]
with pytest.raises(ValueError) as excinfo:
IPAdapterField(weight=weights)

def test_large_list_all_invalid_weights():
"""Test a large list (1000 elements) all out of bounds."""
weights = [2.5 for _ in range(1000)]
with pytest.raises(ValueError) as excinfo:
IPAdapterField(weight=weights)

codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-IPAdapterField.validate_ip_adapter_weight-mhvss6tw and push.

Codeflash Static Badge

The optimization replaces the original `any()` function with generator expression approach with a more direct conditional logic that eliminates intermediate data structure creation and function call overhead.

**Key Changes:**
1. **Eliminated list creation for single floats**: Instead of always converting single floats to `[weights]`, the optimized version handles single floats directly with a simple range check, avoiding list allocation entirely.

2. **Replaced `any()` with explicit loop**: The original code used `any(i < -1 or i > 2 for i in to_validate)` which creates a generator object and involves function call overhead. The optimized version uses a direct `for` loop that short-circuits immediately when an invalid value is found.

3. **Branch specialization**: By using separate `if/else` branches for lists vs single values, each code path is optimized for its specific data type without unnecessary conversions.

**Why This is Faster:**
- **Memory allocation reduction**: Single float validation no longer creates a temporary list
- **Function call overhead elimination**: Removes the `any()` function call and generator creation
- **Early termination**: The explicit loop can return immediately upon finding the first invalid value
- **Better CPU cache behavior**: Direct comparisons are more cache-friendly than generator-based iterations

**Performance Impact:**
The test results show consistent 30-77% speedups across all scenarios, with particularly strong gains for single float validation (up to 77% faster). Even large lists with 1000 elements see ~30% improvement, demonstrating the optimization scales well. The validation is commonly called during model parameter setup, making these microsecond savings meaningful in aggregate.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 12, 2025 09:28
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant