source: git/Singular/LIB/ncrat.lib @ 8628dd

spielwiese
Last change on this file since 8628dd was 8628dd, checked in by Hans Schoenemann <hannes@…>, 4 years ago
fix: ncrat.lib: examples
  • Property mode set to 100644
File size: 56.6 KB
Line 
1////////////////////////////////////////////////////////////
2version="version ncrat.lib 4.1.2.0 Feb_2019 "; // $Id$
3category="Noncommutative";
4info="
5LIBRARY:      ncrat.lib Framework for working with non-commutative rational functions
6
7AUTHOR:       Ricardo Schnur, email: ricardo.schnur@math.uni-sb.de
8
9SUPPORT:      This project has been funded by the SFB-TRR 195
10  'Symbolic Tools in Mathematics and their Application'.
11
12OVERVIEW:     This library provides a framework for working with
13  non-commutative rational functions (or rather, expressions)
14  and their linearized representations
15
16REFERENCES:   T. Mai: On the analytic theory of non-commutative
17   distributions in free probability. Universitaet des Saarlandes,
18   Dissertation, 2017
19
20KEYWORDS:     noncommutative, rational expressions;
21   rational functions; formal linear representations; minimal representations
22
23NOTE: an almost self-explaining introduction to the posibilities of the framework
24can be achieved by running the example for the procedure ncrepGetRegularMinimal.
25
26PROCEDURES:
27  ncInit(list);                 Set up framework, list contains nc variables
28  ncVarsGet();                  List nc variables that are in use
29  ncVarsAdd(list);              Add variables from list to 'NCRING'
30  ncratDefine();                Define element of type ncrat
31  ncratAdd();                   Addition of two ncrat's
32  ncratSubstract();             Substraction of two ncrat's
33  ncratMultiply();              Multiplication of two ncrat's
34  ncratInvert();                Invert an ncrat
35  ncratSPrint();                Print-to-string for ncrat
36  ncratPrint();                 Print for ncrat
37  ncratFromString();            Reads string into ncrat
38  ncratFromPoly();              Converts poly to ncrat
39  ncratPower();                 Raises ncrat to an integer power
40  ncratEvaluateAt();            Evaluate ncrat at scalar or matrix point
41  ncrepGet();                   Calculate representation of ncrat
42  ncrepAdd();                   Addition of two ncrep's
43  ncrepSubstract();             Substraction of two ncrep's
44  ncrepMultiply();              Multiplication of two ncrep's
45  ncrepInvert();                Invert an ncrep
46  ncrepPrint();                 Print for ncrep
47  ncrepDim();                   Return the size of ncrep
48  ncrepSubstitute();            Plug matrices into nc variables in ncrep
49  ncrepEvaluate();              Given (u, Q, v) calculate -u*Q^(-1)*v
50  ncrepEvaluateAt();            Evaluate ncrep at scalar or matrix point
51  ncrepIsDefinedDim();          Random matrix test if ncrep can be evaluated at size dim
52  ncrepIsDefined();             Random matrix test if domain of ncrep is not empty
53  ncrepIsRegular();             Random matrix test if ncrep can be evaluated at scalar point
54  ncrepRegularZeroMinimize();   Yields a minimal representation if regular at zero
55  ncrepRegularMinimize();       Yields a minimal representation if regular at scalar point
56  ncrepGetRegularZeroMinimal(); Get a minimal representation of ncrat regular at zero
57  ncrepGetRegularMinimal();     Get a minimal representation of ncrat regular at scalar point
58  ncrepPencilGet();             Given representation decompose its matrix in linear pencil
59  ncrepPencilCombine();         Given linear pencil add up its elements to single matrix
60";
61
62LIB "linalg.lib";
63LIB "random.lib";
64////////////////////////////////////////////////////////////
65
66/*##########################################################
67
68   STATIC PROCEDURES
69
70##########################################################*/
71
72/*##########################################################
73
74   GENERAL
75
76##########################################################*/
77
78// Check whether all entries of a matrix are 0
79static proc isMatrixEmpty(matrix M)
80{
81  int n = ncols(M);
82  int m = nrows(M);
83
84  int i, j;
85  int isZero = 1;
86  i = 1;
87  while (i <= n)
88  {
89    j = 1;
90    while (isZero and j <= m)
91    {
92      if (not(M[j, i] == 0))
93      {
94        isZero = 0;
95      }
96      j++;
97    }
98    i++;
99  }
100  return (isZero);
101}
102
103/*##########################################################
104
105   STRING
106
107##########################################################*/
108
109/*---------------------------------------------------------/
110
111  Some tools to work on strings
112
113/---------------------------------------------------------*/
114
115// Is first character a special character?
116static proc isSelfRepresented(string s)
117{
118  if (size(s) == 0)
119  {
120    ERROR("Called isSelfRepresented() with empty string.");
121  }
122  if (s[1] == ";" or s[1] == "(" or s[1] == ")" or s[1] == "+" or s[1] == "-" or
123      s[1] == "*" or s[1] == "^" or s[1] == "/")
124  {
125    return (1);
126  }
127  return (0);
128}
129
130// Is first character a whitespace?
131static proc isWhitespace(string s)
132{
133  if (size(s) == 0)
134  {
135    ERROR("Called isWhitespace() with empty string.");
136  }
137  if (s[1] == " " or s[1] == newline)
138  {
139    return (1);
140  }
141  return (0);
142}
143
144// Is first character a digit?
145static proc isDigit(string s)
146{
147  if (size(s) == 0)
148  {
149    ERROR("Called isDigit() with empty string.");
150  }
151  if (s[1] == "0" or s[1] == "1" or s[1] == "2" or s[1] == "3" or s[1] == "4" or
152      s[1] == "5" or s[1] == "6" or s[1] == "7" or s[1] == "8" or s[1] == "9")
153  {
154    return (1);
155  }
156  return (0);
157}
158
159// Is first character a letter?
160static proc isLetter(string s)
161{
162  if (size(s) == 0)
163  {
164    ERROR("Called isLetter() with empty string.");
165  }
166  if (s[1] == "A" or s[1] == "a" or s[1] == "B" or s[1] == "b" or s[1] == "C" or
167      s[1] == "c" or s[1] == "D" or s[1] == "d" or s[1] == "E" or s[1] == "e" or
168      s[1] == "F" or s[1] == "f" or s[1] == "G" or s[1] == "g" or s[1] == "H" or
169      s[1] == "h" or s[1] == "I" or s[1] == "i" or s[1] == "J" or s[1] == "j" or
170      s[1] == "K" or s[1] == "k" or s[1] == "L" or s[1] == "l" or s[1] == "M" or
171      s[1] == "m" or s[1] == "N" or s[1] == "n" or s[1] == "O" or s[1] == "o" or
172      s[1] == "P" or s[1] == "p" or s[1] == "Q" or s[1] == "q" or s[1] == "R" or
173      s[1] == "r" or s[1] == "S" or s[1] == "s" or s[1] == "T" or s[1] == "t" or
174      s[1] == "U" or s[1] == "u" or s[1] == "V" or s[1] == "v" or s[1] == "W" or
175      s[1] == "w" or s[1] == "X" or s[1] == "x" or s[1] == "Y" or s[1] == "y" or
176      s[1] == "Z" or s[1] == "z")
177  {
178    return (1);
179  }
180  return (0);
181}
182
183// Convert string representation of a number into number
184static proc digitToInt(string s)
185{
186  if (size(s) == 0)
187  {
188    ERROR("Called digitToInt() with empty string.");
189  }
190
191  if (s[1] == "0")
192  {
193    return (0);
194  }
195  if (s[1] == "1")
196  {
197    return (1);
198  }
199  if (s[1] == "2")
200  {
201    return (2);
202  }
203  if (s[1] == "3")
204  {
205    return (3);
206  }
207  if (s[1] == "4")
208  {
209    return (4);
210  }
211  if (s[1] == "5")
212  {
213    return (5);
214  }
215  if (s[1] == "6")
216  {
217    return (6);
218  }
219  if (s[1] == "7")
220  {
221    return (7);
222  }
223  if (s[1] == "8")
224  {
225    return (8);
226  }
227  if (s[1] == "9")
228  {
229    return (9);
230  }
231  ERROR("digitToInt() not a digit!");
232}
233
234// Convert string representation of a number into number
235static proc stringToNumber(string s)
236{
237  if (size(s) == 0)
238  {
239    ERROR("Called stringToNumber() with empty string.");
240  }
241
242  int i;
243  number n = 0;
244  for (i = 1; i <= size(s); i++)
245  {
246    n = n + number(digitToInt(s[i]) * 10 ^ (size(s) - i));
247  }
248
249  return (n);
250}
251
252/*##########################################################
253
254  END STRING
255
256##########################################################*/
257
258/*##########################################################
259
260   TOKEN
261
262##########################################################*/
263
264/*---------------------------------------------------------/
265
266  Constructors for token and tokenstream
267
268/---------------------------------------------------------*/
269
270// First argument is Kind
271// Optional arguments: Value, Name
272static proc makeToken(string s, list #)
273{
274  token t;
275  int i, n;
276
277  n = size(#);
278  t.kind = s;
279
280  for (i = 1; i <= n; i++)
281  {
282    if (typeof(#[i]) == "number")
283    {
284      t.value = #[i];
285    }
286    if (typeof(#[i]) == "int")
287    {
288      t.value = number(#[i]);
289    }
290    if (typeof(#[i]) == "string")
291    {
292      t.name = #[i];
293    }
294  }
295
296  return (t);
297}
298
299// Constructor for token_stream
300static proc makeTokenStream()
301{
302  tokenstream ts;
303  ts.full = 0;                    // buffer starts empty
304  ts.position = 0;                // initial position
305  ts.buffer = makeToken("empty"); // empty buffer
306  ts.input = "";                  // no input yet
307  return (ts);
308}
309
310/*---------------------------------------------------------/
311
312  Member functions for TOKENSTREAM
313
314/---------------------------------------------------------*/
315
316// Put token back into stream
317static proc tsPutback(token t)
318{
319  if (TOKENSTREAM.full)
320  {
321    ERROR("tsPutback() into full buffer!");
322  }
323  TOKENSTREAM.buffer = t;
324  TOKENSTREAM.full = 1;
325}
326
327// Compose next token
328static proc tsGet()
329{
330  // Check for token in buffer
331  if (TOKENSTREAM.full)
332  {
333    TOKENSTREAM.full = 0;
334    return (TOKENSTREAM.buffer);
335  }
336
337  // Return empty token if there are no others
338  if (TOKENSTREAM.position == 0 or
339      TOKENSTREAM.position > size(TOKENSTREAM.input))
340  {
341    return (makeToken("empty"));
342  }
343
344  // Get token from TOKENSTREAM.input
345  int i = TOKENSTREAM.position;
346  string s = TOKENSTREAM.input;
347
348  // Skip whitespace
349  while (isWhitespace(s[i]))
350  {
351    i++;
352  }
353
354  if (i > size(s))
355  {
356    ERROR("tsGet() reached end of string!");
357  }
358
359  // switch on s[i]
360  // characters that represent themselves
361  if (isSelfRepresented(s[i]))
362  {
363    TOKENSTREAM.position = i + 1;
364    return (makeToken(s[i]));
365  }
366
367  // numbers
368  if (isDigit(s[i]))
369  {
370    int start = i;
371
372    while (i < size(s))
373    {
374      if (isDigit(s[i + 1]) == 1)
375      {
376        i++;
377      }
378      else
379      {
380        break;
381      }
382    }
383
384    int length = i + 1 - start;
385    string str = s[start, length];
386    TOKENSTREAM.position = i + 1;
387
388    number n = stringToNumber(str);
389    return (makeToken("number", n));
390  }
391
392  // constants,variables and keywords
393  if (isLetter(s[i]))
394  {
395    int start = i;
396
397    while (i < size(s))
398    {
399      if (isLetter(s[i + 1]) == 1 or isDigit(s[i + 1]) == 1 or
400          s[i + 1] == "_")
401      {
402        i++;
403      }
404      else
405      {
406        break;
407      }
408    }
409
410    int length = i + 1 - start;
411    string name = s[start, length];
412    TOKENSTREAM.position = i + 1;
413
414    // keyword
415    if (name == "inv")
416    {
417      return (makeToken("inv"));
418    }
419
420    // constant or variable
421    int isVar = 0;
422    int isDef = 0;
423    string cmd = "if( defined(" + name + ") <> 0 ) {isDef = 1}";
424    execute(cmd);
425    if (isDef)
426    {
427      // constant
428      int isConst = 0;
429      cmd = "if( typeof(" + name + ") == \"number\" ) {isConst = 1}";
430      execute(cmd);
431      cmd = "if( typeof(" + name + ") == \"int\" ) {isConst = 1}";
432      execute(cmd);
433      if (isConst)
434      {
435        cmd = "number value = number(" + name + ");";
436        execute(cmd);
437        return (makeToken("number", value));
438      }
439
440      // variable
441      for (i = 1; i <= size(NCVARIABLES); i++)
442      {
443        if (name == NCVARIABLES[i])
444        {
445          return (makeToken("name", name));
446        }
447      }
448
449      // neither constant nor variable
450      ERROR(name + " already defined, but not a number or a nc variable!");
451    }
452
453    ERROR(name + " is undefined and not a nc variable!");
454  }
455
456  ERROR("Unrecognized input: " + s[i]);
457}
458
459/*##########################################################
460
461  END TOKEN
462
463##########################################################*/
464
465/*##########################################################
466
467   GRAMMAR
468
469##########################################################*/
470
471/*---------------------------------------------------------/
472
473  Input for ncrat function
474  according to the following grammar
475
476    Expression:
477        Term
478        Expression "+" Term
479        Expression "-" Term
480
481    Term:
482        Secondary
483        Term "*" Secondary
484
485    Secondary:
486        Primary
487        Primary "^" int
488        Primary "/" Primary
489
490    Primary:
491        Number
492        "(" Expression ")"
493        "+" Primary
494        "-" Primary
495        "inv(" Expression ")"
496        Name
497
498    Number:
499        digit
500        Number digit
501
502    Name:
503        letter
504        letter Sequence
505
506    Sequence:
507        letter
508        digit
509        "_"
510        letter Sequence
511        digit Sequence
512        "_" Sequence
513
514/---------------------------------------------------------*/
515
516static proc primary()
517{
518  token t = tsGet();
519
520  // switch on t.kind
521  // case "(" Expression ")"
522  if (t.kind == "(")
523  {
524    ncrat f = expression();
525
526    t = tsGet();
527    if (t.kind != ")")
528    {
529      ERROR("')' expected!");
530    }
531    return (f);
532  }
533
534  // unary +
535  if (t.kind == "+")
536  {
537    return (primary());
538  }
539
540  // unary -
541  if (t.kind == "-")
542  {
543    ncrat sign = "Const", list(number(-1));
544    return (sign * primary());
545  }
546
547  // variables and constants
548  if (t.kind == "name")
549  {
550    ncrat f = "Var", list(t.name);
551    return (f);
552  }
553  // numbers
554  if (t.kind == "number")
555  {
556    ncrat f = "Const", list(t.value);
557    return (f);
558  }
559  // inversion
560  if (t.kind == "inv")
561  {
562    t = tsGet();
563    if (t.kind != "(")
564    {
565      ERROR("'(' expected!");
566    }
567
568    ncrat f = expression();
569
570    t = tsGet();
571    if (t.kind != ")")
572    {
573      ERROR(")' expected!");
574    }
575
576    return (ncratInvert(f));
577  }
578
579  ERROR("Primary expected!");
580}
581
582static proc secondary()
583{
584  ncrat left = primary();
585
586  while (1)
587  {
588    token t = tsGet();
589    if (t.kind == "^")
590    {
591      ncrat right = primary();
592
593      if (not(right.kind == "Const"))
594      {
595        ERROR("Expected integer after '^'.");
596      }
597
598      int n = int(right.expr[1]);
599      if (not(number(n) == right.expr[1]))
600      {
601        ERROR(string(right.expr[1]) + " is not an integer!");
602      }
603
604      kill(right);
605      kill(t);
606      return (ncratPower(left, n));
607    }
608
609    if (t.kind == "/")
610    {
611      ncrat right = primary();
612
613      if (not(right.kind == "Const"))
614      {
615        ERROR("Expected number after '/'.");
616      }
617
618      left = left * ncratInvert(right);
619
620      kill(right);
621      kill(t);
622      return (left);
623    }
624
625    tsPutback(t);
626    kill(t);
627    return (left);
628  }
629}
630
631static proc term()
632{
633  ncrat left = secondary();
634
635  while (1)
636  {
637    token t = tsGet();
638    if (t.kind == "*")
639    {
640      ncrat right = secondary();
641      left = left * right;
642      kill(right);
643      kill(t);
644    }
645    else
646    {
647      tsPutback(t);
648      kill(t);
649      return (left);
650    }
651  }
652}
653
654static proc expression()
655{
656  ncrat left = term();
657
658  while (1)
659  {
660    token t = tsGet();
661    if (t.kind == "+")
662    {
663      ncrat right = term();
664      left = left + right;
665      kill(right);
666      kill(t);
667    }
668    else
669    {
670      if (t.kind == "-")
671      {
672        ncrat right = term();
673        left = left - right;
674        kill(right);
675        kill(t);
676      }
677      else
678      {
679        tsPutback(t);
680        kill(t);
681        return (left);
682      }
683    }
684  }
685}
686
687/*##########################################################
688
689  END GRAMMAR
690
691##########################################################*/
692
693/*##########################################################
694
695  END GENERAL
696
697##########################################################*/
698
699/*##########################################################
700
701   NCRAT
702
703##########################################################*/
704
705// Define ring 'NCRING' with variables from list
706static proc ncRingDefine()
707{
708  // Kill old ring if it already exists
709  if (not(defined(NCRING) == 0))
710  {
711    kill(NCRING);
712  }
713
714  // Build new ring
715  int i;
716  string s;
717
718  s = "ring NCRING = (0, I), (";
719  for (i = 1; i <= size(NCVARIABLES); i++)
720  {
721    if (i == 1)
722    {
723      s = s + NCVARIABLES[i];
724    }
725    else
726    {
727      s = s + ", " + NCVARIABLES[i];
728    }
729  }
730  s = s + "), dp; minpoly = I^2+1;";
731  execute(s);
732  short = 0;
733  exportto(Top, NCRING);
734}
735
736static proc ncratIsValid(string s, list l)
737{
738
739  while (1)
740  {
741    if (s == "Const")
742    {
743      if (not((size(l) == 1) and (typeof(l[1]) == "number")))
744      {
745        return (0);
746      }
747      break;
748    }
749
750    if (s == "Var")
751    {
752      if (not((size(l) == 1) and (typeof(l[1]) == "string")))
753      {
754        return (0);
755      }
756      break;
757    }
758
759    if (s == "Add" or s == "Sub" or s == "Mult")
760    {
761      if (not((size(l) == 2) and (typeof(l[1]) == "ncrat") and
762              (typeof(l[2]) == "ncrat")))
763      {
764        return (0);
765      }
766      break;
767    }
768
769    if (s == "Inv")
770    {
771      if (not((size(l) == 1) and (typeof(l[1]) == "ncrat")))
772      {
773        return (0);
774      }
775      break;
776    }
777
778    break;
779  }
780
781  return (1);
782}
783
784/*
785    The following procedures make it possible to evaluate a
786    ncrat f by substituting in the matrices in point for
787    the variables in var
788*/
789
790static proc ncratEvaluateConst(ncrat f, list vars, list point)
791{
792  int g = ncols(point[1]);
793  number n = f.expr[1];
794
795  matrix E[g][g];
796  E = E + 1;
797
798  matrix A = n * E;
799  return (A);
800}
801
802static proc ncratEvaluateAdd(ncrat f, list vars, list point)
803{
804  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
805  matrix B = ncratEvaluateAt(f.expr[2], vars, point);
806  matrix C = A + B;
807  return (C);
808}
809
810static proc ncratEvaluateSub(ncrat f, list vars, list point)
811{
812  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
813  matrix B = ncratEvaluateAt(f.expr[2], vars, point);
814  matrix C = A - B;
815  return (C);
816}
817
818static proc ncratEvaluateMult(ncrat f, list vars, list point)
819{
820  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
821  matrix B = ncratEvaluateAt(f.expr[2], vars, point);
822  matrix C = A * B;
823  return (C);
824}
825
826static proc ncratEvaluateInv(ncrat f, list vars, list point)
827{
828  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
829  matrix C = inverse(A);
830  return (C);
831}
832
833static proc ncratEvaluateVar(ncrat f, list vars, list point)
834{
835  poly p;
836  int i;
837  int index = 0;
838  int g = size(vars);
839
840  for (i = 1; i <= g and index == 0; i++)
841  {
842    p = vars[i];
843    if (string(p) == f.expr[1])
844    {
845      index = i;
846    }
847  }
848
849  matrix C = point[index];
850  return (C);
851}
852
853/*##########################################################
854
855  END NCRAT
856
857##########################################################*/
858
859/*##########################################################
860
861   NCREP
862
863##########################################################*/
864
865// Handle constants
866static proc ncrepConst(number n)
867{
868  ncrep q;
869  matrix left[1][2] = 0, 1;
870  matrix right[2][1] = 0, 1;
871  matrix Q[2][2] = n, -1, -1, 0;
872  q.lvec = left;
873  q.rvec = right;
874  q.mat = Q;
875  return (q);
876}
877
878// Handle variables
879static proc ncrepVar(poly p)
880{
881  ncrep q;
882  matrix left[1][2] = 0, 1;
883  matrix right[2][1] = 0, 1;
884  matrix Q[2][2] = p, -1, -1, 0;
885  q.lvec = left;
886  q.rvec = right;
887  q.mat = Q;
888  return (q);
889}
890
891// Substitute all occurences of VARIABLE*E in M with A
892static proc ncSubMat(matrix M, matrix A, poly VARIABLE)
893{
894  int N = ncols(A);
895  int N2 = ncols(M);
896  int N3 = N2 div N;
897  if (not(N * N3 == N2))
898  {
899    ERROR("Size of arg1 must be a multiple of size of arg2!");
900  }
901
902  int n, m, i, j;
903  poly p;
904  for (i = 1; i <= N3; i++)
905  {
906    for (j = 1; j <= N3; j++)
907    {
908      p = M[1 + (i - 1) * N, 1 + (j - 1) * N] / VARIABLE;
909      if (not(p == 0))
910      {
911        M[1 + (i - 1) * N..i * N, 1 + (j - 1) * N..j * N] = p * A;
912      }
913    }
914  }
915  return (M);
916}
917
918/*
919  list # = (x1, ..., xg) contains the nc variables
920  occuring in g
921  return list(Q0, Q1,... Qg) with scalar matrices Qi s.t.
922    Q = Q0 + Q1*x1 + ... + Qg*xg
923*/
924static proc ncrepLinearPencil(ncrep q, list #)
925{
926  int g = size(#);
927  int n = ncols(q.mat);
928
929  int i, j, k;
930  poly p;
931  matrix Q(0) = q.mat;
932  for (i = 1; i <= g; i++)
933  {
934    matrix Q(i)[n][n];
935    for (j = 1; j <= n; j++)
936    {
937      for (k = 1; k <= n; k++)
938      {
939        p = Q(0)[j, k] / #[i];
940        if (not(p == 0))
941        {
942          Q(i)
943          [j, k] = p;
944        }
945      }
946    }
947    Q(0) = Q(0) - #[i] * Q(i);
948  }
949
950  list l;
951  for (i = 0; i <= g; i++)
952  {
953    l = l + list(Q(i));
954  }
955
956  return (l);
957}
958
959/*##########################################################
960
961   REGULAR CASE
962
963##########################################################*/
964
965/*
966  g - number of nc variables
967  n - dimension
968  q - REGULAR ncrep
969  # - contains occuring ncvariables as 'poly'
970  Returns list(B, C, l) with l = list(A1, ..., Ag) such that
971  -u*Q^-1*v = C * (1 - A1*x1 - ... - Ag*xg)^-1 * B.
972
973  ASSUMPTION: q.mat has to be regular at zero
974*/
975static proc ncrepToMonicDescriptorRealization(int g, int n, ncrep q, list #)
976{
977  if (not(size(#) == g))
978  {
979    ERROR("List has wrong size!");
980  }
981
982  list l = ncrepLinearPencil(q, #);
983  matrix Q(0) = l[1];
984  matrix S = inverse(Q(0));
985
986  if (size(S) == 1 and S[1, 1] == 0)
987  {
988    ERROR("Q0 has to be invertible!");
989  }
990
991  list k;
992  int i;
993  for (i = 1; i <= g; i++)
994  {
995    matrix Q(i) = l[i + 1];
996    matrix A(i) = -S * Q(i);
997    k = k + list(A(i));
998  }
999
1000  matrix C = -q.lvec;
1001  matrix B = S * q.rvec;
1002  return (list(B, C, k));
1003}
1004
1005/*
1006  g - number of nc variables
1007  n - dimension
1008  v - vector in C^n (that is, nx1-matrix)
1009  # - list containing nxn-matrices A_1, ..., A_g
1010
1011  This procedure calculates the following subspace of C^n:
1012    S = span { A_i1 ... A_ik v | k in N, 1 <= i1, ... ik <= g }
1013
1014  It returns a basis of this space.
1015*/
1016static proc calculateControllabilitySpace(int g, int n, matrix v, list #)
1017{
1018  if (size(#) != g)
1019  {
1020    ERROR("List has wrong size!");
1021  }
1022
1023  if (not(ncols(v) == 1 and nrows(v) == n))
1024  {
1025    ERROR("Matrix must be of size " + string(n) + "x1!");
1026  }
1027
1028  int i;
1029  for (i = 1; i <= g; i++)
1030  {
1031    if (typeof(#[i]) != "matrix")
1032    {
1033      ERROR("List must only contain matrices!");
1034    }
1035    matrix A(i) = #[i];
1036  }
1037
1038  // case v = 0
1039  if (isMatrixEmpty(v))
1040  {
1041    return (list(v));
1042  }
1043
1044  // case v != 0
1045  // case n = 1
1046  if (n == 1)
1047  {
1048    return (list(v));
1049  }
1050
1051  // case n > 1
1052  list b = list(v);
1053  list s = b;
1054  matrix baseMat = v;
1055  matrix testMat;
1056  int oldSize = size(b);
1057  int j;
1058
1059  while (1)
1060  {
1061    list m;
1062
1063    // m = {A1, ..., Ag} * s
1064    for (i = 1; i <= g; i++)
1065    {
1066      for (j = 1; j <= size(s); j++)
1067      {
1068        m = m + list(A(i) * s[j]);
1069      }
1070    }
1071
1072    // check if mi is linearly independent of b
1073    // in this case append to b, and build new s
1074    kill(s);
1075    list s;
1076
1077    for (i = 1; i <= size(m); i++)
1078    {
1079      testMat = concat(baseMat, m[i]);
1080
1081      if (rank(testMat) == ncols(testMat))
1082      {
1083        s = s + list(m[i]);
1084        b = b + list(m[i]);
1085        baseMat = testMat;
1086
1087        if (size(b) == n)
1088        {
1089          return (b);
1090        }
1091      }
1092    }
1093
1094    kill(m);
1095    if (size(b) == oldSize)
1096    {
1097      return (b);
1098    }
1099    oldSize = size(b);
1100  }
1101}
1102
1103/*
1104  n - dimension of whole space
1105  b - list containing a basis of S
1106
1107  Calculates a list c containing a basis of S^ortho, i.e.,
1108    C^n = S directsum S^ortho.
1109*/
1110static proc calculateComplement(int n, list b)
1111{
1112  list c;
1113  int i;
1114
1115  // case S = C^n
1116  if (size(b) == n)
1117  {
1118    return (c);
1119  }
1120
1121  for (i = 1; i <= n; i++)
1122  {
1123    matrix e(i)[n][1];
1124    e(i)[i, 1] = 1;
1125  }
1126
1127  // case S = {0}
1128  if (isMatrixEmpty(b[1]))
1129  {
1130    for (i = 1; i <= n; i++)
1131    {
1132      c = c + list(e(i));
1133    }
1134    return (c);
1135  }
1136
1137  // case 0 < dim S < n
1138  matrix baseMat = b[1];
1139  for (i = 2; i <= size(b); i++)
1140  {
1141    baseMat = concat(baseMat, b[i]);
1142  }
1143
1144  matrix testMat;
1145  for (i = 1; i <= n; i++)
1146  {
1147    testMat = concat(baseMat, e(i));
1148
1149    if (rank(testMat) == ncols(testMat))
1150    {
1151      c = c + list(e(i));
1152      baseMat = testMat;
1153
1154      if (ncols(baseMat) == n)
1155      {
1156        return (c);
1157      }
1158    }
1159  }
1160}
1161
1162// INPUT: list containing basis vectors
1163// OUTPUT: orthogonal matrix, whose colums span the same space
1164static proc orthogonalBase(list b)
1165{
1166  matrix B;
1167
1168  if (size(b) == 0)
1169  {
1170    return (B);
1171  }
1172
1173  B = b[1];
1174  int i;
1175  for (i = 2; i <= size(b); i++)
1176  {
1177    B = concat(B, b[i]);
1178  }
1179  return (orthogonalize(B));
1180}
1181
1182/*
1183  bMat - orthogonal matrix whose columns span S
1184  cMat - orthogonal matrix whose columns span S^ortho
1185  # - matrices A1, ..., Ag
1186  Returns ( P^-1 * B, C * P, list( P^-1 * Ai * P ) ), where P = (bMat cMat).
1187*/
1188static proc orthogonalTransform(matrix bMat, matrix cMat, matrix B, matrix C,
1189                                list #)
1190{
1191  int i;
1192  list l;
1193  int bMatEmpty = isMatrixEmpty(bMat);
1194  int cMatEmpty = isMatrixEmpty(cMat);
1195
1196  // Define orthogonal transformation
1197  if (bMatEmpty)
1198  {
1199    if (cMatEmpty)
1200    {
1201      ERROR("Both empty!");
1202    }
1203    else
1204    {
1205      matrix P = cMat;
1206    }
1207  }
1208  else
1209  {
1210    if (cMatEmpty)
1211    {
1212      matrix P = bMat;
1213    }
1214    else
1215    {
1216      matrix P = concat(bMat, cMat);
1217    }
1218  }
1219
1220  matrix PInv = inverse(P);
1221  B = PInv * B;
1222  C = C * P;
1223
1224  for (i = 1; i <= size(#); i++)
1225  {
1226    matrix A(i) = PInv * #[i] * P;
1227    l = l + list(A(i));
1228  }
1229
1230  return (list(B, C, l));
1231}
1232
1233/*
1234  n - dimension to cut down to
1235  offset - where to cut out
1236  # - matrices A1, ..., Ag
1237  C * (1 - A1 x1 - .. - Ag xg)^(-1) * B monic descriptor realization
1238*/
1239static proc cutdown(int n, int offset, matrix B, matrix C, list #)
1240{
1241  int a = 1 + offset;
1242  int b = n + offset;
1243
1244  // Case B or C is zero
1245  if (isMatrixEmpty(B) or isMatrixEmpty(C))
1246  {
1247    matrix zero[1][1] = 0;
1248    list zerolist;
1249    int i;
1250    for (i = 1; i <= size(#); i++)
1251    {
1252      zerolist = zerolist + list(zero);
1253    }
1254    return (zero, zero, zerolist);
1255  }
1256
1257  // Case B and C not zero
1258  matrix B2 = submat(B, a..b, 1..1);
1259  matrix C2 = submat(C, 1..1, a..b);
1260
1261  list l;
1262  int i;
1263  for (i = 1; i <= size(#); i++)
1264  {
1265    matrix A2(i) = submat(#[i], a..b, a..b);
1266    l = l + list(A2(i));
1267  }
1268
1269  return (list(B2, C2, l));
1270}
1271
1272/*##########################################################
1273
1274  END REGULAR CASE
1275
1276##########################################################*/
1277
1278/*##########################################################
1279
1280  END NCREP
1281
1282##########################################################*/
1283
1284/*##########################################################
1285
1286  END STATIC PROCEDURES
1287
1288##########################################################*/
1289
1290/*##########################################################
1291
1292   NON-STATIC PROCEDURES
1293
1294##########################################################*/
1295
1296/*##########################################################
1297
1298   GENERAL
1299
1300##########################################################*/
1301
1302proc ncInit(list vars)
1303"USAGE:   ncInit(vars);
1304  list vars containing strings
1305
1306RETURN:
1307  datatypes ncrat and ncrep (and token, tokenstream,
1308  but they are not meant for users),
1309  sets ring as 'NCRING' with nc variables from list l
1310
1311EXAMPLE:  example ncInit;
1312  shows an example"
1313{
1314  // Check if already initialized
1315  // In this case just add missing variables
1316  if (defined(NCRATINITIALIZE))
1317  {
1318    if (!defined(basering))
1319    {
1320      ncRingDefine();
1321    }
1322    return ();
1323  }
1324  int NCRATINITIALIZE = 1;
1325  export(NCRATINITIALIZE);
1326
1327  // Check if variables are specified
1328  if (size(vars) == 0)
1329  {
1330    ERROR("No nc variables specified!");
1331  }
1332
1333  /*---------------------------------------------------------/
1334
1335      Datatype 'ncrat' for nc rational functions
1336
1337      The following constructions are allowed:
1338        ("Const", [number])           constant
1339        ("Var",   [string])           variable
1340        ("Add",   [ncrat, ncrat])     addition
1341        ("Sub",   [ncrat, ncrat])     substraction
1342        ("Mult",  [ncrat, ncrat])     multiplication
1343        ("Inv",   [ncrat])            inverse
1344
1345  /---------------------------------------------------------*/
1346
1347  newstruct("ncrat", "
1348    string kind,
1349    list expr
1350  ");
1351
1352
1353  /*---------------------------------------------------------/
1354
1355      Struct for representations
1356
1357  /---------------------------------------------------------*/
1358
1359  newstruct("ncrep", "
1360    matrix lvec,
1361    matrix mat,
1362    matrix rvec
1363  ");
1364
1365
1366  /*---------------------------------------------------------/
1367
1368      Structs for handling input
1369
1370  /---------------------------------------------------------*/
1371
1372  newstruct("token", "
1373    string kind,
1374    number value,
1375    string name
1376  ");
1377
1378
1379  newstruct("tokenstream", "
1380    int full,
1381    int position,
1382    token buffer,
1383    string input
1384  ");
1385
1386
1387  /*---------------------------------------------------------/
1388
1389      Overloading operators for ncrat and ncrep
1390
1391  /---------------------------------------------------------*/
1392
1393  system("install", "ncrat", "=", ncratDefine, 1);
1394  system("install", "ncrat", "+", ncratAdd, 2);
1395  system("install", "ncrat", "-", ncratSubstract, 2);
1396  system("install", "ncrat", "*", ncratMultiply, 2);
1397  system("install", "ncrat", "^", ncratPower, 2);
1398  system("install", "ncrat", "print", ncratPrint, 1);
1399  system("install", "ncrep", "+", ncrepAdd, 2);
1400  system("install", "ncrep", "-", ncrepSubstract, 2);
1401  system("install", "ncrep", "*", ncrepMultiply, 2);
1402  system("install", "ncrep", "print", ncrepPrint, 1);
1403
1404
1405  /*---------------------------------------------------------/
1406
1407      Global objects
1408
1409  /---------------------------------------------------------*/
1410
1411  list NCVARIABLES = vars;
1412  export(NCVARIABLES);
1413
1414  tokenstream TOKENSTREAM = makeTokenStream();
1415  export(TOKENSTREAM);
1416
1417  ncRingDefine();
1418}
1419example
1420{
1421  "EXAMPLE:";
1422  echo = 2;
1423  ncInit(list("x", "y", "z"));
1424  NCRING;
1425}
1426
1427proc ncVarsGet()
1428"USAGE:   ncVarsGet();
1429
1430RETURNS:
1431  nc variables that are in use
1432
1433EXAMPLE:  example ncVarsGet;
1434shows an example"
1435{
1436  string(NCVARIABLES);
1437}
1438example
1439{
1440  "EXAMPLE:";
1441  echo = 2;
1442  ncInit(list("x", "y", "z"));
1443  ncVarsGet();
1444}
1445
1446proc ncVarsAdd(list vars)
1447"USAGE:   ncVarsAdd(vars);
1448  list vars contains variables
1449
1450RETURNS:
1451  sets list elements as nc variables
1452
1453EXAMPLE:  example ncVarsAdd;
1454shows an example"
1455{
1456  int i, j;
1457  int exists = 0;
1458
1459  for (i = 1; i <= size(vars); i++)
1460  {
1461    for (j = 1; j <= size(NCVARIABLES); j++)
1462    {
1463      if (vars[i] == NCVARIABLES[j])
1464      {
1465        exists = 1;
1466      }
1467    }
1468    if (exists == 0)
1469    {
1470      NCVARIABLES = NCVARIABLES + list(vars[i]);
1471    }
1472    else
1473    {
1474      exists = 0;
1475    }
1476  }
1477
1478  ncRingDefine();
1479}
1480example
1481{
1482  "EXAMPLE:";
1483  echo = 2;
1484  ncInit(list("x", "y", "z"));
1485  ncVarsGet();
1486  ncVarsAdd(list("a", "b", "c"));
1487  ncVarsGet();
1488}
1489
1490/*##########################################################
1491
1492  END GENERAL
1493
1494##########################################################*/
1495
1496/*##########################################################
1497
1498   NCRAT
1499
1500##########################################################*/
1501
1502proc ncratDefine(string s, list l)
1503"USAGE:   ncrat f = ncratDefine(s, l);
1504  string s contains kind, list l contains expressions
1505
1506RETURN:   ncrat with kind s and expressions l
1507
1508NOTE:
1509  assignment operator '=' for ncrat is overloaded
1510  with this procedure, hence
1511      ncrat f = s, l;
1512  yields the same result as
1513      ncrat f = ncratDefine(s, l);
1514
1515EXAMPLE:  example ncratDefine;
1516  shows an example"
1517{
1518  if (not(ncratIsValid(s, l)))
1519  {
1520    ERROR("Not a valid rational expression!");
1521  }
1522
1523  ncrat f;
1524  f.kind = s;
1525  f.expr = l;
1526  return (f);
1527}
1528example
1529{
1530  "EXAMPLE:";
1531  echo = 2;
1532  ncInit(list("x", "y", "z"));
1533  number n = 5;
1534  ncrat f = ncratDefine("Const", list(n));
1535  typeof(f);
1536  f.kind;
1537  f.expr;
1538  f;
1539  ncrat g = "Const", list(n);
1540  g;
1541}
1542
1543proc ncratAdd(ncrat f, ncrat g)
1544"USAGE:   ncrat h = ncratAdd(f, g);
1545  f, g both of type ncrat
1546
1547RETURN:   h = f + g
1548
1549NOTE:
1550  operator '+' for ncrat is overloaded
1551  with this procedure, hence
1552      ncrat h = f + g;
1553  yields the same result as
1554      ncrat h = ncratAdd(f, g);
1555
1556EXAMPLE:  example ncratAdd;
1557  shows an example"
1558{
1559  ncrat h = "Add", list(f, g);
1560  return (h);
1561}
1562example
1563{
1564  "EXAMPLE:";
1565  echo = 2;
1566  ncInit(list("x", "y", "z"));
1567  ncrat f = ncratFromString("2*x*y");
1568  print(f);
1569  ncrat g = ncratFromString("z");
1570  print(g);
1571  ncrat h1, h2;
1572  h1 = ncratAdd(f, g);
1573  print(h1);
1574  h2 = f + g;
1575  print(h2);
1576}
1577
1578proc ncratSubstract(ncrat f, ncrat g)
1579"USAGE:   ncrat h = ncratSubstract(f, g);
1580  f, g both of type ncrat
1581
1582RETURN:   h = f - g
1583
1584NOTE:
1585  operator '-' for ncrat is overloaded
1586  with this procedure, hence
1587      ncrat h = f - g;
1588  yields the same result as
1589      ncrat h = ncratSubstract(f, g);
1590
1591EXAMPLE:  example ncratSubstract;
1592  shows an example"
1593{
1594  ncrat h = "Sub", list(f, g);
1595  return (h);
1596}
1597example
1598{
1599  "EXAMPLE:";
1600  echo = 2;
1601  ncInit(list("x", "y", "z"));
1602  ncrat f = ncratFromString("2*x*y");
1603  print(f);
1604  ncrat g = ncratFromString("z");
1605  print(g);
1606  ncrat h1, h2;
1607  h1 = ncratSubstract(f, g);
1608  print(h1);
1609  h2 = f - g;
1610  print(h2);
1611}
1612
1613proc ncratMultiply(ncrat f, ncrat g)
1614"USAGE:   ncrat h = ncratMultiply(f, g);
1615  f, g both of type ncrat
1616
1617RETURN:   h = f * g
1618
1619NOTE:
1620  operator '*' for ncrat is overloaded
1621  with this procedure, hence
1622      ncrat h = f * g;
1623  yields the same result as
1624      ncrat h = ncratMultiply(f, g);
1625
1626EXAMPLE:  example ncratMultiply;
1627  shows an example"
1628{
1629  // Both factors are constants
1630  if (f.kind == "Const" and g.kind == "Const")
1631  {
1632    ncrat h = "Const", list(f.expr[1] * g.expr[1]);
1633    return (h)
1634  }
1635
1636  // Only second factor is a constant
1637  // Switch order of multiplication
1638  if (g.kind == "Const")
1639  {
1640    return (ncratMultiply(g, f));
1641  }
1642
1643  // Otherwise
1644  ncrat h = "Mult", list(f, g);
1645  return (h);
1646}
1647example
1648{
1649  "EXAMPLE:";
1650  echo = 2;
1651  ncInit(list("x", "y", "z"));
1652  ncrat f = ncratFromString("2*x*y");
1653  print(f);
1654  ncrat g = ncratFromString("z");
1655  print(g);
1656  ncrat h1, h2;
1657  h1 = ncratMultiply(f, g);
1658  print(h1);
1659  h2 = f * g;
1660  print(h2);
1661}
1662
1663proc ncratInvert(ncrat f)
1664"USAGE:   ncrat h = ncratInvert(f);
1665  f of type ncrat
1666
1667RETURN:   h = inv(f)
1668
1669NOTE:
1670      ncrat h = f^-1;
1671  yields the same result as
1672      ncrat h = ncratInvert(f);
1673
1674EXAMPLE:  example ncratInvert;
1675  shows an example"
1676{
1677  ncrat h;
1678  if (f.kind == "Const")
1679  {
1680    if (f.expr[1] != 0)
1681    {
1682      number n = 1;
1683      number m = f.expr[1];
1684      h = "Const", list(n / m);
1685      return (h);
1686    }
1687  }
1688  h = "Inv", list(f);
1689  return (h);
1690}
1691example
1692{
1693  "EXAMPLE:";
1694  echo = 2;
1695  ncInit(list("x", "y", "z"));
1696  ncrat f = ncratFromString("2*x*y");
1697  print(f);
1698  ncrat h1, h2;
1699  h1 = ncratInvert(f);
1700  print(h1);
1701  h2 = f ^ -1;
1702  print(h2);
1703}
1704
1705proc ncratSPrint(ncrat f)
1706"USAGE:   string s = ncratSPrint(f);
1707  f of type ncrat
1708
1709RETURN:   prints f to string
1710
1711EXAMPLE:  example ncratSPrint;
1712  shows an example"
1713{
1714  string t, h, k;
1715  string s = f.kind;
1716  list l = f.expr;
1717
1718  if (s == "Const")
1719  {
1720    t = string(l[1]);
1721  }
1722
1723  if (s == "Var")
1724  {
1725    t = l[1];
1726  }
1727
1728  if (s == "Add")
1729  {
1730    t = ncratSPrint(l[1]) + "+" + ncratSPrint(l[2]);
1731  }
1732
1733  if (s == "Sub")
1734  {
1735    if (l[2].kind == "Add" or l[2].kind == "Sub")
1736    {
1737      h = "(" + ncratSPrint(l[2]) + ")";
1738    }
1739    else
1740    {
1741      h = ncratSPrint(l[2]);
1742    }
1743    t = ncratSPrint(l[1]) + "-" + h;
1744  }
1745
1746  if (s == "Mult")
1747  {
1748    if (l[1].kind == "Add" or l[1].kind == "Sub")
1749    {
1750      h = "(" + ncratSPrint(l[1]) + ")";
1751    }
1752    else
1753    {
1754      h = ncratSPrint(l[1]);
1755    }
1756    if (l[2].kind == "Add" or l[2].kind == "Sub")
1757    {
1758      k = "(" + ncratSPrint(l[2]) + ")";
1759    }
1760    else
1761    {
1762      k = ncratSPrint(l[2]);
1763    }
1764    t = h + "*" + k;
1765  }
1766
1767  if (s == "Inv")
1768  {
1769    t = "inv(" + ncratSPrint(l[1]) + ")";
1770  }
1771
1772  return (t);
1773}
1774example
1775{
1776  "EXAMPLE:";
1777  echo = 2;
1778  ncInit(list("x", "y", "z"));
1779  ncrat f = ncratFromString("2*x*y");
1780  string s = ncratSPrint(f);
1781  print(s);
1782}
1783
1784proc ncratPrint(ncrat f)
1785"USAGE:   ncratPrint(f);
1786  f of type ncrat
1787
1788RETURN:   prints f
1789
1790NOTE:
1791      print(f);
1792  yields the same result as
1793      ncratPrint(f);
1794
1795EXAMPLE:  example ncratPrint;
1796  shows an example"
1797{
1798  print(ncratSPrint(f));
1799}
1800example
1801{
1802  "EXAMPLE:";
1803  echo = 2;
1804  ncInit(list("x", "y", "z"));
1805  ncrat f = ncratFromString("2*x*y");
1806  ncratPrint(f);
1807  print(f);
1808}
1809
1810proc ncratFromString(string s)
1811"USAGE:   ncrat f = ncratFromString(s);
1812  s of type string
1813
1814RETURN:   read string s into ncrat f
1815
1816EXAMPLE:  example ncratFromString;
1817  shows an example"
1818{
1819  // Clear tokenstream
1820  TOKENSTREAM.input = s;
1821  TOKENSTREAM.position = 1;
1822  TOKENSTREAM.full = 0;
1823
1824  ncrat f = expression();
1825  return (f);
1826}
1827example
1828{
1829  "EXAMPLE:";
1830  echo = 2;
1831  ncInit(list("x", "y", "z"));
1832  ncrat f = ncratFromString("2*x*y");
1833  print(f);
1834}
1835
1836proc ncratFromPoly(poly p)
1837"USAGE:   ncrat f = ncratFromPoly(p);
1838  p of type poly
1839
1840RETURN:   convert poly to ncrat
1841
1842EXAMPLE:  example ncratFromPoly;
1843  shows an example"
1844{
1845  string s = print(p);
1846  ncrat f = ncratFromString(s);
1847  return (f);
1848}
1849example
1850{
1851  "EXAMPLE:";
1852  echo = 2;
1853  ncInit(list("x", "y", "z"));
1854  poly p = 2 * x * y;
1855  ncrat f = ncratFromPoly(p);
1856  print(f);
1857}
1858
1859proc ncratPower(ncrat f, int n)
1860"USAGE:   ncrat h = ncratPower(f, n);
1861  f of type ncrat, n integer
1862
1863RETURN:   h = f^n
1864
1865EXAMPLE:  example ncratPower;
1866  shows an example"
1867{
1868  if (n < 0)
1869  {
1870    return (ncratInvert(ncratPower(f, -n)));
1871  }
1872
1873  if (n == 0)
1874  {
1875    return (ncratFromString("1"));
1876  }
1877
1878  if (n == 1)
1879  {
1880    return (f);
1881  }
1882
1883  return (ncratPower(f, n - 1) * f);
1884}
1885example
1886{
1887  "EXAMPLE:";
1888  echo = 2;
1889  ncInit(list("x", "y", "z"));
1890  ncrat f = ncratFromString("2*x*y");
1891  ncrat h = ncratPower(f, 3);
1892  print(h);
1893}
1894
1895proc ncratEvaluateAt(ncrat f, list vars, list point)
1896"USAGE:   matrix M = ncratEvaluateAt(f, vars, point);
1897
1898RETURN:   Evaluate the ncrat f by substituting in the
1899  matrices contained in point for the respective
1900  variables contained in var, that is, calculate
1901  f(point).
1902
1903EXAMPLE:  example ncratEvaluateAt;
1904  shows an example"
1905{
1906  string s = f.kind;
1907
1908  if (s == "Const")
1909  {
1910    matrix A = ncratEvaluateConst(f, vars, point);
1911    return (A);
1912  }
1913
1914  if (s == "Add")
1915  {
1916    matrix A = ncratEvaluateAdd(f, vars, point);
1917    return (A);
1918  }
1919
1920  if (s == "Sub")
1921  {
1922    matrix A = ncratEvaluateSub(f, vars, point);
1923    return (A);
1924  }
1925
1926  if (s == "Mult")
1927  {
1928    matrix A = ncratEvaluateMult(f, vars, point);
1929    return (A);
1930  }
1931
1932  if (s == "Inv")
1933  {
1934    matrix A = ncratEvaluateInv(f, vars, point);
1935    return (A);
1936  }
1937
1938  if (s == "Var")
1939  {
1940    matrix A = ncratEvaluateVar(f, vars, point);
1941    return (A);
1942  }
1943}
1944example
1945{
1946  "EXAMPLE:";
1947  echo = 2;
1948  ncInit(list("x", "y"));
1949  ncrat f = ncratFromString("x+y");
1950  matrix A[2][2] = 1, 2, 3, 4;
1951  matrix B[2][2] = 5, 6, 7, 8;
1952  matrix M = ncratEvaluateAt(f, list(x, y), list(A, B));
1953  print(M);
1954}
1955
1956/*##########################################################
1957
1958  END NCRAT
1959
1960##########################################################*/
1961
1962/*##########################################################
1963
1964   NCREP
1965
1966##########################################################*/
1967
1968proc ncrepGet(ncrat f)
1969"USAGE:   ncrep q = ncrepGet(f);
1970  f of type ncrat
1971
1972RETURN:   q = (u, Q, v) linear representation of f
1973
1974EXAMPLE:  example ncrepGet;
1975  shows an example"
1976{
1977  ncrep q;
1978
1979  // switch on f.kind
1980  if (f.kind == "Const")
1981  {
1982    q = ncrepConst(f.expr[1]);
1983    return (q);
1984  }
1985
1986  if (f.kind == "Var")
1987  {
1988    string s = "poly p = " + f.expr[1] + ";";
1989    execute(s);
1990    q = ncrepVar(p);
1991    return (q);
1992  }
1993
1994  if (f.kind == "Add")
1995  {
1996    q = ncrepAdd(ncrepGet(f.expr[1]), ncrepGet(f.expr[2]));
1997    return (q);
1998  }
1999
2000  if (f.kind == "Sub")
2001  {
2002    q = ncrepSubstract(ncrepGet(f.expr[1]), ncrepGet(f.expr[2]));
2003    return (q);
2004  }
2005
2006  if (f.kind == "Mult")
2007  {
2008    // First factor is a non-zero constant
2009    if (f.expr[1].kind == "Const")
2010    {
2011      if (f.expr[1].expr[1] != 0) {
2012        q = ncrepGet(f.expr[2]);
2013        q.mat = q.mat / f.expr[1].expr[1];
2014        return (q);
2015      }
2016    }
2017
2018    // Second factor is a non-zero constant
2019    if (f.expr[2].kind == "Const")
2020    {
2021      if (f.expr[2].expr[1] != 0) {
2022        q = ncrepGet(f.expr[1]);
2023        q.mat = q.mat / f.expr[2].expr[1];
2024        return (q);
2025      }
2026    }
2027
2028    // No constant factors
2029    q = ncrepMultiply(ncrepGet(f.expr[1]), ncrepGet(f.expr[2]));
2030    return (q);
2031  }
2032
2033  if (f.kind == "Inv")
2034  {
2035    q = ncrepInvert(ncrepGet(f.expr[1]));
2036    return (q);
2037  }
2038}
2039example
2040{
2041  "EXAMPLE:";
2042  echo = 2;
2043  ncInit(list("x", "y", "z"));
2044  ncrat f = ncratFromString("2*x*y");
2045  ncrep q = ncrepGet(f);
2046  print(q);
2047}
2048
2049proc ncrepAdd(ncrep s, ncrep t)
2050"USAGE:   ncrep s = ncrepAdd(q, r);
2051  q, r both of type ncrep
2052
2053RETURN:   representation s of h = f + g
2054  if q, r are representations of f, g
2055
2056NOTE:
2057  operator '+' for ncrep is overloaded
2058  with this procedure, hence
2059      ncrep s = q + r;
2060  yields the same result as
2061      ncrep s = ncrepAdd(q, r);
2062
2063EXAMPLE:  example ncrepAdd;
2064  shows an example"
2065{
2066  ncrep q;
2067  q.lvec = concat(s.lvec, t.lvec);
2068  q.rvec = transpose(concat(transpose(s.rvec), transpose(t.rvec)));
2069  q.mat = dsum(s.mat, t.mat);
2070  return (q);
2071}
2072example
2073{
2074  "EXAMPLE:";
2075  echo = 2;
2076  ncInit(list("x", "y", "z"));
2077  ncrat f = ncratFromString("x");
2078  ncrat g = ncratFromString("y");
2079  ncrep q = ncrepGet(f);
2080  ncrep r = ncrepGet(g);
2081  ncrep s1, s2;
2082  s1 = ncrepAdd(q, r);
2083  print(s1);
2084  s2 = q + r;
2085  print(s2);
2086}
2087
2088proc ncrepSubstract(ncrep s, ncrep t)
2089"USAGE:   ncrep s = ncrepSubstract(q, r);
2090  q, r both of type ncrep
2091
2092RETURN:   representation s of h = f - g
2093  if q, r are representations of f, g
2094
2095NOTE:
2096  operator '-' for ncrep is overloaded
2097  with this procedure, hence
2098      ncrep s = q - r;
2099  yields the same result as
2100      ncrep s = ncrepSubstract(q, r);
2101
2102EXAMPLE:  example ncrepSubstract;
2103  shows an example"
2104{
2105  ncrep q;
2106  q.lvec = concat(s.lvec, t.lvec);
2107  q.rvec = transpose(concat(transpose(s.rvec), transpose(t.rvec)));
2108  q.mat = dsum(s.mat, -t.mat);
2109  return (q);
2110}
2111example
2112{
2113  "EXAMPLE:";
2114  echo = 2;
2115  ncInit(list("x", "y", "z"));
2116  ncrat f = ncratFromString("x");
2117  ncrat g = ncratFromString("y");
2118  ncrep q = ncrepGet(f);
2119  ncrep r = ncrepGet(g);
2120  ncrep s1, s2;
2121  s1 = ncrepSubstract(q, r);
2122  print(s1);
2123  s2 = q - r;
2124  print(s2);
2125}
2126
2127proc ncrepMultiply(ncrep s, ncrep t)
2128"USAGE:   ncrep s = ncrepMultiply(q, r);
2129  q, r both of type ncrep
2130
2131RETURN:   representation s of h = f * g
2132  if q, r are representations of f, g
2133
2134NOTE:
2135  operator '*' for ncrep is overloaded
2136  with this procedure, hence
2137      ncrep s = q * r;
2138  yields the same result as
2139      ncrep s = ncrepMultiply(q, r);
2140
2141EXAMPLE:  example ncrepMultiply;
2142  shows an example"
2143{
2144  ncrep q;
2145  int dims = ncols(s.lvec);
2146  int dimt = ncols(t.lvec);
2147  matrix lzero[1][dimt] = 0;
2148  matrix rzero[dims][1] = 0;
2149  matrix mzero[dimt][dims] = 0;
2150
2151  q.lvec = concat(lzero, s.lvec);
2152  q.rvec = transpose(concat(transpose(rzero), transpose(t.rvec)));
2153
2154  matrix A = concat(s.rvec * t.lvec, s.mat);
2155  matrix B = concat(t.mat, mzero);
2156  q.mat = transpose(concat(transpose(A), transpose(B)));
2157
2158  return (q);
2159}
2160example
2161{
2162  "EXAMPLE:";
2163  echo = 2;
2164  ncInit(list("x", "y", "z"));
2165  ncrat f = ncratFromString("x");
2166  ncrat g = ncratFromString("y");
2167  ncrep q = ncrepGet(f);
2168  ncrep r = ncrepGet(g);
2169  ncrep s1, s2;
2170  s1 = ncrepMultiply(q, r);
2171  print(s1);
2172  s2 = q * r;
2173  print(s2);
2174}
2175
2176proc ncrepInvert(ncrep s)
2177"USAGE:   ncrep s = ncrepInvert(q);
2178  q of type ncrep
2179
2180RETURN:   representation of h = inv(f)
2181  if q is a representation of f
2182
2183EXAMPLE:  example ncrepInvert;
2184  shows an example"
2185{
2186  ncrep q;
2187  int n = ncols(s.lvec);
2188  matrix one[1][1] = 1;
2189  matrix vzero[1][n] = 0;
2190  matrix mzero[1][1] = 0;
2191
2192  q.lvec = concat(one, vzero);
2193  q.rvec = transpose(q.lvec);
2194
2195  matrix A = concat(mzero, s.lvec);
2196  matrix B = concat(s.rvec, -s.mat);
2197  q.mat = transpose(concat(transpose(A), transpose(B)));
2198
2199  return (q);
2200}
2201example
2202{
2203  "EXAMPLE:";
2204  echo = 2;
2205  ncInit(list("x", "y", "z"));
2206  ncrat f = ncratFromString("2*x*y");
2207  ncrep q = ncrepGet(f);
2208  ncrep s = ncrepInvert(q);
2209  print(s);
2210}
2211
2212proc ncrepPrint(ncrep q)
2213"USAGE:   ncrepPrint(q);
2214  q of type ncrep
2215
2216RETURN:   prints q
2217
2218NOTE:
2219      print(q);
2220  yields the same result as
2221      ncrepPrint(q);
2222
2223EXAMPLE:  example ncrepPrint;
2224  shows an example"
2225{
2226  print("lvec=");
2227  print(q.lvec);
2228  print(newline + "mat=");
2229  print(q.mat);
2230  print(newline + "rvec=");
2231  print(q.rvec);
2232}
2233example
2234{
2235  "EXAMPLE:";
2236  echo = 2;
2237  ncInit(list("x", "y", "z"));
2238  ncrat f = ncratFromString("2*x*y");
2239  ncrep q = ncrepGet(f);
2240  ncrepPrint(q);
2241  print(q);
2242}
2243
2244proc ncrepDim(ncrep q)
2245"USAGE:   ncrepDim(q);
2246  q of type ncrep
2247
2248RETURN:   dimension of q;
2249  returns 0 if q represents the zero-function
2250
2251EXAMPLE:  example ncrepDim;
2252  shows an example"
2253{
2254  int n = ncols(q.mat);
2255  // Does q represent zero?
2256  if (n == 1)
2257  {
2258    if (q.lvec == 0 or q.rvec == 0)
2259    {
2260      n = 0;
2261    }
2262  }
2263  return (n);
2264}
2265example
2266{
2267  "EXAMPLE:";
2268  echo = 2;
2269  ncInit(list("x", "y", "z"));
2270  ncrat f = ncratFromString("2*x*y");
2271  ncrep q = ncrepGet(f);
2272  print(q);
2273  ncrepDim(q);
2274}
2275
2276proc ncrepSubstitute(ncrep q, list vars, list points)
2277"USAGE:     ncrep s = ncrepSubstitute(q, l);
2278  q of type ncrep, vars = (x1, ..., xg),
2279  points = (A1, ... , Ag) with Ai matrices of the
2280  same dimension and xi of type poly are nc variables
2281
2282RETURN:     substitutes in Ai for xi in q
2283
2284EXAMPLE:  example ncrepSubstitute;
2285  shows an example"
2286{
2287  int g = size(vars);
2288  if (not(size(points) == g))
2289  {
2290    ERROR("Number of variables and points does not match!");
2291  }
2292
2293  // Lists empty
2294  if (g == 0)
2295  {
2296    return (q.mat);
2297  }
2298
2299  // Lists non-empty
2300  int i;
2301  list l = ncrepLinearPencil(q, vars);
2302  for (i = 0; i <= g; i++)
2303  {
2304    matrix Q(i) = l[i + 1];
2305  }
2306
2307  int n=1;
2308  if (typeof(points[1])!="poly") { n = ncols(points[1]);}
2309  matrix E[n][n];
2310  E = E + 1;
2311
2312  matrix M = tensor(Q(0), E);
2313  for (i = 1; i <= g; i++)
2314  {
2315    matrix A(i) = points[i];
2316    M = M + tensor(Q(i), A(i));
2317  }
2318
2319  ncrep q2;
2320  q2.mat = M;
2321  q2.lvec = tensor(q.lvec, E);
2322  q2.rvec = tensor(q.rvec, E);
2323
2324  return (q2);
2325}
2326example
2327{
2328  "EXAMPLE:";
2329  echo = 2;
2330  ncInit(list("x", "y", "z"));
2331  ncrat f = ncratFromString("x+y");
2332  ncrep q = ncrepGet(f);
2333  matrix A[2][2] = 1, 2, 3, 4;
2334  matrix B[2][2] = 5, 6, 7, 8;
2335  ncrep s = ncrepSubstitute(q, list(x, y), list(A, B));
2336  print(q);
2337  print(s);
2338}
2339
2340proc ncrepEvaluate(ncrep q)
2341"USAGE:   matrix M = ncrepEvaluate(q);
2342
2343RETURN:   for q=(u, Q, v) calculate -u*Q^(-1)*v
2344
2345EXAMPLE:  example ncrepEvaluate;
2346  shows an example"
2347{
2348  matrix QInv = inverse(q.mat);
2349  if (size(QInv) == 1 and QInv[1, 1] == 0)
2350  {
2351    ERROR("Matrix not invertible!");
2352  }
2353  matrix M = -q.lvec * QInv * q.rvec;
2354  return (M);
2355}
2356example
2357{
2358  "EXAMPLE:";
2359  echo = 2;
2360  ncInit(list("x", "y", "z"));
2361  ncrat f = ncratFromString("x+y");
2362  ncrep q = ncrepGet(f);
2363  matrix A[2][2] = 1, 2, 3, 4;
2364  matrix B[2][2] = 5, 6, 7, 8;
2365  ncrep s = ncrepSubstitute(q, list(x, y), list(A, B));
2366  matrix M = ncrepEvaluate(s);
2367  print(M);
2368}
2369
2370proc ncrepEvaluateAt(ncrep q, list vars, list point)
2371"USAGE:   matrix M = ncrepEvaluateAt(q, vars, point);
2372
2373RETURN:   For q=(u, Q, v) calculate -u*Q(point)^(-1)*v,
2374  that is to say, evaluate the ncrat represented
2375  by q at point (scalar or matrix point).
2376
2377EXAMPLE:  example ncrepEvaluateAt;
2378  shows an example"
2379{
2380  ncrep r = ncrepSubstitute(q, vars, point);
2381  matrix M = ncrepEvaluate(r);
2382  return (M);
2383}
2384example
2385{
2386  "EXAMPLE:";
2387  echo = 2;
2388  ncInit(list("x", "y"));
2389  ncrat f = ncratFromString("x+y");
2390  ncrep q = ncrepGet(f);
2391  matrix A[2][2] = 1, 2, 3, 4;
2392  matrix B[2][2] = 5, 6, 7, 8;
2393  matrix M = ncrepEvaluateAt(q, list(x, y), list(A, B));
2394  print(M);
2395}
2396
2397proc ncrepIsDefinedDim(ncrep q, int N, list vars, int n, int maxcoeff)
2398"USAGE:   list l = ncrepIsDefinedDim(q, N, vars, n, maxcoeff);
2399
2400RETURN:   list(k, list vars, list(A1, ..., Ak)), where:
2401  If k = N then there are matrices A1, ..., Ak of size N
2402  such that q is defined at A = (A1, ..., Ak), i.e.,
2403  q.mat is invertible at A.
2404  If k = 0 then no such point was found.
2405
2406NOTE:     Test whether q.mat is invertible via evaluation
2407  at random matrix points with integer coefficients
2408  in [-maxcoeff, maxcoeff]. Stops after n tries.
2409  Use square matrices of dimension N. The list vars
2410  contains the nc variables which occur in q.
2411
2412EXAMPLE:  example ncrepIsDefinedDim;
2413  shows an example"
2414{
2415  int g = size(vars);
2416  int i, k;
2417  for (i = 1; i <= n; i++)
2418  {
2419    // Substitute random matrices
2420    list points;
2421    for (k = 1; k <= g; k++)
2422    {
2423      matrix A(k) = randommat(N, N, maxideal(0), maxcoeff);
2424      points = points + list(A(k));
2425      kill(A(k));
2426    }
2427    ncrep q2 = ncrepSubstitute(q, vars, points);
2428
2429    // Check for invertibility
2430    if (mat_rk(q2.mat) == ncols(q2.mat))
2431    {
2432      list result = list(N) + list(vars) + list(points);
2433      kill(q2);
2434      kill(points);
2435      return (result);
2436    }
2437    kill(q2);
2438    kill(points);
2439  }
2440  list empty;
2441  list result = list(0) + list(vars) + list(empty);
2442  return (result);
2443}
2444example
2445{
2446  "EXAMPLE:";
2447  echo = 2;
2448  ncInit(list("x", "y"));
2449  ncrat f = ncratFromString("inv(x*y-y*x)");
2450  ncrep q = ncrepGet(f);
2451  ncrepIsDefinedDim(q, 1, list(x, y), 10, 100);
2452  ncrepIsDefinedDim(q, 2, list(x, y), 10, 100);
2453}
2454
2455proc ncrepIsDefined(ncrep q, list vars, int n, int maxcoeff)
2456"USAGE:   list l = ncrepIsDefined(q, vars, n, maxcoeff);
2457
2458RETURN:   list(dim, list vars, list(A1, ..., Ak)), where:
2459  If dim > 0 then there are matrices A1, ..., Ak of size dim
2460  such that q is defined at A = (A1, ..., Ak), i.e.,
2461  q.mat is invertible at A.
2462  If dim = 0 then no such point was found.
2463
2464NOTE:     Test whether q.mat is invertible via evaluation
2465  at random matrix points with integer coefficients
2466  in [-maxcoeff, maxcoeff]. Stops after n tries.
2467  Use ixi-matrix in i-th try. The list vars contains the
2468  nc variables which occur in q.
2469
2470EXAMPLE:  example ncrepIsDefined;
2471  shows an example"
2472{
2473  int i;
2474  list l;
2475  for (i = 1; i <= n; i++)
2476  {
2477    l = ncrepIsDefinedDim(q, i, vars, 1, maxcoeff);
2478    if (l[1] > 0)
2479    {
2480      return (l);
2481    }
2482  }
2483  return (l);
2484}
2485example
2486{
2487  "EXAMPLE:";
2488  echo = 2;
2489  ncInit(list("x", "y"));
2490  ncrat f = ncratFromString("inv(x*y-y*x)");
2491  ncrep q = ncrepGet(f);
2492  ncrepIsDefined(q, list(x, y), 5, 10);
2493  ncrat g = ncratFromString("inv(x-x)");
2494  ncrep r = ncrepGet(g);
2495  ncrepIsDefined(r, list(x), 5, 10);
2496}
2497
2498proc ncrepIsRegular(ncrep q, list vars, int n, int maxcoeff)
2499"USAGE:   list l = ncrepIsRegular(q, vars, n, maxcoeff);
2500
2501RETURN:   list(k, list vars, list(a1, ..., ak)), where:
2502  If k = 1 then there are scalars (1x1-matrices) a1, ..., ak
2503  such that q is defined at a = (a1, ..., ak), i.e.,
2504  q.mat is invertible at a.
2505  If k = 0 then no such point was found.
2506
2507NOTE:     Test whether q.mat is invertible via evaluation
2508  at random integers  in [-maxcoeff, maxcoeff].
2509  Stops after n tries. The list vars
2510  contains the nc variables which occur in q.
2511
2512EXAMPLE:  example ncrepIsRegular;
2513  shows an example"
2514{
2515  list l = ncrepIsDefinedDim(q, 1, vars, n, maxcoeff);
2516  return (l);
2517}
2518example
2519{
2520  "EXAMPLE:";
2521  echo = 2;
2522  ncInit(list("x", "y"));
2523  ncrat f = ncratFromString("inv(x*y-y*x)");
2524  ncrep q = ncrepGet(f);
2525  ncrepIsRegular(q, list(x, y), 10, 100);
2526  ncrat g = ncratFromString("inv(1+x*y-y*x)");
2527  ncrep r = ncrepGet(g);
2528  ncrepIsRegular(r, list(x, y), 10, 100);
2529}
2530
2531proc ncrepPencilGet(ncrep r, list vars)
2532"USAGE:     list pencil = ncrepPencilGet(r, vars);
2533
2534RETURN:     pencil = list(vars, matrices),
2535  where vars = list(1, x1, ..., xg) are the variables
2536  occuring in r and matrices = (Q0, ..., Qg) is a list of
2537  matrices such that
2538    r.mat = Q0 * x0 + ... + Qg * xg
2539  with x0 = 1
2540
2541NOTE:       list vars = list(x1, ..., xn) has to consist
2542  exactly of the nc variables occuring in f
2543
2544EXAMPLE:    example ncrepPencilGet;
2545  shows an example"
2546{
2547  poly p = 1;
2548  list varsNew = list(p) + vars;
2549  list matrices = ncrepLinearPencil(r, vars);
2550  list l = list(varsNew, matrices);
2551  return (l);
2552}
2553example
2554{
2555  "EXAMPLE:";
2556  echo = 2;
2557  ncInit(list("x", "y"));
2558  ncrat f = ncratFromString("x*y");
2559  ncrep r = ncrepGet(f);
2560  print(r.mat);
2561  list l = ncrepPencilGet(r, list(x, y));
2562  print(l[1]);
2563  print(l[2][1]);
2564  print(l[2][2]);
2565  print(l[2][3]);
2566}
2567
2568proc ncrepPencilCombine(list pencil)
2569"USAGE:     matrix Q = ncrepPencilCombine(pencil);
2570
2571RETURN:     matrix Q = Q0*x0 + ... + Qg*xg,
2572  where vars = list(x0, ..., xg) consists of polynomials
2573  and matrices = (Q0, ..., Qg) is a list of matrices
2574
2575EXAMPLE:    example ncrepPencilCombine;
2576  shows an example"
2577{
2578  int g = size(pencil[1]);
2579  int n = ncols(pencil[2][1]);
2580  matrix Q[n][n];
2581  int i;
2582  for (i = 1; i <= g; i++)
2583  {
2584    Q = Q + pencil[1][i] * pencil[2][i];
2585  }
2586  return (Q);
2587}
2588example
2589{
2590  "EXAMPLE:";
2591  echo = 2;
2592  ncInit(list("x", "y"));
2593  ncrat f = ncratFromString("x*y");
2594  ncrep r = ncrepGet(f);
2595  print(r.mat);
2596  list l = ncrepPencilGet(r, list(x, y));
2597  matrix Q = ncrepPencilCombine(l);
2598  print(Q);
2599}
2600
2601/*##########################################################
2602
2603   REGULAR CASE
2604
2605##########################################################*/
2606
2607proc ncrepRegularZeroMinimize(ncrep q, list #)
2608"USAGE:     ncrep s = ncrepRegularZeroMinimize(q, l);
2609
2610RETURN:     ncrep s representing the same rational
2611  function as ncrep q, where s is of minimal size
2612
2613ASSUMPTION: q is regular at zero, i.e.,
2614  if one substitutes in 0 for all nc variables in q
2615  then q.mat has to be invertible
2616
2617NOTE:       list l = list(x1, ..., xn) has to consist
2618  exactly of the nc variables occuring in q
2619
2620EXAMPLE:    example ncrepRegularZeroMinimize;
2621  shows an example"
2622{
2623  int i;
2624  int g = size(#);
2625  int n = ncols(q.mat);
2626  int offset = 0;
2627  list k = ncrepToMonicDescriptorRealization(g, n, q, #);
2628
2629  // cut down on controllable space
2630  list b = calculateControllabilitySpace(g, n, k[1], k[3]);
2631  list c = calculateComplement(n, b);
2632  n = size(b);
2633  matrix bMat = orthogonalBase(b);
2634  matrix cMat = orthogonalBase(c);
2635  k = orthogonalTransform(bMat, cMat, k[1], k[2], k[3]);
2636  k = cutdown(n, offset, k[1], k[2], k[3]);
2637
2638  // cut down on observable space
2639  n = size(b);
2640  list l;
2641
2642  // switch to adjoint system
2643  for (i = 1; i <= g; i++)
2644  {
2645    l = l + list(transpose(k[3][i]));
2646  }
2647  list ktp = list(transpose(k[2]), transpose(k[1]), l);
2648
2649  b = calculateControllabilitySpace(g, n, ktp[1], ktp[3]);
2650  c = calculateComplement(n, b);
2651  n = size(b);
2652  offset = size(c);
2653  bMat = orthogonalBase(b);
2654  cMat = orthogonalBase(c);
2655  ktp = orthogonalTransform(cMat, bMat, ktp[1], ktp[2], ktp[3]);
2656  ktp = cutdown(n, offset, ktp[1], ktp[2], ktp[3]);
2657
2658  // build ncrep
2659  n = size(b);
2660  ncrep r;
2661  r.lvec = -1 * transpose(ktp[1]);
2662  r.rvec = transpose(ktp[2]);
2663
2664  matrix Q[n][n];
2665  Q = Q + 1;
2666  for (i = 1; i <= g; i++)
2667  {
2668    Q = Q - transpose(ktp[3][i]) * #[i];
2669  }
2670  r.mat = Q;
2671
2672  return (r);
2673}
2674example
2675{
2676  "EXAMPLE:";
2677  echo = 2;
2678  ncInit(list("x", "y"));
2679  ncrat f = ncratFromString("inv(1+x*y-y*x)");
2680  ncrep q = ncrepGet(f);
2681  ncrepDim(q);
2682  ncrep s = ncrepRegularZeroMinimize(q, list(x, y));
2683  ncrepDim(s);
2684  s;
2685}
2686
2687proc ncrepRegularMinimize(ncrep q, list vars, list point)
2688"USAGE:     ncrep s = ncrepRegularMinimize(q, vars, point);
2689
2690RETURN:     ncrep s representing the same rational
2691  function as ncrep q, where s is of minimal size
2692
2693ASSUMPTION: q is regular at scalar point a, i.e.,
2694  if one substitutes in ai for all nc variables xi in q
2695  then q.mat has to be invertible
2696
2697NOTE:       list vars = list(x1, ..., xn) has to consist
2698  exactly of the nc variables occuring in q and
2699  list point = list(a1, ..., an) consists of scalars
2700
2701EXAMPLE:    example ncrepRegularMinimize;
2702  shows an example"
2703{
2704  int g = size(vars);
2705  if (not(size(point) == g))
2706  {
2707    ERROR("Lists have to be of the same size!");
2708  }
2709
2710  list shift, backshift;
2711  int i;
2712  poly p1, p2;
2713
2714  // point matrices?
2715  if (g > 0 and typeof(point[1]) == "matrix")
2716  {
2717    if (ncols(point[1]) > 1)
2718    {
2719      ERROR("Not a scalar point!");
2720    }
2721    for (i = 1; i <= g; i++)
2722    {
2723      poly z(i) = point[i][1, 1];
2724    }
2725  }
2726  // point scalars
2727  else
2728  {
2729    for (i = 1; i <= g; i++)
2730    {
2731      poly z(i) = point[i];
2732    }
2733  }
2734
2735  for (i = 1; i <= g; i++)
2736  {
2737    p1 = vars[i] - z(i);
2738    p2 = vars[i] + z(i);
2739    shift = shift + list(p1);
2740    backshift = backshift + list(p2);
2741  }
2742
2743  ncrep s = ncrepSubstitute(q, vars, shift);
2744  ncrep r = ncrepRegularZeroMinimize(s, vars);
2745  ncrep q2 = ncrepSubstitute(r, vars, backshift);
2746
2747  return (q2);
2748}
2749example
2750{
2751  "EXAMPLE:";
2752  echo = 2;
2753  ncInit(list("x", "y"));
2754  ncrat f = ncratFromString("inv(x*y)");
2755  ncrep q = ncrepGet(f);
2756  ncrepDim(q);
2757  ncrep s = ncrepRegularMinimize(q, list(x, y), list(1, 1));
2758  ncrepDim(s);
2759  s;
2760}
2761
2762proc ncrepGetRegularZeroMinimal(ncrat f, list vars)
2763"USAGE:     ncrep q = ncrepGetRegularZeroMinimal(f, vars);
2764
2765RETURN:     q is a representation of f with
2766  minimal dimension
2767
2768ASSUMPTION: f is regular at zero, i.e.,
2769  f(0) has to be defined
2770
2771NOTE:       list vars = list(x1, ..., xn) has to consist
2772  exactly of the nc variables occuring in f
2773
2774EXAMPLE:    example ncrepGetRegularZeroMinimal;
2775  shows an example"
2776{
2777  ncrep q = ncrepGet(f);
2778  ncrep q2 = ncrepRegularZeroMinimize(q, vars);
2779  return (q2);
2780}
2781example
2782{
2783  "EXAMPLE:";
2784  echo = 2;
2785  ncInit(list("x", "y"));
2786  ncrat f = ncratFromString("inv(1+x*y-y*x)");
2787  list vars = list(x, y);
2788  ncrep q = ncrepGetRegularZeroMinimal(f, vars);
2789  q;
2790}
2791
2792proc ncrepGetRegularMinimal(ncrat f, list vars, list point)
2793"USAGE:     ncrep q = ncrepGetRegularMinimal(f, vars, point);
2794
2795RETURN:     q is a representation of f with
2796  minimal dimension
2797
2798ASSUMPTION: f is regular at point, i.e.,
2799  f(point) has to be defined
2800
2801NOTE:       list vars = list(x1, ..., xn) has to consist
2802  exactly of the nc variables occuring in f and
2803  list point = (p1, ..., pn) of scalars such that
2804  f(point) is defined
2805
2806EXAMPLE:    example ncrepGetRegularMinimal;
2807  shows an example"
2808{
2809  ncrep q = ncrepGet(f);
2810  ncrep q2 = ncrepRegularMinimize(q, vars, point);
2811  return (q2);
2812}
2813example
2814{
2815  "EXAMPLE: (Hua's identity)";
2816  echo = 2;
2817  // We want to prove the Hua's identity, telling that for two
2818  // invertible elements x,y from a division ring, one has
2819  // inv(x+x*inv(y)*x)+inv(x+y) = inv(x)
2820  // where inv(t) stands for the two-sided inverse of t
2821  ncInit(list("x", "y"));
2822  ncrat f = ncratFromString("inv(x+x*inv(y)*x)+inv(x+y)-inv(x)");
2823  print(f);
2824  ncrep r = ncrepGet(f);
2825  ncrepDim(r);
2826  ncrep s = ncrepGetRegularMinimal(f, list(x, y), list(1, 1));
2827  ncrepDim(s);
2828  print(s);
2829  // since s represents the zero element, Hua's identity holds.
2830}
2831
2832/*##########################################################
2833
2834  END REGULAR CASE
2835
2836##########################################################*/
2837
2838/*##########################################################
2839
2840  END NCREP
2841
2842##########################################################*/
2843
2844/*##########################################################
2845
2846  END NON-STATIC PROCEDURES
2847
2848##########################################################*/
Note: See TracBrowser for help on using the repository browser.