Skip to content

Commit

Permalink
14 experiments with alternative implementations (#15)
Browse files Browse the repository at this point in the history
* experiments

* experiments
  • Loading branch information
tschm authored Jan 19, 2025
1 parent 6959956 commit 2bc2ded
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

venv:
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv
uv venv --python '3.12'

install: venv ## Install dependencies and setup environment
uv pip install --upgrade pip
Expand Down
13 changes: 13 additions & 0 deletions experiments/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2025 Stanford University Convex Optimization Group
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
23 changes: 23 additions & 0 deletions experiments/alter1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import cvxpy as cp

from cvx.ball.utils.circle import Center, Circle


def min_circle_cvx(points, **kwargs):
# Use con_1 if no constraint construction is defined
# cvxpy variable for the radius
r = cp.Variable(name="Radius")
# cvxpy variable for the midpoint
x = cp.Variable(points.shape[1], name="Midpoint")
objective = cp.Minimize(r)
constraints = [cp.SOC(r, point - x) for point in points]
# * #np.ones(points.shape[0]),
# points - cp.outer(np.ones(points.shape[0]), x),
# axis=1,
# )
# ]

problem = cp.Problem(objective=objective, constraints=constraints)
problem.solve(**kwargs)

return Circle(radius=float(r.value), center=Center(x.value))
23 changes: 23 additions & 0 deletions experiments/alter2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import cvxpy as cp

from cvx.ball.utils.circle import Center, Circle


def min_circle_cvx(points, **kwargs):
# Use con_1 if no constraint construction is defined
# cvxpy variable for the radius
r = cp.Variable(name="Radius")
# cvxpy variable for the midpoint
x = cp.Variable(points.shape[1], name="Midpoint")
objective = cp.Minimize(r)
constraints = [cp.norm2(x - point) <= r for point in points]
# * #np.ones(points.shape[0]),
# points - cp.outer(np.ones(points.shape[0]), x),
# axis=1,
# )
# ]

problem = cp.Problem(objective=objective, constraints=constraints)
problem.solve(**kwargs)

return Circle(radius=float(r.value), center=Center(x.value))
82 changes: 82 additions & 0 deletions experiments/asymptotic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import time
from typing import List, Tuple

import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from cvx.ball.solver import min_circle_cvx


def cvx(n: int) -> float:
points = np.random.rand(n, 5)
return min_circle_cvx(points, solver="CLARABEL")


def measure_execution_time(func, n: int, num_trials: int = 3) -> float:
"""Run multiple trials and return average execution time"""
times = []
for _ in range(num_trials):
start = time.time()
func(n)
times.append(time.time() - start)
return np.mean(times)


def run_analysis() -> Tuple[List[int], List[float]]:
# Test for different values of n (powers of 2)
sequence = np.array([2**n for n in range(4, 20)])
execution_times = []

for n in sequence:
avg_time = measure_execution_time(cvx, int(n))
execution_times.append(avg_time)
print(f"n={n}: {avg_time:.4f} seconds")

return sequence, execution_times


def plot_results(sizes: List[int], times: List[float]) -> None:
# Create figure
fig = make_subplots(specs=[[{"secondary_y": True}]])

# Add actual execution times
fig.add_trace(
go.Scatter(
x=sizes, y=times, name="Actual Time", mode="lines+markers", line=dict(color="blue"), marker=dict(size=8)
)
)

# Add theoretical O(n) complexity line
normalized_n = np.array(sizes) / sizes[0]
fig.add_trace(
go.Scatter(x=sizes, y=normalized_n * times[0], name="O(n)", line=dict(color="red", dash="dash"), mode="lines")
)

# Update layout with log scales
fig.update_layout(
title="Algorithm Performance Analysis",
xaxis=dict(
title="Input Size (n)",
type="log",
dtick="D1", # Show ticks for each power of 10
),
yaxis=dict(title="Execution Time (seconds)", type="log", dtick="D1"),
hovermode="x unified",
showlegend=True,
legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.99),
plot_bgcolor="white",
)

# Add grid lines
fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor="LightGray")
fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor="LightGray")

# Show the plot
fig.show()


if __name__ == "__main__":
# Run the analysis
sizes, times = run_analysis()
plot_results(sizes, times)
32 changes: 32 additions & 0 deletions experiments/speed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import statistics
import timeit as tt

import numpy as np

from cvx.ball.solver import min_circle_cvx
from experiments.alter1 import min_circle_cvx as alter1
from experiments.alter2 import min_circle_cvx as alter2

if __name__ == "__main__":
points = np.random.randn(10000, 5)

def cvx():
min_circle_cvx(points, solver="CLARABEL")

def alter_a():
alter1(points, solver="CLARABEL")

def alter_b():
alter2(points, solver="CLARABEL")

times_clarabel = tt.repeat(cvx, number=1, repeat=5)
print(times_clarabel)
print(statistics.mean(times_clarabel))

times_alter1 = tt.repeat(alter_a, number=1, repeat=5)
print(times_alter1)
print(statistics.mean(times_alter1))

times_alter2 = tt.repeat(alter_b, number=1, repeat=5)
print(times_alter2)
print(statistics.mean(times_alter2))
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/cvxball"]
packages = ["src/cvx"]

[tool.deptry.per_rule_ignores]
DEP002 = ["clarabel"]

0 comments on commit 2bc2ded

Please sign in to comment.