text:
(*
 * 保存不变量分类状态的对象
 *
 * 状态分为：
 *     1 线性偏微分方程组求解失败
 *     2 不变量方程组求解失败
 *     3 取特解失败
 *     4 变换方程求解失败
 *     5 变换方程求解成功，特解可能是代表元，是否是代表元留给人工判断
*)
$ifndef _INVSOL_
$define _INVSOL_

InvSol:=module()
    option object;
    export
        # 导出变量
        stateCode::{1,2,3,4,5},     # 状态代码
        oieq:={},                   # 导出新偏微分方程的不变量方程（如果存在的话）
        oisol,                      # 导出新偏微分方程的不变量方程的解（如果存在的话）
        oeq::set,                   # 导出不变量的偏微分方程
        Delta:=[],                  # 不变量
        orders:=[],                 # 不变量对应的阶数
        ieqCode,                    # 不变量方程的代码
        ieq::list,                  # 不变量方程
        isol,                       # 不变量方程的解（一个InvSol对象只含一个解）
        icon::set,                  # 不变量方程解的条件
        teq:=[[],[]],               # 变换方程（有两个）
        tsol:=[[],[]],              # 变换方程的解，每个方程都有可能有多个解
        tcon:=[[],[]],              # 变换方程的解对于的条件
        rep,                        # 代表元的表达式形式
        rvec,                       # 代表元的系数矩阵形式
        vars,                       # 偏微分方程中的剩余自由变量，初始时为a[1]..a[nvars]
        nvars,                      # 生成元的个数
        As::static,                 # 每个生成元的伴随矩阵
        A::static,                  # 总的伴随变换矩阵
        # 导出函数
        ## 输出相关
        getDisplayIeq::static,      # 简化显示的不变量方程，将不变量的实际表达式简写为Delta
        getDisplayDelta::static,    # 输出不变量
        getDesc::static,            # 获取对象的特征描述
        ModulePrint::static,        # 打印和显示对象的值
        printSol::static,           # 详细显示对象信息
        printTeq::static,           # 显示变换方程的结果
        ## 设置相关
        setRep::static,             # 重新取代表元
        setIsol::static,            # 重新对不变量方程取解
        getRep::static;             # 获取代表元，转化为global对象便于比较

    # 重新取代表元
    setRep:=proc(s::InvSol,rvec::list,{nocheck::boolean:=false})
        local v,r;
        if not nocheck then
            # 解的检验
            r:=eval(subs(seq(a[i]=rvec[i],i=1..numelems(rvec)),s:-ieq));
            if not andmap(evalb,r) then
                error "不是不变量方程的解，代入结果为%1",r;
            end if;
        end if;
        s:-stateCode:=4;
        s:-rvec:=Matrix(rvec);
        s:-rep:=add(rvec[i]*v[i],i=1..numelems(rvec));
        return;
    end proc:

    # 重新对不变量方程取解
    setIsol:=proc(s::InvSol,isol,{nocheck::boolean:=false})
        local r;
        if not nocheck then
            # 解的检验
            r:=RealDomain:-simplify(subs(isol[],s:-ieq));
            if not andmap(evalb,r) then
                error "不是不变量方程的解，代入结果为%1",r;
            end if;
        end if;
        s:-stateCode:=3;
        s:-isol:=isol;
        s:-icon:=findSolutionDomain(isol);
        return;
    end proc:

    # 获取代表元，转化为global对象便于比较
    getRep:=proc(s::InvSol)
        return convert(s:-rep,`global`);
    end proc:

    # 简化显示的不变量方程，将不变量的实际表达式简写为Delta
    getDisplayIeq:=proc(self::InvSol)
        local Delta;
        return {seq(Delta[i]=rhs(self:-ieq[i]),i=1..numelems(self:-Delta))};
    end proc:

    # 输出不变量
    getDisplayDelta:=proc(self::InvSol)
        local Delta;
        return [seq(Delta[i]=self:-Delta[i],i=1..numelems(self:-Delta))];
    end proc:

    # 获取对象的特征描述
    getDesc:=proc(s)
        if   (s:-stateCode=1) then
            return s:-oeq;
        elif (s:-stateCode=2) then
            return getDisplayIeq(s);
        elif (s:-stateCode=3) then
            return s:-isol;
        elif (s:-stateCode=4) then
            return s:-rep;
        elif (s:-stateCode=5) then
            return s:-rep;
        end if;
    end proc:

    # 打印和显示对象的值
    ModulePrint:=proc(s)
        return getDesc(s);
    end proc:

    # 输出解
    printSol:=proc(s::InvSol)
        printf("---------------------------------------------------------");
        if     (s:-stateCode=1) then
            printf("新的不变量求解失败，状态代码1");
            print(s:-oieq);
            printf("取解");
            print(s:-oisol);
            printf("求解失败的偏微分方程为");
            print(s:-oeq);
        elif    (s:-stateCode=2) then
            printf("不变量方程求解失败，状态代码2");
            print(getDisplayIeq(s));
        elif    (s:-stateCode=3) then
            printf("取代表元失败，状态代码3");
            print(getDisplayIeq(s));
            printf("取解");
            print(s:-isol);
        elif    (s:-stateCode=4) then
            printf("变换方程求解失败，状态代码4");
            print(getDisplayIeq(s));
            printf("取解");
            print(s:-isol);
            printf("具有约束");
            print(s:-icon);
            printf("取代表元");
            print(s:-rep);
            printf("求解失败的两个变换方程为");
            print~(s:-teq);
        elif    (s:-stateCode=5) then
            printf("变换方程求解成功，状态代码5");
            print(getDisplayIeq(s));
            printf("取解");
            print(s:-isol);
            printf("具有约束");
            print(s:-icon);
            printf("取代表元");
            print(s:-rep);
            printf("变换方程有解");
            printTeq(s,1);
            printTeq(s,2);
        end if;
        printf("---------------------------------------------------------");
        return;
    end proc:

    # 输出变换方程和解
    printTeq:=proc(sol,pos)
        if (sol:-tsol[pos]=[]) then
            printf("变换方程 %d 无解",pos);
            printf("方程为");
            print(sol:-teq[pos]);
        else
            printf("变换方程 %d 有解",pos);
            printf("方程为");
            print(sol:-teq[pos]);
            printf("有解");
            print(sol:-tsol[pos]);
            printf("具有条件");
            print(sol:-tcon[pos]);
        end if;
    end proc:
end module:

$endif

ext: mpl

lm_label:
1. YES
2. YES


text:
######################################################################
#
# General circle operad framework.

`check_semi_circ_args` := proc(i,m,n,U,V,is_el_CC)
 global reason;

 if not (type(i,posint) and
         type(m,nonnegint) and
	 type(n,nonnegint) and
	 i <= m) then
  reason := [convert(procname,string),
   "numbers (i,m,n) do not satisfy 0 < i <= m; 0 <= n",i,m,n];
  return false;
 fi;

 if not is_el_CC(m)(U) then
  reason := [convert(procname,string),"U is not in C(m)",eval(U),m];
  return false;
 fi;

 if not is_el_CC(n)(U) then
  reason := [convert(procname,string),"V is not in C(n)",eval(V),n];
  return false;
 fi;

 return true;
end;

######################################################################

`check_semi_circ_axiom_nested` :=
 proc(i,j,l,m,n,U,V,W,is_el_CC,is_equal_CC,circ_CC)
 local UV,VW,UVW0,UVW1;
 global reason;

 if not (type(i,posint) and
         type(j,posint) and
	 type(l,nonnegint) and
	 type(m,nonnegint) and
	 type(n,nonnegint) and
	 i <= l and
	 j <= m) then
  reason := [convert(procname,string),
   "numbers (i,j,l,m,n) do not satisfy 0 < i <= l; 0 < j <= m; 0 <= n",
   i,j,l,m,n];
  return false;
 fi;

 if not is_el_CC(l)(U) then
  reason := [convert(procname,string),"U is not in O(l)",l,eval(U)];
  return false;
 fi;

 if not is_el_CC(m)(V) then
  reason := [convert(procname,string),"V is not in O(m)",m,eval(V)];
  return false;
 fi;

 if not is_el_CC(n)(W) then
  reason := [convert(procname,string),"W is not in O(n)",n,eval(W)];
  return false;
 fi;

 UV := circ_CC(i,l,m)(U,V);

 if not is_el_CC(l+m-1)(UV) then
  reason := [convert(procname,string),"U o_i V is not in O(l+m-1)",i,l,m,eval(U),eval(V),eval(UV)];
  return false;
 fi;

 VW := circ_CC(j,m,n)(V,W);

 if not is_el_CC(m+n-1)(VW) then
  reason := [convert(procname,string),"V o_j W is not in O(m+n-1)",j,m,n,eval(VW)];
  return false;
 fi;

 UVW0 := circ_CC(i,l,m+n-1)(U,VW);

 if not is_el_CC(l+m+n-2)(UVW0) then
  reason := [convert(procname,string),"U o_i (V o_j W) is not in O(l+m+n-2)",i,j,l,m,n,eval(UVW0)];
  return false;
 fi;

 UVW1 := circ_CC(i+j-1,l+m-1,n)(UV,W);

 if not is_el_CC(l+m+n-2)(UVW1) then
  reason := [convert(procname,string),"(U o_i V) o_(i+j-1) W is not in O(l+m+n-2)",i,j,l,m,n,eval(UVW1)];
  return false;
 fi;

 if not is_equal_CC(l+m+n-2)(UVW0,UVW1) then
  reason := [convert(procname,string),"UVW0 != UVW1",eval(UVW0),eval(UVW1)];
  return false;
 fi;

 return true;
end;

`check_semi_circ_axiom_disjoint` :=
 proc(i,k,l,m,n,U,V,W,is_el_CC,is_equal_CC,circ_CC)
 local UV,UW,UVW,UWV;
 global reason;

 if not (type(i,posint) and
         type(k,posint) and
	 type(l,nonnegint) and
	 type(m,nonnegint) and
	 type(n,nonnegint) and
	 i < k and
	 k <= l) then
  reason := [convert(procname,string),
   "numbers (i,k,l,m,n) do not satisfy 0 < i < k <= l; 0 < j <= m; 0 <= n",
   i,k,l,m,n];
  return false;
 fi;

 if not is_el_CC(l)(U) then
  reason := [convert(procname,string),"U is not in O(l)",l,eval(U)];
  return false;
 fi;

 if not is_el_CC(m)(V) then
  reason := [convert(procname,string),"V is not in O(m)",m,eval(V)];
  return false;
 fi;

 if not is_el_CC(n)(W) then
  reason := [convert(procname,string),"W is not in O(n)",n,eval(W)];
  return false;
 fi;

 UV := circ_CC(i,l,m)(U,V);

 if not is_el_CC(l+m-1)(UV) then
  reason := [convert(procname,string),"U o_i V is not in O(l+m-1)",i,l,m,eval(U),eval(V),eval(UV)];
  return false;
 fi;

 UW := circ_CC(k,l,n)(U,W);

 if not is_el_CC(l+n-1)(UW) then
  reason := [convert(procname,string),"U o_k W is not in O(l+n-1)",k,l,n,eval(UW)];
  return false;
 fi;

 UVW := circ_CC(k+m-1,l+m-1,n)(UV,W);

 if not is_el_CC(l+m+n-2)(UVW) then
  reason := [convert(procname,string),"(U o_i V) o_(k+m-1) W is not in O(l+m+n-2)",i,k,l,m,n,eval(UVW)];
  return false;
 fi;

 UWV := circ_CC(i,l+n-1,m)(UW,V);

 if not is_el_CC(l+m+n-2)(UWV) then
  reason := [convert(procname,string),"(U o_k W) o_i V is not in O(l+m+n-2)",i,k,l,m,n,eval(UWV)];
  return false;
 fi;

 if not is_equal_CC(l+m+n-2)(UVW,UWV) then
  reason := [convert(procname,string),"UVW != UWV",eval(UVW),eval(UWV)];
  return false;
 fi;

 return true;
end;

lm_label:
1. YES
2. NO