def distill(v70, target_digits_position=7, newton_steps=4,
            skip_gradient_descent=False,
            min_model_digits=None,
            allowed_forms=('diag35s', 'diag35c')):
  """Distills a raw v70 into high-precision few-parameters form."""
  xtol = 10**(-target_digits_position)
  ftol = 100 * xtol * xtol
  sinfo0 = scalar_sector.numpy_scalar_manifold_evaluator(v70)
  def still_good(v70):
    sinfo = scalar_sector.numpy_scalar_manifold_evaluator(v70)
    return (abs(sinfo0.potential - sinfo.potential) < 1e-3 and
            (sinfo.stationarity < 20 * sinfo0.stationarity or
             sinfo.stationarity < 0.01))
  canonicalized = canonicalize_v70(v70, still_good=still_good)
  canon_v70s = [v['v70'] for k, v in canonicalized.items()
                if v is not None and k in allowed_forms]
  iter_models = find_simple_low_dimensional_model(
      canon_v70s,
      min_digits=min_model_digits or int(
          -math.log(sinfo0.stationarity, 10)) // 2 - 2,
      still_good=still_good)
  from_mdnewton = False
  for num_model, model in enumerate(iter_models):
    refined_model, from_mdnewton = distill_model(
        model,
        target_digits_position=target_digits_position,
        newton_steps=newton_steps,
        skip_gradient_descent=skip_gradient_descent)
    if refined_model is not None:
      return refined_model, from_mdnewton
  return None, False
def redistill(distillate_filename, out_filename, expected_dps=60,
              newton_steps=7,
              min_model_digits=None):
  """Second-distills a distillate."""
  if mpmath.mp.dps < expected_dps:
    raise RuntimeError(
        'Precision setting for mpmath is below the expected dps '
        'for this calculation: %s < %s' % (mpmath.mp.dps, expected_dps))
  # Tries to find out if there are further opportunities that reduce the number
  # of parameters which have been missed in 1st distillation, and if so,
  # performs the corresponding reduction.
  # In any case, adds basic information about physics.
  distillate_model = read_distillate_model(distillate_filename)
  v70 = v70_from_model(distillate_model)
  if expected_dps > 15:
    sinfo0 = scalar_sector_mpmath.mpmath_scalar_manifold_evaluator(v70)
  else:
    sinfo0 = scalar_sector.numpy_scalar_manifold_evaluator(v70)
  threshold_deviation = (max(3 * sinfo0.stationarity, 1e-7)
                         if expected_dps >= 40 else 1e-3)
  # First-distillation produced a high-accuracy form of the numerical
  # solution, so we should use a stricter check here.
  def still_good(v70_trial):
    sinfo = scalar_sector.numpy_scalar_manifold_evaluator(v70_trial)
    return (abs(sinfo0.potential - sinfo.potential) < threshold_deviation and
            sinfo.stationarity < threshold_deviation)
  # This is strongly expected to work, given that we already had highly
  # accurate data.
  low_dim_model_take2 = iter(find_simple_low_dimensional_model(
      [v70],
      min_digits=max(3, min_model_digits or int(
          -mpmath.log(sinfo0.stationarity, 10)) // 2 - 2),
      still_good=still_good)).next()
  if len(low_dim_model_take2.params) < len(distillate_model.params):
    print('Note: Could further reduce the number of model parameters '
          '({} -> {}).'.format(distillate_model.params,
                               low_dim_model_take2.params))
  model_take2, mdnewton_ok = distill_model(
      low_dim_model_take2,
      newton_steps=newton_steps,
      still_good=still_good,
      target_digits_position=expected_dps)
  v70_accurate = v70_from_model(model_take2)
  sinfo_accurate = scalar_sector_mpmath.mpmath_scalar_manifold_evaluator(
      v70_accurate)
  stationarity = sinfo_accurate.stationarity
  log10_stationarity = math.floor(mpmath.log(stationarity, 10))
  approx_stationarity_str = (
      '%.3fe%d' %
      (float(stationarity *
             mpmath.mpf(10)**(-log10_stationarity)),
       log10_stationarity))
  with open(out_filename, 'w') as h:
    write_model(h, model_take2,
                dict(mdnewton_ok=mdnewton_ok,
                     potential=str(sinfo_accurate.potential),
                     stationarity=approx_stationarity_str))
def distill_model(low_dimensional_model,
                  target_digits_position=7,
                  newton_steps=4,  # May be None.
                  skip_gradient_descent=False,
                  still_good=lambda _: True):
  """Distills a low-dimensional model to high precision."""
  xtol = 10**(-target_digits_position)
  ftol = 100 * xtol * xtol
  log10_stop_quality = -(2 * target_digits_position + 2)
  from_mdnewton = False
  # First, find out if MDNewton works for refining this model.
  # If it does, this is excellent.
  try:
    if newton_steps is None:
      print('Skipping MDNewton')
      raise StopIteration()
    print('[Distillation] Trying MDNewton, steps=%d, target_digits_position=%d,'
          ' dps=%d' % (newton_steps, target_digits_position, mpmath.mp.dps))
    refined_model, from_mdnewton = (
        refine_model_mdnewton_mpmath(
            low_dimensional_model,
            still_good=still_good,
            log10_stop_quality=log10_stop_quality,
            newton_steps=newton_steps), True)
  except Exception as exn:
    print('[Distillation] MDNewton failed:', exn)
    try:
      if skip_gradient_descent:
        print('Skipping Gradient Descent')
        raise StopIteration()
      refined_pot_stat_pos, from_mdnewton = (
          refine_model_gradient_descent(
              low_dimensional_model,
              log10_stop_quality=log10_stop_quality), False)
      refined_model = get_low_dimensional_model(
          refined_pot_stat_pos[-1],
          # In this case, i.e. when we had to use gradient-descent,
          # export a complete model, and do not allow making guesses.
          # (As these were problematic in the first place!)
          digits=15)
    except Exception as exn:
      print('[Distillation] Gradient descent failed:', exn)
      # Otherwise, try to refine the model using nelder-mead.
      # (May want to change this to use high-precision mpmath Nelder-Mead.)
      refined_model, from_mdnewton = (
          refine_model_nelder_mead(
              low_dimensional_model, xtol=xtol, ftol=ftol), False)
  refined_v70 = v70_from_model(refined_model)
  sinfo = scalar_sector.numpy_scalar_manifold_evaluator(
      refined_v70.astype(float))
  if sinfo.stationarity < 1e-5:
    return refined_model, from_mdnewton
  return None, False
示例#4
0
def canonicalize_v70(v70,
                     do_diagonalize_35s=(True, False),
                     still_good=lambda v70: True):
    """Canonicalizes a 70-vector.

  Finds and applies a suitable SO(8) rotation that minimizes the number of
  entries of the 35s and 35c symmetric traceless matrices.

  Args:
    v70: The vector describing a point on the scalar manifold.
    do_diagonalize_35s: Sequence of values to try for the boolean parameter that
      controls whether to diagonalize 35s or 35c.
    still_good: Function checking whether the canonicalized form
      still describes a physically equivalent point.

  Returns:
    A dict with keys 'diag35s' and 'diag35c', and entries each of the form
    {'35s: <8x8 matrix>, '35c': <8x8 matrix>, 'v70': <reduced 70-vector>,
     'potential': <the potential>, 'stationarity': <stationarity-value>}
    or None (if no longer 'good') that describe the outcome of diagonalizing
    the 35s or 35c.
  """
    ret = {}
    for diagonalize_35s in do_diagonalize_35s:
        m35s0, m35c0 = _diagonalize_half_of_v70(
            v70, diagonalize_35s=diagonalize_35s)
        m35s, m35c = _reduce_second_m35(m35s0, m35c0, diagonalize_35s)
        v70_diag = algebra.e7.v70_from_35s35c(m35s, m35c)
        sinfo = scalar_sector.numpy_scalar_manifold_evaluator(v70_diag)
        if not still_good(v70_diag):
            # We tried to canonicalize but failed - i.e. we changed the solution
            # to something different.
            ret['diag35s' if diagonalize_35s else 'diag35c'] = None
        else:
            ret['diag35s' if diagonalize_35s else 'diag35c'] = {
                '35s': m35s,
                '35c': m35c,
                'v70': v70_diag,
                'potential': sinfo.potential,
                'stationarity': sinfo.stationarity
            }
    return ret
 def still_good(v70_trial):
   sinfo = scalar_sector.numpy_scalar_manifold_evaluator(v70_trial)
   return (abs(sinfo0.potential - sinfo.potential) < threshold_deviation and
           sinfo.stationarity < threshold_deviation)
 def still_good(v70):
   sinfo = scalar_sector.numpy_scalar_manifold_evaluator(v70)
   return (abs(sinfo0.potential - sinfo.potential) < 1e-3 and
           (sinfo.stationarity < 20 * sinfo0.stationarity or
            sinfo.stationarity < 0.01))