Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Jan 22, 2026

📄 22% (0.22x) speedup for lagrange_interpolation in src/numerical/calculus.py

⏱️ Runtime : 5.03 milliseconds 4.14 milliseconds (best of 89 runs)

📝 Explanation and details

The optimization achieves a 21% speedup by eliminating repeated tuple indexing operations in the nested loops.

Key changes:

  1. Pre-extraction of coordinates: The optimized version extracts x_coords and y_coords into separate lists before the main loop using list comprehensions.
  2. Reduced tuple indexing: Instead of accessing points[i][0] and points[j][0] multiple times in the inner loop, the code now accesses x_coords[i] and x_coords[j], which are direct list lookups.
  3. Local variable caching: The value xi = x_coords[i] is cached in the outer loop to avoid repeated list access.

Why this is faster:
In Python, tuple indexing (points[i][1]) requires:

  1. Looking up the tuple object in the list
  2. Performing index validation
  3. Retrieving the element from the tuple

With separate coordinate lists, we eliminate step 3 (tuple unpacking) and reduce the overhead to simple list indexing. In the hot inner loop that executes ~60,000 times (as shown in line profiler), this overhead compounds significantly.

The line profiler shows the critical inner loop line (term *= ...) dropped from 32.5ms to 28.2ms (~13% improvement on that line alone), even though two new list comprehensions add minimal overhead (~0.2ms total).

Test results indicate:

  • Small inputs (2-4 points): 12-30% slower due to list comprehension overhead dominating
  • Medium inputs (20-50 points): 13-22% faster as inner loop benefits emerge
  • Large inputs (50-100 points): 18-25% faster as repeated indexing savings compound

This optimization is most beneficial when n (number of points) is large, making the O(n²) inner loop the dominant cost. For typical use cases with 20+ interpolation points, the speedup justifies the upfront coordinate extraction cost.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 68 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 1 Passed
📊 Tests Coverage 100.0%
🌀 Click to see Generated Regression Tests
import random  # used for deterministic large-scale test randomness
from typing import List, Tuple

# imports
import pytest  # used for our unit tests
from src.numerical.calculus import lagrange_interpolation


def test_basic_linear_two_points():
    # Simple linear function y = 2*x + 1 defined by two points
    points = [(0.0, 1.0), (1.0, 3.0)]
    # Interpolating at 0.5 should give exactly 2.0
    codeflash_output = lagrange_interpolation(points, 0.5)
    interpolated = codeflash_output  # 2.40μs -> 2.95μs (18.8% slower)
    # Interpolating at node x=1 should return the node's y exactly
    codeflash_output = lagrange_interpolation(
        points, 1.0
    )  # 1.11μs -> 1.44μs (22.5% slower)


def test_basic_quadratic_three_points():
    # Quadratic function y = x^2 using three non-collinear points
    points = [(-1.0, 1.0), (0.0, 0.0), (2.0, 4.0)]
    # Interpolate at x = 1.0 should give 1.0
    codeflash_output = lagrange_interpolation(
        points, 1.0
    )  # 2.99μs -> 3.59μs (16.7% slower)
    # Interpolate at x = 0.5 should give 0.25
    codeflash_output = lagrange_interpolation(
        points, 0.5
    )  # 1.57μs -> 1.85μs (15.2% slower)


def test_exact_nodes_return_node_value_for_many_points():
    # Create several arbitrary points sampled from y = 3*x - 7 (linear)
    points = [(-2.0, -13.0), (0.0, -7.0), (1.5, -2.5), (3.0, 2.0)]
    # For each node, interpolation at that node must return the exact node y
    for xi, yi in points:
        # interpolation at a node should reproduce the original node value
        codeflash_output = lagrange_interpolation(
            points, xi
        )  # 10.0μs -> 10.9μs (7.88% slower)


def test_single_point_returns_constant_value():
    # With a single point the interpolation should always return that point's y
    points = [(2.0, 5.0)]
    # Test several x values including negative and large to ensure constant behavior
    for x_test in [-100.0, 0.0, 2.0, 3.14]:
        codeflash_output = lagrange_interpolation(
            points, x_test
        )  # 2.87μs -> 4.07μs (29.5% slower)


def test_empty_points_returns_zero():
    # The implementation initializes result to 0.0 and returns it if no points provided
    points: List[Tuple[float, float]] = []
    codeflash_output = lagrange_interpolation(
        points, 2.0
    )  # 1.08μs -> 1.41μs (23.7% slower)


def test_duplicate_x_values_raise_zero_division_error():
    # If two points share the same x, denominators will be zero -> ZeroDivisionError expected
    points = [(0.0, 0.0), (0.0, 1.0)]
    with pytest.raises(ZeroDivisionError):
        # the algorithm will attempt to divide by (points[i][0] - points[j][0]) == 0
        codeflash_output = lagrange_interpolation(points, 0.5)
        _ = codeflash_output  # 2.43μs -> 3.24μs (24.9% slower)


def test_interpolation_for_higher_degree_polynomial_large_scale():
    # Test that interpolation reconstructs a degree-3 polynomial exactly even with many nodes.
    # Define a cubic polynomial p(x) = 3*x^3 - 2*x^2 + x - 5
    def p(x):
        return 3.0 * x**3 - 2.0 * x**2 + x - 5.0

    # Use 50 distinct nodes (well below 1000) to build the interpolation nodes.
    n_nodes = 50
    # Use deterministic nodes to keep the test reproducible
    xs = [i / 5.0 for i in range(n_nodes)]  # 0.0, 0.2, 0.4, ..., 9.8
    points = [(xi, p(xi)) for xi in xs]

    # Test interpolation at several points (including outside the nodes' convex hull).
    test_xs = [-3.0, -0.5, 1.1, 4.3, 10.0]
    for tx in test_xs:
        # For a polynomial of degree 3, interpolation with >=4 distinct nodes should reproduce p(tx).
        codeflash_output = lagrange_interpolation(
            points, tx
        )  # 1.02ms -> 836μs (22.4% faster)


def test_numerical_stability_close_to_node():
    # Use points from a quadratic y = x^2 and test interpolation extremely close to a node.
    points = [(0.0, 0.0), (1.0, 1.0), (2.0, 4.0)]
    # Choose an x extremely close to 1.0 to ensure numerical stability isn't catastrophically bad.
    tiny = 1e-12
    codeflash_output = lagrange_interpolation(points, 1.0 + tiny)
    interpolated = codeflash_output  # 2.91μs -> 3.40μs (14.4% slower)
    # Expect value close to (1 + tiny)^2 = 1 + 2*tiny + tiny^2
    expected = (1.0 + tiny) ** 2


def test_negative_and_fractional_nodes():
    # Ensure negative and fractional node x-coordinates are handled correctly.
    # We'll use polynomial y = -2*x^2 + 0.5*x + 3
    def q(x):
        return -2.0 * x**2 + 0.5 * x + 3.0

    points = [
        (-2.5, q(-2.5)),
        (-1.1, q(-1.1)),
        (0.0, q(0.0)),
        (0.7, q(0.7)),
        (2.3, q(2.3)),
    ]
    # Test at several negative, zero, and positive fractional x values
    for tx in [-3.0, -1.05, 0.0, 0.33, 1.7]:
        codeflash_output = lagrange_interpolation(
            points, tx
        )  # 15.8μs -> 16.6μs (4.67% slower)


def test_randomized_small_set_reproducible():
    # Basic randomized test ensuring reproducibility by seeding.
    random.seed(12345)

    # Construct a small polynomial of degree 2: r(x) = 4*x^2 - 3*x + 1
    def r(x):
        return 4.0 * x**2 - 3.0 * x + 1.0

    # Pick 6 random distinct x nodes in range [-5, 5] (small size for speed)
    nodes = sorted({random.uniform(-5.0, 5.0) for _ in range(12)})[:6]
    points = [(xi, r(xi)) for xi in nodes]

    # Validate interpolation at a few reproducible test points
    test_points = [random.uniform(-6.0, 6.0) for _ in range(5)]
    for tx in test_points:
        codeflash_output = lagrange_interpolation(
            points, tx
        )  # 20.1μs -> 20.5μs (2.01% slower)


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import pytest
from src.numerical.calculus import lagrange_interpolation


def test_linear_interpolation_two_points():
    """Test interpolation with two points forms a line correctly."""
    # Two points define a line: (0, 0) and (1, 1)
    points = [(0.0, 0.0), (1.0, 1.0)]
    # At x=0.5, the interpolated value should be 0.5
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 2.24μs -> 2.85μs (21.4% slower)


def test_linear_interpolation_exact_point():
    """Test that interpolation returns exact value at known points."""
    # Points: (0, 1) and (2, 5)
    points = [(0.0, 1.0), (2.0, 5.0)]
    # At x=0, should return y=1
    codeflash_output = lagrange_interpolation(points, 0.0)
    result = codeflash_output  # 2.21μs -> 2.83μs (22.0% slower)
    # At x=2, should return y=5
    codeflash_output = lagrange_interpolation(points, 2.0)
    result = codeflash_output  # 1.09μs -> 1.36μs (19.7% slower)


def test_quadratic_interpolation_three_points():
    """Test interpolation with three points through a parabola."""
    # Points: (0, 0), (1, 1), (2, 4) - part of y=x^2
    points = [(0.0, 0.0), (1.0, 1.0), (2.0, 4.0)]
    # At x=0.5, should approximate 0.25
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 2.89μs -> 3.52μs (17.8% slower)


def test_cubic_interpolation_four_points():
    """Test interpolation with four points through a cubic."""
    # Points: (0, 0), (1, 1), (2, 8), (3, 27) - part of y=x^3
    points = [(0.0, 0.0), (1.0, 1.0), (2.0, 8.0), (3.0, 27.0)]
    # At x=1.5, should approximate 3.375 (1.5^3)
    codeflash_output = lagrange_interpolation(points, 1.5)
    result = codeflash_output  # 3.61μs -> 4.33μs (16.6% slower)


def test_negative_coordinates():
    """Test interpolation with negative coordinates."""
    # Points with negative x and y values
    points = [(-2.0, -8.0), (-1.0, -1.0), (0.0, 0.0), (1.0, 1.0)]
    # At x=-0.5, should approximate -0.125 (approximately -0.5^3)
    codeflash_output = lagrange_interpolation(points, -0.5)
    result = codeflash_output  # 3.62μs -> 4.13μs (12.4% slower)


def test_fractional_coordinates():
    """Test interpolation with fractional coordinates."""
    # Points with fractional values
    points = [(0.5, 0.25), (1.5, 2.25), (2.5, 6.25)]
    # At x=1.0, should return interpolated value
    codeflash_output = lagrange_interpolation(points, 1.0)
    result = codeflash_output  # 2.94μs -> 3.58μs (18.0% slower)


def test_duplicate_x_values_different_y():
    """Test that function handles well-defined mathematical problem even with repeated x."""
    # This tests the mathematical correctness - Lagrange doesn't require uniqueness
    # but mathematically repeated x with different y is undefined
    # We test that the function still runs (mathematical correctness is problem-dependent)
    points = [(0.0, 1.0), (1.0, 2.0), (2.0, 3.0)]
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 2.89μs -> 3.47μs (16.8% slower)


def test_single_point():
    """Test interpolation with single point (constant function)."""
    # A single point defines a constant function
    points = [(5.0, 10.0)]
    # At any x, should return the y-value
    codeflash_output = lagrange_interpolation(points, 3.0)
    result = codeflash_output  # 1.42μs -> 1.97μs (27.8% slower)


def test_horizontal_line():
    """Test interpolation with horizontal line (constant y)."""
    # Multiple points with same y-value
    points = [(0.0, 5.0), (1.0, 5.0), (2.0, 5.0)]
    # At any x, should return y=5
    codeflash_output = lagrange_interpolation(points, 1.5)
    result = codeflash_output  # 3.09μs -> 3.56μs (13.3% slower)


def test_interpolation_between_points():
    """Test interpolation at value strictly between known points."""
    points = [(0.0, 0.0), (1.0, 2.0), (2.0, 1.0)]
    # At x=0.5, should be between 0 and 2, and follow parabolic shape
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 3.00μs -> 3.65μs (17.9% slower)


def test_zero_interpolation_point():
    """Test interpolation at x=0 with mixed coordinates."""
    points = [(-1.0, 2.0), (0.0, 5.0), (1.0, 3.0)]
    codeflash_output = lagrange_interpolation(points, 0.0)
    result = codeflash_output  # 3.15μs -> 3.68μs (14.4% slower)


def test_negative_interpolation_point():
    """Test interpolation at negative x values."""
    points = [(0.0, 1.0), (1.0, 2.0), (2.0, 3.0)]
    codeflash_output = lagrange_interpolation(points, -1.0)
    result = codeflash_output  # 3.06μs -> 3.60μs (15.1% slower)


def test_large_x_value_extrapolation():
    """Test interpolation far outside the data range."""
    points = [(0.0, 0.0), (1.0, 1.0), (2.0, 2.0)]
    codeflash_output = lagrange_interpolation(points, 100.0)
    result = codeflash_output  # 3.02μs -> 3.54μs (14.6% slower)


def test_very_small_x_difference():
    """Test with points that have very small x differences."""
    # Points very close together
    points = [(0.0, 0.0), (1e-6, 1e-6), (2e-6, 4e-6)]
    codeflash_output = lagrange_interpolation(points, 0.5e-6)
    result = codeflash_output  # 3.03μs -> 3.71μs (18.5% slower)


def test_very_large_y_values():
    """Test with very large y-coordinate values."""
    points = [(0.0, 1e6), (1.0, 2e6), (2.0, 3e6)]
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 3.12μs -> 3.77μs (17.1% slower)


def test_mixed_positive_negative_y():
    """Test with y-values crossing zero."""
    points = [(-1.0, -10.0), (0.0, 0.0), (1.0, 10.0)]
    codeflash_output = lagrange_interpolation(points, -0.5)
    result = codeflash_output  # 3.09μs -> 3.65μs (15.1% slower)


def test_identical_x_coordinates_same_y():
    """Test mathematical edge case with mathematically consistent identical x."""
    # This is still mathematically undefined, but tests graceful behavior
    points = [(0.0, 1.0), (1.0, 2.0), (2.0, 3.0)]
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 3.10μs -> 3.65μs (15.1% slower)


def test_very_close_x_values():
    """Test numerical stability with very close x-values."""
    # Points separated by 1e-10
    points = [(0.0, 0.0), (1e-10, 1e-10), (2e-10, 4e-10)]
    codeflash_output = lagrange_interpolation(points, 0.5e-10)
    result = codeflash_output  # 2.97μs -> 3.59μs (17.2% slower)


def test_zero_y_values():
    """Test with all y-values being zero."""
    points = [(0.0, 0.0), (1.0, 0.0), (2.0, 0.0)]
    codeflash_output = lagrange_interpolation(points, 5.0)
    result = codeflash_output  # 3.00μs -> 3.61μs (16.9% slower)


def test_single_non_zero_y():
    """Test with only one non-zero y-value."""
    points = [(0.0, 0.0), (1.0, 5.0), (2.0, 0.0)]
    # Symmetric around x=1, so at x=1 should give 5.0
    codeflash_output = lagrange_interpolation(points, 1.0)
    result = codeflash_output  # 3.00μs -> 3.63μs (17.2% slower)


def test_interpolation_at_first_point():
    """Test interpolation exactly at the first data point."""
    points = [(0.0, 3.0), (1.0, 4.0), (2.0, 5.0)]
    codeflash_output = lagrange_interpolation(points, 0.0)
    result = codeflash_output  # 3.10μs -> 3.73μs (16.9% slower)


def test_interpolation_at_last_point():
    """Test interpolation exactly at the last data point."""
    points = [(0.0, 3.0), (1.0, 4.0), (2.0, 5.0)]
    codeflash_output = lagrange_interpolation(points, 2.0)
    result = codeflash_output  # 3.00μs -> 3.60μs (16.7% slower)


def test_interpolation_at_middle_point():
    """Test interpolation exactly at a middle data point."""
    points = [(0.0, 1.0), (1.0, 2.0), (2.0, 3.0)]
    codeflash_output = lagrange_interpolation(points, 1.0)
    result = codeflash_output  # 3.05μs -> 3.60μs (15.3% slower)


def test_unsorted_points():
    """Test that interpolation works with unsorted input points."""
    # Points provided in non-sequential order
    points = [(2.0, 4.0), (0.0, 0.0), (1.0, 1.0)]
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 3.02μs -> 3.65μs (17.4% slower)


def test_very_steep_function():
    """Test with rapidly changing y-values."""
    points = [(0.0, 0.0), (1.0, 1000.0), (2.0, 0.0)]
    codeflash_output = lagrange_interpolation(points, 1.0)
    result = codeflash_output  # 3.07μs -> 3.72μs (17.5% slower)


def test_many_points_polynomial():
    """Test interpolation with many points (50 points)."""
    # Create 50 points along y=sin-like curve
    points = [(float(i), float(i % 10)) for i in range(50)]
    codeflash_output = lagrange_interpolation(points, 25.0)
    result = codeflash_output  # 206μs -> 169μs (22.0% faster)


def test_large_coordinate_values():
    """Test with very large coordinate values."""
    # Points with large x and y values
    points = [(1e5, 1e5), (2e5, 2e5), (3e5, 3e5)]
    codeflash_output = lagrange_interpolation(points, 1.5e5)
    result = codeflash_output  # 2.90μs -> 3.43μs (15.3% slower)


def test_high_degree_polynomial_approximation():
    """Test with many points defining higher-degree polynomial."""
    # 30 points creating a higher-degree polynomial
    points = [(float(i) / 10.0, (float(i) / 10.0) ** 2) for i in range(31)]
    codeflash_output = lagrange_interpolation(points, 1.5)
    result = codeflash_output  # 81.0μs -> 68.5μs (18.3% faster)


def test_dense_point_distribution():
    """Test with densely packed points."""
    # 100 points with very close spacing
    points = [(i / 100.0, (i / 100.0) ** 3) for i in range(101)]
    codeflash_output = lagrange_interpolation(points, 0.5)
    result = codeflash_output  # 841μs -> 674μs (24.7% faster)


def test_performance_with_50_points():
    """Test performance: interpolation completes reasonably with 50 points."""
    # Create 50 random-like but deterministic points
    points = [(float(i), float(i * (i + 1) % 100)) for i in range(50)]
    # Should complete without timeout
    codeflash_output = lagrange_interpolation(points, 25.5)
    result = codeflash_output  # 207μs -> 170μs (21.4% faster)


def test_oscillating_function_many_points():
    """Test with many points defining oscillating function."""
    # 60 points simulating oscillation
    points = [
        (float(i) / 10.0, 10.0 * (1 if (i // 10) % 2 == 0 else -1)) for i in range(60)
    ]
    codeflash_output = lagrange_interpolation(points, 3.5)
    result = codeflash_output  # 294μs -> 240μs (22.4% faster)


def test_monotonic_increasing_many_points():
    """Test with many monotonically increasing points."""
    # 100 monotonically increasing points
    points = [(float(i), float(i * i)) for i in range(100)]
    codeflash_output = lagrange_interpolation(points, 50.5)
    result = codeflash_output  # 819μs -> 658μs (24.4% faster)


def test_monotonic_decreasing_many_points():
    """Test with many monotonically decreasing y-values."""
    # 50 points with decreasing y-values
    points = [(float(i), float(100 - i)) for i in range(51)]
    codeflash_output = lagrange_interpolation(points, 25.0)
    result = codeflash_output  # 214μs -> 176μs (21.7% faster)


def test_piecewise_constant_approximation():
    """Test approximating piecewise constant function with many points."""
    # Points creating step function
    points = [(float(i), 1.0 if i < 50 else 2.0) for i in range(100)]
    codeflash_output = lagrange_interpolation(points, 25.0)
    result = codeflash_output  # 819μs -> 659μs (24.4% faster)


def test_large_scale_extrapolation():
    """Test extrapolation far beyond data range with many points."""
    # 40 points in range [0, 4]
    points = [(float(i) / 10.0, float(i) / 10.0) for i in range(41)]
    # Extrapolate to x=100
    codeflash_output = lagrange_interpolation(points, 100.0)
    result = codeflash_output  # 138μs -> 115μs (20.5% faster)


def test_interpolation_all_points_same_x_offset():
    """Test with all points having same x offset pattern."""
    # Points with regular x spacing: 0, 10, 20, ..., 490
    points = [(float(i * 10), float(i)) for i in range(50)]
    codeflash_output = lagrange_interpolation(points, 25.0)
    result = codeflash_output  # 206μs -> 169μs (21.8% faster)


def test_numerical_stability_large_scale():
    """Test numerical stability with large-scale values."""
    # Large values that could cause overflow in naive implementations
    points = [(i * 1e4, i * 1e4) for i in range(20)]
    codeflash_output = lagrange_interpolation(points, 9.5e4)
    result = codeflash_output  # 35.2μs -> 31.0μs (13.4% faster)


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
from src.numerical.calculus import lagrange_interpolation


def test_lagrange_interpolation():
    lagrange_interpolation([(0.0, 0.0), (2.0, 0.0)], 0.0)
🔎 Click to see Concolic Coverage Tests
Test File::Test Function Original ⏱️ Optimized ⏱️ Speedup
codeflash_concolic_kzhowrmd/tmpph399jvo/test_concolic_coverage.py::test_lagrange_interpolation 2.27μs 2.92μs -22.2%⚠️

To edit these changes git checkout codeflash/optimize-lagrange_interpolation-mkoyw7t5 and push.

Codeflash Static Badge

The optimization achieves a **21% speedup** by eliminating repeated tuple indexing operations in the nested loops. 

**Key changes:**
1. **Pre-extraction of coordinates**: The optimized version extracts `x_coords` and `y_coords` into separate lists before the main loop using list comprehensions.
2. **Reduced tuple indexing**: Instead of accessing `points[i][0]` and `points[j][0]` multiple times in the inner loop, the code now accesses `x_coords[i]` and `x_coords[j]`, which are direct list lookups.
3. **Local variable caching**: The value `xi = x_coords[i]` is cached in the outer loop to avoid repeated list access.

**Why this is faster:**
In Python, tuple indexing (`points[i][1]`) requires:
1. Looking up the tuple object in the list
2. Performing index validation
3. Retrieving the element from the tuple

With separate coordinate lists, we eliminate step 3 (tuple unpacking) and reduce the overhead to simple list indexing. In the hot inner loop that executes ~60,000 times (as shown in line profiler), this overhead compounds significantly.

The line profiler shows the critical inner loop line (`term *= ...`) dropped from **32.5ms to 28.2ms** (~13% improvement on that line alone), even though two new list comprehensions add minimal overhead (~0.2ms total).

**Test results indicate:**
- Small inputs (2-4 points): 12-30% slower due to list comprehension overhead dominating
- Medium inputs (20-50 points): 13-22% faster as inner loop benefits emerge
- Large inputs (50-100 points): 18-25% faster as repeated indexing savings compound

This optimization is most beneficial when `n` (number of points) is large, making the O(n²) inner loop the dominant cost. For typical use cases with 20+ interpolation points, the speedup justifies the upfront coordinate extraction cost.
@codeflash-ai codeflash-ai bot requested a review from KRRT7 January 22, 2026 04:44
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Jan 22, 2026
@KRRT7 KRRT7 closed this Jan 25, 2026
@KRRT7 KRRT7 deleted the codeflash/optimize-lagrange_interpolation-mkoyw7t5 branch January 25, 2026 09:03
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