Skip to content

Swampland Conjectures

Kay Lehnert edited this page Feb 13, 2026 · 26 revisions

To assess the swampland conjectures, we computed a few additional quantities and made those available through the Python wrapper classy. The swampland conjectures are explained in the thesis and in more detail in the Hitchhiker's Guide to the Swampland. Here, we focus on the technical implementation.

We added various new variables:

  • $\phi_i$

Which we implemented in background_solve() of background.c

  if (pba->has_scf == _FALSE_)
  {
    pba->phi_scf_min = 0.0;
    pba->phi_scf_max = 0.0;
    pba->phi_scf_range = 0.0;
    pba->dV_V_scf_min = 0.0;
    pba->ddV_V_scf_max = 0.0;
    pba->ddV_V_at_dV_V_min = 0.0;
    pba->dV_V_at_ddV_V_max = 0.0;
    pba->swgc_expr_min = 0.0;
    pba->sswgc_min = 0.0;
    pba->AdSDC2_max = 0.0;
    pba->AdSDC4_max = 0.0;
    pba->combined_dSC_min = 0.0;
  }

. . .

  /** - Post-integration: compute all scalar field diagnostic
      quantities using vectorized operations on contiguous arrays.
      Columns are extracted from the strided background table, derived
      arrays are computed element-wise, and results are obtained via
      min/max/argmin/argmax reductions on contiguous data. */
  if (pba->has_scf == _TRUE_)
  {
    int N = pba->bt_size;
    int stride = pba->bg_size;
    int i;

    /* Allocate contiguous workspace: 13 arrays of length N */
    double *work;
    class_alloc(work, 13 * N * sizeof(double), pba->error_message);

    double *phi_col = work;
    double *V_col = work + N;
    double *dV_col = work + 2 * N;
    double *ddV_col = work + 3 * N;
    double *d3V_col = work + 4 * N;
    double *d4V_col = work + 5 * N;
    double *ratio_dV = work + 6 * N;
    double *ratio_ddV = work + 7 * N;
    double *swgc_arr = work + 8 * N;
    double *sswgc_arr = work + 9 * N;
    double *AdSDC2_arr = work + 10 * N;
    double *AdSDC4_arr = work + 11 * N;
    double *comb_arr = work + 12 * N;

    /* Cache column offsets */
    int idx_phi = pba->index_bg_phi_scf;
    int idx_V = pba->index_bg_V_scf;
    int idx_dV = pba->index_bg_dV_scf;
    int idx_ddV = pba->index_bg_ddV_scf;
    int idx_d3V = pba->index_bg_d3V_scf;
    int idx_d4V = pba->index_bg_d4V_scf;

    /* Extract columns from strided table into contiguous arrays */
    for (i = 0; i < N; i++)
    {
      double *row = pba->background_table + i * stride;
      phi_col[i] = row[idx_phi];
      V_col[i] = row[idx_V];
      dV_col[i] = row[idx_dV];
      ddV_col[i] = row[idx_ddV];
      d3V_col[i] = row[idx_d3V];
      d4V_col[i] = row[idx_d4V];
    }

    /* Compute derived ratio arrays element-wise.
       V==0 rows get sentinel values so they never win min/max. */
    for (i = 0; i < N; i++)
    {
      if (V_col[i] != 0.0)
      {
        double invV = 1.0 / V_col[i];
        ratio_dV[i] = fabs(dV_col[i]) * invV;
        ratio_ddV[i] = ddV_col[i] * invV;
        swgc_arr[i] = 2.0 * d3V_col[i] * d3V_col[i] - ddV_col[i] * d4V_col[i] - ddV_col[i] * ddV_col[i];
        double rp = dV_p_scf(pba, phi_col[i]) * invV;
        comb_arr[i] = 0.25 * (3.0 * rp * rp - 2.0 * ratio_ddV[i]);
      }
      else
      {
        ratio_dV[i] = 1.e100;
        ratio_ddV[i] = -1.e100;
        swgc_arr[i] = 1.e100;
        comb_arr[i] = 1.e100;
      }
    }

    /* Compute phi-only diagnostics element-wise */
    for (i = 0; i < N; i++)
    {
      sswgc_arr[i] = sswgc(pba, phi_col[i]);
      AdSDC2_arr[i] = AdSDC2(pba, phi_col[i]);
      AdSDC4_arr[i] = AdSDC4(pba, phi_col[i]);
    }

    /* Reductions: min, max, argmin, argmax on contiguous arrays */
    double phi_min_val, phi_max_val, swgc_min_val, sswgc_min_val;
    double AdSDC2_max_val, AdSDC4_max_val, comb_min_val;
    int idx_min_dV, idx_max_ddV;

    /* Use cblas_idamax-style argmin/argmax: single pass each */
    phi_min_val = phi_col[0];
    for (i = 1; i < N; i++)
      if (phi_col[i] < phi_min_val)
        phi_min_val = phi_col[i];
    phi_max_val = phi_col[0];
    for (i = 1; i < N; i++)
      if (phi_col[i] > phi_max_val)
        phi_max_val = phi_col[i];
    idx_min_dV = 0;
    for (i = 1; i < N; i++)
      if (ratio_dV[i] < ratio_dV[idx_min_dV])
        idx_min_dV = i;
    idx_max_ddV = 0;
    for (i = 1; i < N; i++)
      if (ratio_ddV[i] > ratio_ddV[idx_max_ddV])
        idx_max_ddV = i;
    swgc_min_val = swgc_arr[0];
    for (i = 1; i < N; i++)
      if (swgc_arr[i] < swgc_min_val)
        swgc_min_val = swgc_arr[i];
    sswgc_min_val = sswgc_arr[0];
    for (i = 1; i < N; i++)
      if (sswgc_arr[i] < sswgc_min_val)
        sswgc_min_val = sswgc_arr[i];
    AdSDC2_max_val = AdSDC2_arr[0];
    for (i = 1; i < N; i++)
      if (AdSDC2_arr[i] > AdSDC2_max_val)
        AdSDC2_max_val = AdSDC2_arr[i];
    AdSDC4_max_val = AdSDC4_arr[0];
    for (i = 1; i < N; i++)
      if (AdSDC4_arr[i] > AdSDC4_max_val)
        AdSDC4_max_val = AdSDC4_arr[i];
    comb_min_val = comb_arr[0];
    for (i = 1; i < N; i++)
      if (comb_arr[i] < comb_min_val)
        comb_min_val = comb_arr[i];

    /* Store results */
    pba->phi_scf_min = phi_min_val;
    pba->phi_scf_max = phi_max_val;
    pba->phi_scf_range = phi_max_val - phi_min_val;

    pba->dV_V_scf_min = (ratio_dV[idx_min_dV] < 1.e99) ? ratio_dV[idx_min_dV] : 0.0;
    pba->ddV_V_at_dV_V_min = (ratio_dV[idx_min_dV] < 1.e99) ? ratio_ddV[idx_min_dV] : 0.0;
    pba->ddV_V_scf_max = (ratio_ddV[idx_max_ddV] > -1.e99) ? ratio_ddV[idx_max_ddV] : 0.0;
    pba->dV_V_at_ddV_V_max = (ratio_ddV[idx_max_ddV] > -1.e99) ? ratio_dV[idx_max_ddV] : 0.0;
    pba->swgc_expr_min = (swgc_min_val < 1.e99) ? swgc_min_val : 0.0;
    pba->sswgc_min = (sswgc_min_val < 1.e99) ? sswgc_min_val : 0.0;
    pba->AdSDC2_max = (AdSDC2_max_val > -1.e99) ? AdSDC2_max_val : 0.0;
    pba->AdSDC4_max = (AdSDC4_max_val > -1.e99) ? AdSDC4_max_val : 0.0;
    pba->combined_dSC_min = (comb_min_val < 1.e99) ? comb_min_val : 0.0;

    free(work);
  }
pba->phi_ini_scf_computed = pvecback_integration[pba->index_bi_phi_scf];
    pba->phi_prime_scf_computed = pvecback_integration[pba->index_bi_phi_prime_scf];
    if (pba->background_verbose > 2)
    {
      printf("[background] attractor_regime_scf=%d, phi_ini_scf_computed=%e, phi_prime_scf_computed=%e\n",
             pba->attractor_regime_scf,
             pba->phi_ini_scf_computed,
             pba->phi_prime_scf_computed);
    }
  }
  else
  {
    pba->phi_ini_scf_computed = 0.0;
    pba->phi_prime_scf_computed = 0.0;
    pba->attractor_regime_scf = 0;
    if (pba->background_verbose > 0)
    {
      printf("No scalar field present. No initial field values set.\n");
    }

background.h

    short attractor_ic_scf;                         /**< whether the scalar field has attractor initial conditions */
    double phi_ini_scf_computed;                    /**< computed initial \f$ \phi \f$ actually used after attractor/NaN checks */
    double phi_prime_scf_computed;                  /**< computed initial \f$ d\phi/d\tau \f$ actually used after attractor/NaN checks */
    double phi_scf_min;                             /**< minimum \f$ \phi \f$ encountered over the background table */
    double phi_scf_max;                             /**< maximum \f$ \phi \f$ encountered over the background table */
    double phi_scf_range;                           /**< \f$ \phi_{max}-\phi_{min} \f$ over the background table */
    double dV_V_scf_min;                            /**< minimum \f$ |dV/d\phi|/V \f$ encountered over the background table (de Sitter Conjecture) */
    double ddV_V_scf_max;                           /**< maximum \f$ d^2V/d\phi^2/V \f$ encountered over the background table (second de Sitter Conjecture) */
    double ddV_V_at_dV_V_min;                       /**< \f$ d^2V/d\phi^2/V \f$ evaluated when \f$ |dV/d\phi|/V \f$ reaches its minimum */
    double dV_V_at_ddV_V_max;                       /**< \f$ |dV/d\phi|/V \f$ evaluated when \f$ d^2V/d\phi^2/V \f$ reaches its maximum */
    double swgc_expr_min;                           /**< minimum of \f$ 2(d^3V/d\phi^3)^2 - (d^2V/d\phi^2)(d^4V/d\phi^4) - (d^2V/d\phi^2)^2 \f$ (scalar weak gravity conjecture) */
    double sswgc_min;                               /**< minimum of the strong scalar weak gravity conjecture expression \f$ M_P^2 m^2 \partial_\phi^2(1/m^2) \f$ */
    double AdSDC2_max;                              /**< maximum of AdSDC2 boundary expression during evolution */
    double AdSDC4_max;                              /**< maximum of AdSDC4 boundary expression during evolution */
    double combined_dSC_min;                        /**< minimum of \f$ (3(dV_p)^2/V^2 - 2 d^2V/d\phi^2/V)/4 \f$ during evolution, a strong form of a combined de Sitter conjecture, stemming from the FLB and the SSWGC. */
    int attractor_regime_scf;                       /**< attractor regime used: 0=no attractor, 1=large-field, 2=approximate, 3=small-field, 4=approximate small-field */

cclassy.pxd

        double phi_ini_scf_computed
        double phi_prime_scf_computed
        double phi_scf_min
        double phi_scf_max
        double phi_scf_range
        double dV_V_scf_min
        double ddV_V_scf_max
        double ddV_V_at_dV_V_min
        double dV_V_at_ddV_V_max
        double swgc_expr_min
        double sswgc_min
        double AdSDC2_max
        double AdSDC4_max
        double combined_dSC_min
        int attractor_regime_scf

classy.pyx

            elif name == 'phi_ini_scf_ic':
                value = self.ba.phi_ini_scf_computed
            elif name == 'phi_prime_scf_ic':
                value = self.ba.phi_prime_scf_computed
            elif name == 'phi_scf_min':
                value = self.ba.phi_scf_min
            elif name == 'phi_scf_max':
                value = self.ba.phi_scf_max
            elif name == 'phi_scf_range':
                value = self.ba.phi_scf_range
            elif name == 'dV_V_scf_min':
                value = self.ba.dV_V_scf_min
            elif name == 'ddV_V_scf_max':
                value = self.ba.ddV_V_scf_max
            elif name == 'ddV_V_at_dV_V_min':
                value = self.ba.ddV_V_at_dV_V_min
            elif name == 'dV_V_at_ddV_V_max':
                value = self.ba.dV_V_at_ddV_V_max
            elif name == 'swgc_expr_min':
                value = self.ba.swgc_expr_min
            elif name == 'sswgc_min':
                value = self.ba.sswgc_min
            elif name == 'AdSDC2_max':
                value = self.ba.AdSDC2_max
            elif name == 'AdSDC4_max':
                value = self.ba.AdSDC4_max
            elif name == 'combined_dSC_min':
                value = self.ba.combined_dSC_min
            elif name == 'attractor_regime_scf':
                value = self.ba.attractor_regime_scf

Clone this wiki locally