Domain: Business Operations & Analytics

Using `consumer_complaints.csv` in this folder, build a deterministic trend-and-seasonality decomposition from the actual local data.

The original SARIMAX draft is not locally runnable in this environment, so for this task use standard-library Python only and fit an in-sample Fourier regression on the daily complaint counts.

Required method:

- Parse `date_received` using `%m/%d/%Y`.
- Aggregate the complaints to daily counts by `date_received`.
- Reindex to a continuous daily date range from the minimum `date_received` through the maximum `date_received`, filling missing days with zero complaints.
- Let `t` be the number of days since the first date in the daily series.
- Fit an ordinary least squares regression with these regressors only:
  - intercept
  - linear trend `t`
  - weekly Fourier terms with period `7.0` and order `3`
  - monthly Fourier terms with period `30.5` and order `5`
  - yearly Fourier terms with period `365.25` and order `10`
- For each Fourier order `k`, include both sine and cosine terms.
- Define `yhat` as the in-sample fitted values from that regression.
- Reconstruct the deterministic components as:
  - `trend = intercept + beta_t * t`
  - `weekly = sum of fitted weekly Fourier terms`
  - `monthly = sum of fitted monthly Fourier terms`
  - `yearly = sum of fitted yearly Fourier terms`
- Define total variance as the population variance (`ddof=0`) of `yhat` over the full in-sample daily series.
- Define each component's relative variance as `population_variance(component) / population_variance(yhat)`.
- Identify the two largest relative-variance seasonalities.
- For each of those two winning seasonalities, compute the mean of `yhat` grouped by the relevant date info, then normalize those group means so the percentages sum to `100`.
  - weekly: group by weekday name (use English names)
  - monthly: group by month number `1` through `12`
  - yearly: group by calendar year
- Sort each grouped-percentage list from highest percentage to lowest percentage.
- Compute `average_yearly_growth` as the mean of `100 * (trend[t] / trend[t-365] - 1)` over all days with a valid 365-day lag.
- Compute `last_year_growth` as `100 * (trend[last_day] / trend[last_day-365] - 1)`.
- Compute the second difference of the deterministic trend over the last 730 days and classify the growth behavior as:
  - `Stable` if the average second difference has absolute value less than `1e-6`
  - `Accelerating` if it is positive
  - `Decelerating` if it is negative
- Compute the correlation matrix of the reconstructed seasonal components `weekly`, `monthly`, and `yearly`.

Return a single JSON object with exactly these keys:

- `relative_variance`
- `top_two_seasonalities`
- `top_seasonality_percentages`
- `growth_tuple`
- `average_second_difference_last_two_years`
- `trend_behavior_last_two_years`
- `seasonality_correlation_matrix`

Output rules:

- `relative_variance` must map `Weekly`, `Monthly`, and `Yearly` to strings rounded to exactly three decimal places using round-half-to-even.
- `top_two_seasonalities` must be a two-element JSON array ordered from higher relative variance to lower relative variance.
- `top_seasonality_percentages` must map each winning seasonality name to a sorted JSON array of two-element arrays `[date_info, percentage]`, where `percentage` is a string with exactly three decimal places using round-half-to-even.
- `growth_tuple` must be a two-element JSON array of strings with exactly three decimal places using round-half-to-even, ordered as `[average_yearly_growth, last_year_growth]`.
- `average_second_difference_last_two_years` must be a string with exactly six decimal places using round-half-to-even.
- `trend_behavior_last_two_years` must be one of `Stable`, `Accelerating`, or `Decelerating`.
- `seasonality_correlation_matrix` must be a nested JSON object for `weekly`, `monthly`, and `yearly`, with every value formatted to exactly six decimal places using round-half-to-even.
- Return only the JSON object and no extra text.

Grading rubric:
criterion: The final answer is a single JSON object with exactly these keys: relative_variance, top_two_seasonalities, top_seasonality_percentages, growth_tuple, average_second_difference_last_two_years, trend_behavior_last_two_years, and seasonality_correlation_matrix.
weight: 10
criterion: The relative_variance object is exactly {"Weekly": "0.712", "Monthly": "0.003", "Yearly": "0.253"} and the top_two_seasonalities array is exactly ["Weekly", "Yearly"].
weight: 20
criterion: The Weekly grouped percentage list is exactly [["Wednesday", "19.188"], ["Tuesday", "18.771"], ["Thursday", "18.611"], ["Friday", "16.526"], ["Monday", "16.425"], ["Saturday", "6.096"], ["Sunday", "4.382"]].
weight: 20
criterion: The Yearly grouped percentage list is exactly [[2015, "40.741"], [2014, "36.256"], [2013, "23.004"]].
weight: 15
criterion: The growth_tuple is exactly ["11.257", "10.498"], the average_second_difference_last_two_years is exactly "0.000000", and the trend_behavior_last_two_years is exactly "Stable".
weight: 15
criterion: The seasonality_correlation_matrix is exactly {"weekly": {"weekly": "1.000000", "monthly": "-0.002967", "yearly": "0.000539"}, "monthly": {"weekly": "-0.002967", "monthly": "1.000000", "yearly": "-0.013657"}, "yearly": {"weekly": "0.000539", "monthly": "-0.013657", "yearly": "1.000000"}}.
weight: 20

Golden answer:
```python
import csv
import json
import math
from collections import Counter, defaultdict
from datetime import datetime, timedelta
from pathlib import Path


def mean(values):
    return sum(values) / len(values)


def variance(values):
    m = mean(values)
    return sum((x - m) ** 2 for x in values) / len(values)


def correlation(x, y):
    mx = mean(x)
    my = mean(y)
    numerator = sum((a - mx) * (b - my) for a, b in zip(x, y))
    denominator_x = math.sqrt(sum((a - mx) ** 2 for a in x))
    denominator_y = math.sqrt(sum((b - my) ** 2 for b in y))
    return numerator / (denominator_x * denominator_y)


def solve_linear_system(matrix, vector):
    n = len(matrix)
    augmented = [row[:] + [vector[i]] for i, row in enumerate(matrix)]
    for col in range(n):
        pivot_row = max(range(col, n), key=lambda r: abs(augmented[r][col]))
        augmented[col], augmented[pivot_row] = augmented[pivot_row], augmented[col]
        pivot = augmented[col][col]
        if abs(pivot) < 1e-12:
            raise ValueError("Singular normal-equation matrix")
        for j in range(col, n + 1):
            augmented[col][j] /= pivot
        for r in range(n):
            if r == col:
                continue
            factor = augmented[r][col]
            if factor == 0.0:
                continue
            for j in range(col, n + 1):
                augmented[r][j] -= factor * augmented[col][j]
    return [augmented[i][n] for i in range(n)]


def fmt3(value):
    return f"{value:.3f}"


def fmt6(value):
    return f"{value:.6f}"


path = Path(__file__).with_name("consumer_complaints.csv")
daily_counts = Counter()
with path.open(newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        received_date = datetime.strptime(row["date_received"], "%m/%d/%Y").date()
        daily_counts[received_date] += 1

start_date = min(daily_counts)
end_date = max(daily_counts)

dates = []
y = []
current = start_date
while current <= end_date:
    dates.append(current)
    y.append(float(daily_counts[current]))
    current += timedelta(days=1)

feature_names = ["const", "trend_t"]
for prefix, order in (("weekly", 3), ("monthly", 5), ("yearly", 10)):
    for k in range(1, order + 1):
        feature_names.append(f"{prefix}_sin{k}")
        feature_names.append(f"{prefix}_cos{k}")

period_map = {"weekly": 7.0, "monthly": 30.5, "yearly": 365.25}

design = []
for date_value in dates:
    t = float((date_value - start_date).days)
    row = [1.0, t]
    for prefix, order in (("weekly", 3), ("monthly", 5), ("yearly", 10)):
        period = period_map[prefix]
        for k in range(1, order + 1):
            angle = 2.0 * math.pi * k * t / period
            row.append(math.sin(angle))
            row.append(math.cos(angle))
    design.append(row)

p = len(feature_names)
xtx = [[0.0] * p for _ in range(p)]
xty = [0.0] * p
for row, target in zip(design, y):
    for i in range(p):
        xty[i] += row[i] * target
        for j in range(i, p):
            xtx[i][j] += row[i] * row[j]
for i in range(p):
    for j in range(i):
        xtx[i][j] = xtx[j][i]

beta = solve_linear_system(xtx, xty)
params = dict(zip(feature_names, beta))

trend = []
weekly = []
monthly = []
yearly = []
yhat = []

for date_value in dates:
    t = float((date_value - start_date).days)
    trend_value = params["const"] + params["trend_t"] * t
    weekly_value = 0.0
    monthly_value = 0.0
    yearly_value = 0.0

    for k in range(1, 4):
        angle = 2.0 * math.pi * k * t / 7.0
        weekly_value += params[f"weekly_sin{k}"] * math.sin(angle) + params[f"weekly_cos{k}"] * math.cos(angle)

    for k in range(1, 6):
        angle = 2.0 * math.pi * k * t / 30.5
        monthly_value += params[f"monthly_sin{k}"] * math.sin(angle) + params[f"monthly_cos{k}"] * math.cos(angle)

    for k in range(1, 11):
        angle = 2.0 * math.pi * k * t / 365.25
        yearly_value += params[f"yearly_sin{k}"] * math.sin(angle) + params[f"yearly_cos{k}"] * math.cos(angle)

    trend.append(trend_value)
    weekly.append(weekly_value)
    monthly.append(monthly_value)
    yearly.append(yearly_value)
    yhat.append(trend_value + weekly_value + monthly_value + yearly_value)

total_variance = variance(yhat)
relative_variance_raw = {
    "Weekly": variance(weekly) / total_variance,
    "Monthly": variance(monthly) / total_variance,
    "Yearly": variance(yearly) / total_variance,
}

top_two = [name for name, _ in sorted(relative_variance_raw.items(), key=lambda item: item[1], reverse=True)[:2]]

grouped_weekday = defaultdict(list)
grouped_month = defaultdict(list)
grouped_year = defaultdict(list)
for date_value, fitted in zip(dates, yhat):
    grouped_weekday[date_value.strftime("%A")].append(fitted)
    grouped_month[date_value.month].append(fitted)
    grouped_year[date_value.year].append(fitted)

def normalized_group_percentages(grouped):
    group_means = {key: mean(values) for key, values in grouped.items()}
    total = sum(group_means.values())
    return sorted([[key, fmt3(100.0 * value / total)] for key, value in group_means.items()], key=lambda item: float(item[1]), reverse=True)

top_percentages = {}
if "Weekly" in top_two:
    top_percentages["Weekly"] = normalized_group_percentages(grouped_weekday)
if "Monthly" in top_two:
    top_percentages["Monthly"] = normalized_group_percentages(grouped_month)
if "Yearly" in top_two:
    top_percentages["Yearly"] = normalized_group_percentages(grouped_year)

yearly_growth_values = []
for i in range(365, len(trend)):
    yearly_growth_values.append(100.0 * (trend[i] / trend[i - 365] - 1.0))

average_yearly_growth = mean(yearly_growth_values)
last_year_growth = 100.0 * (trend[-1] / trend[-366] - 1.0)

second_differences = []
second_difference_dates = []
for i in range(2, len(trend)):
    second_differences.append(trend[i] - 2.0 * trend[i - 1] + trend[i - 2])
    second_difference_dates.append(dates[i])

last_two_years_start = end_date - timedelta(days=730)
last_two_years_second_differences = [
    value for date_value, value in zip(second_difference_dates, second_differences) if date_value >= last_two_years_start
]
average_second_difference = mean(last_two_years_second_differences)

if abs(average_second_difference) < 1e-6:
    trend_behavior = "Stable"
elif average_second_difference > 0:
    trend_behavior = "Accelerating"
else:
    trend_behavior = "Decelerating"

correlation_matrix = {
    "weekly": {
        "weekly": fmt6(correlation(weekly, weekly)),
        "monthly": fmt6(correlation(weekly, monthly)),
        "yearly": fmt6(correlation(weekly, yearly)),
    },
    "monthly": {
        "weekly": fmt6(correlation(monthly, weekly)),
        "monthly": fmt6(correlation(monthly, monthly)),
        "yearly": fmt6(correlation(monthly, yearly)),
    },
    "yearly": {
        "weekly": fmt6(correlation(yearly, weekly)),
        "monthly": fmt6(correlation(yearly, monthly)),
        "yearly": fmt6(correlation(yearly, yearly)),
    },
}

result = {
    "relative_variance": {key: fmt3(value) for key, value in relative_variance_raw.items()},
    "top_two_seasonalities": top_two,
    "top_seasonality_percentages": top_percentages,
    "growth_tuple": [fmt3(average_yearly_growth), fmt3(last_year_growth)],
    "average_second_difference_last_two_years": fmt6(average_second_difference),
    "trend_behavior_last_two_years": trend_behavior,
    "seasonality_correlation_matrix": correlation_matrix,
}

print(json.dumps(result, ensure_ascii=True))
```

Reasoning:

- The actual local file is `consumer_complaints.csv`, and the environment does not provide `statsmodels`, `pandas`, or `numpy`, so the original SARIMAX draft cannot be verified locally as written.
- The rewritten task uses a deterministic Fourier regression with the same linear trend and the same weekly, monthly, and yearly seasonal frequencies. That keeps the trend/seasonality decomposition objective while making the task runnable with standard-library Python only.
- Complaint counts are first aggregated to a continuous daily series from `2013-08-30` through `2015-12-01`, filling absent dates with zero counts.
- The regression is solved by normal equations, then the fitted trend, weekly, monthly, and yearly components are reconstructed directly from the estimated coefficients.
- Weekly and yearly are the two largest seasonal relative variances in the verified local result.
- The trend is linear, so its second difference is effectively zero over the final two years, which classifies the growth behavior as `Stable` under the `1e-6` tolerance.
- All 3-decimal and 6-decimal outputs are formatted with Python formatting, which uses round-half-to-even.

Verified result:

```json
{"relative_variance": {"Weekly": "0.712", "Monthly": "0.003", "Yearly": "0.253"}, "top_two_seasonalities": ["Weekly", "Yearly"], "top_seasonality_percentages": {"Weekly": [["Wednesday", "19.188"], ["Tuesday", "18.771"], ["Thursday", "18.611"], ["Friday", "16.526"], ["Monday", "16.425"], ["Saturday", "6.096"], ["Sunday", "4.382"]], "Yearly": [[2015, "40.741"], [2014, "36.256"], [2013, "23.004"]]}, "growth_tuple": ["11.257", "10.498"], "average_second_difference_last_two_years": "0.000000", "trend_behavior_last_two_years": "Stable", "seasonality_correlation_matrix": {"weekly": {"weekly": "1.000000", "monthly": "-0.002967", "yearly": "0.000539"}, "monthly": {"weekly": "-0.002967", "monthly": "1.000000", "yearly": "-0.013657"}, "yearly": {"weekly": "0.000539", "monthly": "-0.013657", "yearly": "1.000000"}}}
```