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
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))