All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aya.guest0x0.tyck.Normalizer Maven / Gradle / Ivy

package org.aya.guest0x0.tyck;

import kala.collection.mutable.MutableMap;
import org.aya.guest0x0.cubical.CofThy;
import org.aya.guest0x0.cubical.Formula;
import org.aya.guest0x0.cubical.Partial;
import org.aya.guest0x0.cubical.Restr;
import org.aya.guest0x0.syntax.BdryData;
import org.aya.guest0x0.syntax.Keyword;
import org.aya.guest0x0.syntax.Term;
import org.aya.guest0x0.tyck.HCompPDF.Transps;
import org.aya.guest0x0.util.LocalVar;
import org.aya.guest0x0.util.Param;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public record Normalizer(
  @NotNull MutableMap rho
) implements CofThy.SubstObj {
  public static @NotNull Normalizer create() {
    return new Normalizer(MutableMap.create());
  }

  public static @NotNull Term rename(@NotNull Term term) {
    return new Renamer(MutableMap.create()).term(term);
  }

  public boolean propExt(Restr ll, Restr rr) {
    return CofThy.propExt(this, ll, rr, Normalizer::restr);
  }

  public Param param(Param param) {
    return new Param<>(param.x(), term(param.type()));
  }

  @Override public void put(LocalVar i, boolean isLeft) {
    rho.put(i, Term.end(isLeft));
  }

  @Override public boolean contradicts(LocalVar i, boolean newIsLeft) {
    if (!rho.containsKey(i)) return false;
    if (!(rho.get(i).asFormula() instanceof Formula.Lit lit)) return false;
    return lit.isLeft() != newIsLeft;
  }

  @Override public @Nullable LocalVar asRef(@NotNull Term term) {
    return term instanceof Term.Ref ref ? ref.var() : null;
  }

  @Override public @NotNull Normalizer derive() {
    return new Normalizer(MutableMap.from(rho));
  }

  public Term term(Term term) {
    return switch (term) {
      case Term.Ref ref -> rho.getOption(ref.var())
        .map(Normalizer::rename)
        .map(this::term).getOrDefault(ref);
      case Term.UI u -> u;
      case Term.Lam lam -> new Term.Lam(lam.x(), term(lam.body()));
      case Term.DT dt -> new Term.DT(dt.isPi(), param(dt.param()), term(dt.cod()));
      case Term.Two two -> {
        var f = term(two.f());
        var a = term(two.a());
        // Either a tuple or a stuck term is preserved
        if (!two.isApp() || !(f instanceof Term.Lam lam)) yield new Term.Two(two.isApp(), f, a);
        rho.put(lam.x(), a);
        var body = term(lam.body());
        rho.remove(lam.x());
        yield body;
      }
      case Term.Proj proj -> {
        var t = term(proj.t());
        if (!(t instanceof Term.Two tup)) yield new Term.Proj(t, proj.isOne());
        assert !tup.isApp();
        yield proj.isOne() ? tup.f() : tup.a();
      }
      case Term.Call call -> {
        var fn = call.fn().core;
        fn.telescope().zip(call.args()).forEach(zip -> rho.put(zip._1.x(), term(zip._2)));
        yield term(fn.body());
      }
      case Term.Path path -> new Term.Path(path.data().fmap(this::term));
      case Term.PLam pLam -> new Term.PLam(pLam.dims(), term(pLam.fill()));
      case Term.PCall pApp -> {
        var i = pApp.i().map(this::term);
        var p = term(pApp.p());
        if (p instanceof Term.PLam pLam) {
          pLam.dims().zipView(i).forEach(rho::put);
          var fill = term(pLam.fill());
          pLam.dims().forEach(rho::remove);
          yield fill;
        }
        var b = pApp.b();
        // b.dims().zipView(i).forEach(zip -> rho.put(zip._1, zip._2));
        var partial = partial(b);
        if (partial instanceof Partial.Const what) yield what.u();
        // b.dims().forEach(rho::remove);
        yield new Term.PCall(p, i, partial);
      }
      case Term.Mula f -> formulae(f.asFormula().fmap(this::term));
      case Term.Cof cof -> new Term.Cof(restr(cof.restr()));
      case Term.Transp transp -> {
        var parkerLiu = restr(transp.restr().restr());
        // Because of his talk about lax 2-functors!
        if (CofThy.satisfied(parkerLiu)) yield Term.id("x");
        yield transp(new LocalVar("i"), term(transp.cover()), new Term.Cof(parkerLiu));
      }
      case Term.PartTy par -> new Term.PartTy(term(par.ty()), term(par.restr()));
      case Term.PartEl par -> new Term.PartEl(partial(par.inner()));
      case Term.Sub sub -> new Term.Sub(term(sub.ty()), partial(sub.par()));
      case Term.InS inS -> {
        var restr = restr(inS.restr());
        var e = term(inS.e());
        if (e instanceof Term.OutS outS && propExt(outS.par().restr(), restr))
          yield outS.e();
        yield new Term.InS(e, restr);
      }
      case Term.OutS outS -> {
        var partial = partial(outS.par());
        if (partial instanceof Partial.Const what) yield what.u();
        var e = term(outS.e());
        if (e instanceof Term.InS inS) yield inS.e();
        yield new Term.OutS(e, partial);
      }
      case Term.Hcomp hcomp -> {
        var data = hcomp.data().fmap(this::term);
        if (data.walls().app(Term.end(false)) instanceof Term.PartEl p
          && p.inner() instanceof Partial.Const c) yield c.u();
        yield new Term.Hcomp(data);
      }
    };
  }

  public @NotNull Partial partial(@NotNull Partial partial) {
    return partial.flatMap(this::term);
  }

  public Restr restr(@NotNull Restr restr) {
    return restr.fmap(this::term).normalize();
  }

  private Term transp(LocalVar i, Term cover, Term.Cof cof) {
    return switch (cover.app(new Term.Ref(i))) {
      case Term.DT dt && dt.isPi() -> Term.mkLam("f", u0 -> Term.mkLam("x", v -> {
        var laptop = new Transps(rename(new Term.Lam(i, dt.param().type())), cof);
        var w = laptop.invFill(i).app(v);
        // w0 = w.subst(i, 0), according to Minghao Liu
        var w0 = laptop.inv().app(v);
        var cod = rename(new Term.Lam(i, dt.codomain(w)));
        return new Term.Transp(cod, cof).app(u0.app(w0));
      }));
      case Term.UI u && u.keyword() == Keyword.U -> Term.id("u");
      case Term.DT dt /*&& !dt.isPi()*/ -> Term.mkLam("t", u0 -> {
        var laptop = new Transps(rename(new Term.Lam(i, dt.param().type())), cof);
        // Simon Huber wrote u0.1 both with and without parentheses, extremely confusing!!
        var v = laptop.fill(i).app(u0.proj(true));
        return new Term.Two(false, laptop.mk().app(u0.proj(true)),
          new Term.Transp(rename(new Term.Lam(i, dt.codomain(v))), cof).app(u0.proj(false)));
      });
      default -> new Term.Transp(cover, cof);
    };
  }

  private Term formulae(Formula formula) {
    return Restr.formulae(formula, Term.Mula::new);
  }

  record Renamer(MutableMap map) {
    /** @implNote Make sure to rename param before bodying */
    public Term term(Term term) {
      return switch (term) {
        case Term.Lam lam -> {
          var param = param(lam.x());
          yield new Term.Lam(param, term(lam.body()));
        }
        case Term.UI u -> u;
        case Term.Ref ref -> new Term.Ref(vv(ref.var()));
        case Term.DT dt -> {
          var param = param(dt.param());
          yield new Term.DT(dt.isPi(), param, term(dt.cod()));
        }
        case Term.Two two -> new Term.Two(two.isApp(), term(two.f()), term(two.a()));
        case Term.Proj proj -> new Term.Proj(term(proj.t()), proj.isOne());
        case Term.Call call -> new Term.Call(call.fn(), call.args().map(this::term));
        case Term.Path path -> new Term.Path(boundaries(path.data()));
        case Term.PLam pLam -> {
          var params = pLam.dims().map(this::param);
          yield new Term.PLam(params, term(pLam.fill()));
        }
        case Term.PCall pApp -> new Term.PCall(term(pApp.p()), pApp.i().map(this::term), partEl(pApp.b()));
        case Term.Mula f -> new Term.Mula(f.asFormula().fmap(this::term));
        case Term.Transp tr -> new Term.Transp(term(tr.cover()), tr.restr().fmap(this::term));
        case Term.Cof cof -> cof.fmap(this::term);
        case Term.PartTy par -> new Term.PartTy(term(par.ty()), term(par.restr()));
        case Term.PartEl par -> new Term.PartEl(partEl(par.inner()));
        case Term.Sub sub -> new Term.Sub(term(sub.ty()), partEl(sub.par()));
        case Term.InS inS -> new Term.InS(term(inS.e()), inS.restr().fmap(this::term));
        case Term.OutS outS -> new Term.OutS(term(outS.e()), partEl(outS.par()));
        case Term.Hcomp hcomp -> new Term.Hcomp(hcomp.data().fmap(this::term));
      };
    }

    private @NotNull Partial partEl(Partial par) {
      return par.map(this::term);
    }

    private @NotNull BdryData boundaries(@NotNull BdryData data) {
      return data.fmap(this::term, data.dims().map(this::param));
    }

    private @NotNull LocalVar vv(@NotNull LocalVar var) {
      return map.getOrDefault(var, var);
    }

    private Param param(Param param) {
      return new Param<>(param(param.x()), term(param.type()));
    }

    private LocalVar param(LocalVar param) {
      var var = new LocalVar(param.name());
      map.put(param, var);
      return var;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy