# Functions of the polycon package.

# Extended k:th Lie derivative of h w.r.t. f.
# Takes inputs into account, up to 10:th derivative of inputs.
# Syntax: lieder(h,f,k,vars,invar)  [invar may be a list]
# K. Forsman 1992-04-14, 1992-08-06

lieder:=proc()
   local dinvar,f,h,i,ind,invar,n,nu,res,var,vars;

   if nargs<2 then ERROR(`not enough input arguments.`) fi;

   h:=args[1]; f:=args[2];
   if not type(h,scalar) then
     ERROR(`first argument should be a scalar.`) fi;
   if not type(f,vector) then
     ERROR(`second argument should be a vector.`) fi;
   if nargs=2 then ind:=1; else ind:=args[3]; fi;
   if not type(ind,integer) then
      ERROR(`third argument should be an integer.`) fi;
   n:=linalg[vectdim](f);
   if nargs<4 then vars:=[x.(1..n)]; else vars:=args[4] fi;
   if not type(vars,list) then
      ERROR(`fourth argument should be a list of variables.`)
   fi;
   if nops(vars)<>n then
     ERROR(`wrong number of variables given.`) fi;
   if nargs<5 then invar:=[u]; elif type(args[5],name) then
      invar:=[args[5]] else invar:=args[5] fi;
   if not type(invar,list(name)) then
     ERROR(`fifth argument should be a name or a list of names of input variables.`,
           `If default: u must be unassigned.`) fi;
   nu:=nops(invar):

   for var in invar do
      f:=subs(var=cat(var,0),op(f)):
      h:=subs(var=cat(var,0),h)
   od:

   dinvar:=[]:
   for var in invar do
      dinvar:=[op(dinvar),[seq(cat(var,i),i=0..10)]]
   od:
   vars:=[op(vars),seq(dinvar[i][1..10],i=1..nu)]:

   f:=linalg[vector]([op(convert(f,list)),seq(dinvar[i][2..11],i=1..nu)]);
   res:=h:
   for i to ind do res:=auxlieder(res,f,vars) od
end:


# Auxiliary Lie-derivative function.
# Lie derivative of h w.r.t. f without safety jacket. Variables: vars
# Syntax: auxlieder(h,f,vars)
# K. Forsman 1992-02-04

auxlieder:=proc(h,f,vars)
   linalg[dotprod](f,map((a,b) -> diff(b,a),vars,h))
end:


# List of successive Lie-derivatives. Requires lieder.
# Changed and renamed (from Lieder2) 1992-02-24 to replace former Lieder1.
# K. Forsman 1992-02-24, 1992-02-25

liederlist:=proc(h,f,n,stvars,invar)
   local i,L,tmp:
   L:=[h]: tmp:=h:
   for i to n do
      tmp:=lieder(tmp,f,1,stvars,invar):
      L:=[op(L),tmp]; od
end:


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


# Extended k:th Lie homomorphism of h w.r.t. f.
# Takes inputs into account, up to 10:th time-shift of input.
# Syntax: liehom(h,f,k,vars,invar)   [invar may be a list]
# K. Forsman 1992-04-14, 1992-08-06

liehom:=proc()
   local dinvar,f,h,i,ind,invar,n,nu,res,var,vars;

   if nargs<2 then ERROR(`not enough input arguments.`) fi;

   h:=args[1]; f:=args[2];
   if not type(h,scalar) then
     ERROR(`first argument should be a scalar.`) fi;
   if not type(f,vector) then
     ERROR(`second argument should be a vector.`) fi;
   f:=convert(f,list):
   if nargs=2 then ind:=1; else ind:=args[3]; fi;
   if not type(ind,integer) then
      ERROR(`third argument should be an integer.`) fi;
   n:=nops(f):
   if nargs<4 then vars:=[x.(1..n)]; else vars:=args[4] fi;
   if not type(vars,list) then
      ERROR(`fourth argument should be a list of variables.`)
   fi;
   if nops(vars)<>n then
     ERROR(`wrong number of state variables given.`) fi;
   if nargs<5 then invar:=[u]; elif type(args[5],name) then
      invar:=[args[5]] else invar:=args[5] fi;
   if not type(invar,list(name)) then
     ERROR(`fifth argument should be a name or a list of names of input variables.`,
           `If default: u must be unassigned.`) fi;
   nu:=nops(invar):

   for var in invar do
      f:=subs(var=cat(var,0),f):
      h:=subs(var=cat(var,0),h)
   od:

   dinvar:=[]:
   for var in invar do
      dinvar:=[op(dinvar),[seq(cat(var,i),i=0..10)]]
   od:
   vars:=[op(vars),seq(dinvar[i][1..10],i=1..nu)]:

   f:=[op(f),seq(dinvar[i][2..11],i=1..nu)]: res:=h:
   for i to ind do
      res:=subs(zip((X,Y)->X=Y,vars,f),res)
   od
end:

# List of successive Lie-homomorphisms. Requires liehom.
# K. Forsman 1992-02-04, 1992-02-24

liehomlist:=proc(h,f,n,stvars,invar)
   local L,i,tmp:
   L:=[h]: tmp:=h:
   for i to n do
      tmp:=liehom(tmp,f,1,stvars,invar):
      L:=[op(L),tmp]:
   od
end:


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

# Derivative of p w.r.t. t: diff(u0,t$k)=uk, diff(y0,t$k)=yk
# Uses auxlieder. Syntax: uyder(p,k,invar,outvar)
# K. Forsman 1992-02-12, 1992-02-25

uyder:=proc()
   local i,invar,dinvar,k,outvar,outvars,p:

   p:=args[1]:
   if not type(p,scalar) then
     ERROR(`first argument should be a scalar.`) fi;
   if nargs=1 then k:=1 else k:=args[2] fi:
   if nargs<3 then invar:=u else invar:=args[3] fi;
   if not type(invar,name) then
     ERROR(`third argument should be an input variable name.`,
           `If default: u must be unassigned.`) fi;
   if nargs<4 then outvar:=y else outvar:=args[4] fi;
   if not type(outvar,name) then
     ERROR(`fourth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;

   dinvar:=[seq(cat(invar,i),i=0..10)];
   outvars:=[seq(cat(outvar,i),i=0..10)];

   p:=subs({invar=cat(invar,0),outvar=cat(outvar,0)},p):
   for i to k do
      p:=auxlieder(p,linalg[vector]([dinvar[2..11],outvars[2..11]]),
         [dinvar[1..10],outvars[1..10]]);
   od
end:


# Difference of p: delta^k(u0)=uk, delta^k(y0)=yk
# Uses liehom.
# Syntax: uyhom(p,k,invar,outvar)
# K. Forsman 1992-02-24, 1992-02-25

uyhom:=proc()
   local i,invar,dinvar,k,outvar,outvars,p:

   p:=args[1]:
   if not type(p,scalar) then
     ERROR(`first argument should be a scalar.`) fi;
   if nargs=1 then k:=1 else k:=args[2] fi:
   if nargs<3 then invar:=u else invar:=args[3] fi;
   if not type(invar,name) then
     ERROR(`third argument should be an input variable name.`,
           `If default: u must be unassigned.`) fi;
   if nargs<4 then outvar:=y else outvar:=args[4] fi;
   if not type(outvar,name) then
     ERROR(`fourth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;

   dinvar:=[seq(cat(invar,i),i=0..10)];
   outvars:=[seq(cat(outvar,i),i=0..10)];

   p:=subs({invar=cat(invar,0),outvar=cat(outvar,0)},p):
   liehom(p,linalg[vector]([dinvar[2..11],outvars[2..11]]),k,
            [dinvar[1..10],outvars[1..10]])
end:

# Input-output relation for continuous time rational systems
# in state-space form. Uses liederlist.
# Syntax: ss2ioc(f,h,stvars,invars,outvar)   {invars can be a list}
# K. Forsman 1992-06-16, 1992-08-07

ss2ioc:=proc()
   local f,h,i,invars,L,n,outvar,p,stvars,var:

   if nargs<2 then ERROR(`not enough input arguments.`) fi;

   f:=args[1]: h:=args[2]:
   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(h,scalar) then
     ERROR(`second argument should be a scalar.`) fi;
   n:=linalg[vectdim](f):
   if nargs<3 then
       stvars:=[x.(1..n)] else stvars:=args[3] fi;
   if not type(stvars,list(name)) then
     ERROR(`third argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(stvars)<>n then
     ERROR(`wrong number of state variables given.`) fi;

   if nargs<4 then invars:=[u]; elif type(args[4],name) then
      invars:=[args[4]] else invars:=args[4] fi;
   if not type(invars,list(name)) then
     ERROR(cat(`fourth argument should be a name or a list of names of`,
            `input variables.`),`If default: u must be unassigned.`) fi;

   for var in invars do
      for i from 0 to n do
         if not type(eval(cat(var,i)),name) then
           ERROR(cat(cat(var,i),` must be unassigned.`)) fi;
         od                 #This is a little tough.
   od:

   if nargs<5 then outvar:=y else outvar:=args[5] fi;
   if not type(outvar,name) then
     ERROR(`fifth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(outvar,i)),name) then
        ERROR(cat(cat(outvar,i),` must be unassigned.`)) fi;
      od:

   for var in invars do h:=subs(var=cat(var,0),h) od:

   L:=liederlist(h,f,n,stvars,invars):
   L:=zip(<X-Y>,[seq(cat(outvar,i),i=0..n)],[op(L)]);
   L:=map(numer@expand,L):
   p:=grobner[finduni](cat(outvar,n),L,{op(stvars),cat(outvar,n)});
   if p=NULL then
         print(`WARNING: System realization is not minimal.`);
         print(`(Disregard potential warning message that follows.)`);
         for i from n by -1 to 1 while p=NULL do
         p:=grobner[finduni](cat(outvar,i-1),[L[1..i]],
                   {op(stvars),cat(outvar,i-1)}); od:
   fi;
   sort(p,[seq(cat(outvar,n-i),i=0..n)],'plex')
end:


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

# Input-output relation for discrete time rational systems
# in state-space form. Uses liehomlist.
# Syntax: ss2iod(f,h,stvars,invars,outvar)
# K. Forsman 1992-04-14, 1992-08-07

ss2iod:=proc()
   local f,h,i,invars,L,n,outvar,p,stvars,var:

   if nargs<2 then ERROR(`not enough input arguments.`) fi;

   f:=args[1]: h:=args[2]:
   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(h,scalar) then
     ERROR(`second argument should be a scalar.`) fi;
   n:=linalg[vectdim](f):
   if nargs<3 then
      stvars:=[x.(1..n)] else stvars:=args[3] fi;
   if not type(stvars,list(name)) then
     ERROR(`third argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(stvars)<>n then
     ERROR(`wrong number of state variables given.`) fi;

   if nargs<4 then invars:=[u]; elif type(args[4],name) then
      invars:=[args[4]] else invars:=args[4] fi;
   if not type(invars,list(name)) then
     ERROR(`fifth argument should be a name or a list of names of input variables.`,
           `If default: u must be unassigned.`) fi;
   for var in invars do
      for i from 0 to n do
         if not type(eval(cat(var,i)),name) then
           ERROR(cat(cat(var,i),` must be unassigned.`)) fi;
         od                 #This is a little tough.
   od:

   if nargs<5 then outvar:=y else outvar:=args[5] fi;
   if not type(outvar,name) then
     ERROR(`fifth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(outvar,i)),name) then
        ERROR(cat(cat(outvar,i),` must be unassigned.`)) fi;
      od:

   for var in invars do h:=subs(var=cat(var,0),h) od:

   L:=liehomlist(h,f,n,stvars,invars):
   L:=zip(<X-Y>,[seq(cat(outvar,i),i=0..n)],[op(L)]);
   L:=map(numer@expand,L):

   p:=grobner[finduni](cat(outvar,n),L,{op(stvars),cat(outvar,n)});
   if p=NULL then
         print(`WARNING: System realization is not minimal.`);
         print(`(Disregard potential warning message that follows.)`);
         for i from n by -1 to 1 while p=NULL do
         p:=grobner[finduni](cat(outvar,i-1),[L[1..i]],
                   {op(stvars),cat(outvar,i-1)}); od:
   fi;
   sort(p,[seq(cat(outvar,n-i),i=0..n)],'plex')
end:


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

# Expert version of ss2io: no safety jackets, returns the entire GB.
# K. Forsman 1992-04-14, 1992-06-16

xss2ioc:=proc()
   local f,h,i,invars,L,n,outvar,stvars,tmplist,var:

   f:=args[1]: h:=args[2]:
   n:=linalg[vectdim](f):
   if nargs<3 then
       stvars:=[x.(1..n)] else stvars:=args[3] fi;
   if nargs<4 then invars:=[u]; elif type(args[4],name) then
      invars:=[args[4]] else invars:=args[4] fi;
   if nargs<5 then outvar:=y else outvar:=args[5] fi;

   for var in invars do h:=subs(var=cat(var,0),h) od:

   L:=liederlist(h,f,n,stvars,invars):
   L:=zip(<X-Y>,[seq(cat(outvar,i),i=0..n)],[op(L)]);
   L:=map(numer@expand,L):
   tmplist:=[op(stvars),seq(cat(outvar,n-i),i=0..n)];
   grobner[gbasis](L,tmplist,'plex')
end:


xss2iod:=proc()
   local f,h,i,invars,L,n,outvar,stvars,tmplist,var:

   f:=args[1]: h:=args[2]:
   n:=linalg[vectdim](f):
   if nargs<3 then
      stvars:=[x.(1..n)] else stvars:=args[3] fi;
   if nargs<4 then invars:=[u]; elif type(args[4],name) then
      invars:=[args[4]] else invars:=args[4] fi;
   if nargs<5 then outvar:=y else outvar:=args[5] fi;

   for var in invars do h:=subs(var=cat(var,0),h) od:

   L:=liehomlist(h,f,n,stvars,invars):
   L:=zip(<X-Y>,[seq(cat(outvar,i),i=0..n)],[op(L)]);
   L:=map(numer@expand,L):
   tmplist:=[op(stvars),seq(cat(outvar,n-i),i=0..n)];
   grobner[gbasis](L,tmplist,'plex')
end:

# I/O form to state space form for given states. Continuous time.
# Returns a list consisting of the rhs vector field and the output map.
# SYNTAX: io2ssc(p,S,stvars,invar,outvar,ssmod) where p is the I/O-relation
# and S is a list containing the suggested states:
# S=[s1,...,sn] si\in k<invar,outvar> and stvars is a list of
# suggested state variables.
# The parameter ssmod determines if the state space model should allow
#   1) derivatives of the input
#   2) implicit state equations
# If ssmod='kalman' then neither 1 nor 2 are allowed
#          'der' then 1 but not 2 is allowed
#          'impl' then 2 but not 1 is allowed
#          'derimpl' then both 1 and 2 are allowed
# Default is ssmod='kalman'
# Uses uyder (and thus lieder).
# K. Forsman 1992-04-14, 1992-08-06

io2ssc:=proc()
   local DS,dstvars,explxflag,explyflag,f,failind,G,h,i,invar,invars,j,L,n,
         OKvars,outvar,outvars,p,res,S,ssm,ssmod,stvars,xflag,yflag:

   if nargs<2 then ERROR(`not enough input arguments.`) fi;
   p:=args[1]: S:=args[2]: n:=nops(S):

   if not type(p,scalar) then
     ERROR(`first argument should define an I/O equation.`) fi;
   if type(p,equation) then p:=numer(lhs(p)-rhs(p)) fi;
   if not type(S,list) then
     ERROR(`second argument should be a list defining the states.`) fi;
   if nargs<3 then stvars:=[x.(1..n)] else stvars:=args[3] fi;
   if not type(stvars,list(name)) then
     ERROR(`third argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(stvars)<>n then
     ERROR(`wrong number of state variables given.`) fi;

   if nargs<4 then invar:=u else invar:=args[4] fi;
   if not type(invar,name) then
     ERROR(`fourth argument should be an input variable name.`,
           `If default: u must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(invar,i)),name) then
        ERROR(cat(cat(invar,i),` must be unassigned.`)) fi;
      od:                #This is a little tough.

   if nargs<5 then outvar:=y else outvar:=args[5] fi;
   if not type(outvar,name) then
     ERROR(`fifth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(outvar,i)),name) then
        ERROR(cat(cat(outvar,i),` must be unassigned.`)) fi;
      od:

   if nargs<6 then ssmod:='kalman' else ssmod:=args[6] fi;

# Simple internal representation of the parameter ssmod.
# ssm[1] <->  derivatives of input allowed
# ssm[2] <-> implicit equations allowed
   if ssmod='derimpl' then ssm:=[true,true]
      elif ssmod='der' then ssm:=[true,false]
      elif ssmod='impl' then ssm:=[false,true]
      else ssm:=[false,false] fi;

   p:=subs({invar=cat(invar,0),outvar=cat(outvar,0)},p):
   S:=subs({invar=cat(invar,0),outvar=cat(outvar,0)},S):

   DS:=map(uyder,S,1,invar,outvar):
   L:=zip(<X-Y>,stvars,S):
   dstvars:=[seq(cat('d',stvars[j]),j=1..n)];
   for i to n do if not type(cat('d',(stvars[i])),name) then
      ERROR(cat('d',stvars[i],` should not be assigned.`)) fi od;

   L:=[p,op(L),op(zip(<X-Y>,dstvars,DS))]:
   L:=map(numer@expand,L):
   f:=linalg[vector](n):
   invars:=[seq(cat(invar,j),j=0..n)];
   outvars:=[seq(cat(outvar,j),j=0..n)];
   xflag:=true: explxflag:=true:

# Search for allowable expressions for the time derivatives of the states
# and for the output:
   if ssm[1] then
      OKvars:={op(invars),op(stvars)}:
      for i to n while (xflag and explxflag) do
         G:=grobner[gbasis](L,[dstvars[1..i-1],dstvars[i+1..n],
              op(outvars),dstvars[i]],'plex'):
         f[i]:=G[nops(G)];
         xflag:=evalb(indets(f[i]) minus OKvars = {dstvars[i]});
         if not xflag then failind:=i fi:
         if xflag and (not ssm[2])
            then explxflag:=evalb(degree(f[i],dstvars[i])=1) fi;
      od;
      G:=grobner[gbasis](L,[op(dstvars),seq(outvars[n-j+1],j=0..n)],'plex'):
      h:=G[nops(G)]:
      yflag:=evalb(indets(h) minus OKvars = {outvars[1]});
      if yflag and (not ssm[2]) then
         explyflag:=evalb(degree(h,outvars[1])=1) fi;

   else
      OKvars:={invars[1],op(stvars)}:
      for i to n while xflag do
         G:=grobner[gbasis](L,[dstvars[1..i-1],dstvars[i+1..n],
              op(outvars),invars[2..n+1],dstvars[i]],'plex'):
         f[i]:=G[nops(G)];
         xflag:=evalb(indets(f[i]) minus OKvars = {dstvars[i]});
         if not xflag then failind:=i fi:
         if xflag and (not ssm[2]) and explxflag
            then explxflag:=evalb(degree(f[i],dstvars[i])=1) fi;
      od;
      G:=grobner[gbasis](L,[op(dstvars),invars[2..n+1],
           seq(outvars[n-j+1],j=0..n)],'plex'):
      h:=G[nops(G)]:
      yflag:=evalb(indets(h) minus OKvars = {outvars[1]});
      if yflag and (not ssm[2]) then
         explyflag:=evalb(degree(h,outvars[1])=1) fi;
   fi;

# If fail, return depressing message:
   if not xflag then
      print(cat(`No expression exists for the time derivative of `,
                 stvars[failind],`.`))
   fi;
   if not yflag then
      print(cat(`No expression exists for `,outvar,`.`))
   fi;

# If success in at least one respect, return the results obtained,
# considering the specification given by ssmod.

   res:=[]:

   if xflag then
      if ssm[2] then res:=[op(f)]
      elif explxflag then
           f:=convert(f,list): f:=zip(solve,f,dstvars):
           res:=[linalg[vector](f)]:
      else
         print(cat(`No explicit expression exists for `,dstvars));
      fi;
   fi;

   if yflag then
      if ssm[2] then res:=[op(res),h]
      elif explyflag then
           h:=solve(h,outvars[1]):
           res:=[op(res),h]:
      else
         print(cat(`No explicit expression exists for `,outvar));
      fi;
   fi;

   res
end:


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

# I/O-form to state space form for given states. Discrete time.
# Returns a list consisting of the rhs "vector field" and
# the output map.
# SYNTAX: io2ssd(p,S,stvars,invar,outvar,ssmod) where p is the I/O-relation
# and S is a list# containing the suggested states:
# L=[s1,...,sn] si\in k<u,y> and  stvars is a list of
# suggested state variables.
# The parameter ssmod determines if the state space model should allow
#   1) non-causality in the input
#   2) implicit state equations
# If ssmod=`kalman` then neither 1 nor 2 are allowed
#          `nc` then 1 but not 2 is allowed
#          `impl` then 2 but not 1 is allowed
#          `ncimpl` then both 1 and 2 are allowed
# Default is ssmod=`kalman`
# Requires uyhom (and thus liehom).
# K. Forsman 1992-04-14, 1992-08-06

io2ssd:=proc()
   local DS,dstvars,explxflag,explyflag,f,failind,G,h,i,invar,invars,j,L,n,
         OKvars,outvar,outvars,p,res,S,ssm,ssmod,stvars,xflag,yflag:

   if nargs<2 then ERROR(`not enough input arguments.`) fi;
   p:=args[1]: S:=args[2]: n:=nops(S):

   if not type(p,scalar) then
     ERROR(`first argument should define an I/O equation.`) fi;
   if type(p,equation) then p:=numer(lhs(p)-rhs(p)) fi;
   if not type(S,list) then
     ERROR(`second argument should be a list defining the states.`) fi;
   if nargs<3 then stvars:=[x.(1..n)] else stvars:=args[3] fi;
   if not type(stvars,list(name)) then
     ERROR(`third argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(stvars)<>n then
     ERROR(`wrong number of state variables given.`) fi;

   if nargs<4 then invar:=u else invar:=args[4] fi;
   if not type(invar,name) then
     ERROR(`fourth argument should be an input variable name.`,
           `If default: u must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(invar,i)),name) then
        ERROR(cat(cat(invar,i),` must be unassigned.`)) fi;
      od:                #This is a little tough.

   if nargs<5 then outvar:=y else outvar:=args[5] fi;
   if not type(outvar,name) then
     ERROR(`fifth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(outvar,i)),name) then
        ERROR(cat(cat(outvar,i),` must be unassigned.`)) fi;
      od:

   if nargs<6 then ssmod:='kalman' else ssmod:=args[6] fi;

# Simple internal representation of the parameter ssmod.
# ssm[1] <->  input allowed to occur non-causally
# ssm[2] <-> implicit equations allowed
   if ssmod='ncimpl' then ssm:=[true,true]
      elif ssmod='nc' then ssm:=[true,false]
      elif ssmod='impl' then ssm:=[false,true]
      else ssm:=[false,false] fi;

   p:=subs({invar=cat(invar,0),outvar=cat(outvar,0)},p):
   S:=subs({invar=cat(invar,0),outvar=cat(outvar,0)},S):

   DS:=map(uyhom,S,1,invar,outvar):
   L:=zip(<X-Y>,stvars,S):
   dstvars:=[seq(cat('d',stvars[j]),j=1..n)];
   for i to n do if not type(cat('d',(stvars[i])),name) then
      ERROR(cat('d',stvars[i],` should not be assigned.`)) fi od;

   L:=[p,op(L),op(zip(<X-Y>,dstvars,DS))]:
   L:=map(numer@expand,L):
   f:=linalg[vector](n):
   invars:=[seq(cat(invar,j),j=0..n)];
   outvars:=[seq(cat(outvar,j),j=0..n)];
   xflag:=true: explxflag:=true:

# Search for allowable expressions for the time lags of the states
# and for the output.

   if ssm[1] then
      OKvars:={op(invars),op(stvars)}:
      for i to n while (xflag and explxflag) do
         G:=grobner[gbasis](L,[dstvars[1..i-1],dstvars[i+1..n],
              op(outvars),dstvars[i]],'plex'):
         f[i]:=G[nops(G)];
         xflag:=evalb(indets(f[i]) minus OKvars = {dstvars[i]});
         if not xflag then failind:=i fi:
         if xflag and (not ssm[2])
            then explxflag:=evalb(degree(f[i],dstvars[i])=1) fi;
      od;
      G:=grobner[gbasis](L,[op(dstvars),seq(outvars[n-j+1],j=0..n)],'plex'):
      h:=G[nops(G)]:
      yflag:=evalb(indets(h) minus OKvars = {outvars[1]});
      if yflag and (not ssm[2]) then
         explyflag:=evalb(degree(h,outvars[1])=1) fi;

   else
      OKvars:={invars[1],op(stvars)}:
      for i to n while xflag do
         G:=grobner[gbasis](L,[dstvars[1..i-1],dstvars[i+1..n],
              op(outvars),invars[2..n+1],dstvars[i]],'plex'):
         f[i]:=G[nops(G)];
         xflag:=evalb(indets(f[i]) minus OKvars = {dstvars[i]});
         if not xflag then failind:=i fi:
         if xflag and (not ssm[2]) and explxflag
            then explxflag:=evalb(degree(f[i],dstvars[i])=1) fi;
      od;
      G:=grobner[gbasis](L,[op(dstvars),invars[2..n+1],
           seq(outvars[n-j+1],j=0..n)],'plex'):
      h:=G[nops(G)]:
      yflag:=evalb(indets(h) minus OKvars = {outvars[1]});
      if yflag and (not ssm[2]) then
         explyflag:=evalb(degree(h,outvars[1])=1) fi;
   fi;

# If fail, return depressing message:
   if not xflag then
      print(cat(`No expression found for the time lag of `,
                 stvars[failind],`.`))
   fi;
   if not yflag then
      print(cat(`No expression found for `,outvar,`.`))
   fi;

# If success in at least one respect, return the results obtained,
# considering the specification given by ssmod.

   res:=[]:

   if xflag then
      if ssm[2] then res:=[op(f)]
      elif explxflag then
           f:=convert(f,list): f:=zip(solve,f,dstvars):
           res:=[linalg[vector](f)]:
      else
         print(cat(`No explicit expression found for `,dstvars));
      fi;
   fi;

   if yflag then
      if ssm[2] then res:=[op(res),h]
      elif explyflag then
           h:=solve(h,outvars[1]):
           res:=[op(res),h]:
      else
         print(cat(`No explicit expression found for `,outvar));
      fi;
   fi;

   res
end:

# Find state space transformation for two I/O-equivalent continuous time
# systems. Syntax: sstrac(f,a,g,b,ost,nst,oinp,ninp,form)
# The original system is in the variables ost (default: x) and the new one
# is in the variables nst (default: z).
# The parameter form determines the form of the output:
#   if form='expl' (default) then the output is a vector
#   and if form='impl' then the output is a list of polynomials, the i:th
#   one defining zi as an algebraic function of the x.
# The transformation obtained may involve the input. Requires liederlist.
# K. Forsman 1992-06-16, 1992-08-06

sstrac:=proc()
   local a,b,explflag,f,failind,form,g,i,L,Lf,Lg,n,ninp,nst,oinp,ost,T:

   if nargs<4 then ERROR(`not enough input arguments.`) fi;

   f:=args[1]: a:=args[2]: g:=args[3]: b:=args[4]:
   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(a,scalar) then
     ERROR(`second argument should be a scalar.`) fi;
   if not type(g,vector) then
     ERROR(`third argument should be a vector.`) fi;
   if not type(b,scalar) then
     ERROR(`fourth argument should be a scalar.`) fi;

   n:=linalg[vectdim](f):
   if n<>linalg[vectdim](g) then
      ERROR(`incompatible system dimensions.`) fi;

   if nargs<5 then ost:=[x.(1..n)] else ost:=args[5] fi;
   if not type(ost,list(name)) then
     ERROR(`fifth argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(ost)<>n then
     ERROR(`wrong number of old state variables given.`) fi;


   if nargs<6 then nst:=[z.(1..n)] else nst:=args[6] fi;
   if not type(nst,list(name)) then
     ERROR(`sixth argument should be a list of names of state variables`,
           `If default: z1,...,zn must be unassigned.`) fi;
   if nops(nst)<>n then
     ERROR(`wrong number of new state variables given.`) fi;

   if nargs<7 then oinp:=u else oinp:=args[7] fi;
   if not type(oinp,name) then
      ERROR(`seventh argument should be an input variable name`,
            `If default: u must be unassigned.`) fi;
   if nargs<8 then ninp:=u else ninp:=args[8] fi;
   if not type(ninp,name) then
      ERROR(`eighth argument should be an input variable name`,
            `If default: u must be unassigned.`) fi;
   if nargs<9 then form:='expl' else form:=args[9] fi;

   Lf:=liederlist(a,f,n,ost,oinp):
   Lg:=liederlist(b,g,n,nst,ninp):
   L:=zip(<X-Y>,Lf,Lg):
   L:=map(numer@expand,L): # Support rational functions, even though proof
                           # does not cover this case...

   T:=linalg[vector](n);
   explflag:=true:

   for i to n while explflag do
      T[i]:=grobner[finduni](nst[i],L,{op(nst)}):
      explflag:=evalb(form='impl' or degree(T[i],nst[i])=1);
      if not explflag then failind:=i fi;
   od:

   if form='impl' then convert(T,list);
   else
     if not explflag then
        print(cat(`No explicit expression for `,nst[failind],` exists.`));
     else
        T:=zip(solve,convert(T,list),nst);
     fi;
   fi
end:

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


# Find state space transformation for two I/O-equivalent discrete time
# systems.  Syntax: sstrad(f,a,g,b,ost,nst,oinp,ninp,form)
# The original system is in the variables ost (default: x) and the new one
# is in the variables nst (default: z).
# The parameter form determines the form of the output:
#   if form='expl' (default) then the output is a vector
#   and if form='impl' then the output is a list of polynomials, the i:th
#   one defining zi as an algebraic function of the x.
# The transformation obtained may involve the input. Requires liehomlist.
# K. Forsman 1992-06-16, 1992-08-06

sstrad:=proc()
   local a,b,explflag,f,failind,form,g,i,L,Lf,Lg,n,ninp,nst,oinp,ost,T:

   if nargs<4 then ERROR(`not enough input arguments.`) fi;

   f:=args[1]: a:=args[2]: g:=args[3]: b:=args[4]:
   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(a,scalar) then
     ERROR(`second argument should be a scalar.`) fi;
   if not type(g,vector) then
     ERROR(`third argument should be a vector.`) fi;
   if not type(b,scalar) then
     ERROR(`fourth argument should be a scalar.`) fi;

   n:=linalg[vectdim](f):
   if n<>linalg[vectdim](g) then
      ERROR(`incompatible system dimensions`) fi;

   if nargs<5 then ost:=[x.(1..n)] else ost:=args[5] fi;
   if not type(ost,list(name)) then
     ERROR(`fifth argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(ost)<>n then
     ERROR(`wrong number of old state variables given.`) fi;

   if nargs<6 then nst:=[z.(1..n)] else nst:=args[6] fi;
   if not type(nst,list(name)) then
     ERROR(`sixth argument should be a list of names of state variables`,
           `If default: z1,...,zn must be unassigned.`) fi;
   if nops(nst)<>n then
     ERROR(`wrong number of new state variables given.`) fi;

   if nargs<7 then oinp:=u else oinp:=args[7] fi;
   if not type(oinp,name) then
      ERROR(`seventh argument should be an input variable name`,
            `If default: u must be unassigned.`) fi;
   if nargs<8 then ninp:=u else ninp:=args[8] fi;
   if not type(ninp,name) then
      ERROR(`eighth argument should be an input variable name`,
            `If default: u must be unassigned.`) fi;
   if nargs<9 then form:='expl' else form:=args[9] fi;

   Lf:=liehomlist(a,f,n,ost,oinp):
   Lg:=liehomlist(b,g,n,nst,ninp):
   L:=zip(<X-Y>,Lf,Lg):
   L:=map(numer@expand,L): # Support rational functions, even though proof
                           # does not cover this case...

   T:=linalg[vector](n);
   explflag:=true:

   for i to n while explflag do
      T[i]:=grobner[finduni](nst[i],L,{op(nst)}):
      explflag:=evalb(form='impl' or degree(T[i],nst[i])=1);
      if not explflag then failind:=i fi;
   od:

   if form='impl' then convert(T,list);
   else
     if not explflag then
        print(cat(`No explicit expression for `,nst[failind],` exists.`));
     else
        T:=zip(solve,convert(T,list),nst);
     fi;
   fi
end:

# Go from a given rational parametrization of a hypersurface
# to a state space description of a continuous time system.
# Syntax: par2ssc(H,vars)  where H is a list of polynomials in
# the variables vars.
# K. Forsman 1992-06-16, 1992-08-10

par2ssc:=proc()
   local A,b,G,H,i,n,vars:

   H:=args[1]: n:=nops(H)-1:
   if nargs=1 then vars:=[x.(1..n)] else vars:=args[2] fi;
   if not type(vars,list(name)) then
     ERROR(`second argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(vars)<>n then
      ERROR(`H and vars have incompatible dimensions.`) fi;

   G:=linalg[grad](H[1],vars):
   A:=linalg[matrix]([convert(G,list)]):
   for i from 2 to n do
      G:=linalg[grad](H[i],vars):
      A:=linalg[stack](A,G):
   od;
   if det(A)=0 then
      ERROR(`H[1], ..., H[n-1] are algebraically dependent.`) fi;
   b:=linalg[vector]([H[2..(n+1)]]);
   linalg[linsolve](A,b)
end:

# "Observer relation" for continuous time rational SISO system
# in state-space form. Requires liederlist. Uses finduni.
# Syntax: obsvc(f,h,obsvar,stvars,invars,outvar,form)
# obsvar must be a member of stvars. invars may be a list.
# K. Forsman 1992-06-16, 1992-08-07

obsvc:=proc()
   local dinvars,f,form,G,h,i,ind,invars,IOvars,n,L,obsflag,obsvar,
         OKvars,outvar,res,stvars,var,varflag:

   if nargs<3 then ERROR(`not enough input arguments.`) fi;
   f:=args[1]: h:=args[2]: obsvar:=args[3]:

   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(h,scalar) then
     ERROR(`second argument should be a scalar.`) fi;
   if not type(obsvar,name) then
     ERROR(`third argument should be a variable name.`) fi;

   n:=linalg[vectdim](f):
   if nargs<4 then stvars:=[x.(1..n)] else stvars:=args[4] fi;
   if not type(stvars,list(name)) then
     ERROR(`fourth argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(stvars)<>n then
     ERROR(`wrong number of state variables given.`) fi;

   varflag:=member(obsvar,stvars,ind):
   if not varflag then
     ERROR(cat(obsvar,` is not an element of `,stvars,`.`)) fi;

   if nargs<5 then invars:=[u] elif type(args[5],name) then
      invars:=[args[5]] else invars:=args[5] fi;
   if not type(invars,list(name)) then
     ERROR(cat(`fifth argument should be a name or a list of names of`,
            `input variables.`),`If default: u must be unassigned.`) fi;
   for var in invars do
      for i from 0 to n do
         if not type(eval(cat(var,i)),name) then
           ERROR(cat(cat(var,i),` must be unassigned.`)) fi;
         od:                #This is a little tough.
   od:

   if nargs<6 then outvar:=y else outvar:=args[6] fi;
   if not type(outvar,name) then
     ERROR(`sixth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(outvar,i)),name) then
        ERROR(cat(cat(outvar,i),` must be unassigned.`)) fi;
      od:

   if nargs<7 then form:='expl' else form:=args[7] fi;

   for var in invars do
      h:=subs(var=cat(var,0),h):
      f:=subs(var=cat(var,0),op(f)):
   od:

   dinvars:=[]:
   for i from 0 to n do
      for var in invars do
         dinvars:=[cat(var,i),op(dinvars)]
      od:
   od:
   IOvars:=[]:
   for i from 0 to n do
      for var in [op(invars),outvar] do
         IOvars:=[cat(var,i),op(IOvars)]
      od:
   od:

   OKvars:=convert(IOvars,set): #To handle parameters in the state eqs.
   for i to n do
      OKvars:=(indets(f[i]) minus convert(stvars,set)) union OKvars
   od:

   L:=liederlist(h,f,n,stvars,invars):
   L:=zip(<X-Y>,[seq(cat(outvar,i),i=0..n)],[op(L)]);
   L:=map(numer@expand,L):
   G:=grobner[gbasis](L,[stvars[1..ind-1],
         stvars[ind+1..n],obsvar,op(IOvars)],'plex');

#  Check the GB for relations involving obsvar and IOvars only:

   res:=[]; obsflag:=false:
   for i to nops(G) do
      if (indets(G[i]) minus OKvars = {obsvar}) then
         obsflag:=true:
         if form='impl' then res:=[op(res),collect(G[i],obsvar)];
         elif degree(G[i],obsvar)=1 then res:=[op(res),solve(G[i],obsvar)];
      fi;
      fi;
   od;
   if not obsflag then
      print(cat(obsvar,` is not algebraically observable.`))
   elif form='expl' then
      if res=[] then
         print(cat(`No explicit expression for `,obsvar,` exists.`))
      else res; fi;
   else res; fi
end:

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

# "Observer relation" for discrete time rational SISO system
# in state-space form. Requires liehomlist. Uses finduni.
# Syntax: obsvd(f,h,obsvar,stvars,invars,outvar,form)
# obsvar must be a member of stvars.
# K. Forsman 1992-06-16, 1992-08-07

obsvd:=proc()
   local dinvars,f,form,G,h,i,ind,invars,IOvars,n,L,obsflag,obsvar,
         OKvars,outvar,res,stvars,var,varflag:

   if nargs<3 then ERROR(`not enough input arguments.`) fi;
   f:=args[1]: h:=args[2]: obsvar:=args[3]:

   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(h,scalar) then
     ERROR(`second argument should be a scalar.`) fi;
   if not type(obsvar,name) then
     ERROR(`third argument should be a variable name.`) fi;

   n:=linalg[vectdim](f):
   if nargs<4 then stvars:=[x.(1..n)] else stvars:=args[4] fi;
   if not type(stvars,list(name)) then
     ERROR(`fourth argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(stvars)<>n then
     ERROR(`wrong number of state variables given.`) fi;

   varflag:=member(obsvar,stvars,ind):
   if not varflag then
     ERROR(cat(obsvar,` is not an element of `,stvars,`.`)) fi;

   if nargs<5 then invars:=[u] elif type(args[5],name) then
      invars:=[args[5]] else invars:=args[5] fi;
   if not type(invars,list(name)) then
     ERROR(cat(`fifth argument should be a name or a list of names of`,
            `input variables.`),`If default: u must be unassigned.`) fi;
   for var in invars do
      for i from 0 to n do
         if not type(eval(cat(var,i)),name) then
           ERROR(cat(cat(var,i),` must be unassigned.`)) fi;
         od:                #This is a little tough.
   od:

   if nargs<6 then outvar:=y else outvar:=args[6] fi;
   if not type(outvar,name) then
     ERROR(`sixth argument should be an output variable name.`,
           `If default: y must be unassigned.`) fi;
   for i from 0 to n do
      if not type(eval(cat(outvar,i)),name) then
        ERROR(cat(cat(outvar,i),` must be unassigned.`)) fi;
      od:

   if nargs<7 then form:='expl' else form:=args[7] fi;

   for var in invars do
      h:=subs(var=cat(var,0),h):
      f:=subs(var=cat(var,0),op(f)):
   od:

   dinvars:=[]:
   for i from 0 to n do
      for var in invars do
         dinvars:=[cat(var,i),op(dinvars)]
      od:
   od:

   IOvars:=[]:
   for i from 0 to n do
      for var in [op(invars),outvar] do
         IOvars:=[cat(var,i),op(IOvars)]
      od:
   od:

   OKvars:=convert(IOvars,set): #To handle parameters in the state eqs.
   for i to n do
      OKvars:=(indets(f[i]) minus convert(stvars,set)) union OKvars
   od:

   L:=liehomlist(h,f,n,stvars,invars):
   L:=zip(<X-Y>,[seq(cat(outvar,i),i=0..n)],[op(L)]);
   L:=map(numer@expand,L):
   G:=grobner[gbasis](L,[stvars[1..ind-1],
         stvars[ind+1..n],obsvar,op(IOvars)],'plex');

#  Check the GB for relations involving obsvar and IOvars only:

   res:=[]; obsflag:=false:
   for i to nops(G) do
      if (indets(G[i]) minus OKvars = {obsvar}) then
         obsflag:=true:
         if form='impl' then res:=[op(res),collect(G[i],obsvar)];
         elif degree(G[i],obsvar)=1 then res:=[op(res),solve(G[i],obsvar)];
      fi;
      fi;
   od;
   if not obsflag then
      print(cat(obsvar,` is not algebraically observable.`))
   elif form='expl' then
      if res=[] then
         print(cat(`No explicit expression for `,obsvar,` found.`))
      else res; fi;
   else res; fi
end:

# Find the transformed system T(f) where f is a vector and T a list
# expressing the new states in terms of the old ones.
# Continuous time.
# Syntax: newsysc(f,T,ost,nst,invar,form)
# The parameter form determines the form of the output:
#   if form='expl' (default) then the output is a vector (rhs of the new system)
#   and if form='impl' then the output is a list (polynomials defining dz).
#   Thus form='impl' means that implicit state equations are allowed.
# Requires lieder.
# K. Forsman 1992-02-24, 1992-03-02

newsysc:=proc()
   local dz,dzdef,explflag,f,failind,form,g,i,invar,j,L,n,nst,ost,T,zdef:

   if nargs<2 then ERROR(`not enough input arguments.`) fi;

   f:=args[1]: T:=args[2]:
   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(T,list) then
     ERROR(`second argument should be a list.`) fi;

   n:=linalg[vectdim](f);

   if nargs<3 then ost:=[x.(1..n)] else ost:=args[3] fi;
   if not type(ost,list) then
      ERROR(`third argument should be a list of state variables.`) fi;
   if nargs<4 then nst:=[z.(1..n)] else nst:=args[4] fi;
   if not type(nst,list) then
      ERROR(`fourth argument should be a list of state variables.`) fi;
   if nargs<5 then invar:=u else invar:=args[5] fi;
   if not type(invar,name) then
      ERROR(`fifth argument should be an input variable name.`,
            `If default: u must be unassigned.`) fi;
   if nargs<6 then form:='expl' else form:=args[6] fi;

   f:=subs(invar=cat(invar,0),op(f)):
   T:=subs(invar=cat(invar,0),T):

   zdef:=zip(<X-Y>,nst,T):
   dz:=[seq(cat('d',nst[j]),j=1..n)];
   for i to n do if not type(cat('d',(nst[i])),name) then
      ERROR(cat('d',nst[i],` must not be assigned.`)) fi od;

   dzdef:=zip(<X-Y>,dz,map(lieder,T,f,1,ost,invar)):
   L:=[op(dzdef),op(zdef)]:
   L:=map(numer@expand,L):
   g:=linalg[vector](n);
   explflag:=true:

   for i to n while explflag do
      g[i]:=grobner[finduni](dz[i],L,{op(ost),op(dz)}):
      explflag:=evalb(form='impl' or degree(g[i],dz[i])=1);
      if not explflag then failind:=i fi;
   od:

   if form='impl' then
      g:=convert(g,list);
   elif not explflag then
        print(cat(`No explicit expression for `,dz[failind],` exists.`));
   else
        g:=zip(solve,g,linalg[vector](dz));
   fi
end:

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


# Find the transformed system T(f) where f is a vector and T a list
# expressing the new states in terms of the old ones.
# Discrete time.
# Syntax: newsysd(f,T,ost,nst,invar,form)
# The parameter form determines the form of the output:
#   if form='expl' (default) then the output is a vector (rhs of the new system)
#   and if form='impl' then the output is a list (polynomials defining dz).
#   Thus form='impl' means that implicit state equations are allowed.
# Requires liehom.
# K. Forsman 1992-02-25, 1992-03-02

newsysd:=proc()
   local dz,dzdef,explflag,f,failind,form,g,i,invar,j,L,n,nst,ost,T,zdef:

   if nargs<2 then ERROR(`not enough input arguments.`) fi;

   f:=args[1]: T:=args[2]:
   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(T,list) then
     ERROR(`second argument should be a list.`) fi;

   n:=linalg[vectdim](f);

   if nargs<3 then ost:=[x.(1..n)] else ost:=args[3] fi;
   if not type(ost,list) then
      ERROR(`third argument should be a list of state variables.`) fi;
   if nargs<4 then nst:=[z.(1..n)] else nst:=args[4] fi;
   if not type(nst,list) then
      ERROR(`fourth argument should be a list of state variables.`) fi;
   if nargs<5 then invar:=u else invar:=args[5] fi;
   if not type(invar,name) then
      ERROR(`fifth argument should be an input variable name.`,
            `If default: u must be unassigned.`) fi;
   if nargs<6 then form:='expl' else form:=args[6] fi;

   f:=subs(invar=cat(invar,0),op(f)):
   T:=subs(invar=cat(invar,0),T):

   zdef:=zip(<X-Y>,nst,T):
   dz:=[seq(cat('d',nst[j]),j=1..n)];
   for i to n do if not type(cat('d',(nst[i])),name) then
      ERROR(cat('d',nst[i],` must not be assigned.`)) fi od;

   dzdef:=zip(<X-Y>,dz,map(liehom,T,f,1,ost,invar)):
   L:=[op(dzdef),op(zdef)]:
   L:=map(numer@expand,L):
   g:=linalg[vector](n);
   explflag:=true:

   for i to n while explflag do
      g[i]:=grobner[finduni](dz[i],L,{op(ost),op(dz)}):
      explflag:=evalb(form='impl' or degree(g[i],dz[i])=1);
      if not explflag then failind:=i fi;
   od:

   if form='impl' then
      convert(g,list);
   elif not explflag then
        print(cat(`No explicit expression for `,dz[failind],` exists.`));
   else
        g:=zip(solve,g,linalg[vector](dz));
   fi
end:

# Function for computing critical d for local Lyapunov functions.
# lambda eliminated before finduni or gbasis is applied.
# Syntax: loclyap(f,V,vars,lvar,met)
# K. Forsman 1992-03-03, 1992-08-06

loclyap:=proc()
   local f,g,gdeg,i,ind,L,lvar,md,met,mindeg,minind,n,Q,
         V,vars,Vx,Vxdeg:

   if nargs<2 then ERROR(`not enough input arguments.`) fi;

   f:=args[1]: V:=args[2]:
   if not type(f,vector) then
     ERROR(`first argument should be a vector.`) fi;
   if not type(V,scalar) then
     ERROR(`second argument should be a scalar.`) fi;
   n:=linalg[vectdim](f):
   if nargs<3 then vars:=[x.(1..n)] else vars:=args[3] fi;
   if not type(vars,list(name)) then
     ERROR(`third argument should be a list of names of state variables`,
           `If default: x1,...,xn must be unassigned.`) fi;
   if nops(vars)<>n then
     ERROR(`wrong number of variables given in parameter vars.`) fi;
   if nargs<4 then lvar:=d else lvar:=args[4] fi;
   if not type(lvar,name) then
     ERROR(`fourth argument should be a name.`,
           `If default: d must be unassigned.`) fi;
   if nargs<5 then met:='pol' else met:=args[5] fi;

   Vx:=linalg[grad](V,linalg[vector](vars)):
   Q:=linalg[dotprod](f,Vx):
   g:=evalm(linalg[grad](Q,linalg[vector](vars))):
   gdeg:=map(degree,convert(g,list),{op(vars)});
   Vxdeg:=map(degree,convert(Vx,list),{op(vars)});
   md:=zip(max,gdeg,Vxdeg);
   mindeg:=min(op(md));
   member(mindeg,md,minind);
   ind:=[$(1..(minind-1)),$((minind+1)..n)];
   L:=[];

   for i in ind do
	L:=[op(L),g[i]*Vx[minind]-g[minind]*Vx[i]];
   od;
   L:=map(expand,[V-lvar,Q,op(L)]);

   if met='tot' then
         grobner[gbasis](L,[op(vars),lvar],'plex')
      else
         factor(grobner[finduni](lvar,L,{op(vars),lvar}));
   fi
end:

# K. Forsman 1992-06-15

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

`help/text/lieder`:=TEXT(``,
`FUNCTION: lieder - Lie derivative`,``,
`CALLING SEQUENCE:`,
`   lieder(h,f)`,
`   lieder(h,f,k)`,
`   lieder(h,f,k,vars,invar)`,``,
`PARAMETERS:`,
`   h     - scalar`,
`   f     - vector`,
`   k     - integer (optional). Default: 1`,
`   vars  - list of n names where n=vectdim(f) (optional).`,
`           Default: [x1,...,xn]`,
`   invar - name or list of names (optional). Default: u`,
``,
`SYNOPSIS:`,
`- The call lieder(h,f) returns the Lie derivative of h with respect to f.`,
`  If there are no inputs present this is equal to`,
``,
`            sum(f[i]*diff(h,xi,i=1..n))`,
``,
`  If there are inputs, the Lie derivative is the time derivative of h, using`,
`  the substitution rules diff(xi,t) = f[i], diff(ui,t) = u.(i+1)`,``,
`- lieder(h,f,k) renders the k:th Lie derivative of h w.r.t. f`,``,
`- If a parameter vars is given then the result returned is`,
``,
`            sum(f[i]*diff(h,vars[i]))`,
``,
`- In the result returned, time derivatives of the input are represented by`,
`  subindices, so that e.g. u2=diff(u(t),t,t) and u(t)=u0.`,``,
`- lieder is used internally in e.g. ss2ioc.`,``,
`- Some may prefer to call this simply "directional derivative".`,``,
`EXAMPLE: `,``,
`> lieder(x1*x2^2-u,vector([-x1^2,x2*u]),2);`,
``,
`     2           2       2                    2                              2`,
` - x1  (- 2 x1 x2  + 2 x2  u0) + x2 u0 (- 2 x1  x2 + 4 x1 x2 u0) + 2 u1 x1 x2`,
``,
`      - u2`,``,
`> lieder(z1^2+a*z2,vector([-z2,z1*v]),1,[z1,z2],v);`,
``,
`                              - 2 z2 z1 + z1 v0 a`,``,
`SEE ALSO:  liederlist, liehom, auxlieder`):


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

`help/text/auxlieder`:=TEXT(``,
`FUNCTION: auxlieder - auxiliary Lie derivative`,``,
`CALLING SEQUENCE:`,
`   auxlieder(h,f,vars)`,``,
`PARAMETERS:`,
`   h    - scalar`,
`   f    - vector`,
`   vars - list of names`,``,
`SYNOPSIS:`,
`- Auxiliary function for computing the Lie derivative of h w.r.t. f`,
`  Called from within lieder (q.v.)`,``,
`SEE ALSO:  lieder`):

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

`help/text/liederlist`:=TEXT(``,
`FUNCTION: liederlist - list of n first Lie derivatives`,``,
`CALLING SEQUENCE:`,
`   liederlist(h,f,n,stvars,invar)`,``,
`PARAMETERS:`,
`   h      - scalar`,
`   f      - vector`,
`   n      - integer`,
`   stvars - list of names of state variables`,
`   invar  - name of input variable`,
`SYNOPSIS:`,
`-  Computes the n first Lie derivatives of h w.r.t. f`,
``,
`SEE ALSO:  lieder,liehomlist`):


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

`help/text/liehom`:=TEXT(``,
`FUNCTION: liehom -  Lie homomorphism`,``,
`CALLING SEQUENCE:`,
`   liehom(h,f)`,
`   liehom(h,f,k)`,
`   liehom(h,f,k,vars,invar)`,``,
`PARAMETERS:`,
`    h     - scalar`,
`    f     - vector`,
`    k     - integer (optional). Default: 1`,
`    vars  - list of names of state variables`,
`            Default: [x1,...,xn]`,
`    invar - name or list of names (optional). Default: u`,``,
`SYNOPSIS:`,
`- The call liehom(h,f) returns the Lie homomorphism (my terminology) of h with`,
`  respect to f. This is what you get when you replace xi -> f[i], ui -> u.(i+1)`,
`  in h (if u is the input variable).`,``,
`- liehom(h,f,k) renders the k:th Lie homorphism of h w.r.t. f`,``,
`- If parameters vars and invar are given then the homorphism is defined by`,
``,
`         vars[i] -> f[i],  invar.i -> invar.(i+1)`,
``,
`- In the result returned, time shifts of the input are represented by subindices,`,
`  so that e.g. u2=u(t+2) and u(t)=u0.`,``,
`- liehom is used internally in e.g. ss2iod.`,``,
`EXAMPLE: `,
`> liehom(x1*x2,vector([-x1*x2,x2*u]),2);`,
``,
`                                   3   2`,
`                                 x2  u0  u1 x1`,
``,
`> liehom(p*z1,vector([-z1*z2*v,z2^2]),1,[z1,z2],v);`,
``,
`                                  - p z1 z2 v0`,
``,
`SEE ALSO:  lieder,liehomlist`):


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


`help/text/liehomlist`:=TEXT(``,
`FUNCTION: liehomlist -  list of n first Lie homomorphisms`,``,
`CALLING SEQUENCE:`,
`   liehomlist(h,f,n,vars,invar)`,``,
`PARAMETERS:`,
`   h      - scalar`,
`   f      - vector`,``,
`   n      - integer`,
`   stvars - list of names of state variables`,
`   invar  - name of input variable`,
`SYNOPSIS:`,
``,
`SEE ALSO:  liehom,liederlist`):

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

`help/text/uyder`:=TEXT(``,
`FUNCTION: uyder - time derivative using subscript notation`,``,
`CALLING SEQUENCE:`,
`   uyder(p)`,
`   uyder(p,k)`,
`   uyder(p,k,invar,outvar)`,``,
`PARAMETERS:`,
`   p      - scalar`,
`   k      - integer (optional). Default: 1`,
`   invar  - name of input variable (optional). Default: u`,
`   outvar - name of output variable (optional). Default: y`,``,
`SYNOPSIS:`,
`- Computes the k:th derivative of p w.r.t. t using the subscript notation`,
`  diff(u0,t$k)=uk, diff(y0,t$k)=yk`,``,
`- This trivial function is mainly for internal use (in sstrac).`,``,
`EXAMPLE: `,``,
`> uyder(u^2-y*u);`,
`                         u1 (2 u0 - y0) - u0 y1`,
``,
`SEE ALSO:  uyhom, lieder`):

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

`help/text/uyhom`:=TEXT(``,
`FUNCTION: uyhom - time shift using subscript notation`,``,
`CALLING SEQUENCE:`,
`   uyhom(p)`,
`   uyhom(p,k)`,
`   uyhom(p,k,invar,outvar)`,``,
`PARAMETERS:`,
`   p      - scalar`,
`   k      - integer (optional). Default: 1`,
`   invar  - name of input variable (optional). Default: u`,
`   outvar - name of output variable (optional). Default: y`,``,
`SYNOPSIS:`,
`- Computes the k:th shift of p w.r.t. t using the subscript notation`,
`  u(t+i)=ui, y(t+i)=yi. Thus this function only does a simple substitution`,
``,`                     ui -> u.(i+1), yi -> y.(i+1)`,``,
`  in p, iterated k times.`,``,
`- This trivial function is mainly for internal use (in sstrad).`,
``,
`EXAMPLE: `,``,
`> uyhom(u^2-y*u1^2,2);`,
`                                 2        2`,
`                               u2  - y2 u3`,
``,
`SEE ALSO:  uyder, liehom`):
# K. Forsman 1992-06-15

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

`help/text/io2ssc`:=TEXT(``,
`FUNCTION: io2ssc - state space realization for continuous time control system`,
``,
`CALLING SEQUENCE:`,
`   io2ssc(p,S)`,
`   io2ssc(p,S,stvars)`,
`   io2ssc(p,S,stvars,invar,outvar,ssmod)`,``,
`PARAMETERS:`,
`   p      - polynomial or polynomial equation in invar, outvar`,
`            and their derivatives`,
`   S      - list of rational functions in invar, outvar and their derivatives`,
`   stvars - list of names (optional)`,
`            Default is [x1,...,xn] where n=length of S`,
`   invar  - name (optional). Default is u`,
`   outvar - name (optional). Default is y`,
`   ssmod  - parameter determining what state space models that`,
`            are allowed (optional). Default is ``kalman``.`,
``,
`SYNOPSIS:`,
`- The call io2ssc(p,S) returns a list consisting of the rhs and`,
`  the output map of the state space equation for a continuous time`,
`  polynomial SISO system given in I/O form: p=0.`,``,
`- The list S should contain expressions for the suggested states, i.e.`,
`  rational functions of the input (and its derivatives) and the output`,
`  (and its derivatives). Thus xi=S[i]. It might well happen that the given`,
`  S is not a legal choice of states. There can be two reasons for this:`,
`     1) It is not possible to express diff(xi,t) in terms of the other states`,
`        and the input`,
`     2) It is not possible to express the output in terms of the states`,
`        and the input`,
`  In both cases a warning message is printed.`,``,
`- In p and S, time derivatives are to be represented by subindices,`,
`  so that e.g. y2=diff(y(t),t,t) and u(t)=u0.`,``,
`- The parameter ssmod determines if the state space model should allow`,
`     1) derivatives of the input`,
`     2) implicit state equations`,
`  If ssmod=``kalman`` then neither 1 nor 2 are allowed`,
`           ``der`` then 1 but not 2 is allowed`,
`           ``impl`` then 2 but not 1 is allowed`,
`           ``derimpl`` then both 1 and 2 are allowed`,
`  The default is ``kalman``.`,
`  If implicit equations are allowed the state equations are given as a list of`,
`  polynomials in d.stvars and stvars. The dynamic equations are then these`,
`  polynomials equated to zero. d.stvars[i] represents the time derivative of`,
`  the i:th state variable.`,``,
``,
`EXAMPLES: `,``,
`> p:=y2*y0-y1^2+y1^2*y0:`,
`> A:=io2ssc(p,[y0,y0/y1]);`,
`                                     x1`,
`                            A := [[ ----, u0 ], x1]`,
`                                     x2`,
``,
`> io2ssc(y2-y1=y0^2,[y0^2,y1-y0]);`,
``,
`                 No explicit expression exists for .[dx1, dx2]`,
``,
`                      No explicit expression exists for y`,
``,
`                                       []`,
``,
`> io2ssc(y2-y1=y0^2,[y0^2,y1-y0],[x1,x2],u,y,impl);`,
``,
`                2          2                 2                         2`,
`       [[ - 4 x2  x1 + 4 x1  - 4 x1 dx1 + dx1 , - x1 + dx2 ], - x1 + y0 ]`,
``,
`SEE ALSO:  par2ssc, ss2ioc, io2ssd`):


# Some warning about stvars <> invar <> outvar


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

# K. Forsman 1992-06-15

`help/text/io2ssd`:=TEXT(``,
`FUNCTION: io2ssd - state space realization for discrete time control system`,
``,
`CALLING SEQUENCE:`,
`   io2ssd(p,S,stvars)`,
`   io2ssd(p,S,stvars,invar,outvar)`,
`   io2ssd(p,S,stvars,invar,outvar,ssmod)`,``,
`PARAMETERS:`,
`   p      - polynomial or polynomial equation in invar, outvar`,
`            and their time shifts`,
`   S      - list of rational functions in invar, outvar and their time shifts`,
`   stvars - list of names (optional)`,
`            Default is [x1,...,xn] where n=length of S`,
`   invar  - name (optional). Default is u`,
`   outvar - name (optional). Default is y`,
`   ssmod  - parameter determining what state space models that`,
`            are allowed (optional). Default is ``kalman``.`,
``,
`SYNOPSIS:`,
`- The call io2ssd(p,S) returns a list consisting of the rhs and`,
`  the output map of the state space equation for a discrete time`,
`  polynomial SISO system given in I/O form: p=0`,``,
`- In p and S, time shifts are to be represented by subindices,`,
`  so that e.g. y2=y(t+2) and u(t)=u0.`,``,
`- The parameter ssmod determines if the state space model should allow`,
`     1) non-causality in the input`,
`     2) implicit state equations`,
`  If ssmod=``kalman`` then neither 1 nor 2 are allowed`,
`           ``nc`` then 1 but not 2 is allowed`,
`           ``impl`` then 2 but not 1 is allowed`,
`           ``ncimpl`` then both 1 and 2 are allowed`,
`  The default is ``kalman``.`,
`  If implicit equations are allowed the state equations are given as a list`,
`  of polynomials in d.stvars and stvars. The dynamic equations are then`,
`  these polynomials equated to zero. d.stvars[i] represents the time shift of`,
`  the i:th state variable.`,
``,
`EXAMPLES: `,``,
`> p:=y2-y1*(y-u): S:=[y0,y1/y0]:`,
`> io2ssd(p,S);`,
``,
`                           [[ x2 x1, - u0 + x1 ], x1]`,
``,
`SEE ALSO:  ss2iod, io2ssc`):



`help/text/io2ss`:=TEXT(``,
`HELP FOR: state space realization`,``,
`See par2ssc, io2ssc (continuous time) or io2ssd (discrete time)`,``):

# Some warning about stvars <> invar <> outvar
# K. Forsman 1992-06-15

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

`help/text/loclyap`:=TEXT(``,
`FUNCTION: loclyap - critical level for local Lyapunov function`,
``,
`CALLING SEQUENCE:`,
`   loclyap(f,V)`,
`   loclyap(f,V,vars)`,
`   loclyap(f,V,vars,lvar,met)`,
``,
`PARAMETERS:`,
`   f    - vector representing the rhs of the DE`,
`   V    - scalar function (local Lyapunov function) in vars`,
`   vars - list of names (state variables) (optional)`,
`          Default is [x1,...,xn] where n=vectdim(f)`,
`   lvar - level variable (optional). Default is d`,
`   met  - parameter determining method to be used (optional).`,
`          Also determines the form of the output. Default is ``pol```,
``,
`SYNOPSIS:`,
`- The function loclyap(f,V) is used to determine the critical level of`,
`  a given local Lyapunov function V for the continuous time system`,``,
`                    dx/dt = f(x)`,``,
`- The components of the vector f should be rational functions in vars,`,
`  as should V.`,``,
`- The output is either a single polynomial in lvar or a list of polynomials`,
`  in vars and lvar, depending on the parameter met.`,``,
`- If met=``pol`` then a polynomial in lvar is returned, one zero of which`,
`  is the critical level.`,``,
`  If met=``tot`` then a list of polynomials (a Grobner base) in vars and lvar`,
`  is returned. The last element of this list is exactly the polynomial`,
`  obtained for met=``pol``; the other ones can be used to check which root of`,
`  this last element is actually the critical level.`,``,
`  The reason to use met=``pol`` is that it is (generally) far more efficient.`,
``,
`EXAMPLES: `,``,
`> with(linalg):`,
`> f:=vector([-x1+2*x1^2*x2,-x2]):  V:=3*x1^2+4*x1*x2+4*x2^2:`,
`> loclyap(f,V);`,
`                    2                      2      3`,
`                   d  (2048 + 768 d - 147 d  + 4 d )`,
``,
`> fsolve(");`,
``,
`                      0, -1.9223, 8.9657, 29.707`,
``,
`> G:=loclyap(vector([-z1+z2^2,-2*z2]),z1^2+z2^2,[z1,z2],q,tot):`,
`> factor(G[nops(G)]);`,
``,
`                         2                  2`,
`                        q  (- 71 q + 8 + 4 q )`,
``,
``):
# K. Forsman 1992-06-16

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

`help/text/newsysc`:=TEXT(``,
`FUNCTION: newsysc - state equation for transformed continuous time`,
`                    control system`,``,
`CALLING SEQUENCE:`,
`   newsysc(f,T)`,
`   newsysc(f,T,ost,nst)`,
`   newsysc(f,T,ost,nst,invar,form)`,``,
`PARAMETERS:`,
`   f     - vector`,
`   T     - list of rational functions in the variables ost`,
`   ost   - list of names (optional). Default: [x1,...,xn]`,
`   nst   - list of names (optional). Default: [z1,...,zn]`,
`   invar - name (optional). Default: u`,
`   form  - optional parameter determining the type of state equations that are`,
`           allowed. Also affects the form of the output.`,
`           The default is ``expl``.`,
``,
`SYNOPSIS:`,
`- newsysc(f,T) returns either a vector or a list of polynomials describing`,
`  the state equations obtained as the continuous time control system`,``,
`                        dx/dt=f(x,u)`,
`  is transformed into`,
`                        dz/dt=g(z,u)`,``,
`  in the way described by the list T. See below for a full description of`,
`  the output format.`,``,
`- The components of the vector f are to be rational functions in ost.`,``,
`- T is a list of rational functions, so that zi=T[i].`,``,
`- ost and nst (if given) are lists of names of the old and the new state`,
`  variables, respectively. Thus the transformation is defined by nst[i]=T[i].`,
``,
`- If form=``expl`` (default) then the output is the vector g above, if there`,
`  is an explicit state space representation in the new coordinates. If there`,
`  is no such representation a warning message is printed.`,
`  If form=``impl`` then the output is a list of n polynomials. The i:th`,
`  element of the list is a polynomial in d.nst[i] and nst, where d.nst[i]`,
`  denotes the time derivative of the i:th new state. The polynomial put`,
`  equal to zero gives the dynamical equation for nst[i].`,``,
`- There is a lack of symmetry here, since sstrac may produce an implicit`,
`  transformation, whereas this function requires the transformation to be`,
`  explicitly given. This is for theoretical reasons.`,``,
`EXAMPLE: `,``,
`> with(linalg):`,
`> T:=[2*x1-x2^2,3*x2-1]: f:=vector([-x1^2,u-x1*x2]):`,
`> newsysc(f,T);`,
``,
`                                2           4          3          2`,
` [ - 2/3 u0 z2 - 2/3 u0 - 1/2 z1  + 1/162 z2  + 2/81 z2  + 1/27 z2`,
``,
`        + 2/81 z2 + 1/162,`,
`                                        3         2`,
`     3 u0 - 1/2 z1 z2 - 1/2 z1 - 1/18 z2  - 1/6 z2  - 1/6 z2 - 1/18 ]`,
``,
`SEE ALSO:  sstrac, newsysd`):


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

# K. Forsman 1992-06-16

`help/text/newsysd`:=TEXT(``,
`FUNCTION: newsysd - state equation for transformed discrete time system`,``,
`CALLING SEQUENCE:`,
`   newsysd(f,T)`,
`   newsysd(f,T,ost,nst)`,
`   newsysd(f,T,ost,nst,invar,form)`,``,
`PARAMETERS:`,
`   f     - vector`,
`   T     - list of rational functions in the variables ost`,
`   ost   - list of names (optional). Default: [x1,...,xn]`,
`   nst   - list of names (optional). Default: [z1,...,zn]`,
`   invar - name (optional). Default: u`,
`   form  - optional parameter determining the type of state equations that are`,
`           allowed. Also affects the form of the output.`,
`           The default is ``expl``.`,
``,
`SYNOPSIS:`,
`- newsysd(f,T) returns either a vector or a list of polynomials describing`,
`  the state equations obtained as the discrete time control system`,``,
`                        x(t+1)=f(x(t),u(t))`,
`  is transformed into`,
`                        z(t+1)=g(z(t),u(t))`,``,
`  in the way described by the list T. See below for a full description of`,
`  the output format.`,``,
`- The components of the vector f are to be rational functions in ost.`,``,
`- T is a list of rational functions, so that zi=T[i].`,``,
`- ost and nst (if given) are lists of names of the old and the new state`,
`  variables, respectively. Thus the transformation is defined by nst[i]=T[i].`,
``,
`- If form=``expl`` (default) then the output is the vector g above, if there`,
`  is an explicit state space representation in the new coordinates. If there`,
`  is no such representation a warning message is printed.`,
`  If form=``impl`` then the output is a list of n polynomials. The i:th`,
`  element of the list is a polynomial in d.nst[i] and nst, where d.nst[i]`,
`  denotes the time shift of the i:th new state. The polynomial put`,
`  equal to zero gives the dynamical equation for nst[i].`,``,
`- There is a lack of symmetry here, since sstrad may produce an implicit`,
`  transformation, whereas this function requires the transformation to be`,
`  explicitly given. This is for theoretical reasons.`,``,
`EXAMPLE: `,``,
`> with(linalg):`,
`> T:=[2*x1-1,3*x2+x1^2]: f:=vector([-(1/2)*x1,u*x2]):`,
`> newsysd(f,T);`,
``,
`[ - 3/2 - 1/2 z1,`,
``,
`                  2                                  2`,
`    u0 z2 - 1/4 z1  u0 - 1/2 z1 u0 - 1/4 u0 + 1/16 z1  + 1/8 z1 + 1/16`,
``,
`     ]`,``,
`SEE ALSO:  sstrad, newsysc`):

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

`help/text/newsys`:=TEXT(``,
`HELP FOR: system equations in new coordinates`,``,
`See newsysc (continuous time) or newsysd (discrete time)`,``):
# K. Forsman 1992-06-16

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

`help/text/obsvc`:=TEXT(``,
`FUNCTION: obsvc - observer relation for continuous time control system`,
``,
`CALLING SEQUENCE:`,
`   obsvc(f,h,obsvar)`,
`   obsvc(f,h,obsvar,stvars)`,
`   obsvc(f,h,obsvar,stvars,invars,outvar,form)`,``,
`PARAMETERS:`,
`   f      - rhs vector`,
`   h      - output map`,
`   obsvar - variable, relation for which is sought`,
`   stvars - list of names of state variables (optional)`,
`            Default is [x1,...,xn] where n=vectdim(f)`,
`   invars - name or list of names of input variable(s) (optional).`,
`            Default is u.`,
`   outvar - output variable (optional). Default is y.`,
`   form   - optional parameter determining what kinds of relations that are`,
`            allowed. Also affects the shape of the output. Default: ``expl```,
``,
`SYNOPSIS:`,
`- The call obsvc(f,h,obsvar) returns a list consisting of polynomials`,
`  describing how the variable obsvar is related to the inputs and the output`,
`  of a continuous time rational system given in state space form:`,``,
`                    dx/dt = f(x,u),  y = h(x,u)`,``,
`  The exact format of the output is described below.`,``,
`- Time derivatives are represented by subindices, so that e.g. y2 means`,
`  diff(y(t),t,t).`,``,
`- If form=``expl`` (default) then the output is a list of rational expressions`,
`  for obsvar in inputs and output (and their derivatives). If no such expressions`,
`  exist then an error message is printed.`,
`  If form=``impl`` then the output is a list of polynomials in inputs`,
`  and output (and their derivatives) and obsvar. These polynomials all equal`,
`  zero.`,``,
`- If obsvar is not algebraically observable, an error message is printed.`,
``,
`EXAMPLES: `,``,
`> with(linalg):`,
`> f:=vector([x1*x2-u,x1^2]):`,
`> S:=obsvc(f,x2,x1);`,
``,
`                                u0 y1           y2 - 2 y1 y0`,
`                  S := [- 2 ------------, - 1/2 ------------]`,
`                            y2 - 2 y1 y0             u0`,``,
`> T:=obsvc(f,x2,x1,[x1,x2],u,y,impl);`,
``,
`                    2`,
`     T := [- y1 + x1 , (y2 - 2 y1 y0) x1 + 2 u0 y1, y2 + 2 x1 u0 - 2 y1 y0]`,
``,
`SEE ALSO:  obsvd, ss2ioc`):


# Some warning about stvars <> invar <> outvar

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

# K. Forsman 1992-06-16

`help/text/obsvd`:=TEXT(``,
`FUNCTION: obsvd - observer relation for discrete time control system`,
``,
`CALLING SEQUENCE:`,
`   obsvd(f,h,obsvar)`,
`   obsvd(f,h,obsvar,stvars)`,
`   obsvd(f,h,obsvar,stvars,invars,outvar,form)`,``,
`PARAMETERS:`,
`   f      - rhs vector`,
`   h      - output map`,
`   obsvar - variable, relation for which is sought`,
`   stvars - list of names of state variables (optional)`,
`            Default is [x1,...,xn] where n=vectdim(f).`,
`   invars - name or list of names of input variable(s) (optional).`,
`            Default is u.`,
`   outvar - output variable (optional). Default is y.`,
`   form   - optional parameter determining which kinds of relations that are`,
`            allowed. Also affects the shape of the output. Default: ``expl```,
``,
`SYNOPSIS:`,
`- The call obsvd(f,h,obsvar) returns a list consisting of polynomials`,
`  describing how the variable obsvar is related to the inputs and the output`,
`  of a discrete time rational control system given in state space form:`,``,
`                    x(t+1) = f(x(t),u(t)),  y = h(x,u)`,``,
`  The exact format of the output is described below.`,``,
`- Time shifts are represented by subindices, so that e.g. y2 means y(t+2).`,``,
`- If form=``expl`` (default) then the output is a list of rational expressions`,
`  for obsvar in inputs and output (and their shifts). If no such expressions`,
`  exist then an error message is printed.`,
`  If form=``impl`` then the output is a list of polynomials in inputs`,
`  and output (and their shifts) and obsvar. These polynomials all equal`,
`  zero.`,``,
`- If obsvar is not algebraically observable, an error message is printed.`,
``,
`EXAMPLES: `,``,
`> with(linalg):`,
`> f:=vector([x1*x2-u,x1^2]):`,
`> S:=obsvd(f,x2,x1);`,
``,
`                                                       2        2`,
`                            y1 y0 u0            y2 - u0  - y1 y0`,
`             S := [- 2 -----------------, - 1/2 -----------------]`,
`                              2        2              y0 u0`,
`                       y2 - u0  - y1 y0`,
``,
`> obsvd(vector([x^3]),x^2,x,[x]);`,
``,
`                      No explicit expression for x found.`,
``,
`SEE ALSO:  obsvc, ss2iod`):


`help/text/obsv`:=TEXT(``,
`HELP FOR: observer relations`,``,
`See obsvc (continuous time) or obsvd (discrete time)`,``):

# K. Forsman 1992-06-16

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

`help/text/par2ssc`:=TEXT(``,
`FUNCTION: par2ssc - state space realisation for continuous time control system`,
``,
`CALLING SEQUENCE:`,
`   par2ssc(H,stvars)`,``,
`PARAMETERS:`,
`   H      - a list of rational functions in the variables stvars`,
`   stvars - list of names of state variables (optional)`,
`            Default is [x1,...,xn] where n=length of H`,
``,
`SYNOPSIS:`,
`- The call par2ssc(H,stvars) returns the rhs vector of the state equation for`,
`  a continuous time rational SISO system. The functions in H parametrize the`,
`  hypersurface p=0, where p is the I/O-relation, so that y0=H[1], y1=H[2], etc.`,
``,
`  In other words, par2ssc finds the rhs f of an equation`,``,
`                    dx/dt = f(x,u),  y = h(x,u)`,``,
`  such that H[i] is the i:th Lie-derivative of h w.r.t. f.`,``,
`- It is required that H[1], ..., H[n-1] are algebraically independent.`,``,
`- Time derivatives of the output are represented by subindices, so that`,
`  e.g. y2 means diff(y(t),t,t).`,
``,
`EXAMPLES: `,``,
`> par2ssc([x1*x2,x2,x1]);`,
``,
`                                2`,
`                            - x1  + x2`,
`                          [ ----------, x1 ]`,
`                                x2`,
``,
`> par2ssc([z^2-1,z+1],[z]);`,
``,
`                                   z + 1`,
`                             [ 1/2 ----- ]`,
`                                     z`,
``,
`SEE ALSO:  io2ssc, ss2ioc`):
# K. Forsman 1992-08-10

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

`help/text/polycon`:=TEXT(``,
`HELP FOR: The polynomial and rational control systems package`,
``,
`CALLING SEQUENCE:`,
`   <function>(args)`,
#`   polycon[<function>](args)`,
``,
`SYNOPSIS:`,
`- This package includes functions for analysis of polynomial and rational`,
`  control systems, i.e. control systems of the type`,``,
`                    dx/dt=f(x(t),u(t)),  y=h(x,u)`,
`  or`,
`                   x(t+1)=f(x(t),u(t)),  y=h(x,u)`,
``,
`  where h and all components of f are rational functions in x = (x1,...,xn)`,
`  and u. In some functions only polynomial nonlinearities are allowed.`,``,
`- Most functions are available in a continuous time and a discrete time version;`,
`  the convention is that the names of continuous time functions end in c and`,
`  names of discrete time functions end in d.`,
`  Exceptions are lieder - liehom and the like.`,``,
`- The package is aimed at questions related to state space realizations:`,``,
`   * state space to input-output conversion (ss2ioc, ss2iod)`,
`   * realization of input-output relations (par2ssc, io2ssc, io2ssd)`,
`   * observability (obsvc, obsvd)`,
`   * transformation of systems (newsysc, newsysd)`,
`   * finding the transformation between two equivalent systems (sstrac, sstrad)`,
``,
`  There is also a function loclyap for analysis of local Lyapunov functions.`,``,
`- Some functions available are:`,``,
`  io2ssc    io2ssd    lieder    liehom`,   
`  loclyap   newsysc   newsysd   obsvc`,
`  obsvd     par2ssc   ss2ioc    ss2iod`,
`  sstrac    sstrad    uyder     uyhom`,``,
`- In the polycon package, time derivatives and time shifts of dependent`,
`  variables are represented by subindices, so that e.g. in continuous time`,
`  y0=y(t), y1=diff(y(t),t), y2=diff(y(t),t$2) etc. while in discrete time`,
`  y0=y(t), y1=y(t+1), y2=y(t+2). This rule holds for input and output variables.`,
``,
`  The user is allowed to write u instead of u0 and y instead of y0 when calling`,
`  a function.`,``,
`  Derivatives or shifts of state variables do not occur, so state variables are`,
`  still called x1,...,xn by default.`,``,
`  To differentiate an expression in u and y using this convention the function`,
`  uyder can be applied.`,``,
`- Some functions use global variables and most functions have default values`,
`  of input parameters that are names. The following default names are used:`,
``,
`     state variables:                        x1,...,xn`,
`     (second state representation):          z1,...,zn`,
`     derivatives/shifts of state variables:  dx1,...,dxn,dz1,...,dzn`,
`     input variable:                         u or u0`,
`     derivatives/shifts of input variable:   u1,u2,...`,
`     output variable:                        y or y0`,
`     derivatives/shifts of output variable:  y1,y2,... `,
``,
`  In all cases where global names occur, the user is warned if there is a`,
`  conflict.`,``,
`- The theoretical background, with proofs for the correctness of the algorithms`,
`  is given in the authors PhD-thesis:`,``,
`   K. Forsman: "Constructive Commutative Algebra in  Nonlinear Control Theory"`,
`   Dept. of EE, Linkoping University, S - 581 83 Linkoping, Sweden, 1991`,``):
# K. Forsman 1992-06-16

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

`help/text/ss2ioc`:=TEXT(``,
`FUNCTION: ss2ioc - input-output relation for continuous time control system`,
``,
`CALLING SEQUENCE:`,
`   ss2ioc(f,h)`,
`   ss2ioc(f,h,stvars)`,
`   ss2ioc(f,h,stvars,invars,outvar)`,``,
`PARAMETERS:`,
`   f      - vector`,
`   h      - rational function of stvars`,
`   stvars - list of names (optional)`,
`            Default is [x1,...,xn] where n=vectdim(f)`,
`   invars - name or list of names (optional). Default is u.`,
`   outvar - name (optional). Default is y.`,
``,
`SYNOPSIS:`,
`- The call ss2ioc(f,h) returns the input-output relation for a continuous`,
`  time control system given in state-space form:`,``,
`                    dx/dt = f(x,u),  y = h(x,u)`,``,
`  All nonlinearities in f and h are required to be rational functions`,
`  of x and u.`,``,
`- In the I/O-relation returned, time derivatives are represented by subindices,`,
`  so that e.g. y2=diff(y(t),t,t) and u(t)=u0.`,``,
`- The parameter stvars is a list containing the names of the state variables,`,
`  if not [x1,...,xn].`,``,
`- The parameter invars is the name(s) of the input variable(s), if not u.`,
`  Similarly, outvar is the output variable, if not y.`,``,
`- If the state-space realization is not minimal a warning message is printed.`,``,
`- There is an expert version of this function, called xss2iod.`,``,
`EXAMPLES: `,``,
`> with(linalg):`,
`> f:=vector([x1*x2-u,x1^2]):`,
`> ss2ioc(f,x2);`,
``,
`                    2   2          2                  2`,
`                4 y0  y1  - 4 y1 u0  - 4 y1 y0 y2 + y2`,
``,
`> p:=ss2ioc(vector([v*z2,v*z1]),z2+v*z1,[z1,z2],v,q):`,
`> collect(p,[q2,q1,q0]);`,
``,
`              3                      2`,
`         (- v0  + v0 + v1) q2 + (3 v0  v1 - v1 - v2) q1`,
``,
`                   2        3     5       2             2`,
`              + (v0  v2 - v0  + v0  - 3 v0  v1 - 3 v0 v1 ) q0`,
``,
`SEE ALSO:  par2ssc, io2ssc, ss2iod`):


# Some warning about stvars <> invar <> outvar

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

# K. Forsman 1992-06-15

`help/text/ss2iod`:=TEXT(``,
`FUNCTION: ss2iod - input-output relation for discrete time systems`,``,
`CALLING SEQUENCE:`,
`   ss2iod(f,h)`,
`   ss2iod(f,h,stvars)`,
`   ss2iod(f,h,stvars,invars,outvar)`,``,
`PARAMETERS:`,
`   f      - vector`,
`   h      - rational function of stvars`,
`   stvars - list of names (optional)`,
`            Default is [x1,...,xn] where n=vectdim(f)`,
`   invars - name or list of names (optional). Default is u.`,
`   outvar - name (optional). Default is y.`,
``,
`SYNOPSIS:`,
`- The call ss2iod(f,h) returns the input-output relation for a discrete`,
`  time control system given in state-space form:`,``,
`                    x(t+1) = f(x(t),u(t)),  y = h(x,u)`,``,
`  All nonlinearities in f and h are required to be rational functions`,
`  of x and u.`,``,
`- In the I/O-relation returned, time shifts are represented by subindices,`,
`  so that e.g. y2=y(t+2) and u(t)=u0.`,``,
`- The parameter stvars is a list containing the names of the state variables,`,
`  if not [x1,...,xn].`,``,
`- The parameter invars is the name(s) of the input variable(s), if not u.`,
`  Similarly, outvar is the output variable, if not y.`,``,
`- If the state-space realization is not minimal a warning message is printed.`,``,
`- There is an expert version of this function, called xss2iod.`,``,
`EXAMPLE: `,``,
`> with(linalg):`,
`> ss2iod(vector([-(1/2)*x1*x2,x2^2-u]),x1-u^2):`,
`> collect(",[y2,y1,y0]);`,
``,
`      2          2       4           3        2   2`,
` (2 y0  + 4 y0 u0  + 2 u0 ) y2 + 4 y1  + 12 y1  u1`,
``,
`             2        5        4          3            2        2    2`,
`      + (- y0  u0 - u0  + 12 u1  - 2 y0 u0 ) y1 + (2 u2  - u0 u1 ) y0`,
``,
`             2   2       3   2         5   2       4   2       6`,
`      + (4 u0  u2  - 2 u0  u1 ) y0 - u0  u1  + 2 u0  u2  + 4 u1`,
``,
`SEE ALSO:  ss2ioc, io2ssd`):

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

`help/text/ss2io`:=TEXT(``,
`HELP FOR: state-space to input-output conversion`,``,
`See ss2ioc (continuous time) or ss2iod (discrete time)`,``):

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

`help/text/xss2ioc`:=TEXT(``,
`FUNCTION: xss2ioc - input-output relation for continuous time control system:`,
`                    expert version`,``,
` This function has exactly the same syntax as ss2ioc (q.v.), but returns`,
` the entire Grobner base for the ideal defining yi as the i:th Lie-derivative`,
` of h w.r.t. f.`):

`help/text/xss2iod`:=TEXT(``,
`FUNCTION: xss2iod - input-output relation for discrete time control system:`,
`                    expert version`,``,
` This function has exactly the same syntax as ss2iod (q.v.), but returns`,
` the entire Grobner base for the ideal defining yi as the i:th Lie-derivative`,
` of h w.r.t. f.`):

# K. Forsman 1992-06-15

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

`help/text/sstrac`:=TEXT(``,
`FUNCTION: sstrac - find state space transformation between continuous time`,
`                   control systems`,``,
`CALLING SEQUENCE:`,
`   sstrac(f,a,g,b)`,
`   sstrac(f,a,g,b,ost,nst)`,
`   sstrac(f,a,g,b,ost,nst,oinp,ninp,form)`,``,
`PARAMETERS:`,
`   f,g       - vectors`,
`   a,b       - polynomials in the variables ost and nst respectively`,
`   ost,nst   - lists of names (optional).`,
`               Defaults: ost=[x1,...,xn], nst=[z1,...,zn]`,
`   oinp,ninp - names of input variables (optional). Default: oinp=ninp=u`,
`   form      - optional parameter determining what kinds of state space`,
`               transformations are allowed. Also affects the shape of output.`,
`               The default is ``expl``.`,
``,
`SYNOPSIS:`,
`- sstrac(f,a,g,b) returns a list defining the state space transformation`,
`  between the two continuous time SISO control systems`,``,
`                      dx/dt=f(x,u), y=a(x,u)`,
`  and`,
`                      dz/dt=g(z,u), y=b(z,u)`,
``,
`  having the same I/O-equation. The components of f and g have to be`,
`  polynomials in the states and the input.`,``,
`- ost and nst are lists of state variables for the old and the new system.`,
`  Default values are as described above.`,``,
`- oinp and ninp are the names of the old and the new input respectively.`,``,
`- If form=``expl`` (default) then only explicit transformations are allowed,`,
`  and the output is a list L defining the transformation: nst[i]=L[i].`,
`  If form=``impl`` then implicit (algebraic) transformations are allowed,`,
`  and the output-list L is such that L[i] is a polynomial in nst[i] and ost.`,
``,
`EXAMPLES: `,``,
`> with(linalg):`,
`> f:=vector([x2,-x1]):`,
`> g:=vector([2*z2-(1/2)*z1^2,z1*z2-(1/2)*z1-1/4*z1^3]):`,
`> Q:=sstrac(f,x2,g,-(1/2)*z1);`,
``,
`                                             2`,
`                        Q := [- 2 x2, x1 + x2 ]`,
``,
`> f:=vector([x1^2]): a:=x1^2: g:=vector([(1/2)*z1^3]): b:=z1^4:`,
`> sstrac(f,a,g,b);`,
``,
`                 No explicit expression for z1 exists.`,
``,
`> sstrac(f,a,g,b,[x1],[z1],u,u,impl);`,
``,
`                                 2`,
`                              [z1  - x1]`,
``,
`SEE ALSO:  newsysc, sstrad`):


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

# K. Forsman 1992-06-15

`help/text/sstrad`:=TEXT(``,
`FUNCTION: sstrad - find state space transformation between discrete time`,
`                   control systems`,``,
`CALLING SEQUENCE:`,
`   sstrad(f,a,g,b)`,
`   sstrad(f,a,g,b,ost,nst)`,
`   sstrad(f,a,g,b,ost,nst,oinp,ninp,form)`,``,
`PARAMETERS:`,
`   f,g       - vectors`,
`   a,b       - polynomials in the variables ost and nst respectively`,
`   ost,nst   - lists of names (optional).`,
`               Defaults: ost=[x1,...,xn], nst=[z1,...,zn]`,
`   oinp,ninp - names of input variables (optional). Default: oinp=ninp=u`,
`   form      - optional parameter determining what kinds of state space`,
`               transformations are allowed. Also affects the shape of output.`,
`               The default is ``expl``.`,
``,
`SYNOPSIS:`,
`- sstrad(f,a,g,b) returns a list defining the state space transformation`,
`  between the two discrete time SISO control systems`,``,
`                      x(t+1)=f(x(t),u(t)),  y=a(x,u)`,
`  and`,
`                      z(t+1)=g(z(t),u(t)),  y=b(z,u)`,
``,
`  having the same I/O-equation. The components of f and g have to be`,
`  polynomials in the states and the input.`,``,
`- ost and nst are lists of state variables for the old and the new system.`,
`  Default values are as described above.`,``,
`- oinp and ninp are the names of the old and the new input respectively.`,``,
`- If form=``expl`` (default) then only explicit transformations are allowed,`,
`  and the output is a list L defining the transformation: nst[i]=L[i].`,
`  If form=``impl`` then implicit (algebraic) transformations are allowed,`,
`  and the output-list L is such that L[i] is a polynomial in nst[i] and ost.`,
``,
`EXAMPLE: `,``,
`> with(linalg):`,
`> f:=vector([x2*u,-x1]):`,
`> g:=vector([z1^2*u-u*z2,u^2*z2^2-2*z2*z1^2*u^2+z1^4*u^2+z1]):`,
`> sstrad(f,x1,g,-z1);`,
``,
`                                         2`,
`                           [- x1, x2 + x1 ]`,``,
`SEE ALSO:  newsysd, sstrac`):

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

`help/text/sstra`:=TEXT(``,
`HELP FOR: obtaining state space transformations`,``,
`See sstrac (continuous time) or sstrad (discrete time)`,``):

polycon := `The polynomial and rational control systems package`:
#save `polycon.m`;
#quit
