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

> Learn to use Euclidean Manhattan Chebyshev and Weighted distance metrics in SQuADDS Analyzer's find_closest function Configure custom metrics for advanced analysis.

- Repository: [Levenson-Falk Lab/squadds](https://github.com/lfl-lab/squadds)
- Tags: how-to-guide
- Published: 2026-03-06

---

**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`](https://github.com/lfl-lab/squadds/blob/main/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`](https://github.com/lfl-lab/squadds/blob/main/squadds/core/analysis.py) (lines 89-99), the `find_closest` method implements metric selection through a conditional strategy pattern:

```python
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`](https://github.com/lfl-lab/squadds/blob/main/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:

```python
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:

```python
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`](https://github.com/lfl-lab/squadds/blob/main/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

```python
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

```python
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

```python
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`](https://github.com/lfl-lab/squadds/blob/main/squadds/core/metrics.py) and selected via the strategy pattern in [`squadds/core/analysis.py`](https://github.com/lfl-lab/squadds/blob/main/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`](https://github.com/lfl-lab/squadds/blob/main/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`](https://github.com/lfl-lab/squadds/blob/main/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`](https://github.com/lfl-lab/squadds/blob/main/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`](https://github.com/lfl-lab/squadds/blob/main/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.