| import math
|
| from typing import Dict, Optional
|
|
|
|
|
| class ComplexityScorer:
|
| """
|
| Complexity scoring for feature selection algorithms
|
| based on instantiated time and space complexity.
|
| """
|
|
|
| def __init__(self, alpha: float = 0.7, log_base: float = math.e):
|
| """
|
| Parameters
|
| ----------
|
| alpha : float
|
| Weight for time complexity in the final score.
|
| Typical values: 0.6 ~ 0.8
|
| log_base : float
|
| Base of logarithm (default: natural log).
|
| """
|
| self.alpha = alpha
|
| self.log_base = log_base
|
|
|
|
|
|
|
|
|
|
|
| def _log(self, x: float) -> float:
|
| """Logarithm with configurable base."""
|
| if self.log_base == math.e:
|
| return math.log(x)
|
| return math.log(x, self.log_base)
|
|
|
| def complexity_score(self, value: float, min_value: float) -> float:
|
| """
|
| Generic complexity-to-score mapping.
|
|
|
| Parameters
|
| ----------
|
| value : float
|
| Instantiated complexity value of an algorithm.
|
| min_value : float
|
| Minimum complexity among all compared algorithms.
|
|
|
| Returns
|
| -------
|
| score : float
|
| Normalized score in (0, 1].
|
| """
|
| if value <= 0 or min_value <= 0:
|
| raise ValueError("Complexity values must be positive.")
|
|
|
| ratio = value / min_value
|
| return 1.0 / (1.0 + self._log(ratio))
|
|
|
| def time_score(self, f_t: float, f_t_min: float) -> float:
|
| """Time complexity score."""
|
| return self.complexity_score(f_t, f_t_min)
|
|
|
| def space_score(self, f_s: float, f_s_min: float) -> float:
|
| """Space complexity score."""
|
| return self.complexity_score(f_s, f_s_min)
|
|
|
| def total_score(
|
| self,
|
| f_t: float,
|
| f_t_min: float,
|
| f_s: float,
|
| f_s_min: float,
|
| ) -> float:
|
| """Combined complexity score."""
|
| s_t = self.time_score(f_t, f_t_min)
|
| s_s = self.space_score(f_s, f_s_min)
|
| return self.alpha * s_t + (1.0 - self.alpha) * s_s
|
|
|
|
|
|
|
|
|
|
|
|
|
| def instantiate_complexity(
|
| formula: str,
|
| n: int,
|
| d: int,
|
| k: Optional[int] = None
|
| ) -> float:
|
| """
|
| Instantiate asymptotic complexity formula.
|
|
|
| Supported variables: n, d, k
|
|
|
| Examples
|
| --------
|
| "n * d**2"
|
| "n * d * k"
|
| "d**2"
|
| "d + k"
|
| """
|
| local_vars = {"n": n, "d": d}
|
| if k is not None:
|
| local_vars["k"] = k
|
|
|
| try:
|
| return float(eval(formula, {"__builtins__": {}}, local_vars))
|
| except Exception as e:
|
| raise ValueError(f"Invalid complexity formula: {formula}") from e
|
|
|
|
|
| n, d, k = 1000, 50, 10
|
|
|
| algorithms = {
|
| "mRMR": {"time": "n * d**2", "space": "d**2"},
|
| "JMIM": {"time": "n * d * k", "space": "d * k"},
|
| "CFR": {"time": "n * d * k","space": "d + k"},
|
| "DCSF": {"time": "n * d * k", "space": "d + k"},
|
| "IWFS": {"time": "n * d * k", "space": "d + k"},
|
| "MRI": {"time": "n * d * k", "space": "d + k"},
|
| "MRMD": {"time": "n * d**2", "space": "d**2"},
|
| "UCRFS": {"time": "n * d + n**2", "space": "n**2"},
|
|
|
|
|
| }
|
|
|
|
|
| time_vals = []
|
| space_vals = {}
|
|
|
| for name, comp in algorithms.items():
|
| f_t = instantiate_complexity(comp["time"], n, d, k)
|
| f_s = instantiate_complexity(comp["space"], n, d, k)
|
| time_vals.append(f_t)
|
| space_vals[name] = (f_t, f_s)
|
|
|
| f_t_min = min(time_vals)
|
| f_s_min = min(v[1] for v in space_vals.values())
|
|
|
| scorer = ComplexityScorer(alpha=0.7)
|
|
|
| for name, (f_t, f_s) in space_vals.items():
|
| score = scorer.total_score(f_t, f_t_min, f_s, f_s_min)
|
| print(f"{name}: complexity score = {score:.4f}")
|
|
|