Gradient-Free-Optimizers icon indicating copy to clipboard operation
Gradient-Free-Optimizers copied to clipboard

⚡️ Speed up method `DiagonalGridSearchOptimizer.grid_move` by 108%

Open misrasaurabh1 opened this issue 8 months ago • 3 comments

📄 108% (1.08x) speedup for DiagonalGridSearchOptimizer.grid_move in src/gradient_free_optimizers/optimizers/grid/diagonal_grid_search.py

⏱️ Runtime : 5.84 milliseconds 2.81 milliseconds (best of 55 runs)

📝 Explanation and details

To optimize the given DiagonalGridSearchOptimizer implementation, we can focus on improving the performance of the grid_move method by avoiding repeated calls to np.prod which is computationally expensive if repeatedly used. Additionally, we can use Python's integer arithmetic to achieve our requirements more efficiently. Below is the optimized code.

Explanation of Optimizations.

  1. Precompute cumulative products: The cumulative product of dimensions (cumprod_dims) is computed only once, and in reverse order. This helps in avoiding repeated computation via np.prod, making the process faster.
  2. Use of divmod: The divmod function replaces the need to use division and remainder operations separately, thus making the operations more efficient.
  3. Avoid recursive slicing of lists: By precomputing the cumulative products, we avoid multiple slicing operations within the loop, which can be expensive.

This optimization primarily focuses on improving the efficiency of the grid_move function which is the core logic for this optimizer.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 1028 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests Details
import numpy as np
# imports
import pytest  # used for our unit tests
from gradient_free_optimizers.optimizers.base_optimizer import BaseOptimizer
from gradient_free_optimizers.optimizers.core_optimizer import CoreOptimizer
from gradient_free_optimizers.optimizers.grid.diagonal_grid_search import \
    DiagonalGridSearchOptimizer

# Author: Simon Blanke
# Email: [email protected]
# License: MIT License




class BaseOptimizer(CoreOptimizer):
    def __init__(
        self,
        search_space,
        initialize={"grid": 4, "random": 2, "vertices": 4},
        constraints=[],
        random_state=None,
        rand_rest_p=0,
        nth_process=None,
    ):
        super().__init__(
            search_space=search_space,
            initialize=initialize,
            constraints=constraints,
            random_state=random_state,
            rand_rest_p=rand_rest_p,
            nth_process=nth_process,
        )

        self.optimizers = [self]


# unit tests

# Mock the necessary parts of the optimizer
class MockConv:
    def __init__(self, dim_sizes):
        self.dim_sizes = dim_sizes
        self.n_dimensions = len(dim_sizes)

class MockOptimizer(DiagonalGridSearchOptimizer):
    def __init__(self, dim_sizes, high_dim_pointer):
        self.conv = MockConv(dim_sizes)
        self.high_dim_pointer = high_dim_pointer

# Basic Functionality
def test_basic_single_dimension():
    optimizer = MockOptimizer([10], 3)

def test_basic_multiple_dimensions():
    optimizer = MockOptimizer([3, 3], 4)

# Edge Cases


def test_high_dimensionality():
    optimizer = MockOptimizer([10] * 100, 123456789)
    codeflash_output = optimizer.grid_move(); result = codeflash_output


def test_random_pointers_fixed_dimensions():
    dim_sizes = [10, 10, 10]
    pointer = np.random.randint(0, 1000)
    optimizer = MockOptimizer(dim_sizes, pointer)
    codeflash_output = optimizer.grid_move(); result = codeflash_output

def test_random_dimension_sizes():
    dim_sizes = [np.random.randint(1, 10) for _ in range(10)]
    pointer = np.random.randint(0, np.prod(dim_sizes))
    optimizer = MockOptimizer(dim_sizes, pointer)
    codeflash_output = optimizer.grid_move(); result = codeflash_output

# Degenerate Cases
def test_single_element_each_dimension():
    optimizer = MockOptimizer([1, 1, 1], 0)

def test_all_dimensions_one_except_one():
    optimizer = MockOptimizer([1, 1, 1, 10], 5)

# Sequential Pointers
def test_sequential_pointers_fixed_dimensions():
    dim_sizes = [4, 4]
    for pointer in range(16):
        optimizer = MockOptimizer(dim_sizes, pointer)
        codeflash_output = optimizer.grid_move(); result = codeflash_output

def test_sequential_pointers_large_dimensions():
    dim_sizes = [100, 100]
    for pointer in range(1000):
        optimizer = MockOptimizer(dim_sizes, pointer)
        codeflash_output = optimizer.grid_move(); result = codeflash_output

# Performance and Scalability
def test_very_large_dimension_sizes():
    optimizer = MockOptimizer([10000, 10000], 50000000)
    codeflash_output = optimizer.grid_move(); result = codeflash_output

def test_high_dimensionality_large_sizes():
    optimizer = MockOptimizer([100] * 20, 1234567890)
    codeflash_output = optimizer.grid_move(); result = codeflash_output
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

import numpy as np
# imports
import pytest  # used for our unit tests
from gradient_free_optimizers.optimizers.base_optimizer import BaseOptimizer
from gradient_free_optimizers.optimizers.core_optimizer import CoreOptimizer
from gradient_free_optimizers.optimizers.grid.diagonal_grid_search import \
    DiagonalGridSearchOptimizer

# Author: Simon Blanke
# Email: [email protected]
# License: MIT License

class BaseOptimizer(CoreOptimizer):
    def __init__(
        self,
        search_space,
        initialize={"grid": 4, "random": 2, "vertices": 4},
        constraints=[],
        random_state=None,
        rand_rest_p=0,
        nth_process=None,
    ):
        super().__init__(
            search_space=search_space,
            initialize=initialize,
            constraints=constraints,
            random_state=random_state,
            rand_rest_p=rand_rest_p,
            nth_process=nth_process,
        )

        self.optimizers = [self]

# unit tests

# Basic Functionality Tests



















from gradient_free_optimizers.optimizers.grid.diagonal_grid_search import DiagonalGridSearchOptimizer

To edit these changes git checkout codeflash/optimize-DiagonalGridSearchOptimizer.grid_move-m8gnxbqn and push.

Codeflash

misrasaurabh1 avatar Mar 20 '25 01:03 misrasaurabh1

Hi, can I help in any way with moving forward with merging this optimization?

misrasaurabh1 avatar Apr 08 '25 05:04 misrasaurabh1

Could you provide measurements of the speedup in a realistic example? You could use a test-function for this.

SimonBlanke avatar Apr 15 '25 18:04 SimonBlanke

HI @SimonBlanke , the performance was measured with the set of examples that are attached in the "Generated Regression Tests Details" in the PR description.

misrasaurabh1 avatar Apr 15 '25 18:04 misrasaurabh1