text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

#
# Typ ::
#
# Value ::
#    t = <type>
#    v = <.>
#
# Types:
#   TReal
#   TComplex
#   TInt
#   TArray(<type>, <size>)
#   TVect(<type>, <vlen>)
#
# Value(<type>, <.>)
# V(<.>)   infers type automatically
#

Declare(Value, IsExp, IsValue, TArray, TVect, BitVector, T_UInt);

_evInt := v -> Cond(IsInt(v), v, IsList(v), List(v, i->_evInt(i)), v.ev());

#----------------------------------------------------------------------------------------------
# Typ : data types
#----------------------------------------------------------------------------------------------
Class(TypOps, rec(
    Print := x-> When(IsBound(x.print), x.print(), Print(x.__name__)),
    \= := RewritableObjectOps.\=,
    \< := RewritableObjectOps.\<
));
Class(TypOpsNoPrint, ClassOps, rec(
    \= := RewritableObjectOps.\=,
    \< := RewritableObjectOps.\<
));

Declare(RangeT);

Class(RangeTOps, PrintOps, rec(
    \= := (v1,v2) -> When( ObjId(v1)<>RangeT or ObjId(v2)<>RangeT, false,
        v1.max=v2.max and v1.min=v2.min and v1.eps=v2.eps),
    \< := (v1,v2) -> Error("Operation '<' is undefined for RangeT."),
    \+ := (v1,v2) -> When( ObjId(v1)<>RangeT or ObjId(v2)<>RangeT, Error("'+' is defined for RangeT only"),
        RangeT(Min2(v1.min, v2.min), Max2(v1.max, v2.max), Max2(v1.eps, v2.eps))),
    \* := (v1,v2) -> When( ObjId(v1)<>RangeT or ObjId(v2)<>RangeT, Error("'*' is defined for RangeT only"),
        RangeT(Max2(v1.min, v2.min), Min2(v1.max, v2.max), Max2(v1.eps, v2.eps))),
));

#F RangeT(<min>, <max>, <eps>): data type range
#F  <min> smallest value, <max> largest value, <eps> unit roundoff
Class(RangeT, rec(
    __call__ := (self, min, max, eps) >>
        WithBases(self, rec( min := min, max := max, eps := eps, operations := RangeTOps)),
    print    := self >> Print(self.__name__, "(", self.min, ", ", self.max, ", ", self.eps, ")"),
));

Class(Typ, rec(
    operations := TypOps,
    isType := true,
    isSigned := self >> true,
    doHashValues := false,
    check := v -> v,
    #normalize := (self, v) >> Value(self,v),
    eval := self >> self,

    vbase := rec(),

    value := meth(self, v)
        local ev;
        if IsExp(v) then
            ev := v.eval();
            if IsSymbolic(ev) and not IsValue(ev) then
                v.t := self;
                return v;
            fi;
        fi;

        if IsValue(v) then return Value.new(self, self.check(v.v));
        else return Value.new(self,self.check(v));
        fi;
    end,

    realType := self >> self,

    product  := (v1, v2) -> v1 * v2,
    sum      := (v1, v2) -> v1 + v2,
    base_t   := self >> self, # composite types should return base data type (without recursion).
    saturate := abstract(), # (self, v) >> ...
    # range should return RangeT
    range    := abstract(), # (self) >> ...
));

Class(CompositeTyp, Typ, rec(operations := TypOpsNoPrint));

Class(AtomicTyp, Typ, rec(
    doHashValues := true,
    isAtomic := true,
    rChildren := self >> [],
    from_rChildren := (self, rch) >> Checked(rch=[], self),
    free := self >> Union(List(self.rChildren(), FreeVars)),
    vtype := (self,v) >> TVect(self, v),
    csize := self >> sizeof(self)
));

IsType := x -> IsRec(x) and IsBound(x.isType) and x.isType;

Class(TFunc, RewritableObject, Typ, rec(
    check := v -> v, #Checked(IsFunction(v), v),
    product := (v1, v2) -> Error("Can not multiply functions"),
    sum  := (v1, v2) -> Error("Can not add functions"),
    zero := (v1, v2) -> Error("TFunc.zero() is not supported"),
    one  := (v1, v2) -> Error("TFunc.one() is not supported"),
    free := self >> Union(List(self.params, FreeVars)),
    updateParams := self >> Checked(ForAll(self.params, e->IsType(e) or IsValue(e) or IsInt(e) or IsSymbolic(e)), true),
    csize := self >> sizeof(self)
));

IsFuncT := x -> IsType(x) and ObjId(x)=TFunc;

Class(ValueOps, PrintOps, rec(
    \= := (v1,v2) -> Cond(
        not IsValue(v2), v1.v=v2,
        not IsValue(v1), v1=v2.v,
        IsBound(v1.t.vequals), v1.t.vequals(v1.v, v2.v),
        IsBound(v2.t.vequals), v2.t.vequals(v1.v, v2.v),
        v1.v = v2.v),
    \< := (v1,v2) -> Cond(
        not IsValue(v2), When(IsRec(v2), ObjId(v1) < ObjId(v2), v1.v < v2),
        not IsValue(v1), When(IsRec(v1), ObjId(v1) < ObjId(v2), v1   < v2.v),
        v1.v < v2.v)
 ));

#----------------------------------------------------------------------------------------------
# Value : values or constants
# NB: All values are automatically hashed in GlobalConstantHash
#     This can reduce memory footprint, since lots of values are repetitive,
#     like 1s and 0s, and also float values that are too close to each other will
#     hash to same value (by virtue of ValueOps.\=), which will prevent compiler
#     from putting them in separate registers, and thus degrading performance.
#
#     This has negligible effect on accuracy, as long as <type>.vequals is valid.
#
#----------------------------------------------------------------------------------------------
Class(Value, rec(
    isValue := true,
    __call__ := (self, t, v) >> t.value(v),

    new := (self,t,v) >> # HashedValue(GlobalConstantHash,  <-- this hashes the Value upon construction, disabled now
                         # due to slowness with large data() blocks, which aren't hashed, unless this option is used
	Cond(t.vbase=rec(),
            WithBases(self, rec(t:=t, v:=v, operations := ValueOps)),
            WithBases(self, Inherit(t.vbase, rec(t:=t, v:=v, operations:=ValueOps)))
	),
    #),

    ev := self >> self.v,
    eval := self >> self,
    free := self >> Set([]),

    from_rChildren := (self, rch) >> self,
#   print := self >> Print(self.__name__, "(", self.t, ",", self.v, ")"),
#   print := self >> Print(self.v),
    print := self >> Cond(IsString(self.v), Print("V(\"",self.v, "\")"), Print("V(", self.v, ")")),

    dims := self >> Cond(
	IsArrayT(self.t), self.t.dims(),
	Error("<self>.dims() is only valid when self.t is a TArray"))
));

IsValue := x -> IsRec(x) and IsBound(x.isValue) and x.isValue;

#----------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------

Declare(TComplex);

Class(TUnknown, AtomicTyp, rec( one := self >> 1, zero := self >> 0));
Class(TVoid,    AtomicTyp);
Class(TDummy,   AtomicTyp); # used in autolib for Lambda parameters that are ignored

Class(TReal, AtomicTyp, rec(
    cutoff := 1e-15,
    hash := (val, size) -> 1 + (DoubleRep64(Double(val)) mod size), #(IntDouble(1.0*val*size) mod size),

    check := (self,v) >> Cond(
        IsExp(v),     ReComplex(Complex(code.EvalScalar(v))),
        IsInt(v),     Double(v),
        IsRat(v),     v,
        IsDouble(v),  When(AbsFloat(v) < self.cutoff, 0.0, v),
        IsCyc(v),     ReComplex(Complex(v)),
        IsComplex(v), ReComplex(v),
        Error("<v> must be a double or an expression")),

    vequals := (self, v1,v2) >> When(
        (IsDouble(v1) or IsInt(v1) or IsRat(v1)) and (IsDouble(v2) or IsInt(v2) or IsRat(v2)),
        AbsFloat(Double(v1)-Double(v2)) < self.cutoff,
        false),

    zero := self >> self.value(0.0),
    one := self >> self.value(1.0),
    strId := self >> "f",

    complexType := self >> TComplex,
));

TDouble:=TReal;

#
# format:  | sign | integer bits | frac bits |
# # make sure we have space at least for the sign bit
#
_fpdouble := (val,b,fb) -> let(res := IntDouble(val * 2.0^fb),
    Cond(
	val = 1 and (fb = b-1), # we can represent 1 as 0.999999, if we use frac bits only
	    2^fb - 1,
	val = -1 and (fb = b-1), # we can represent 1 as 0.999999, if we use frac bits only
	    -(2^fb - 1),
	Log2Int(res)+2 > b, Error("Overflow, value=", val, ", signed width=",
                                   Log2Int(res)+2, ", max width=", b),
         res));

# format:  | integer bits | frac bits |
#
_ufpdouble := (val,b,fb) -> let(res := IntDouble(val * 2.0^fb),
    When(Log2Int(res)+1 > b, Error("Overflow, value=", val, ", unsigned width=",
                                   Log2Int(res)+1, ", max width=", b),
         res));

#F TFixedPt(<bits>, <fracbits>)   -- fixed point data type
#F
#F   <bits> -- total # of bits (including sign bit)
#F   <fracbits> -- number of fractional bits
#F
#F   Number of integer bits is assumed to be bits-1-fracbits (1 = sign bit)
#F
Class(TFixedPt, TReal, rec(
    operations := TypOpsNoPrint, # NOTE: do not inherit from TReal, and then this line won't be needed

    __call__ := (self, bits, fracbits) >> WithBases(self, rec(
            bits := bits,
            fracbits := fracbits,
            operations := TypOps)),

    rChildren := self >> [self.bits, self.fracbits],
    rSetChild := rSetChildFields("bits", "fracbits"),
    from_rChildren := (self, rch) >> ApplyFunc(ObjId(self), rch),

    print := self >> Print(self.__name__, "(", self.bits, ", ", self.fracbits, ")"),

    check := (self, v) >> _fpdouble(v, self.bits, self.fracbits)
));

# TUFixedPt(<bits>, <fracbit>)  -- unsigned fixed point data type
#
Class(TUFixedPt, TFixedPt);

Class(TComplex, AtomicTyp, rec(
    hash := (val, size) -> let(
        cplx := Complex(val),
        #h := IntDouble(size * (ReComplex(cplx)+ImComplex(cplx))),
        h := DoubleRep64(ReComplex(cplx)) + DoubleRep64(ImComplex(cplx)),
        1 + (h mod size)),

    check := v -> Cond(
        BagType(v) in [T_CYC, T_RAT, T_INT], v, # exact representation
        IsDouble(v),  When(AbsFloat(v) < TReal.cutoff, 0, v),
        IsComplex(v), Complex(TReal.check(ReComplex(v)), TReal.check(ImComplex(v))),
        IsExp(v),     Complex(v.ev())),

    realType    := self >> TReal,
    complexType := self >> self,

    zero := self >> self.value(0.0),
    one := self >> self.value(1.0),
));

Class(TBool, AtomicTyp, rec(
    hash := (val, size) -> 1 + (InternalHash(val) mod size),
    check := v -> Cond(IsBool(v), v, Error("<v> must be a boolean")),
    one := self >> self.value(true),
    zero := self >> self.value(false),
));

Class(TInt_Base, AtomicTyp, rec(
    hash    := (val, size) -> 1 + (10047871*val mod size),
    bits    := 32,
    check   := v -> Cond(IsExp(v), Int(v.ev()),
                         IsInt(v), v,
                         IsDouble(v) and IsInt(IntDouble(v)), IntDouble(v),
                         Error("<v> must be an integer or an expression")),
    one  := self >> self.value(1),
    zero := self >> self.value(0),

    complexType := self >> TComplex,
));

Class(TInt, TInt_Base, rec(strId := self >> "i"));
Class(TUInt, TInt_Base, rec(isSigned := False, strId := self >> "ui"));
Class(TULongLong, TInt_Base);

IsChar := (x)->When(BagType(x)=T_CHAR, true, false);

Class(TChar, TInt_Base, rec(
    hash := (val, size) -> When(IsChar(val), 1 + (InternalHash(val) mod size), TInt_Base.hash(val, size)),
    bits := 8,
    check := v -> Cond(IsExp(v), Int(v.ev()),
                       IsInt(v), v,
                       IsChar(v), v,
                       Error("<v> must be an integer or an expression")),
));

Class(TUChar, TInt_Base, rec(
    bits := 8,
    isSigned := self >> false,
    check := v -> Cond(IsExp(v), Int(v.ev()),
                       IsInt(v), v,
                       Error("<v> must be an integer or an expression")),
));

Class(TString, AtomicTyp, rec(
    doHashValues := true,
    hash := (val, size) -> 1 + (InternalHash(val) mod size),
    check := v -> Cond(IsString(v), v, Error("<v> must be a string")),
    one := self >> Error("TString.one() is not allowed"),
    zero := self >> Error("TString.zero() is not allowed"),
));

Class(TList, CompositeTyp, rec(
    isListT := true,
    hash := (val, size) -> Error("Not implemented"),
    __call__ := (self, t) >>
        WithBases(self, rec(
        t    := Checked(IsType(t), t),
        operations := PrintOps)),
    print := self >> Print(self.__name__, "(", self.t, ")"),
    check := v -> Cond(IsList(v), v, Error("<v> must be a list")),

    one  := self >> Error("TList.one() is not allowed"),
    zero := self >> Error("TList.zero() is not allowed"),

    rChildren := self >> [self.t],
    rSetChild := rSetChildFields("t"),
    from_rChildren := (self, rch) >> ApplyFunc(ObjId(self), rch),

));

Class(TSym, CompositeTyp, rec(
    hash := (val, size) -> Error("Not implemented"),
    check := v -> v,
    __call__ := (self, id) >>
        WithBases(self, rec(
        id    := Checked(IsString(id), id),
        operations := TypOps)),

    rChildren := self >> [self.id],
    rSetChild := rSetChildFields("id"),
    from_rChildren := (self, rch) >> ApplyFunc(ObjId(self), rch),

    print := self >> Print(self.__name__, "(\"", self.id, "\")"),
    csize := self >> sizeof(self)
));

#F TArrayBase -- base class for array-like element collection types
#F
#F Subclasses: TPtr, TArray, TVect, BitVector
#F
#F Default constructor:
#F
#F  __call__(<element-type>, <size>) - array type of <size> elements of <element-type>
#F
Class(TArrayBase, CompositeTyp, rec(
     __call__ := (self, t, size) >>
        WithBases(self, rec(
        t    := Checked(IsType(t), t),
        size := Checked(IsPosInt0Sym(size), size),
        operations := TypOps)),

    hash := (self, val, size) >> (Sum(val, x -> x.t.hash(x.v, size)) mod size) + 1,

    rChildren := self >> [self.t, self.size],
    rSetChild := rSetChildFields("t", "size"),
    from_rChildren := (self, rch) >> ApplyFunc(ObjId(self), rch),

    isSigned := self >> self.t.isSigned(),

    print := self >> Print(self.__name__, "(", self.t, ", ", self.size, ")"),

    check := (self, v) >> Checked(IsList(v), Length(v) = self.size,
    ForAll(v, el -> el.t = self.t), v),

    # these fields go into values
    vbase := rec(
        free := self >> Union(List(self.v, e -> e.free())),
        rChildren := self >> self.v,
        rSetChild := meth(self, n, newC) self.v[n] := newC; end
    ),

    zero := self >> self.value(Replicate(_unwrap(self.size), self.t.zero())),
    one  := self >> self.value(Replicate(_unwrap(self.size), self.t.one())),

    value := (self, v) >> let(vv := When(IsValue(v), v.v, v),
        Cond(IsExp(vv), vv,
             Checked(IsList(vv),
                     Value.new(self, List(vv, e->self.t.value(e)))))),

    # array type can have free variables in .size field
    free := self >> Union(FreeVars(self.size), FreeVars(self.t)),

    csize := self >> self.t.csize() * self.size,

    realType := self >> ObjId(self)(self.t.realType(), self.size),

    base_t := self >> self.t,
    range  := self >> self.t.range(),
));

Declare(TPtr, TArray);

#F TArray(<element-type>, <size>) - array type of <size> elements of <element-type>
#F
Class(TArray, TArrayBase, rec(
    isArrayT := true,
    vtype := (self, v) >> TArray(self.t.vtype(v), self.size/v),
    toPtrType := self >> TPtr(self.t),
    doHashValues := true,

    dims := self >> Cond(
        ObjId(self.t)=TArray, [self.size] :: self.t.dims(),
        [self.size])
));

# [ptrAligned, ptrUnaligned] are TPtr.alignment values
ptrUnaligned := [1,0];
ptrAligned4  := [4,0];
ptrAligned8  := [8,0];
ptrAligned16 := [16,0];
ptrAligned := ptrAligned16;

# NOTE: this is a hack, esp because 16 byte boundary is hardcoded in ptrAligned
#        It should be in SpiralDefaults somehow
TArray.alignment := ptrAligned;
TArray.qualifiers := [];

TypeDomain := (dom, els) ->
    Cond(Same(dom, Rationals) or Same(dom, Scalars) or Same(dom, Doubles), TReal,
     Same(dom, Complexes), TComplex,
     Same(dom, Cyclotomics), When(ForAll(els, x->Im(x)=0), TReal, TComplex),
     Same(dom, Integers), TInt,
     Error("Unrecognized domain <dom>"));

# IsArrayT(<t>) - checks whether <t> is an array type object
IsArrayT := x -> IsType(x) and IsBound(x.isArrayT) and x.isArrayT;

# IsListT(<t>) - checks whether <t> is a list type object
IsListT := x -> IsType(x) and IsBound(x.isListT) and x.isListT;

# IsVecT(<t>) - checks whether <t> is an vector type object
IsVecT := x -> IsType(x) and IsBound(x.isVecT) and x.isVecT;

# IsPtrT(<t>) - checks whether <t> is a pointer type object
IsPtrT := x-> IsType(x) and IsBound(x.isPtrT) and x.isPtrT;

# IsUnalignedPtrT(<t>) - checks whether <t> is a unaligned pointer type object,
#       unaligned means aligned with smaller granularity than child type (t.t)
#       size.
IsUnalignedPtrT := x -> IsPtrT(x) and x.alignment<>ptrAligned;

# obsolete, use IsArrayT
IsArray := IsArrayT;

Class(TPtr, TArrayBase, rec(
     isPtrT := true,
     __call__ := arg >> let(self := arg[1],
         t          := arg[2],
         qualifiers := When(IsBound(arg[3]), arg[3], []),
         alignment  := When(IsBound(arg[4]), arg[4], ptrAligned16),
         WithBases(self, rec(
            t    := Checked(IsType(t), t),
            size := 0,
            qualifiers := qualifiers,
            _restrict  := false,
            alignment  := alignment,
            operations := TypOps)).normalizeAlignment()),

     # value := (self, v) >> Error("Values of TPtr type are not allowed"),
     value := Typ.value,

     check := (self, v) >> Cond(
        IsList(v), Checked(
           Length(v) = self.size,
           ForAll(v, el -> el.t = self.t),
           v
        ),
        IsInt(v), v,
        Error("TPtr needs to either point to an array or some value")
     ),

     # this looks crazy, but sometimes this happens (in LRB backend actually) : X - X
     # where X is a pointer. Internally this can become X + (-X), and then becomes 0
     isSigned := self >> true,

     rChildren := self >> [self.t, self.qualifiers, self.alignment],
     rSetChild := rSetChildFields("t", "qualifiers", "alignment"),

     zero := self >> TInt.zero(),
     one := self >> TInt.one(),

     print := self >> Print(self.__name__, "(", self.t,
         When(self.qualifiers<>[], Print(", ", self.qualifiers)), ")",
         When(self._restrict, ".restrict()", ""),
         ".aligned(", self.alignment, ")"
         ),

     restrict := (self) >> CopyFields(self, rec(_restrict := true)),
     unRestricted := (self) >> CopyFields(self, rec(_restrict := false)),

     csize := self >> sizeof(self),

     realType := self >> Cond(self._restrict,
         ObjId(self)(self.t.realType(), self.qualifiers).restrict(),
         ObjId(self)(self.t.realType(), self.qualifiers)
     ),

     aligned   := (self, a) >> CopyFields(self, rec( alignment := Checked(IsList(a) and Length(a)=2, a)  )).normalizeAlignment(),
     unaligned := (self) >> CopyFields(self, rec( alignment := [1,0] )),

     normalizeAlignment := meth(self)
         if IsValue(self.alignment[2]) then self.alignment[2] := self.alignment[2].v;
         elif IsSymbolic(self.alignment[2]) then self.alignment := ptrUnaligned; # NOTE: Conservative assumption
         fi;
         Constraint(IsInt(self.alignment[2]));
         self.alignment[2] := self.alignment[2] mod self.alignment[1];
         return self;
     end,

     withAlignment := (self, value) >> CopyFields(self, rec(
         alignment := When(IsPtrT(value), value.alignment, value))),

     # things get a little strange here because we allow pointers
     # to be set to some int based offset
     #
     vbase := rec(
         free := self >> Cond(
             IsList(self.v), Union(List(self.v, e -> e.free())),
             IsInt(self.v), [],
             Error("hmm.")
         ),
         rChildren := self >> Cond(
             IsList(self.v), self.v,
             IsInt(self.v), [],
             Error("hmm.")
         ),

         rSetChild := meth(arg)
             local _self;
             _self := arg[1];

             if Length(arg) = 3 then
                _self.v[arg[2]] := arg[3];
             elif Length(arg) = 2 then
                _self.v := arg[2];
             else
                Error("choke");
             fi;
         end,
     ),
));

# -- TVect ----------------------------------------------------------------------

Class(TVect, TArrayBase, rec(
    isVecT := true,
    doHashValues := true,
    __call__ := (self, t, size) >> Cond(t=T_UInt(1), BitVector(size), Inherited(t, size)),

    product := (v1, v2) -> Checked(IsList(v1) or IsList(v2), let(
        vv1 := When(not IsList(v1), Replicate(Length(v2), v1), v1),
        vv2 := When(not IsList(v2), Replicate(Length(v1), v2), v2),
        l := Length(vv1),
        Checked(l = Length(vv2),
            List([1..l], i -> vv1[i]*vv2[i])))),

    sum := (v1, v2) -> Checked(IsList(v1) or IsList(v2), let(
        vv1 := When(not IsList(v1), Replicate(Length(v2), v1), v1),
        vv2 := When(not IsList(v2), Replicate(Length(v1), v2), v2),
        l := Length(vv1),
        Checked(l = Length(vv2),
            List([1..l], i -> vv1[i]+vv2[i])))),

    value := (self, v) >> Cond( IsValue(v) and self=v.t, v, let(
        vv := When(IsValue(v), v.v, v),
        Cond(IsExp(vv), vv,
             IsList(vv), Value.new(self, List(vv,                       e -> self.t.value(e))),
             <#else#>
                         Value.new(self, List(Replicate(self.size, vv), e -> self.t.value(e)))))),

    saturate := (self, v) >> let( vv := _unwrap(v), Cond(not IsList(vv) or Length(vv)<>self.size, v,
        Value.new(self, List(vv, e -> self.t.saturate(e)))) ),

    toUnsigned := self >> TVect(self.t.toUnsigned(), self.size),
    toSigned   := self >> TVect(self.t.toSigned(),   self.size),
    double     := self >> TVect(self.t.double(),     self.size/2),

));

IsTVectDouble := x -> IsVecT(x) and x.t = TReal;

TVectDouble := vlen -> TVect(TReal, vlen);

#Class(T_Type, Typ, rec(
#     __call__ := (self, bits) >>
#        WithBases(self, rec(
#        bits := Checked(IsPosInt(bits), bits),
#        operations := TypOps)),
#
#     hash := (self, val, size) >>  1 + (10047871*val mod size),
#
#     rChildren := self >> [],
#     rSetChild := self >> Error("This function should not be called"),
#     print := self >> Print(self.__name__, "(", self.bits, ")"),
#     free := self >> Union(List(self.rChildren(), FreeVars)),
#     vtype := (self,v) >> TVect(self, v)
#));

Class(T_Type, RewritableObject, rec(
    isType := true,

    isSigned := self >> true,
    realType := self >> self,

    doHashValues := false,
    check := v -> v,
    vbase := rec(),

    value := meth(self, v)
        local ev;
        if IsExp(v) then
            ev := v.eval();
            if IsSymbolic(ev) and not IsValue(ev) then
                v.t := self;
                return v;
            fi;
        fi;
        if IsValue(v) then
            return Value.new(self, self.check(v.v));
        else
            return Value.new(self, self.check(v));
        fi;
    end,

    eval     := self >> self,
    product  := (v1, v2) -> v1 * v2,
    sum      := (v1, v2) -> v1 + v2,
    zero     := self >> self.value(0),
    one      := self >> self.value(1),
    csize    := self >> sizeof(self),
    base_t   := self >> self, # composite types should return base type (without recursion).
    saturate := abstract(), # (self, v) >> ...
    range    := abstract(), # (self) >> ...
));

Declare(T_Int, T_UInt, T_Complex);

Class(T_Ord, T_Type, rec(
    hash := (val, size) -> 1 + (10047871*val mod size),
    saturate := (self, v) >> let( b := self.range(),
        Cond( IsExp(v), v, self.value(Max2(b.min, Min2(b.max, _unwrap(v)))))),
));

Class(T_Int, T_Ord, rec(
    check := (self, v) >> let(
        i := Cond(IsDouble(v), IntDouble(v),
                  IsRat(v), Int(v),
                  Error("Can't convert <v> to an integer")),
        b := self.params[1],
        ((i + 2^(b-1)) mod 2^b) - 2^(b-1)),

    strId    := self >> "i"::StringInt(self.params[1]),
    range    := self >> RangeT(-2^(self.params[1]-1),  2^(self.params[1]-1)-1,  1),

    isSigned   := True,
    toUnsigned := self >> T_UInt(self.params[1]),
    toSigned   := self >> self,
    double     := self >> T_Int(2*self.params[1]),
));

Class(T_UInt, T_Ord, rec(
    check := (self, v) >> let(
        i := Cond(IsDouble(v), IntDouble(v),
                  IsRat(v), Int(v),
                  Error("Can't convert <v> to an integer")),
        b := self.params[1],
        i mod 2^b),

    strId    := self >> "ui"::StringInt(self.params[1]),
    range    := self >> RangeT(0, 2^self.params[1]-1, 1),

    isSigned   := False,
    toUnsigned := self >> self,
    toSigned   := self >> T_Int(self.params[1]),
    double     := self >> T_UInt(2*self.params[1]),
));

Class(BitVector, TArrayBase, rec(
    isVecT := true,
    __call__ := (self, size) >> Inherited(T_UInt(1), size),

    print := self >> Print(self.__name__, "(", self.size, ")"),
    vbase := rec(
        print := self >> let(n:=Length(self.v), Print("h'", HexStringInt(Sum([1..n], i->self.v[i] * 2^(n-i))))),
    ),

    isSigned := self >> false,

    rChildren := self >> [self.size],
    rSetChild := rSetChildFields("size"),

    one := self >> self.value(Replicate(self.size, 1)),
    zero := self >> self.value(Replicate(self.size, 0)),

    hash := (self, val, size) >> let(n:=Length(val),
        1 + (Sum([1..n], i -> val[i] * 2^(n-i)) mod size)),

    product := TVect.product,
    sum := TVect.sum,

    _uint1 := T_UInt(1),

    value := (self, v) >> When( IsValue(v) and v.t = self, v,
        let(vv := When(IsValue(v), v.v, v),
            Cond(IsExp(vv), vv,
                 Checked(IsList(vv),
                     Value.new(self, List(vv, e->self._uint1.check(e))))))),
));

Class(T_Real, T_Type, rec(
   #correct cutoffs are floor(log10(2^(mantissa bits + 1)))
   cutoff := self>>Cond(
       self.params[1] = 128, 1e-34,
       self.params[1] = 80, 1e-19,
       self.params[1] = 64, 1e-15,
       self.params[1] = 32, 1e-7,
       Error("cutoff not supported")
   ),

   hash := TReal.hash,

   check := (self,v) >> let( r := Cond(
            IsExp(v),     ReComplex(Complex(code.EvalScalar(v))),
            IsInt(v),     Double(v),
            IsRat(v),     v,
            IsDouble(v),  v,
            IsCyc(v),     ReComplex(Complex(v)),
            IsComplex(v), ReComplex(v),
            # else
                Error("<v> must be a double or an expression")),
        When(AbsFloat(r) < self.cutoff(), 0.0, r)),

   vequals := (self, v1,v2) >> When(
        (IsDouble(v1) or IsInt(v1)) and (IsDouble(v2) or IsInt(v2)),
        AbsFloat(Double(v1)-Double(v2)) < self.cutoff(),
        false),

   zero := self >> self.value(0.0),
   one := self >> self.value(1.0),
   isSigned := (self) >> true,
   strId := self >> "f"::StringInt(self.params[1]),
   range := self >> Cond(
       self.params[1] = 128, RangeT(
           -1.7976931348623157e+308 - 10e291, #INF
           1.7976931348623157e+308 + 10e291, #INF
           1e-34
       ),
       self.params[1] = 80, RangeT(
           -1.7976931348623157e+308 - 10e291, #INF
           1.7976931348623157e+308 + 10e291, #INF
           1e-19
       ),
       self.params[1] = 64, RangeT(
           -1.7976931348623157e+308,
            1.7976931348623157e+308,
            1.1102230246251565e-016
       ),
       self.params[1] = 32, RangeT(
           -3.4028234e+038,
            3.4028234e+038,
            5.96046448e-008
       )),

   complexType := self >> T_Complex(self),
));

Class(T_Complex, T_Type, rec(
    hash := TComplex.hash,
    realType    := self >> self.params[1],
    complexType := self >> self,

    isSigned := self >> self.params[1].isSigned(),
    strId    := self >> "c"::self.params[1].strId(),

    check := (self, v) >> let(
	realt := self.params[1],
	cpx := Complex(v),
	Complex(realt.check(ReComplex(cpx)),
	        realt.check(ImComplex(cpx))))
));

# # complex type is made up of TWO T_Real, T_Uint, or T_Int types.

# Class(T_Complex, TArrayBase, rec(
#     isComplex := true,
#     __call__ := (arg) >> let(
#         self := arg[1],
#         t := arg[2],
#         Checked(
#             ObjId(t) in [T_Real, T_UInt, T_Int],
#             WithBases(self, rec(
#                 t := t,
#                 qualifiers := When(Length(arg) > 2, arg[3], []),
#                 operations := TypOps,
#                 size := 0
#             ))
#         )
#     ),

#     rChildren := self >> [self.t, self.qualifiers],
#     rSetChild := rSetChildFields("t", "qualifiers"),

#     print := self >> Print(self.__name__, "(", self.t,
#         When(self.qualifiers <> [],
#             Print(", ", self.qualifiers)
#         ),
#         ")"
#     )
# ));

_IsVar := (e) -> code.IsVar(e);

#F T_Struct: structure type.
#F
#F T_Struct("structname", [<var1>, <var2>, ... , <varN>])
#F
Class(T_Struct, T_Type, rec(
    updateParams := meth(self)
        Constraint(IsString(self.params[1]));
        Constraint(IsList(self.params[2]));
        Constraint(ForAll(self.params[2], e -> _IsVar(e)));
    end,

    getName := self >> self.params[1],
    getVars := self >> self.params[2]
));

IsIntT := (t) -> IsType(t) and t in [TChar, TInt] or ObjId(t) = T_Int;
IsUIntT := (t) -> IsType(t) and t in [TUChar, TUInt] or ObjId(t) = T_UInt;
IsOrdT := (t) -> IsIntT(t) or IsUIntT(t);

IsFixedPtT := (t) -> IsType(t) and ObjId(t)=TFixedPt;

IsRealT := (t) -> IsType(t) and t=TReal or ObjId(t)=T_Real;

IsComplexT := (t) -> IsType(t) and t=TComplex or ObjId(t)=T_Complex;

IsOddInt :=  n -> When(IsValue(n), n.v mod 2 = 1, IsInt(n) and n mod 2 = 1);

IsEvenInt := n -> When(IsValue(n), n.v mod 2 =0, IsInt(n) and n mod 2 = 0);


text:
# Copyright (c) 2018-2020, Carnegie Mellon University
# See LICENSE for details
#
# Utility functions for checking properties of the adjacency matrix NISQ topology
#

##
#F GetEdges( <arch>, <q> )
##
## Gets a list of edges in arch for a target qubit q
GetEdges := function(arch, q)
    local row, inqub, edges, e, edges;
    row := arch[q+1];
    inqub := 0;
    edges := [];
    for e in row do
        if e = 1 then
            Add(edges, inqub);
        fi;
        inqub := inqub + 1;
    od;
    # now have a list of adjacent qubits to the chosen qubit
    return edges;
end;

##
#F HasEdge( <i>, <j>, <arch> )
##
#F Checks if there is an edge between qubits i and j in arch
HasEdge:= function (i, j, arch)
    local row;
    row := arch[i+1];
    return row[j+1];
end;

##
#F GetDist( <i>, <j>, <arch> )
##
#F Returns the minimum distance in the architecture from qubit i to qubit j
GetDist := function (i, j, arch)
    local es, distances, dist, adjmat, n, inc;
    if (i = j) then
        return 0;
    fi;
    adjmat := arch;
    n := Length(arch);
    dist := 1;
    inc := 0;
    while (adjmat[i+1][j+1] <= 0 and inc <= n) do
        adjmat := adjmat * adjmat;
        dist := dist + 1;
        inc := inc + 1;
    od;
    if inc > n then # not possible, maybe do something better than returning null
        return n+2; #psuedo-null
    fi;
    return dist;
end;

##
#F Best_Move( <i>, <j>, <arch> )
##
#F Returns the most straightforward swap to perform to bring i and j closer
Best_Move := function (i, j, arch)
    local es, distances, shortest_path, e, best_move, l, tes;
    es := GetEdges(arch, i);
    tes := GetEdges(arch, j);
    if ContainsElement(es, j) then # if immediate neighbors
        return j;
    fi;
    l := Filtered(es, (e)-> ContainsElement(tes, e)); # find the immediate children they share, see if any match
    if l <> [] then
        return l[1];
    fi;
    # have to calculate distances
    distances := Map(es, e -> (GetDist(e, j, arch)));
    shortest_path := Minimum(distances);
    shortest_path := PositionProperty(distances, (e) -> (e = shortest_path));
    best_move := es[shortest_path];
    return best_move;
end;

##
#F VerifyPath( <target>, <source>, <arch> )
##
#F verifies that target and source are connected in arch
VerifyPath := function (target, source, arch)
    local i, q;
    i := 1;
    for q in target do
        if(GetDist(target[i], source[i], arch) > Length(arch)) then
            return false;
        fi;
        i := i + 1;
    od;
    return true;
end;

ext: gi

max_stars_repo_name: spiral-software/spiral-package-quantum

max_issues_repo_name: spiral-software/spiral-package-quantum

max_forks_repo_name: spiral-software/spiral-package-quantum


text:
package main

import (
	"github.com/containous/yaegi/interp"
)

func main() {
	i := interp.New(interp.Opt{})
	i.Eval(`println("Hello")`)
}

// Output:
// Hello

max_stars_repo_name: blasrodri/yaegi

max_issues_repo_name: blasrodri/yaegi

max_forks_repo_name: blasrodri/yaegi


text:
##  Copyright (c) 2018-2021, Carnegie Mellon University
##  See LICENSE for details

Class(TResample, Tagged_tSPL_Container, rec(
	     abbrevs :=  [ (odims, idims) -> [ odims, idims, [] ],
			   (odims, idims, shifts) -> [ odims, idims, shifts ],],
	     dims := self >> [Product(self.params[1]), Product(self.params[2])],
	     isReal := True,
	     terminate := self >> Error("Not yet implemented."),
	     transpose := self >> ObjId(self)(self.params[2], self.params[1], -1.0 * self.params[3]).withTags(self.getTags())
	     ));

max_stars_repo_name: franzfranchetti/spiral-package-fftx

max_issues_repo_name: franzfranchetti/spiral-package-fftx

max_forks_repo_name: franzfranchetti/spiral-package-fftx


text:
#
# francy: Interactive Discrete Mathematics in GAP
#

#############################################################################
##
#M  Chart( <chart type> ) .
##
InstallMethod(Chart,
  "a chart type, chart defaults",
  true,
  [IsChartType,
   IsChartDefaults],
  0,
function(chartType, options)
  return MergeObjects(Objectify(ChartObjectType, rec(
    id   := GenerateID(),
    data := rec(),
    axis := DefaultAxis(chartType),
    type := chartType!.value,
  )), options);
end);

InstallOtherMethod(Chart,
  "a Chart type",
  true,
  [IsChartType],
  0,
function(chartType)
  return Chart(chartType, ChartDefaults);
end);

#############################################################################
##
#M  DefaultAxis( <chart type> ) .
##
InstallMethod(DefaultAxis,
  "a chart type",
  true,
  [IsChartType],
  0,
function(chartType)
  local axis;
  axis := rec();
  # default is linear
  axis.x := XAxis(AxisScaleType.LINEAR, "", []);
  axis.y := YAxis(AxisScaleType.LINEAR, "", []);
  if chartType!.value = ChartType.BAR!.value then
    axis.x := XAxis(AxisScaleType.BAND, "", []);
  fi;
  return axis;
end);

#############################################################################
##
#M  Add( <chart>, <francy object> ) . . . . . add objects to canvas
##
InstallOtherMethod(Add,
  "a Chart, a dataset",
  true,
  [IsChart,
   IsDataset],
  0,
function(chart, object)
  chart!.data!.(object!.title) := object!.data;
  return chart;
end);

InstallOtherMethod(Add,
  "a Chart, a list of francy objects",
  true,
  [IsChart,
   IsList],
  0,
function(chart, objects)
  local object;
  for object in objects do
    Add(chart, object);
  od;
  return chart;
end);

#############################################################################
##
#M  Remove( <chart>, <francy object> ) . . . . . remove object from canvas
##
InstallOtherMethod(Remove,
  "a chart, a dataset",
  true,
  [IsChart,
   IsDataset],
  0,
function(chart, object)
  Unbind(chart!.data!.(object!.title));
  return chart;
end);

InstallOtherMethod(Remove,
  "a Chart, a list of francy objects",
  true,
  [IsChart,
   IsList],
  0,
function(chart, objects)
  local object;
  for object in objects do
    Remove(chart, object);
  od;
  return chart;
end);

#############################################################################
##
#M  Dataset( <title>, <list of data> ) . . . . . create a dataset
##
InstallMethod(Dataset,
  "a title, a list of data",
  true,
  [IsString,
   IsList],
  0,
function(title, list)
  return Objectify(DatasetObjectType, rec(
    title := title,
    data  := list
  ));
end);

#############################################################################
##
#M  XAxis( <axis scale type>, <title>, <domain range> )
##
InstallMethod(XAxis,
  "the axis scale type, a title, a list of data",
  true,
  [IsAxisScaleType,
   IsString,
   IsList],
  0,
function(axisScale, title, list)
  return Objectify(XAxisObjectType, rec(
    scale  := axisScale!.value,
    title  := title,
    domain := list
  ));
end);

InstallOtherMethod(XAxis,
  "the axis scale type, a title",
  true,
  [IsAxisScaleType,
   IsString],
  0,
function(axisScale, title)
  return XAxis(axisScale, title, []);
end);

#############################################################################
##
#M  YAxis( <axis scale type>, <title>, <domain range> )
##
InstallMethod(YAxis,
  "the axis scale type, a title, a list of data",
  true,
  [IsAxisScaleType,
   IsString,
   IsList],
  0,
function(axisScale, title, list)
  return Objectify(YAxisObjectType, rec(
    scale  := axisScale!.value,
    title  := title,
    domain := list
  ));
end);

InstallOtherMethod(YAxis,
  "the axis scale type, a title",
  true,
  [IsAxisScaleType,
   IsString],
  0,
function(axisScale, title)
  return YAxis(axisScale, title, []);
end);

max_stars_repo_name: LaGuer/francy

max_issues_repo_name: LaGuer/francy

max_forks_repo_name: LaGuer/francy


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

# ----------------------------------------------------------------------------------
# Visitor - base class for objects implementing the visitor pattern from Gamma book
# ----------------------------------------------------------------------------------
# This class basically implements a somewhat modified variant of the original
# Visitor pattern from the book by Gamma, et al. "Design Patterns".
#
# Usage example:
#
# define the following class
#
# Class(LispGen, Visitor, rec(
#     add := (self, o) >> Print("(+ ", self(o.args[1]), " ", self(o.args[2]), ")"),
#     mul := (self, o) >> Print("(* ", self(o.args[1]), " ", self(o.args[2]), ")"),
#     sub := (self, o) >> Print("(- ", self(o.args[1]), " ", self(o.args[2]), ")"),
#     var := (self, o) >> Print("(var ", o.id, ")"),
#     Value := (self, o) >> Print("(value ", o.v, ")")
# ));
#
# spiral> LispGen(4*X+2);
# (+ (* (value 4) (var X)) (value 2))spiral>
#
# Note that instead of using 'self' as a function (which invokes __call__),
# we can use self.visit, and make __call__ a constructor for LispGen.
#
# Ie., the methods would look like
#     add := (self, o) >> Print("(+ ", self.visit(o.args[1]), " ", self.visit(o.args[2]), ")"),
#
Class(Visitor, rec(
   __call__ := arg >> ApplyFunc(arg[1].visit, arg{[2..Length(arg)]}),

    # this is a rewrite of the lambda expression. The lambda was getting
    # way too long. This implements the double dispach for the visitor
    # class.
    visit := meth(arg)
        local self, o, len;

        Constraint(Length(arg) >= 2);

        self := arg[1];
        o := arg[2];
        len := Length(arg);

        if IsRec(o) or IsList(o) then
            o := ObjId(o);
            if IsBound(self.(o.name)) then
                ApplyFunc(self.(o.name), arg{[2..len]});

            # this is just here to trap the hacks, rather than silently fail
            elif IsBound(o.visitAs) then
                Error("visitAs has been removed. Don't use it.");

            else
		        Error("Cannot visit <arg[2]>. Visitor ", self,
                " does not have field '", o.name, "'",
                    When(IsBound(o.visitAs),
			            Concat(" or ",o.visitAs, " (from .visitAs)"),
                        ""
                    )
                );
            fi;
        else
            ApplyFunc(self.atomic, arg{[2..len]});
        fi;
    end
));

#F
#F# getVisitAs
#F
#F get the .visitAs if it exists.
#F

getVisitAs := function(v, o)

    o := ObjId(o);

    # if this object has a visitor, or if visitAs is unbound
    if IsBound(v.(o.__name__)) or not IsBound(o.visitAs) then
        return false;
    fi;

    return o.visitAs;
end;

#F HierarchicalVisitor -- same as Visitor, but does not use .visitAs,
#F   instead traverses the super class chain
#F
Class(HierarchicalVisitor, rec(
   __call__ := arg >> ApplyFunc(arg[1].visit, arg{[2..Length(arg)]}),

#F the hierarchical visitor function.
#F
#F we consider the objects by level, in order of the objects in __bases__
#F
#F here's an example:
#F objA
#F  |---parA
#F  | |---parA1
#F  | \---parA2
#F  \---parB
#F
#F traverse order is: objA parA parB parA1 parA2
#F
    warnings := Set([]),
    paranoiaMode := false, # <-- if this is true, then .visit() aborts when there is a mismatch of
                          # the method it finds with what .visitAs prescribes, otherwise,
                          # it silently adds the mismatch to .warnings and continues

    visit := meth(arg)
        local self, o, orig, len, parents, newparents, v;

        Constraint(Length(arg) >= 2);

        self := arg[1];
        o   := arg[2];
        len := Length(arg);

        # lists are handled with .ListClass, records with .<objid>,
        # other objects with .atomic
        if not (IsRec(o) or IsList(o)) or IsString(o) then
            return ApplyFunc(self.atomic, arg{[2..len]});

        # objects are handled here
        else
            # this will be eventually removed, but for the time being,
            # we try to figure out the object which would be selected
            # by .visitAs and compare it to the object which is chosen
            # hierarchically. If there is a difference, we throw an
            # error.

            v := getVisitAs(self, o);

            # paranoia check to make sure we have an object
            Constraint(IsList(o) or (IsRec(o) and IsBound(o.__name__)));

            parents := Cond(IsList(o), [ObjId(o)], ShallowCopy(o.__bases__));

            # traverse the parent tree as given in the function comments
            for o in parents do
                if IsBound(self.(o.__name__)) then

                    # here is our paranoia check which will eventually
                    # be removed after the transition is complete.
                    if (v <> false and v <> o.__name__) then
                        if self.paranoiaMode then
                            Error("visitAs object is different from object picked by hierarchy traversal. Call Marek.");
                        else
                            AddSet(self.warnings, [self,v,o]);
                        fi;
                    fi;

                    return ApplyFunc(self.(o.__name__), arg{[2..len]});
                elif IsBound(o.__bases__) then
                    Append(parents, o.__bases__);
                fi;
            od;

            return Error("Cannot visit <arg[2]>. visitAs was ", v);
        fi;
    end,

    #F
    #F getBases()
    #F
    #F build a list of all the bases according to the order
    #F given in the .visitAs method
    #F
    getBases := meth(self)
        local b, i;

        b := [self];
        i := 1;

        while i <= Length(b) do
            Append(b, ShallowCopy(b[i].__bases__));
            i := i + 1;
        od;

        return b;
    end,

    #F
    #F showMatches(obj)
    #F
    #F returns the ordered list of visitors triggered by this object.
    showMatches := meth(self, o)
        local b, bb, res, i, m;

        Constraint(IsRec(o));

        b := self.getBases();

        bb := ShallowCopy(o.__bases__);
        res := [];
        i := 1;

        while i <= Length(bb) do
            m := Filtered(b, e -> bb[i].name in UserRecFields(e));

            if m <> [] then
                Append(res, [bb[i]] :: m);
            fi;

            Append(bb, ShallowCopy(bb[i].__bases__));
            i := i + 1;
        od;

        return res;
    end,
));

#F HierarchicalVisitorCx -- HierarchicalVisitor with context accessible through
#F   self.cx field. Drawback - start visitor using <walk> method instead of
#F   __call__.
#F
#F   Ex: MyVisitor.walk(tree, arg1, arg2);
#F

Class(HierarchicalVisitorCx, HierarchicalVisitor, rec(

    walk := (arg) >> ApplyFunc(CopyFields(arg[1], rec(
        cx := empty_cx(), _current := false )), Drop(arg, 1)),

    visit := meth(arg)
        local self, parent, res;

        self          := arg[1];
        parent        := self._current;
        self._current := arg[2];

        if parent=false then
            res := ApplyFunc(Inherited, Drop(arg, 1));
        else
            cx_enter(self.cx, parent);
            res := ApplyFunc(Inherited, Drop(arg, 1));
            cx_leave(self.cx, parent);
        fi;

        self._current := parent;

        return res;
    end,
));


text:
Random([1, 10, 100]);

# Random permutation of 1..200
Random(SymmetricGroup(200));

# Random element of Z/23Z :
Random(Integers mod 23);

ext: gap

max_issues_repo_name: seanwallawalla-forks/RosettaCodeData

max_forks_repo_name: seanwallawalla-forks/RosettaCodeData


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

_sum2 := function(lst)
    local i, res;
    res := 0;
    for i in [2..Length(lst)] do
        res := res + lst[i][1] + lst[i][2];
    od;
    return res;
end;

# objhead = [ objid_addr, param1_uid, param2_uid, ... ]
# uid is unique position in the hashtable returned by HashAdd
Class(ObjHashBase, HashTable(
    (objhead,size) -> When(IsInt(objhead), 1 + (objhead mod size),
                       1 + ((objhead[1] + _sum2(objhead)) mod size)),
    (objhead1, objhead2) -> objhead1 = objhead2)
);

ObjHashBase.operations := WithBases(HashOps, rec(
    Print := o -> Print(o.name)
));

Class(ObjHash, ObjHashBase, rec(
    liveEntries := self >> Filtered(self.entries, True),
    numLiveEntries := self >> Sum(List(self.liveEntries(), Length)),

    nonrecLookupAdd := meth(self, o)
        local lkup;
	lkup := HashLookupUID(self, InternalHash(o));
	if Same(lkup, false) then
	    return HashAdd(self, InternalHash(o), o);
	else return lkup;
	fi;
    end,

    listLookupAdd := meth(self, o)
        local lkup, uids;
	uids := [T_LIST];
	Append(uids, List(o, e -> self.uidObj(e)));
	lkup := HashLookupUID(self, uids);
	if Same(lkup, false) then
	    return HashAdd(self, uids, o);
	else return lkup;
	fi;
    end,

    uidObj := (self,o) >> Cond(
    IsRec(o) and IsBound(o.uid), o.uid,
    IsRec(o), Error("Unhashed object <o>"),
    IsList(o), self.listLookupAdd(o),
    self.nonrecLookupAdd(o)),

    objAdd := meth(self, res, h)
        local uid;
    uid := HashAdd(self, h, res);
    res.h := h;
    res.uid := uid;
    return res;
    end,

    singletonAdd := (self, o) >> self.objAdd(o, [BagAddr(o)]),

    _prList := meth(self, lst)
        local p;
    for p in lst do
            if IsRec(p) then Print(ObjId(p));
        elif IsList(p) then Print("(",self._prList(p), ")");
        else Print(p);
        fi;
        Print(":",self.uidObj(p), " ");
        od;
    end,

    debug := true,

    objLookup := meth(self, objid, params)
        local h,lkup,hcodes;
	h := [BagAddr(objid)];
	Append(h, List(params, p -> self.uidObj(p)));
	lkup := HashLookup(self, h);

	if self.debug then
	    if Same(lkup,false) then
		Print("(", objid, " ", self._prList(params), ")\n");
	    else
		Print(objid, " : hit ", lkup.uid, "\n");
	    fi;
	fi;

	return [lkup,h];
    end,

    memClassFunc := meth(self, cls, orig, bck)
        Constraint(IsBound(cls.(orig)));
        #Constraint(not IsBound(cls.__call_no_memo__));
    cls.(bck) := cls.(orig);
    cls._hash := self;
    bck := RecName(bck); # this will make lookup a bit faster

    cls.(orig) := meth(arg)
            local clsself, params, lkup, res, h;
        clsself := arg[1]; params := Drop(arg,1);
        h := clsself._hash;
        if h<>false then
        lkup := h.objLookup(clsself, params);
        if lkup[1] <> false then return lkup[1]; fi;
        fi;
        res := ApplyFunc(clsself.(bck), params);
        if h<>false then
        return h.objAdd(res, lkup[2]);
        else return res;
        fi;
    end;
    end,

    memClass := (self,cls) >> self.memClassFunc(cls, "__call__", "__call_no_memo__")
));


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

Class(LoopGath, Gath);
Class(LoopScat, Scat);
Class(LoopPrm, Prm);

FuncClass.gath := self >> Gath(self);
FuncClass.scat := self >> Scat(self);

fId.gath := self >> I(self.params[1]);
fId.scat := self >> I(self.params[1]);

L.scat := self >> let(m:=self.params[2], n:=self.params[1]/self.params[2], j:=Ind(m), fid := fId(n), fbase := fBase(m,j),
                      gath := Gath(fTensor(fid, fbase)), scat := Scat(fTensor(fbase, fid)),
                      ISum(j, m, scat*gath));

L.gath := self >> let(m:=self.params[2], n:=self.params[1]/self.params[2], j:=Ind(n), fid := fId(m), fbase := fBase(n,j),
                      gath := Gath(fTensor(fbase, fid)), scat := Scat(fTensor(fid, fbase)),
                      ISum(j, n, scat*gath));

fCompose.gath := self >> Compose(Reversed(List(self.children(), i->i.gath())));
fCompose.scat := self >> Compose(List(self.children(), i->i.scat()));

fTensorBuf := function(func, combine)
    local ch, n, loopvars, i, lv, newch1, newch2, res;
    ch := func.children();
    n := Length(ch);
    loopvars := List(Filtered(ch, c -> ObjId(c)=fId), c -> Ind(c.size));

    lv := 1; newch1 := []; newch2 := [];
    for i in [1..n] do
        if ObjId(ch[i]) <> fId then
	    Add(newch1, ch[i]);
	else
	    Add(newch1, fBase(loopvars[lv]));
	    Add(newch2, fBase(loopvars[lv]));
	    lv := lv+1;
	fi;
    od;

    res := combine(fTensor(newch1), fTensor(newch2));

    # lv here is number of loopvars + 1
    for i in Reversed([1..lv-1]) do
        res := ISum(loopvars[i], res);
	# unroll inner loop
	#if i=lv-1 then res:=BB(res); fi;
    od;
    return res;
end;

#fTensor.gath := self >> Tensor(List(self.children(), i->i.gath()));

fTensor.scat := self >> fTensorBuf(self, (f1, f2) -> BB(Scat(f1) * Gath(f2)));
fTensor.gath := self >> fTensorBuf(self, (f1, f2) -> BB(Scat(f2) * Gath(f1)));


text:
#
# SharedMemory: Shared Memory Parallelism in GAP
#
# Implementations
#

max_stars_repo_name: markuspf/ShmIng

max_issues_repo_name: markuspf/ShmIng

max_forks_repo_name: markuspf/SharedMemory


text:
# The incidence graph of a Desarguesian projective plane.
BindGlobal("DesarguesianPlaneIncidenceGraph", function(q)
    local G, V, dp;
    V := GF(q)^3;
    dp := DirectProduct(GL(3, q), SymmetricGroup(2));
    G := Graph(dp, Union(List([1,2], d -> Subspaces(V, d))),
                OnProjectivePlane(V, dp), function(x, y)
                    return x <> y and Intersection(x, y) in [x, y];
                end, true);
    G.halfDuality := Sum;
    G.halfPrimality := Intersection;
    return G;
end);

# The incidence graph of a Hall plane.
BindGlobal("HallPlaneIncidenceGraph", function(q)
    local c, p, G, H, L, P, dp, mul;
    H := GF(q)^2;
    p := DefiningPolynomial(GF(GF(q), 2));
    c := CoefficientsOfUnivariatePolynomial(p);
    mul := HallMultiplication(p);
    P := Union([[]], List(H, x -> [x]), Cartesian(H, H));
    L := Union([Union([[]], List(H, z -> [z]))],
                List(H, x -> Union([[]], List(H, z -> [x, z]))),
                List(Cartesian(H, H), w -> Union([[w[1]]],
                    List(H, z -> [z, mul(z, w[1]) + w[2]]))));
    dp := DirectProduct(Concatenation(ListWithIdenticalEntries(5,
                                        FieldAdditionPermutationGroup(q)),
                        [FieldMultiplicationPermutationGroup(q),
                         Group([[c[2], Z(q)^0], [-c[1], 0*Z(q)]])]));
    G := Graph(dp, Union(P, L), OnHallPlane(q, dp),
                PointLineIncidence, true);
    G.halfDuality := DefaultDualityFunction;
    G.halfPrimality := DefaultPrimalityFunction;
    return G;
end);

# The incidence graph of a Hughes plane. If the second parameter n is zero or
# unspecified, a Dickson semifield of order q^2 is used and the first parameter
# q must be an odd prime power. Otherwise, an exceptional near-field of order
# q^2 is used, so q must be 5, 7, 11, 23, 29, or 59. As there are two
# exceptional near-fields of order 11^2, setting n to 1 or 2 chooses one of
# these semifields when q = 11.
BindGlobal("HughesPlaneIncidenceGraph", function(arg)
    local c, n, q, A, B, F, G, H, P, df, dp, th, mul, rdiv, gens, orth;
    if Length(arg) < 1 then
        Error("at least one argument expected");
        return fail;
    fi;
    q := arg[1];
    if Length(arg) > 1 then
        n := arg[2];
    else
        n := 0;
    fi;
    th := Z(q^2)^((q+1)/2);
    B := Basis(GF(q^2), [Z(q)^0, th]);
    if n = 0 then
        mul := DicksonMultiplication(q);
        rdiv := DicksonRightDivision(q);
    else
        gens := [[[0, -1], [1, 0]]];
        if q = 5 then
            gens[2] := [[1, -2], [-1, -2]];
        elif q = 7 then
            gens[2] := [[1, 3], [-1, -2]];
        elif q = 11 and n = 1 then
            gens[2] := [[1, 5], [-5, -2]];
            gens[3] := [[4, 0], [0, 4]];
        elif q = 11 and n = 2 then
            gens[2] := [[2, 4], [1, -3]];
        elif q = 23 then
            gens[2] := [[1, -6], [12, -2]];
            gens[3] := [[2, 0], [0, 2]];
        elif q = 29 then
            gens[2] := [[1, -7], [-12, -2]];
            gens[3] := [[16, 0], [0, 16]];
        elif q = 59 then
            gens[2] := [[9, 15], [-10, -10]];
            gens[3] := [[4, 0], [0, 4]];
        else
            Error("the specified exceptional near-field does not exist");
            return fail;
        fi;
        G := Group(gens * Z(q)^0);
        F := Union([NullMat(2, 2, GF(q))], Elements(G));
        SortBy(F, x -> IntVecFFE(x[1]));
        mul := ExceptionalMultiplication(q, F, B);
        rdiv := ExceptionalRightDivision(q, F, B);
    fi;
    c := CoefficientsOfUnivariatePolynomial(DefiningPolynomial(GF(GF(q), 3)));
    A := [[-c[3], Z(q)^0, 0*Z(q)],
          [-c[2], 0*Z(q), Z(q)^0],
          [-c[1], 0*Z(q), 0*Z(q)]];
    P := Filtered(GF(q^2)^3,
            x -> not IsZero(x) and IsOne(First(x, y -> not IsZero(y))));
    dp := DirectProduct(Group(A), SymmetricGroup(2));
    orth := function(x, y)
        local z;
        z := TransposedMat(List(y, w -> Coefficients(B, w)));
        return IsZero(x*z[1] + mul(th, x*z[2]));
    end;
    H := Graph(dp, Cartesian([1, 2], P), OnHughesPlane(q, rdiv, dp),
                function(x, y)
                    return x[1] <> y[1] and orth(x[2], y[2]);
                end, true);
    df := x -> [x[1][1]^(1, 2),
                Intersection(List(x,
                                    y -> Filtered(P, z -> orth(y[2], z))))[1]];
    H.halfDuality := df;
    H.halfPrimality := df;
    return H;
end);

# The collinearity graph of the generalized quadrangle Q(d, q)
# of order (q, q^{d-3}).
BindGlobal("GeneralizedQuadrangleQ", function(d, q)
    return PolarGraphO(4-d, d+1, q);
end);

# The collinearity graph of the generalized quadrangle H(d, r^2)
# of order (r^2, r^{d-5/2}).
BindGlobal("GeneralizedQuadrangleH", function(d, r)
    return PolarGraphU(d+1, r);
end);

# The collinearity graph of the generalized quadrangle W(q) of order (q, q).
BindGlobal("GeneralizedQuadrangleW", q -> PolarGraphSp(4, q));

# The collinearity graph of the generalized quadrangle T_d(O) of order
# (q, q^{d-1}) derived from the projective space PG(d+1, q) containing the
# oval or ovoid O in a hyperplane.
BindGlobal("GeneralizedQuadrangleT", function(arg)
    local d, o, q, G, H, O, V, gr;
    if Length(arg) < 1 then
        Error("at least one argument expected");
        return fail;
    elif Length(arg) < 3 then
        d := arg[1].d;
        q := arg[1].q;
        o := arg[1].points;
        G := arg[1].group;
    else
        d := arg[1];
        q := arg[2];
        o := arg[3];
        if Length(arg) > 3 then
            G := arg[4];
        else
            G := Group(IdentityMat(d+1, GF(q)));
        fi;
    fi;
    V := GF(q)^(d+2);
    H := Subspace(V, BasisVectors(CanonicalBasis(V)){[2..d+2]}, "basis");
    O := List(o, x -> Subspace(V,
            [Concatenation([0*Z(q)], BasisVectors(Basis(x))[1])], "basis"));
    gr := Graph(Group(List(GeneratorsOfGroup(G),
                            g -> Concatenation([Concatenation([Z(q)^0],
                                    ListWithIdenticalEntries(d+1, 0*Z(q)))],
                                List(g, l -> Concatenation([0*Z(q)], l))))),
        Union(Filtered(Subspaces(V, 1), x -> not IsSubset(H, x)),
                Filtered(Subspaces(V, d+1),
                    x -> Length(Filtered(O, y -> IsSubset(x, y))) = 1), [V]),
        OnSubspaces(V), function(x, y)
            local dx, dy, xy, yx;
            dx := Dimension(x);
            dy := Dimension(y);
            xy := x+y;
            yx := Intersection(x, y);
            return (dx = d+2 and dy = d+1) or (dx = d+1 and dy = d+2) or
                (dx = 1 and dy = 1 and ForAny(O, z -> IsSubset(xy, z))) or
                (dx = 1 and dy = d+1 and ForAny(O, z -> IsSubset(y, x+z))) or
                (dx = d+1 and dy = 1 and ForAny(O, z -> IsSubset(x, y+z))) or
                (dx = d+1 and dy = d+1 and x <> y and
                                            ForAny(O, z -> IsSubset(yx, z)));
        end, true);
    gr.duality := function(x)
        if V in x then
            return First(O, y -> IsSubset(Intersection(x), y));
        else
            return Sum(Filtered(x, y -> Dimension(y) = 1));
        fi;
    end;
    gr.primality := function(x)
        if ForAll(x, y -> Dimension(y) = 1) then
            return V;
        elif ForAll(x, y -> Dimension(y) = 2) then
            return Intersection(x);
        else
            return Sum(x);
        fi;
    end;
    return gr;
end);

# The collinearity graph of the generalized quadrangle T*(O) of order
# (2^h-1, 2^h+1) derived from the projective space PG(3, 2^h) containing the
# hyperoval O in a hyperplane.
BindGlobal("GeneralizedQuadrangleTstar", function(arg)
    local o, q, G, H, O, V, gr;
    if Length(arg) < 1 then
        Error("at least one argument expected");
        return fail;
    elif Length(arg) < 3 then
        q := arg[1].q;
        o := arg[1].points;
        G := arg[1].group;
    else
        q := 2^arg[1];
        o := arg[2];
        if Length(arg) > 2 then
            G := arg[3];
        else
            G := Group(IdentityMat(3, GF(q)));
        fi;
    fi;
    V := GF(q)^4;
    H := Subspace(V, BasisVectors(CanonicalBasis(V)){[2..4]}, "basis");
    O := List(o, x -> Subspace(V,
            [Concatenation([0*Z(q)], BasisVectors(Basis(x))[1])], "basis"));
    gr := Graph(Group(List(GeneratorsOfGroup(G),
                            g -> Concatenation([Concatenation([Z(q)^0],
                                    ListWithIdenticalEntries(3, 0*Z(q)))],
                                List(g, l -> Concatenation([0*Z(q)], l))))),
                Filtered(Subspaces(V, 1), x -> not IsSubset(H, x)),
                OnSubspaces(V), function(x, y)
                    local xy;
                    xy := x+y;
                    return not IsSubset(H, xy)
                        and ForAny(O, z -> IsSubset(xy, z));
                end, true);
    gr.duality := Sum;
    gr.primality := Intersection;
    return gr;
end);

# The collinearity graph of the generalized quadrangle P(G, z) of
# order (s-1, s+1) derived by removing the neighbourhood of a regular point z
# of a generalized quadrangle G of order (s, s).
BindGlobal("GeneralizedQuadrangleP", function(Q, z)
    local H, P;
    H := Graph(Stabilizer(Q.group, z), DistanceSet(Q, 2, z), OnPoints,
            function(x, y)
                local c;
                c := Intersection(Adjacency(Q, x), Adjacency(Q, y));
                return not z in c and (y in Adjacency(Q, x)
                                    or ForAll(c, w -> z in Adjacency(Q, w)));
            end, true);
    AssignVertexNames(H, Q.names{H.names});
    CheckDualityFunctions(Q);
    H.duality := function(x)
        local p;
        p := List(x, u -> Position(Q.names, u));
        if ForAny(Cartesian(p, p), w -> Distance(Q, w[1], w[2]) = 2) then
            return [2, Set(x)];
        else
            return [1, Q.duality(Union(x,
                    Q.names{Intersection(List(p, v -> Adjacency(Q, v)))}))];
        fi;
    end;
    H.primality := x -> Q.primality(List(Filtered(x, y -> y[1] = 1),
                                    w -> w[2]));
    return H;
end);

# The collinearity graph of the generalized quadrangle AS(q)
# of order (q-1, q+1).
BindGlobal("GeneralizedQuadrangleAS",
    q -> GeneralizedQuadrangleP(GeneralizedQuadrangleW(q), 1));

# The incidence graph of a projective plane read from a file as on
#   http://www.uwyo.edu/moorhouse/pub/planes/       or
#   http://www.uwyo.edu/moorhouse/pub/genpoly/
# The optional second parameter is a file containing generators of the
# automorphism group.
BindGlobal("IncidenceGraphFromFile", function(arg)
    local l, m, n, G, L, fst, lst, lns;
    if Length(arg) < 1 then
        Error("at least one argument expected");
        return fail;
    fi;
    lns := ReadLines(arg[1]);
    n := Length(lns);
    L := List(lns, l -> List(SplitString(l, " "), x -> Int(x)+n+1));
    if Length(arg) > 1 then
        lns := ReadLines(arg[2]);
        m := Length(lns);
        fst := Filtered([1..m], i -> IntChar(lns[i][1]) <> 32);
        l := Length(fst);
        lst := List(fst{[2..l]}, i -> i-1);
        Add(lst, m);
        G := Group(List([1..l], i -> PermList(List(SplitString(
                    JoinStringsWithSeparator(lns{[fst[i]..lst[i]]}, ""),
                    " "), x -> Int(x)+1))));
    else
        G := Group(());
    fi;
    return Graph(G, [1..2*n], OnPoints, function(x, y)
            return (x <= n and y in L[x]) or (y <= n and x in L[y]);
        end, true);
end);

# The collinearity graph of a projective plane read from a file as on
#   http://www.uwyo.edu/moorhouse/pub/genpoly/
# The optional second parameter is a file containing generators of the
# automorphism group.
BindGlobal("CollinearityGraphFromFile", function(arg)
    local l, m, n, G, L, fst, lst, lns;
    if Length(arg) < 1 then
        Error("at least one argument expected");
        return fail;
    fi;
    lns := ReadLines(arg[1]);
    n := Length(lns);
    L := List(lns, l -> List(SplitString(l, " "), x -> Int(x)));
    if Length(arg) > 1 then
        lns := ReadLines(arg[2]);
        m := Length(lns);
        fst := Filtered([1..m], i -> IntChar(lns[i][1]) <> 32);
        l := Length(fst);
        lst := List(fst{[2..l]}, i -> i-1);
        Add(lst, m);
        G := Group(List([1..l], i -> PermList(Filtered(List(SplitString(
                    JoinStringsWithSeparator(lns{[fst[i]..lst[i]]}, ""),
                    " "), x -> Int(x)+1), y -> y <= n))));
    else
        G := Group(());
    fi;
    return Graph(G, [1..n], OnPoints, function(x, y)
            return Length(Intersection(L[x], L[y])) = 1;
        end, true);
end);

max_stars_repo_name: jaanos/gap-graphs

max_issues_repo_name: jaanos/gap-graphs

max_forks_repo_name: jaanos/gap-graphs


text:
RequirePackage("grape");

GC := function(x,y,i,j) return x[i]*y[j] - x[j]*y[i]; end;

G2 := function(q)
    local P, Q;
    if q mod 2 = 0 then
        Q := [[0,0,0,0,1,0,0],[0,0,0,0,0,1,0],[0,0,0,0,0,0,1],[0,0,0,1,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]]*Z(q)^0;;
    else
        Q := [[0,0,0,0,1,0,0],[0,0,0,0,0,1,0],[0,0,0,0,0,0,1],[0,0,0,1,0,0,0],[1,0,0,0,0,0,0],[0,1,0,0,0,0,0],[0,0,1,0,0,0,0]]*Z(q)^0;;
    fi;
    P := Filtered(List(Subspaces(GF(q)^7, 1), y -> Elements(y)[2]), x -> x*Q*x = 0*Z(q));;

    return Graph(Group(()), P, function(x,y) return x; end,
        function(x,y)
            return x <> y and x*Q*y = 0*Z(q) and y*Q*x = 0*Z(q) and
            [ GC(x,y,2,3), GC(x,y,6,5), GC(x,y,3,1), GC(x,y,7,6), GC(x,y,1,2), GC(x,y,5,7) ] =
            [ GC(x,y,4,5), GC(x,y,4,3), GC(x,y,4,6), GC(x,y,4,1), GC(x,y,4,7), GC(x,y,4,2) ];
        end, true);;
end;


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

#
# keys.gi -- define string constants used as keys in scriptgen package
#

# transforms

SGKEY_FFT		:= "FFT";
SGKEY_FFT_2D	:= "FFT2D";
SGKEY_FFT_3D	:= "FFT3D";
SGKEY_IFFT		:= "IFFT";
SGKEY_IFFT_2D	:= "IFFT2D";
SGKEY_IFFT_3D	:= "IFFT3D";
SGKEY_WHT		:= "WHT";

# data types

SGKEY_DPCX		:= "DPCX";
SGKEY_SPCX		:= "SPCX";

# ScriptGen settings

SGKEY_DATATYPE		:= "datatype";
SGKEY_FILENAME		:= "filename";
SGKEY_FUNCNAME		:= "funcname";
SGKEY_SIZE			:= "size";
SGKEY_TRANSFORM		:= "transform";

# ScriptGen settings details

SGKEY_DISPLAYNAME		:= "displayname";
SGKEY_MULTIPLEVALUES	:= "multipleValues";
SGKEY_NAME				:= "name";
SGKEY_TYPE				:= "type";

# Special keys

SGKEY_DEFAULT	:= "default";

# String constants

SGSTR_STDOUT	:= "*stdout*";

SGSTR_ALL			:= "all";
SGSTR_CONSTRUCTOR	:= "constructor";
SGSTR_RUNRANDOMALL	:= "runRandomAll";
SGSTR_RUNALL		:= "runAll";

# Settings types

SGTYPE_INT		:= "i";
SGTYPE_BOOL		:= "b";
SGTYPE_STRING	:= "s";

# display names associated with keys

_SG_displayNames := rec(
	(SGKEY_FFT)			:= "Fast Fourier Transform",
	(SGKEY_FFT_2D)		:= "2D Fast Fourier Transform",
	(SGKEY_FFT_3D)		:= "3D Fast Fourier Transform",
	(SGKEY_IFFT)		:= "Inverse Fast Fourier Transform",
	(SGKEY_IFFT_2D)		:= "2D Inverse Fast Fourier Transform",
	(SGKEY_IFFT_3D)		:= "2D Inverse Fast Fourier Transform",
	(SGKEY_WHT)			:= "Walsh-Hadamard Transform",

	(SGKEY_DPCX)		:= "Double-Precision Complex",
	(SGKEY_SPCX)		:= "Single-Precision Complex",

	(SGKEY_DATATYPE)	:= "Data Type",
	(SGKEY_FILENAME)	:= "File Name",
	(SGKEY_FUNCNAME)	:= "Function Name",
	(SGKEY_SIZE)		:= "Size",
	(SGKEY_TRANSFORM)	:= "Transform",

	(SGSTR_RUNRANDOMALL) := "Generate Code (quick search)",
	(SGSTR_RUNALL)		 := "Generate Code (in-depth search)",
);

GetScriptGenDisplayName := function(key)
	if IsString(key) and IsBound(_SG_displayNames.(key)) then
		return _SG_displayNames.(key);
	elif (not IsString(key)) and IsList(key) and (Length(key) = 2) then
		if ForAll(key, IsInt) then
			return StringPrint(key[1], " x ", key[2]);
		fi;
	fi;

	return StringPrint(key);
end;

SetScriptGenDisplayName := function(key, string)
	if not ( IsString(key) and IsString(string) ) then
		Error("usage: SetScriptGenDisplayName(key, string)\n  both <key> and <string> must be strings");
	fi;

	_SG_displayNames.(key) := string;
end;

# documentation associated with keys

_SG_docunmentationForKeys := rec(
);

GetScriptGenDocumentation := function(key)
	if IsString(key) and IsBound(_SG_docunmentationForKeys.(key)) then
		return _SG_docunmentationForKeys.(key);
	fi;

	return "";
end;

SetScriptGenDocumentation := function(key, string)
	if not ( IsString(key) and IsString(string) ) then
		Error("usage: SetScriptGenDocumentation(key, string)\n  both <key> and <string> must be strings");
	fi;

	_SG_docunmentationForKeys.(key) := string;
end;


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

Rows := s -> Cond(
    IsMat(s),
        Length(s),

    IsBound(s.rng) and IsBound(s.dmn),
        s.dims()[1],

    IsValue(s) or IsSymbolic(s),
        Checked(IsArrayT(s.t), IsArrayT(s.t.t),
	    s.t.size),

    s.dimensions[1]
);

Cols := s -> Cond(
    IsMat(s),
        Length(s[1]),

    IsBound(s.rng) and IsBound(s.dmn),
        s.dims()[2],

    IsValue(s) or IsSymbolic(s),
        Checked(IsArrayT(s.t), IsArrayT(s.t.t),
	    s.t.t.size),

    s.dimensions[2]
);

olRows := s -> Flat([Rows(s)]);
olCols := s -> Flat([Cols(s)]);

#F SPL(<rec>)
#F    Set operations field to SPLOps. This function should be called
#F    to initialize SPL instances.
SPL := function(record)
   record.operations := SPLOps;
   return record;
end;

HashAsSPL := o -> Cond(
    IsList(o),
        List(o, HashAsSPL),
    not IsRec(o) or (not IsBound(o.hashAs) and not IsBound(o.from_rChildren)),
        o,
    IsBound(o.hashAs),
        o.hashAs(),
    IsValue(o),
        o.v,
    o.from_rChildren(List(o.rChildren(), HashAsSPL))
);

# ==========================================================================
# ClassSPL
#
# Base class for all SPL constructs
# ==========================================================================
Class(ClassSPL, AttrMixin, rec(
    isSPL := true,
    transposed := false,

#DD this allows objects which are not TaggedNonTerminals to drop tags automagically
#DD and without error.
    withTags := (self, t) >> self,

    _short_print := false,
    _newline := i ->  Print("\n", Blanks(i)),
    _indent  := i ->  Print(Blanks(i)),
    _indentStr := Blanks,

    __call__ := meth(arg)
        local self, params, nump, A,p,res,h,lkup;
        self := arg[1];
        params := arg{[2..Length(arg)]};
        nump := Length(params);

        if not IsBound(self.new)  then
            Error("Constructor for this class is not implemented");
        elif IsBound(self.abbrevs) and self.abbrevs <> [] then
            for A in self.abbrevs do
                if NumArgs(A) = -1 or NumArgs(A) = nump then
                    params := ApplyFunc(A, params);
                fi;
            od;
        fi;

        if NumArgs(self.new)-1 <> Length(params) then
            Error("Constructor requires ", NumArgs(self.new)-1, " parameters (",
                Length(arg)-1, " given): ",
                ParamsMeth(self.new));
        else
            h := self.hash;
            if h<>false then
                lkup := h.objLookup(self, params);
                if lkup[1] <> false then return lkup[1]; fi;
            fi;

            res := ApplyFunc(self.new, params);

            if h<>false then return h.objAdd(res, lkup[2]);
            else return res;
            fi;
        fi;
    end,

    hash := false,

    checkDims := self >> DimensionsMat(MatSPL(self)) = self.dimensions,

    #-----------------------------------------------------------------------
    # create a new object with .<name> field set to true
    setAttr := meth(self, name)
        local s;
        s:= Copy(self);
        s.(name) := true;
        return s;
    end,
    # ----------------------------------------------------------------------
    # create a new object with .<name> field set to <val>
    setAttrTo := meth(self, name, val)
        local s;
        s:= Copy(self);
        s.(name) := val;
        return s;
    end,

    #---------Backwards Compatibility for the new dimension system------
    setDims := meth(self) self.dimensions := self.dims(); return self; end,

    dims := self >> [ StripList(List(self.rng(), l -> l.size)),
	              StripList(List(self.dmn(), l -> l.size)) ],

    advdims := (self) >> let(d := self.dims(), [ [[ d[1] ]], [[ d[2] ]] ]),
    arity   := (self) >> List(self.dims(), e -> Length(Flat([e]))),

    TType:=TUnknown,

    rng := meth(self) local d;
        if IsBound(self.dims) then
            d := Flat([self.dims()[1]]);
        else
            d := [self.dimensions[1]];
        fi;
        if IsBound(self.a.t_out) then
            return List(TransposedMat([self.a.t_out, d]), e -> TArray(e[1], e[2]));
        else
            return List(d, e -> TArray(self.TType, e));
        fi;
    end,

    dmn := meth(self) local d;
        if IsBound(self.dims) then
            d := Flat([self.dims()[2]]);
        else
            d := [self.dimensions[2]];
        fi;
        if IsBound(self.a.t_in) then
            return List(TransposedMat([self.a.t_in, d]), e -> TArray(e[1], e[2]));
        else
            return List(d, e -> TArray(self.TType, e));
        fi;
    end,

    free := self >> Union(List(self.rChildren(), FreeVars)),

    equals := (self, o) >>
        ObjId(self) = ObjId(o) and self.rChildren() = o.rChildren() and self.a = o.a,

    lessThan := (self, o) >> Cond(
        ObjId(self) <> ObjId(o), ObjId(self) < ObjId(o),
        [ ObjId(self), self.rChildren(), self.a ] < [ ObjId(o), o.rChildren(), o.a ]
    ),

    from_rChildren := (self, rch) >> ApplyFunc(ObjId(self), rch).appendAobj(self),

    print := (self, i, is) >> self._print(self.rChildren(), i, is),

    _print := meth(self, ch, indent, indentStep)
        local s, first, newline;

	if self._short_print or ForAll(ch, x->not IsRec(x) or IsSPLSym(x) or IsSPLMat(x)) then
	    newline := Ignore;
	else
	    newline := self._newline;
	fi;

	first := true;
        Print(self.__name__, "(");
	for s in ch do
            if(first) then first:=false;
            else Print(", "); fi;
            newline(indent + indentStep);
            When(IsSPL(s) or (IsRec(s) and IsBound(s.print) and NumGenArgs(s.print)=2),
                 s.print(indent + indentStep, indentStep),
		 Print(s));
	od;
	newline(indent);
	Print(")");
        self.printA();

	if IsBound(self._setDims) then
            Print(".overrideDims(", self._setDims, ")");
	fi;
    end,

    printlatex := meth(self)
        local s, first, newline, i;

	first := true;
        Print("(");
        i := Length(self.rChildren());
        for s in self.rChildren() do
            When(IsSPL(s) or (IsRec(s) and IsBound(s.printlatex) and NumGenArgs(s.printlatex)=0),
                 s.printlatex(),
		 Print(s));
                 if i >=2 then
                    Print(" ", When(IsBound(self.latexSymbol), self.latexSymbol, ""), " ");
                 fi;
                 i := i-1;
	od;
	Print(")");
    end,

    overrideDims := (self, dims) >> CopyFields(self, rec(_setDims := dims, dimensions := dims)),

    terminate     := self >> self.from_rChildren(List(self.rChildren(), x->When(IsSPL(x), x.terminate(), x))),

    # ------------------------- Required methods ---------------------------\
    transposeSymmetric := True,
    dims          := meth(self) Error("Not implemented"); end,
    isPermutation := meth(self) Error("Not implemented"); end,
    isTerminal    := meth(self) Error("Not implemented"); end,
    isReal        := meth(self) Error("Not implemented"); end,
    isInplace     := self >> Rows(self)=Cols(self) and let(ch:=self.children(), Cond(Length(ch)=0, false, ForAll(ch, x->x.isInplace()))),
    children      := meth(self) return []; end,
    numChildren   := meth(self) return 0; end,
    child         := meth(self,n) Error("Not implemented"); end,
    setChild      := meth(self,n,what) Error("Not implemented"); end,
    toAMat        := meth(self) Error("Not implemented"); end,
    transpose     := meth(self) Error("Not implemented"); end,
    conjTranspose  := meth(self) Error("Not implemented"); end,
));

#F <SPL> * <SPL>
#F <scalar> * <SPL>
#F   is equivalent to ComposeSPL and ScalarMultiple resp.
#F
SPLOps.\* := (S1, S2) ->
    Cond(IsSPL(S1) and IsSPL(S2),   Compose(S1, S2),
         IsSPL(S2),                 Scale(S1, S2),
     IsSPL(S1),                 Scale(S2, S1),
     Error("do not know how to compute <S1> * <S2>"));

#F <SPL> + <SPL>
#F   is equivalent to SUM(<S1>, <S2>)
#F
SPLOps.\+ := (S1, S2) ->
    Cond(IsSPL(S1) and IsSPL(S2),   SUM(S1, S2),
     Error("do not know how to compute <S1> + <S2>"));

#F S1 ^ S2
#F   is equivalent to ConjugateSPL(S1, S2).
#F
SPLOps.\^ := (S1, S2) ->
    When(IsSPL(S1) and IsSPL(S2),
         Conjugate(S1, S2),
     Error("do not know how to compute S1 ^ S2"));


text:
#
# flinting: FLINT in GAP
#
# Implementations
#

max_stars_repo_name: markuspf/flinting

max_issues_repo_name: markuspf/flinting

max_forks_repo_name: markuspf/flinting


max_stars_repo_name: HelloSunilSaini/RoboSONE

max_issues_repo_name: HelloSunilSaini/RoboSONE

max_forks_repo_name: HelloSunilSaini/RoboSONE


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

# ==========================================================================
# ColDirectSum
# ==========================================================================
Class(ColDirectSum, BaseOverlap, rec(
    #-----------------------------------------------------------------------
    abbrevs := [
        function(arg)
          arg:=Flat(arg);
          return [arg[1], arg{[2..Length(arg)]}];
        end ],
    #-----------------------------------------------------------------------
    new := meth(self, overlap, spls)
       return self._new(0, overlap, spls);
    end,
    #-----------------------------------------------------------------------
    dims := meth(self)
        local ovdim;
	ovdim := self.ovDim(self.overlap,
	                    List(self._children, t -> t.dimensions[1]));
	return [ ovdim[3] - ovdim[2] + 1, # max - min + 1
	         Sum(self._children, t -> t.dimensions[2]) ];
    end,
    #-----------------------------------------------------------------------
    toAMat := meth(self)
        return
	   AMatSPL(
	       Sparse(
		   self._coloverlap(
		       List(self._children, t -> t.dimensions[1]),
		       self.overlap
		   )
	       )
	   ) *
	   DirectSumAMat(List(self._children, AMatSPL));
    end,
));

ColDirectSum._transpose_class := RowDirectSum;
RowDirectSum._transpose_class := ColDirectSum;