How to Use Euclidean, Manhattan, Chebyshev, and Weighted Distance Metrics in SQuADDS Analyzer

The SQuADDS Analyzer class supports five distance metrics—Euclidean, Manhattan, Chebyshev, Weighted Euclidean, and Custom—selected via the metric parameter in find_closest, where weighted and custom options require pre-configuration of metric_weights or custom_metric_func attributes.

The Analyzer class in the lfl-lab/squadds repository enables targeted searches through the SQuADDS quantum device database using the find_closest method. By specifying different distance metrics in this method, you control how the algorithm calculates similarity between your target design parameters and existing simulated designs.

Supported Distance Metrics Overview

The available metrics are defined in the Analyzer.__supported_metrics__ list located in squadds/core/analysis.py (lines 72-73). When you invoke find_closest, the method validates your metric argument against this list and instantiates the appropriate calculation strategy.

The five supported metrics are:

  • Euclidean: Standard L2 norm measuring straight-line distance in parameter space.
  • Manhattan: L1 norm summing absolute differences across all dimensions.
  • Chebyshev: Maximum absolute difference across any single dimension.
  • Weighted Euclidean: L2 norm with per-parameter weighting factors.
  • Custom: User-defined distance function.

Selecting a Metric in find_closest

Inside squadds/core/analysis.py (lines 89-99), the find_closest method implements metric selection through a conditional strategy pattern:

if metric == "Euclidean":
    self.set_metric_strategy(EuclideanMetric())
elif metric == "Manhattan":
    self.set_metric_strategy(ManhattanMetric())
elif metric == "Chebyshev":
    self.set_metric_strategy(ChebyshevMetric())
elif metric == "Weighted Euclidean":
    self.set_metric_strategy(WeightedEuclideanMetric(self.metric_weights))
elif metric == "Custom":
    self.set_metric_strategy(CustomMetric(self.custom_metric_func))

Each branch instantiates a specific strategy class defined in squadds/core/metrics.py, passing configuration data where required.

Euclidean Distance

Pass metric="Euclidean" to find_closest. This uses the EuclideanMetric class and requires no additional configuration. It calculates the square root of the sum of squared differences between target and simulated parameters.

Manhattan Distance

Pass metric="Manhattan" to use the ManhattanMetric class. This metric sums the absolute differences across all parameter dimensions, making it robust to outliers in individual dimensions.

Chebyshev Distance

Pass metric="Chebyshev" to employ the ChebyshevMetric class. This metric returns the maximum absolute difference across any single parameter dimension, useful when the worst-case deviation determines design compatibility.

Weighted Euclidean Distance

Pass metric="Weighted Euclidean" to use the WeightedEuclideanMetric class. You must set the analyzer.metric_weights dictionary before calling find_closest, mapping each target parameter key to a numerical weight:

analyzer.metric_weights = {
    "cavity_frequency_GHz": 2.0,
    "kappa_kHz": 1.0,
    "anharmonicity_MHz": 0.5,
    "g_MHz": 1.5,
}

Higher weights increase the penalty for deviations in that parameter, effectively prioritizing specific design characteristics during the search.

Custom Metrics

Pass metric="Custom" to use the CustomMetric class. You must assign a callable to analyzer.custom_metric_func that accepts two dictionaries—(target_dict, simulated_dict)—and returns a float distance value:

def my_metric(target, simulated):
    return sum(abs(target[k] - simulated.get(k, 0)) for k in target)

analyzer.custom_metric_func = my_metric

How Distance Calculation Works Internally

Each metric strategy inherits from the abstract MetricStrategy base class defined in squadds/core/metrics.py (lines 11-71). The strategies implement two core methods (lines 27-71, 74-98, 100-129):

  • calculate(target, simulated): Computes distance for a single design row.
  • calculate_vectorized(target_df, simulated_df): Performs optimized batch calculations across the entire DataFrame.

The find_closest method leverages calculate_vectorized for performance, falling back to calculate only when necessary. This architecture allows you to switch metrics without modifying the search algorithm's core logic.

Practical Code Examples

Using Weighted Euclidean Distance

from squadds import Analyzer, SQuADDS_DB

db = SQuADDS_DB()
analyzer = Analyzer(db)

target = {
    "cavity_frequency_GHz": 7.5,
    "kappa_kHz": 0.1,
    "anharmonicity_MHz": -0.3,
    "g_MHz": 0.02,
}

analyzer.metric_weights = {
    "cavity_frequency_GHz": 2.0,
    "kappa_kHz": 1.0,
    "anharmonicity_MHz": 0.5,
    "g_MHz": 1.5,
}

closest_df = analyzer.find_closest(
    target_params=target,
    num_top=5,
    metric="Weighted Euclidean",
    display=False,
)

Comparing Multiple Metrics

for metric_name in ["Euclidean", "Manhattan", "Chebyshev"]:
    df = analyzer.find_closest(
        target_params=target,
        num_top=3,
        metric=metric_name,
        display=False,
    )
    print(f"\nTop 3 using {metric_name}:")
    print(df[["cavity_frequency_GHz", "kappa_kHz", "anharmonicity_MHz", "g_MHz"]])

Implementing a Custom Metric

def weighted_absolute_error(target, simulated):
    return sum(
        3 * abs(target[k] - simulated.get(k, 0)) if k == "cavity_frequency_GHz" 
        else abs(target[k] - simulated.get(k, 0))
        for k in target
    )

analyzer.custom_metric_func = weighted_absolute_error

df = analyzer.find_closest(
    target_params=target,
    num_top=4,
    metric="Custom",
    display=False,
)

Summary

  • The Analyzer.find_closest method accepts a metric parameter with five valid options: Euclidean, Manhattan, Chebyshev, Weighted Euclidean, and Custom.
  • Euclidean, Manhattan, and Chebyshev metrics require no setup; pass the metric name directly to find_closest.
  • Weighted Euclidean requires pre-setting analyzer.metric_weights with a dictionary mapping parameter names to importance factors.
  • Custom metrics require assigning a callable to analyzer.custom_metric_func before searching.
  • All metric strategies are implemented in squadds/core/metrics.py and selected via the strategy pattern in squadds/core/analysis.py (lines 89-99).

Frequently Asked Questions

What is the default distance metric if I do not specify one?

If you omit the metric parameter, the Analyzer class defaults to Euclidean distance. The find_closest method instantiates EuclideanMetric() when no metric is explicitly provided, applying standard L2 normalization across all target parameters.

Can I use different weights for different parameters when searching?

Yes, use the Weighted Euclidean metric by setting analyzer.metric_weights to a dictionary where keys match your target parameter names and values represent relative importance weights. The WeightedEuclideanMetric class in squadds/core/metrics.py applies these weights during the vectorized distance calculation, penalizing deviations in high-weight parameters more severely.

How do I implement a completely custom distance calculation?

Set analyzer.custom_metric_func to a function that accepts two arguments—target (dict) and simulated (dict)—and returns a float distance value. Then call find_closest with metric="Custom". The CustomMetric class wraps your function and integrates it into the vectorized search pipeline defined in squadds/core/metrics.py (lines 131-179).

Where are the metric calculations actually performed in the source code?

The metric logic resides in squadds/core/metrics.py, where classes like EuclideanMetric, ManhattanMetric, and ChebyshevMetric implement calculate_vectorized for efficient DataFrame operations. The Analyzer class in squadds/core/analysis.py (lines 72-99) selects and instantiates these strategies based on your metric argument, delegating all distance computations to the selected strategy object.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →