Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Oct 29, 2025

📄 561% (5.61x) speedup for IntLogUniformDistribution._asdict in optuna/distributions.py

⏱️ Runtime : 132 microseconds 20.0 microseconds (best of 48 runs)

📝 Explanation and details

The optimization replaces copy.deepcopy(self.__dict__) with self.__dict__.copy() in the _asdict() method. This change delivers a 560% speedup by switching from deep copying to shallow copying.

Key optimization:

  • Deep copy → Shallow copy: copy.deepcopy() recursively copies all nested objects, while dict.copy() only copies the top-level dictionary structure
  • Removed unnecessary import: The copy module import is no longer needed

Why this works:

  • The IntLogUniformDistribution object only contains simple primitive fields (low, high, step, log) that are integers and booleans
  • Since there are no nested mutable objects in __dict__, a shallow copy provides the same isolation as a deep copy
  • copy.deepcopy() has significant overhead from traversing object graphs and checking for circular references, even for simple objects

Performance impact:
The line profiler shows the deep copy operation took 729,813ns (95% of total time), while the shallow copy takes only 50,262ns. This optimization is consistently effective across all test cases, showing 300-560% speedups regardless of the distribution's parameter values or range size.

Safety: The optimization maintains the same behavior - the returned dictionary is still independent from the original object, preventing mutations from affecting the source instance.

Correctness verification report:

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

# imports
import pytest
from optuna.distributions import IntLogUniformDistribution


# function to test
class BaseDistribution:
    pass

def _adjust_int_uniform_high(low, high, step):
    # Implements the adjustment described in the docstring
    if step == 1:
        return high
    k = (high - low) // step
    return low + k * step

class IntDistribution(BaseDistribution):
    def __init__(self, low: int, high: int, log: bool = False, step: int = 1) -> None:
        if log and step != 1:
            raise ValueError(
                "Samplers and other components in Optuna only accept step is 1 "
                "when `log` argument is True."
            )
        if low > high:
            raise ValueError(f"`low <= high` must hold, but got ({low=}, {high=}).")
        if log and low < 1:
            raise ValueError(f"`low >= 1` must hold for `log=True`, but got ({low=}, {high=}).")
        if step <= 0:
            raise ValueError(f"`step > 0` must hold, but got {step=}.")
        self.log = log
        self.step = int(step)
        self.low = int(low)
        high = int(high)
        self.high = _adjust_int_uniform_high(self.low, high, self.step)
from optuna.distributions import IntLogUniformDistribution

# unit tests

# ------------------- BASIC TEST CASES -------------------

def test_asdict_basic_fields():
    # Test with typical values
    dist = IntLogUniformDistribution(low=1, high=10, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 6.50μs -> 1.20μs (440% faster)


def test_asdict_high_equals_low():
    # Test with high == low
    dist = IntLogUniformDistribution(low=5, high=5, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 7.61μs -> 1.19μs (539% faster)


def test_asdict_minimum_low():
    # Test with minimum allowed low for log domain (low=1)
    dist = IntLogUniformDistribution(low=1, high=100, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 5.93μs -> 923ns (543% faster)




def test_asdict_high_less_than_low_raises():
    # Should raise ValueError if high < low
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=10, high=5, step=1)

def test_asdict_low_less_than_one_raises():
    # Should raise ValueError if low < 1 in log domain
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=0, high=5, step=1)

def test_asdict_step_zero_raises():
    # Should raise ValueError if step <= 0
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=1, high=10, step=0)

def test_asdict_step_negative_raises():
    # Should raise ValueError if step < 0
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=1, high=10, step=-5)

def test_asdict_log_field_absent():
    # The returned dict should NOT have 'log'
    dist = IntLogUniformDistribution(low=1, high=10, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 7.50μs -> 1.26μs (494% faster)

def test_asdict_mutation_safety():
    # Changing returned dict does not affect the object
    dist = IntLogUniformDistribution(low=1, high=10, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 6.17μs -> 940ns (556% faster)
    d["low"] = 999

# ------------------- LARGE SCALE TEST CASES -------------------

def test_asdict_large_range():
    # Test with large range
    dist = IntLogUniformDistribution(low=1, high=999, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 6.04μs -> 914ns (561% faster)



def test_asdict_performance_large():
    # Test performance with large number of calls
    dists = [IntLogUniformDistribution(low=1, high=999, step=1) for _ in range(100)]
    dicts = [dist._asdict() for dist in dists]
    for d in dicts:
        pass


#------------------------------------------------
import copy

# imports
import pytest
from optuna.distributions import IntLogUniformDistribution


# function to test
class BaseDistribution:
    pass

def _adjust_int_uniform_high(low, high, step):
    # Mimics the adjustment described in the docstring.
    if step == 1:
        return high
    # Find the largest value <= high such that (value - low) % step == 0
    k = (high - low) // step
    return k * step + low

class IntDistribution(BaseDistribution):
    def __init__(self, low: int, high: int, log: bool = False, step: int = 1) -> None:
        if log and step != 1:
            raise ValueError(
                "Samplers and other components in Optuna only accept step is 1 "
                "when `log` argument is True."
            )
        if low > high:
            raise ValueError(f"`low <= high` must hold, but got ({low=}, {high=}).")
        if log and low < 1:
            raise ValueError(f"`low >= 1` must hold for `log=True`, but got ({low=}, {high=}).")
        if step <= 0:
            raise ValueError(f"`step > 0` must hold, but got {step=}.")
        self.log = log
        self.step = int(step)
        self.low = int(low)
        high = int(high)
        self.high = _adjust_int_uniform_high(self.low, high, self.step)
from optuna.distributions import IntLogUniformDistribution

# unit tests

# 1. Basic Test Cases

def test_asdict_basic_case():
    # Test with typical values
    dist = IntLogUniformDistribution(low=1, high=10, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 7.74μs -> 1.23μs (528% faster)



def test_asdict_no_side_effects():
    # Ensure _asdict does not mutate the original object
    dist = IntLogUniformDistribution(low=1, high=5, step=1)
    orig_dict = copy.deepcopy(dist.__dict__)
    codeflash_output = dist._asdict(); _ = codeflash_output # 4.15μs -> 1.04μs (300% faster)

def test_asdict_returns_new_dict():
    # The returned dict should not be the same object as __dict__
    dist = IntLogUniformDistribution(low=1, high=5, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 6.16μs -> 1.01μs (507% faster)
    # Changing the returned dict should not affect the original
    d['low'] = 999

# 2. Edge Test Cases

def test_asdict_low_equals_high():
    # low == high, only one value in range
    dist = IntLogUniformDistribution(low=5, high=5, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 5.88μs -> 955ns (516% faster)


def test_asdict_step_is_one():
    # step=1, should not adjust high
    dist = IntLogUniformDistribution(low=1, high=100, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 7.70μs -> 1.17μs (560% faster)




def test_asdict_zero_step_raises():
    # step=0 should raise ValueError
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=1, high=10, step=0)

def test_asdict_negative_step_raises():
    # step<0 should raise ValueError
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=1, high=10, step=-1)

def test_asdict_low_greater_than_high_raises():
    # low > high should raise ValueError
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=10, high=1, step=1)

def test_asdict_low_less_than_one_with_log_raises():
    # low < 1 with log=True should raise ValueError
    with pytest.raises(ValueError):
        IntLogUniformDistribution(low=0, high=10, step=1)

def test_asdict_log_and_step_not_one_raises():
    # log=True and step!=1 should raise ValueError
    with pytest.raises(ValueError):
        IntDistribution(low=1, high=10, log=True, step=2)

# 3. Large Scale Test Cases

def test_asdict_large_range_step_one():
    # Test large range with step=1
    dist = IntLogUniformDistribution(low=1, high=999, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 7.78μs -> 1.18μs (558% faster)




def test_asdict_performance_large():
    # Test performance on large objects (but < 1000 elements)
    dist = IntLogUniformDistribution(low=1, high=1000, step=1)
    codeflash_output = dist._asdict(); d = codeflash_output # 7.77μs -> 1.27μs (513% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from optuna.distributions import IntLogUniformDistribution

def test_IntLogUniformDistribution__asdict():
    IntLogUniformDistribution._asdict(IntLogUniformDistribution(1, 1, step=1))
🔎 Concolic Coverage Tests and Runtime
Test File::Test Function Original ⏱️ Optimized ⏱️ Speedup
codeflash_concolic_qluqolhr/tmpusxyoa3o/test_concolic_coverage.py::test_IntLogUniformDistribution__asdict 6.09μs 985ns 519%✅

To edit these changes git checkout codeflash/optimize-IntLogUniformDistribution._asdict-mhbj3cz9 and push.

Codeflash

The optimization replaces `copy.deepcopy(self.__dict__)` with `self.__dict__.copy()` in the `_asdict()` method. This change delivers a **560% speedup** by switching from deep copying to shallow copying.

**Key optimization**: 
- **Deep copy → Shallow copy**: `copy.deepcopy()` recursively copies all nested objects, while `dict.copy()` only copies the top-level dictionary structure
- **Removed unnecessary import**: The `copy` module import is no longer needed

**Why this works**:
- The `IntLogUniformDistribution` object only contains simple primitive fields (`low`, `high`, `step`, `log`) that are integers and booleans
- Since there are no nested mutable objects in `__dict__`, a shallow copy provides the same isolation as a deep copy
- `copy.deepcopy()` has significant overhead from traversing object graphs and checking for circular references, even for simple objects

**Performance impact**:
The line profiler shows the deep copy operation took 729,813ns (95% of total time), while the shallow copy takes only 50,262ns. This optimization is consistently effective across all test cases, showing **300-560% speedups** regardless of the distribution's parameter values or range size.

**Safety**: The optimization maintains the same behavior - the returned dictionary is still independent from the original object, preventing mutations from affecting the source instance.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 29, 2025 05:01
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 29, 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