source: git/Singular/LIB/ncrat.lib

spielwiese
Last change on this file was e78236, checked in by Hans Schoenemann <hannes@…>, 12 months ago
format
  • Property mode set to 100644
File size: 56.7 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 possibilities 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();             Subtraction 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();             Subtraction 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 = "(";
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 + ")";
731  ring NCRING = create_ring("(0, I)", s, "dp");
732  minpoly = I^2+1;
733  short = 0;
734  exportto(Top, NCRING);
735}
736
737static proc ncratIsValid(string s, list l)
738{
739
740  while (1)
741  {
742    if (s == "Const")
743    {
744      if (not((size(l) == 1) and (typeof(l[1]) == "number")))
745      {
746        return (0);
747      }
748      break;
749    }
750
751    if (s == "Var")
752    {
753      if (not((size(l) == 1) and (typeof(l[1]) == "string")))
754      {
755        return (0);
756      }
757      break;
758    }
759
760    if (s == "Add" or s == "Sub" or s == "Mult")
761    {
762      if (not((size(l) == 2) and (typeof(l[1]) == "ncrat") and
763              (typeof(l[2]) == "ncrat")))
764      {
765        return (0);
766      }
767      break;
768    }
769
770    if (s == "Inv")
771    {
772      if (not((size(l) == 1) and (typeof(l[1]) == "ncrat")))
773      {
774        return (0);
775      }
776      break;
777    }
778
779    break;
780  }
781
782  return (1);
783}
784
785/*
786    The following procedures make it possible to evaluate a
787    ncrat f by substituting in the matrices in point for
788    the variables in var
789*/
790
791static proc ncratEvaluateConst(ncrat f, list vars, list point)
792{
793  int g = ncols(point[1]);
794  number n = f.expr[1];
795
796  matrix E[g][g];
797  E = E + 1;
798
799  matrix A = n * E;
800  return (A);
801}
802
803static proc ncratEvaluateAdd(ncrat f, list vars, list point)
804{
805  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
806  matrix B = ncratEvaluateAt(f.expr[2], vars, point);
807  matrix C = A + B;
808  return (C);
809}
810
811static proc ncratEvaluateSub(ncrat f, list vars, list point)
812{
813  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
814  matrix B = ncratEvaluateAt(f.expr[2], vars, point);
815  matrix C = A - B;
816  return (C);
817}
818
819static proc ncratEvaluateMult(ncrat f, list vars, list point)
820{
821  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
822  matrix B = ncratEvaluateAt(f.expr[2], vars, point);
823  matrix C = A * B;
824  return (C);
825}
826
827static proc ncratEvaluateInv(ncrat f, list vars, list point)
828{
829  matrix A = ncratEvaluateAt(f.expr[1], vars, point);
830  matrix C = inverse(A);
831  return (C);
832}
833
834static proc ncratEvaluateVar(ncrat f, list vars, list point)
835{
836  poly p;
837  int i;
838  int index = 0;
839  int g = size(vars);
840
841  for (i = 1; i <= g and index == 0; i++)
842  {
843    p = vars[i];
844    if (string(p) == f.expr[1])
845    {
846      index = i;
847    }
848  }
849
850  matrix C = point[index];
851  return (C);
852}
853
854/*##########################################################
855
856  END NCRAT
857
858##########################################################*/
859
860/*##########################################################
861
862   NCREP
863
864##########################################################*/
865
866// Handle constants
867static proc ncrepConst(number n)
868{
869  ncrep q;
870  matrix left[1][2] = 0, 1;
871  matrix right[2][1] = 0, 1;
872  matrix Q[2][2] = n, -1, -1, 0;
873  q.lvec = left;
874  q.rvec = right;
875  q.mat = Q;
876  return (q);
877}
878
879// Handle variables
880static proc ncrepVar(poly p)
881{
882  ncrep q;
883  matrix left[1][2] = 0, 1;
884  matrix right[2][1] = 0, 1;
885  matrix Q[2][2] = p, -1, -1, 0;
886  q.lvec = left;
887  q.rvec = right;
888  q.mat = Q;
889  return (q);
890}
891
892// Substitute all occurences of VARIABLE*E in M with A
893static proc ncSubMat(matrix M, matrix A, poly VARIABLE)
894{
895  int N = ncols(A);
896  int N2 = ncols(M);
897  int N3 = N2 div N;
898  if (not(N * N3 == N2))
899  {
900    ERROR("Size of arg1 must be a multiple of size of arg2!");
901  }
902
903  int n, m, i, j;
904  poly p;
905  for (i = 1; i <= N3; i++)
906  {
907    for (j = 1; j <= N3; j++)
908    {
909      p = M[1 + (i - 1) * N, 1 + (j - 1) * N] / VARIABLE;
910      if (not(p == 0))
911      {
912        M[1 + (i - 1) * N..i * N, 1 + (j - 1) * N..j * N] = p * A;
913      }
914    }
915  }
916  return (M);
917}
918
919/*
920  list # = (x1, ..., xg) contains the nc variables
921  occurring in g
922  return list(Q0, Q1,... Qg) with scalar matrices Qi s.t.
923    Q = Q0 + Q1*x1 + ... + Qg*xg
924*/
925static proc ncrepLinearPencil(ncrep q, list #)
926{
927  int g = size(#);
928  int n = ncols(q.mat);
929
930  int i, j, k;
931  poly p;
932  matrix Q(0) = q.mat;
933  for (i = 1; i <= g; i++)
934  {
935    matrix Q(i)[n][n];
936    for (j = 1; j <= n; j++)
937    {
938      for (k = 1; k <= n; k++)
939      {
940        p = Q(0)[j, k] / #[i];
941        if (not(p == 0))
942        {
943          Q(i)
944          [j, k] = p;
945        }
946      }
947    }
948    Q(0) = Q(0) - #[i] * Q(i);
949  }
950
951  list l;
952  for (i = 0; i <= g; i++)
953  {
954    l = l + list(Q(i));
955  }
956
957  return (l);
958}
959
960/*##########################################################
961
962   REGULAR CASE
963
964##########################################################*/
965
966/*
967  g - number of nc variables
968  n - dimension
969  q - REGULAR ncrep
970  # - contains occurring ncvariables as 'poly'
971  Returns list(B, C, l) with l = list(A1, ..., Ag) such that
972  -u*Q^-1*v = C * (1 - A1*x1 - ... - Ag*xg)^-1 * B.
973
974  ASSUMPTION: q.mat has to be regular at zero
975*/
976static proc ncrepToMonicDescriptorRealization(int g, int n, ncrep q, list #)
977{
978  if (not(size(#) == g))
979  {
980    ERROR("List has wrong size!");
981  }
982
983  list l = ncrepLinearPencil(q, #);
984  matrix Q(0) = l[1];
985  matrix S = inverse(Q(0));
986
987  if (size(S) == 1 and S[1, 1] == 0)
988  {
989    ERROR("Q0 has to be invertible!");
990  }
991
992  list k;
993  int i;
994  for (i = 1; i <= g; i++)
995  {
996    matrix Q(i) = l[i + 1];
997    matrix A(i) = -S * Q(i);
998    k = k + list(A(i));
999  }
1000
1001  matrix C = -q.lvec;
1002  matrix B = S * q.rvec;
1003  return (list(B, C, k));
1004}
1005
1006/*
1007  g - number of nc variables
1008  n - dimension
1009  v - vector in C^n (that is, nx1-matrix)
1010  # - list containing nxn-matrices A_1, ..., A_g
1011
1012  This procedure calculates the following subspace of C^n:
1013    S = span { A_i1 ... A_ik v | k in N, 1 <= i1, ... ik <= g }
1014
1015  It returns a basis of this space.
1016*/
1017static proc calculateControllabilitySpace(int g, int n, matrix v, list #)
1018{
1019  if (size(#) != g)
1020  {
1021    ERROR("List has wrong size!");
1022  }
1023
1024  if (not(ncols(v) == 1 and nrows(v) == n))
1025  {
1026    ERROR("Matrix must be of size " + string(n) + "x1!");
1027  }
1028
1029  int i;
1030  for (i = 1; i <= g; i++)
1031  {
1032    if (typeof(#[i]) != "matrix")
1033    {
1034      ERROR("List must only contain matrices!");
1035    }
1036    matrix A(i) = #[i];
1037  }
1038
1039  // case v = 0
1040  if (isMatrixEmpty(v))
1041  {
1042    return (list(v));
1043  }
1044
1045  // case v != 0
1046  // case n = 1
1047  if (n == 1)
1048  {
1049    return (list(v));
1050  }
1051
1052  // case n > 1
1053  list b = list(v);
1054  list s = b;
1055  matrix baseMat = v;
1056  matrix testMat;
1057  int oldSize = size(b);
1058  int j;
1059
1060  while (1)
1061  {
1062    list m;
1063
1064    // m = {A1, ..., Ag} * s
1065    for (i = 1; i <= g; i++)
1066    {
1067      for (j = 1; j <= size(s); j++)
1068      {
1069        m = m + list(A(i) * s[j]);
1070      }
1071    }
1072
1073    // check if mi is linearly independent of b
1074    // in this case append to b, and build new s
1075    kill(s);
1076    list s;
1077
1078    for (i = 1; i <= size(m); i++)
1079    {
1080      testMat = concat(baseMat, m[i]);
1081
1082      if (rank(testMat) == ncols(testMat))
1083      {
1084        s = s + list(m[i]);
1085        b = b + list(m[i]);
1086        baseMat = testMat;
1087
1088        if (size(b) == n)
1089        {
1090          return (b);
1091        }
1092      }
1093    }
1094
1095    kill(m);
1096    if (size(b) == oldSize)
1097    {
1098      return (b);
1099    }
1100    oldSize = size(b);
1101  }
1102}
1103
1104/*
1105  n - dimension of whole space
1106  b - list containing a basis of S
1107
1108  Calculates a list c containing a basis of S^ortho, i.e.,
1109    C^n = S directsum S^ortho.
1110*/
1111static proc calculateComplement(int n, list b)
1112{
1113  list c;
1114  int i;
1115
1116  // case S = C^n
1117  if (size(b) == n)
1118  {
1119    return (c);
1120  }
1121
1122  for (i = 1; i <= n; i++)
1123  {
1124    matrix e(i)[n][1];
1125    e(i)[i, 1] = 1;
1126  }
1127
1128  // case S = {0}
1129  if (isMatrixEmpty(b[1]))
1130  {
1131    for (i = 1; i <= n; i++)
1132    {
1133      c = c + list(e(i));
1134    }
1135    return (c);
1136  }
1137
1138  // case 0 < dim S < n
1139  matrix baseMat = b[1];
1140  for (i = 2; i <= size(b); i++)
1141  {
1142    baseMat = concat(baseMat, b[i]);
1143  }
1144
1145  matrix testMat;
1146  for (i = 1; i <= n; i++)
1147  {
1148    testMat = concat(baseMat, e(i));
1149
1150    if (rank(testMat) == ncols(testMat))
1151    {
1152      c = c + list(e(i));
1153      baseMat = testMat;
1154
1155      if (ncols(baseMat) == n)
1156      {
1157        return (c);
1158      }
1159    }
1160  }
1161}
1162
1163// INPUT: list containing basis vectors
1164// OUTPUT: orthogonal matrix, whose columns span the same space
1165static proc orthogonalBase(list b)
1166{
1167  matrix B;
1168
1169  if (size(b) == 0)
1170  {
1171    return (B);
1172  }
1173
1174  B = b[1];
1175  int i;
1176  for (i = 2; i <= size(b); i++)
1177  {
1178    B = concat(B, b[i]);
1179  }
1180  return (orthogonalize(B));
1181}
1182
1183/*
1184  bMat - orthogonal matrix whose columns span S
1185  cMat - orthogonal matrix whose columns span S^ortho
1186  # - matrices A1, ..., Ag
1187  Returns ( P^-1 * B, C * P, list( P^-1 * Ai * P ) ), where P = (bMat cMat).
1188*/
1189static proc orthogonalTransform(matrix bMat, matrix cMat, matrix B, matrix C,
1190                                list #)
1191{
1192  int i;
1193  list l;
1194  int bMatEmpty = isMatrixEmpty(bMat);
1195  int cMatEmpty = isMatrixEmpty(cMat);
1196
1197  // Define orthogonal transformation
1198  if (bMatEmpty)
1199  {
1200    if (cMatEmpty)
1201    {
1202      ERROR("Both empty!");
1203    }
1204    else
1205    {
1206      matrix P = cMat;
1207    }
1208  }
1209  else
1210  {
1211    if (cMatEmpty)
1212    {
1213      matrix P = bMat;
1214    }
1215    else
1216    {
1217      matrix P = concat(bMat, cMat);
1218    }
1219  }
1220
1221  matrix PInv = inverse(P);
1222  B = PInv * B;
1223  C = C * P;
1224
1225  for (i = 1; i <= size(#); i++)
1226  {
1227    matrix A(i) = PInv * #[i] * P;
1228    l = l + list(A(i));
1229  }
1230
1231  return (list(B, C, l));
1232}
1233
1234/*
1235  n - dimension to cut down to
1236  offset - where to cut out
1237  # - matrices A1, ..., Ag
1238  C * (1 - A1 x1 - .. - Ag xg)^(-1) * B monic descriptor realization
1239*/
1240static proc cutdown(int n, int offset, matrix B, matrix C, list #)
1241{
1242  int a = 1 + offset;
1243  int b = n + offset;
1244
1245  // Case B or C is zero
1246  if (isMatrixEmpty(B) or isMatrixEmpty(C))
1247  {
1248    matrix zero[1][1] = 0;
1249    list zerolist;
1250    int i;
1251    for (i = 1; i <= size(#); i++)
1252    {
1253      zerolist = zerolist + list(zero);
1254    }
1255    return (zero, zero, zerolist);
1256  }
1257
1258  // Case B and C not zero
1259  matrix B2 = submat(B, a..b, 1..1);
1260  matrix C2 = submat(C, 1..1, a..b);
1261
1262  list l;
1263  int i;
1264  for (i = 1; i <= size(#); i++)
1265  {
1266    matrix A2(i) = submat(#[i], a..b, a..b);
1267    l = l + list(A2(i));
1268  }
1269
1270  return (list(B2, C2, l));
1271}
1272
1273/*##########################################################
1274
1275  END REGULAR CASE
1276
1277##########################################################*/
1278
1279/*##########################################################
1280
1281  END NCREP
1282
1283##########################################################*/
1284
1285/*##########################################################
1286
1287  END STATIC PROCEDURES
1288
1289##########################################################*/
1290
1291/*##########################################################
1292
1293   NON-STATIC PROCEDURES
1294
1295##########################################################*/
1296
1297/*##########################################################
1298
1299   GENERAL
1300
1301##########################################################*/
1302
1303proc ncInit(list vars)
1304"USAGE:   ncInit(vars);
1305  list vars containing strings
1306
1307RETURN:
1308  datatypes ncrat and ncrep (and token, tokenstream,
1309  but they are not meant for users),
1310  sets ring as 'NCRING' with nc variables from list l
1311
1312EXAMPLE:  example ncInit;
1313  shows an example"
1314{
1315  // Check if already initialized
1316  // In this case just add missing variables
1317  if (defined(NCRATINITIALIZE))
1318  {
1319    if (!defined(basering))
1320    {
1321      ncRingDefine();
1322    }
1323    return ();
1324  }
1325  int NCRATINITIALIZE = 1;
1326  export(NCRATINITIALIZE);
1327
1328  // Check if variables are specified
1329  if (size(vars) == 0)
1330  {
1331    ERROR("No nc variables specified!");
1332  }
1333
1334  /*---------------------------------------------------------/
1335
1336      Datatype 'ncrat' for nc rational functions
1337
1338      The following constructions are allowed:
1339        ("Const", [number])           constant
1340        ("Var",   [string])           variable
1341        ("Add",   [ncrat, ncrat])     addition
1342        ("Sub",   [ncrat, ncrat])     sustraction
1343        ("Mult",  [ncrat, ncrat])     multiplication
1344        ("Inv",   [ncrat])            inverse
1345
1346  /---------------------------------------------------------*/
1347
1348  newstruct("ncrat", "
1349    string kind,
1350    list expr
1351  ");
1352
1353
1354  /*---------------------------------------------------------/
1355
1356      Struct for representations
1357
1358  /---------------------------------------------------------*/
1359
1360  newstruct("ncrep", "
1361    matrix lvec,
1362    matrix mat,
1363    matrix rvec
1364  ");
1365
1366
1367  /*---------------------------------------------------------/
1368
1369      Structs for handling input
1370
1371  /---------------------------------------------------------*/
1372
1373  newstruct("token", "
1374    string kind,
1375    number value,
1376    string name
1377  ");
1378
1379
1380  newstruct("tokenstream", "
1381    int full,
1382    int position,
1383    token buffer,
1384    string input
1385  ");
1386
1387
1388  /*---------------------------------------------------------/
1389
1390      Overloading operators for ncrat and ncrep
1391
1392  /---------------------------------------------------------*/
1393
1394  system("install", "ncrat", "=", ncratDefine, 1);
1395  system("install", "ncrat", "+", ncratAdd, 2);
1396  system("install", "ncrat", "-", ncratSubstract, 2);
1397  system("install", "ncrat", "*", ncratMultiply, 2);
1398  system("install", "ncrat", "^", ncratPower, 2);
1399  system("install", "ncrat", "print", ncratPrint, 1);
1400  system("install", "ncrep", "+", ncrepAdd, 2);
1401  system("install", "ncrep", "-", ncrepSubstract, 2);
1402  system("install", "ncrep", "*", ncrepMultiply, 2);
1403  system("install", "ncrep", "print", ncrepPrint, 1);
1404
1405
1406  /*---------------------------------------------------------/
1407
1408      Global objects
1409
1410  /---------------------------------------------------------*/
1411
1412  list NCVARIABLES = vars;
1413  export(NCVARIABLES);
1414
1415  tokenstream TOKENSTREAM = makeTokenStream();
1416  export(TOKENSTREAM);
1417
1418  ncRingDefine();
1419}
1420example
1421{
1422  "EXAMPLE:";
1423  echo = 2;
1424  ncInit(list("x", "y", "z"));
1425  NCRING;
1426}
1427
1428proc ncVarsGet()
1429"USAGE:   ncVarsGet();
1430
1431RETURNS:
1432  nc variables that are in use
1433
1434EXAMPLE:  example ncVarsGet;
1435shows an example"
1436{
1437  string(NCVARIABLES);
1438}
1439example
1440{
1441  "EXAMPLE:";
1442  echo = 2;
1443  ncInit(list("x", "y", "z"));
1444  ncVarsGet();
1445}
1446
1447proc ncVarsAdd(list vars)
1448"USAGE:   ncVarsAdd(vars);
1449  list vars contains variables
1450
1451RETURNS:
1452  sets list elements as nc variables
1453
1454EXAMPLE:  example ncVarsAdd;
1455shows an example"
1456{
1457  int i, j;
1458  int exists = 0;
1459
1460  for (i = 1; i <= size(vars); i++)
1461  {
1462    for (j = 1; j <= size(NCVARIABLES); j++)
1463    {
1464      if (vars[i] == NCVARIABLES[j])
1465      {
1466        exists = 1;
1467      }
1468    }
1469    if (exists == 0)
1470    {
1471      NCVARIABLES = NCVARIABLES + list(vars[i]);
1472    }
1473    else
1474    {
1475      exists = 0;
1476    }
1477  }
1478
1479  ncRingDefine();
1480}
1481example
1482{
1483  "EXAMPLE:";
1484  echo = 2;
1485  ncInit(list("x", "y", "z"));
1486  ncVarsGet();
1487  ncVarsAdd(list("a", "b", "c"));
1488  ncVarsGet();
1489}
1490
1491/*##########################################################
1492
1493  END GENERAL
1494
1495##########################################################*/
1496
1497/*##########################################################
1498
1499   NCRAT
1500
1501##########################################################*/
1502
1503proc ncratDefine(string s, list l)
1504"USAGE:   ncrat f = ncratDefine(s, l);
1505  string s contains kind, list l contains expressions
1506
1507RETURN:   ncrat with kind s and expressions l
1508
1509NOTE:
1510  assignment operator '=' for ncrat is overloaded
1511  with this procedure, hence
1512      ncrat f = s, l;
1513  yields the same result as
1514      ncrat f = ncratDefine(s, l);
1515
1516EXAMPLE:  example ncratDefine;
1517  shows an example"
1518{
1519  if (not(ncratIsValid(s, l)))
1520  {
1521    ERROR("Not a valid rational expression!");
1522  }
1523
1524  ncrat f;
1525  f.kind = s;
1526  f.expr = l;
1527  return (f);
1528}
1529example
1530{
1531  "EXAMPLE:";
1532  echo = 2;
1533  ncInit(list("x", "y", "z"));
1534  number n = 5;
1535  ncrat f = ncratDefine("Const", list(n));
1536  typeof(f);
1537  f.kind;
1538  f.expr;
1539  f;
1540  ncrat g = "Const", list(n);
1541  g;
1542}
1543
1544proc ncratAdd(ncrat f, ncrat g)
1545"USAGE:   ncrat h = ncratAdd(f, g);
1546  f, g both of type ncrat
1547
1548RETURN:   h = f + g
1549
1550NOTE:
1551  operator '+' for ncrat is overloaded
1552  with this procedure, hence
1553      ncrat h = f + g;
1554  yields the same result as
1555      ncrat h = ncratAdd(f, g);
1556
1557EXAMPLE:  example ncratAdd;
1558  shows an example"
1559{
1560  ncrat h = "Add", list(f, g);
1561  return (h);
1562}
1563example
1564{
1565  "EXAMPLE:";
1566  echo = 2;
1567  ncInit(list("x", "y", "z"));
1568  ncrat f = ncratFromString("2*x*y");
1569  print(f);
1570  ncrat g = ncratFromString("z");
1571  print(g);
1572  ncrat h1, h2;
1573  h1 = ncratAdd(f, g);
1574  print(h1);
1575  h2 = f + g;
1576  print(h2);
1577}
1578
1579proc ncratSubstract(ncrat f, ncrat g)
1580"USAGE:   ncrat h = ncratSubstract(f, g);
1581  f, g both of type ncrat
1582
1583RETURN:   h = f - g
1584
1585NOTE:
1586  operator '-' for ncrat is overloaded
1587  with this procedure, hence
1588      ncrat h = f - g;
1589  yields the same result as
1590      ncrat h = ncratSubstract(f, g);
1591
1592EXAMPLE:  example ncratSubstract;
1593  shows an example"
1594{
1595  ncrat h = "Sub", list(f, g);
1596  return (h);
1597}
1598example
1599{
1600  "EXAMPLE:";
1601  echo = 2;
1602  ncInit(list("x", "y", "z"));
1603  ncrat f = ncratFromString("2*x*y");
1604  print(f);
1605  ncrat g = ncratFromString("z");
1606  print(g);
1607  ncrat h1, h2;
1608  h1 = ncratSubstract(f, g);
1609  print(h1);
1610  h2 = f - g;
1611  print(h2);
1612}
1613
1614proc ncratMultiply(ncrat f, ncrat g)
1615"USAGE:   ncrat h = ncratMultiply(f, g);
1616  f, g both of type ncrat
1617
1618RETURN:   h = f * g
1619
1620NOTE:
1621  operator '*' for ncrat is overloaded
1622  with this procedure, hence
1623      ncrat h = f * g;
1624  yields the same result as
1625      ncrat h = ncratMultiply(f, g);
1626
1627EXAMPLE:  example ncratMultiply;
1628  shows an example"
1629{
1630  // Both factors are constants
1631  if (f.kind == "Const" and g.kind == "Const")
1632  {
1633    ncrat h = "Const", list(f.expr[1] * g.expr[1]);
1634    return (h)
1635  }
1636
1637  // Only second factor is a constant
1638  // Switch order of multiplication
1639  if (g.kind == "Const")
1640  {
1641    return (ncratMultiply(g, f));
1642  }
1643
1644  // Otherwise
1645  ncrat h = "Mult", list(f, g);
1646  return (h);
1647}
1648example
1649{
1650  "EXAMPLE:";
1651  echo = 2;
1652  ncInit(list("x", "y", "z"));
1653  ncrat f = ncratFromString("2*x*y");
1654  print(f);
1655  ncrat g = ncratFromString("z");
1656  print(g);
1657  ncrat h1, h2;
1658  h1 = ncratMultiply(f, g);
1659  print(h1);
1660  h2 = f * g;
1661  print(h2);
1662}
1663
1664proc ncratInvert(ncrat f)
1665"USAGE:   ncrat h = ncratInvert(f);
1666  f of type ncrat
1667
1668RETURN:   h = inv(f)
1669
1670NOTE:
1671      ncrat h = f^-1;
1672  yields the same result as
1673      ncrat h = ncratInvert(f);
1674
1675EXAMPLE:  example ncratInvert;
1676  shows an example"
1677{
1678  ncrat h;
1679  if (f.kind == "Const")
1680  {
1681    if (f.expr[1] != 0)
1682    {
1683      number n = 1;
1684      number m = f.expr[1];
1685      h = "Const", list(n / m);
1686      return (h);
1687    }
1688  }
1689  h = "Inv", list(f);
1690  return (h);
1691}
1692example
1693{
1694  "EXAMPLE:";
1695  echo = 2;
1696  ncInit(list("x", "y", "z"));
1697  ncrat f = ncratFromString("2*x*y");
1698  print(f);
1699  ncrat h1, h2;
1700  h1 = ncratInvert(f);
1701  print(h1);
1702  h2 = f ^ -1;
1703  print(h2);
1704}
1705
1706proc ncratSPrint(ncrat f)
1707"USAGE:   string s = ncratSPrint(f);
1708  f of type ncrat
1709
1710RETURN:   prints f to string
1711
1712EXAMPLE:  example ncratSPrint;
1713  shows an example"
1714{
1715  string t, h, k;
1716  string s = f.kind;
1717  list l = f.expr;
1718
1719  if (s == "Const")
1720  {
1721    t = string(l[1]);
1722  }
1723
1724  if (s == "Var")
1725  {
1726    t = l[1];
1727  }
1728
1729  if (s == "Add")
1730  {
1731    t = ncratSPrint(l[1]) + "+" + ncratSPrint(l[2]);
1732  }
1733
1734  if (s == "Sub")
1735  {
1736    if (l[2].kind == "Add" or l[2].kind == "Sub")
1737    {
1738      h = "(" + ncratSPrint(l[2]) + ")";
1739    }
1740    else
1741    {
1742      h = ncratSPrint(l[2]);
1743    }
1744    t = ncratSPrint(l[1]) + "-" + h;
1745  }
1746
1747  if (s == "Mult")
1748  {
1749    if (l[1].kind == "Add" or l[1].kind == "Sub")
1750    {
1751      h = "(" + ncratSPrint(l[1]) + ")";
1752    }
1753    else
1754    {
1755      h = ncratSPrint(l[1]);
1756    }
1757    if (l[2].kind == "Add" or l[2].kind == "Sub")
1758    {
1759      k = "(" + ncratSPrint(l[2]) + ")";
1760    }
1761    else
1762    {
1763      k = ncratSPrint(l[2]);
1764    }
1765    t = h + "*" + k;
1766  }
1767
1768  if (s == "Inv")
1769  {
1770    t = "inv(" + ncratSPrint(l[1]) + ")";
1771  }
1772
1773  return (t);
1774}
1775example
1776{
1777  "EXAMPLE:";
1778  echo = 2;
1779  ncInit(list("x", "y", "z"));
1780  ncrat f = ncratFromString("2*x*y");
1781  string s = ncratSPrint(f);
1782  print(s);
1783}
1784
1785proc ncratPrint(ncrat f)
1786"USAGE:   ncratPrint(f);
1787  f of type ncrat
1788
1789RETURN:   prints f
1790
1791NOTE:
1792      print(f);
1793  yields the same result as
1794      ncratPrint(f);
1795
1796EXAMPLE:  example ncratPrint;
1797  shows an example"
1798{
1799  print(ncratSPrint(f));
1800}
1801example
1802{
1803  "EXAMPLE:";
1804  echo = 2;
1805  ncInit(list("x", "y", "z"));
1806  ncrat f = ncratFromString("2*x*y");
1807  ncratPrint(f);
1808  print(f);
1809}
1810
1811proc ncratFromString(string s)
1812"USAGE:   ncrat f = ncratFromString(s);
1813  s of type string
1814
1815RETURN:   read string s into ncrat f
1816
1817EXAMPLE:  example ncratFromString;
1818  shows an example"
1819{
1820  // Clear tokenstream
1821  TOKENSTREAM.input = s;
1822  TOKENSTREAM.position = 1;
1823  TOKENSTREAM.full = 0;
1824
1825  ncrat f = expression();
1826  return (f);
1827}
1828example
1829{
1830  "EXAMPLE:";
1831  echo = 2;
1832  ncInit(list("x", "y", "z"));
1833  ncrat f = ncratFromString("2*x*y");
1834  print(f);
1835}
1836
1837proc ncratFromPoly(poly p)
1838"USAGE:   ncrat f = ncratFromPoly(p);
1839  p of type poly
1840
1841RETURN:   convert poly to ncrat
1842
1843EXAMPLE:  example ncratFromPoly;
1844  shows an example"
1845{
1846  string s = print(p);
1847  ncrat f = ncratFromString(s);
1848  return (f);
1849}
1850example
1851{
1852  "EXAMPLE:";
1853  echo = 2;
1854  ncInit(list("x", "y", "z"));
1855  poly p = 2 * x * y;
1856  ncrat f = ncratFromPoly(p);
1857  print(f);
1858}
1859
1860proc ncratPower(ncrat f, int n)
1861"USAGE:   ncrat h = ncratPower(f, n);
1862  f of type ncrat, n integer
1863
1864RETURN:   h = f^n
1865
1866EXAMPLE:  example ncratPower;
1867  shows an example"
1868{
1869  if (n < 0)
1870  {
1871    return (ncratInvert(ncratPower(f, -n)));
1872  }
1873
1874  if (n == 0)
1875  {
1876    return (ncratFromString("1"));
1877  }
1878
1879  if (n == 1)
1880  {
1881    return (f);
1882  }
1883
1884  return (ncratPower(f, n - 1) * f);
1885}
1886example
1887{
1888  "EXAMPLE:";
1889  echo = 2;
1890  ncInit(list("x", "y", "z"));
1891  ncrat f = ncratFromString("2*x*y");
1892  ncrat h = ncratPower(f, 3);
1893  print(h);
1894}
1895
1896proc ncratEvaluateAt(ncrat f, list vars, list point)
1897"USAGE:   matrix M = ncratEvaluateAt(f, vars, point);
1898
1899RETURN:   Evaluate the ncrat f by substituting in the
1900  matrices contained in point for the respective
1901  variables contained in var, that is, calculate
1902  f(point).
1903
1904EXAMPLE:  example ncratEvaluateAt;
1905  shows an example"
1906{
1907  string s = f.kind;
1908
1909  if (s == "Const")
1910  {
1911    matrix A = ncratEvaluateConst(f, vars, point);
1912    return (A);
1913  }
1914
1915  if (s == "Add")
1916  {
1917    matrix A = ncratEvaluateAdd(f, vars, point);
1918    return (A);
1919  }
1920
1921  if (s == "Sub")
1922  {
1923    matrix A = ncratEvaluateSub(f, vars, point);
1924    return (A);
1925  }
1926
1927  if (s == "Mult")
1928  {
1929    matrix A = ncratEvaluateMult(f, vars, point);
1930    return (A);
1931  }
1932
1933  if (s == "Inv")
1934  {
1935    matrix A = ncratEvaluateInv(f, vars, point);
1936    return (A);
1937  }
1938
1939  if (s == "Var")
1940  {
1941    matrix A = ncratEvaluateVar(f, vars, point);
1942    return (A);
1943  }
1944}
1945example
1946{
1947  "EXAMPLE:";
1948  echo = 2;
1949  ncInit(list("x", "y"));
1950  ncrat f = ncratFromString("x+y");
1951  matrix A[2][2] = 1, 2, 3, 4;
1952  matrix B[2][2] = 5, 6, 7, 8;
1953  matrix M = ncratEvaluateAt(f, list(x, y), list(A, B));
1954  print(M);
1955}
1956
1957/*##########################################################
1958
1959  END NCRAT
1960
1961##########################################################*/
1962
1963/*##########################################################
1964
1965   NCREP
1966
1967##########################################################*/
1968
1969proc ncrepGet(ncrat f)
1970"USAGE:   ncrep q = ncrepGet(f);
1971  f of type ncrat
1972
1973RETURN:   q = (u, Q, v) linear representation of f
1974
1975EXAMPLE:  example ncrepGet;
1976  shows an example"
1977{
1978  ncrep q;
1979
1980  // switch on f.kind
1981  if (f.kind == "Const")
1982  {
1983    q = ncrepConst(f.expr[1]);
1984    return (q);
1985  }
1986
1987  if (f.kind == "Var")
1988  {
1989    string s = "poly p = " + f.expr[1] + ";";
1990    execute(s);
1991    q = ncrepVar(p);
1992    return (q);
1993  }
1994
1995  if (f.kind == "Add")
1996  {
1997    q = ncrepAdd(ncrepGet(f.expr[1]), ncrepGet(f.expr[2]));
1998    return (q);
1999  }
2000
2001  if (f.kind == "Sub")
2002  {
2003    q = ncrepSubstract(ncrepGet(f.expr[1]), ncrepGet(f.expr[2]));
2004    return (q);
2005  }
2006
2007  if (f.kind == "Mult")
2008  {
2009    // First factor is a non-zero constant
2010    if (f.expr[1].kind == "Const")
2011    {
2012      if (f.expr[1].expr[1] != 0) {
2013        q = ncrepGet(f.expr[2]);
2014        q.mat = q.mat / f.expr[1].expr[1];
2015        return (q);
2016      }
2017    }
2018
2019    // Second factor is a non-zero constant
2020    if (f.expr[2].kind == "Const")
2021    {
2022      if (f.expr[2].expr[1] != 0) {
2023        q = ncrepGet(f.expr[1]);
2024        q.mat = q.mat / f.expr[2].expr[1];
2025        return (q);
2026      }
2027    }
2028
2029    // No constant factors
2030    q = ncrepMultiply(ncrepGet(f.expr[1]), ncrepGet(f.expr[2]));
2031    return (q);
2032  }
2033
2034  if (f.kind == "Inv")
2035  {
2036    q = ncrepInvert(ncrepGet(f.expr[1]));
2037    return (q);
2038  }
2039}
2040example
2041{
2042  "EXAMPLE:";
2043  echo = 2;
2044  ncInit(list("x", "y", "z"));
2045  ncrat f = ncratFromString("2*x*y");
2046  ncrep q = ncrepGet(f);
2047  print(q);
2048}
2049
2050proc ncrepAdd(ncrep s, ncrep t)
2051"USAGE:   ncrep s = ncrepAdd(q, r);
2052  q, r both of type ncrep
2053
2054RETURN:   representation s of h = f + g
2055  if q, r are representations of f, g
2056
2057NOTE:
2058  operator '+' for ncrep is overloaded
2059  with this procedure, hence
2060      ncrep s = q + r;
2061  yields the same result as
2062      ncrep s = ncrepAdd(q, r);
2063
2064EXAMPLE:  example ncrepAdd;
2065  shows an example"
2066{
2067  ncrep q;
2068  q.lvec = concat(s.lvec, t.lvec);
2069  q.rvec = transpose(concat(transpose(s.rvec), transpose(t.rvec)));
2070  q.mat = dsum(s.mat, t.mat);
2071  return (q);
2072}
2073example
2074{
2075  "EXAMPLE:";
2076  echo = 2;
2077  ncInit(list("x", "y", "z"));
2078  ncrat f = ncratFromString("x");
2079  ncrat g = ncratFromString("y");
2080  ncrep q = ncrepGet(f);
2081  ncrep r = ncrepGet(g);
2082  ncrep s1, s2;
2083  s1 = ncrepAdd(q, r);
2084  print(s1);
2085  s2 = q + r;
2086  print(s2);
2087}
2088
2089proc ncrepSubstract(ncrep s, ncrep t)
2090"USAGE:   ncrep s = ncrepSubstract(q, r);
2091  q, r both of type ncrep
2092
2093RETURN:   representation s of h = f - g
2094  if q, r are representations of f, g
2095
2096NOTE:
2097  operator '-' for ncrep is overloaded
2098  with this procedure, hence
2099      ncrep s = q - r;
2100  yields the same result as
2101      ncrep s = ncrepSubstract(q, r);
2102
2103EXAMPLE:  example ncrepSubstract;
2104  shows an example"
2105{
2106  ncrep q;
2107  q.lvec = concat(s.lvec, t.lvec);
2108  q.rvec = transpose(concat(transpose(s.rvec), transpose(t.rvec)));
2109  q.mat = dsum(s.mat, -t.mat);
2110  return (q);
2111}
2112example
2113{
2114  "EXAMPLE:";
2115  echo = 2;
2116  ncInit(list("x", "y", "z"));
2117  ncrat f = ncratFromString("x");
2118  ncrat g = ncratFromString("y");
2119  ncrep q = ncrepGet(f);
2120  ncrep r = ncrepGet(g);
2121  ncrep s1, s2;
2122  s1 = ncrepSubstract(q, r);
2123  print(s1);
2124  s2 = q - r;
2125  print(s2);
2126}
2127
2128proc ncrepMultiply(ncrep s, ncrep t)
2129"USAGE:   ncrep s = ncrepMultiply(q, r);
2130  q, r both of type ncrep
2131
2132RETURN:   representation s of h = f * g
2133  if q, r are representations of f, g
2134
2135NOTE:
2136  operator '*' for ncrep is overloaded
2137  with this procedure, hence
2138      ncrep s = q * r;
2139  yields the same result as
2140      ncrep s = ncrepMultiply(q, r);
2141
2142EXAMPLE:  example ncrepMultiply;
2143  shows an example"
2144{
2145  ncrep q;
2146  int dims = ncols(s.lvec);
2147  int dimt = ncols(t.lvec);
2148  matrix lzero[1][dimt] = 0;
2149  matrix rzero[dims][1] = 0;
2150  matrix mzero[dimt][dims] = 0;
2151
2152  q.lvec = concat(lzero, s.lvec);
2153  q.rvec = transpose(concat(transpose(rzero), transpose(t.rvec)));
2154
2155  matrix A = concat(s.rvec * t.lvec, s.mat);
2156  matrix B = concat(t.mat, mzero);
2157  q.mat = transpose(concat(transpose(A), transpose(B)));
2158
2159  return (q);
2160}
2161example
2162{
2163  "EXAMPLE:";
2164  echo = 2;
2165  ncInit(list("x", "y", "z"));
2166  ncrat f = ncratFromString("x");
2167  ncrat g = ncratFromString("y");
2168  ncrep q = ncrepGet(f);
2169  ncrep r = ncrepGet(g);
2170  ncrep s1, s2;
2171  s1 = ncrepMultiply(q, r);
2172  print(s1);
2173  s2 = q * r;
2174  print(s2);
2175}
2176
2177proc ncrepInvert(ncrep s)
2178"USAGE:   ncrep s = ncrepInvert(q);
2179  q of type ncrep
2180
2181RETURN:   representation of h = inv(f)
2182  if q is a representation of f
2183
2184EXAMPLE:  example ncrepInvert;
2185  shows an example"
2186{
2187  ncrep q;
2188  int n = ncols(s.lvec);
2189  matrix one[1][1] = 1;
2190  matrix vzero[1][n] = 0;
2191  matrix mzero[1][1] = 0;
2192
2193  q.lvec = concat(one, vzero);
2194  q.rvec = transpose(q.lvec);
2195
2196  matrix A = concat(mzero, s.lvec);
2197  matrix B = concat(s.rvec, -s.mat);
2198  q.mat = transpose(concat(transpose(A), transpose(B)));
2199
2200  return (q);
2201}
2202example
2203{
2204  "EXAMPLE:";
2205  echo = 2;
2206  ncInit(list("x", "y", "z"));
2207  ncrat f = ncratFromString("2*x*y");
2208  ncrep q = ncrepGet(f);
2209  ncrep s = ncrepInvert(q);
2210  print(s);
2211}
2212
2213proc ncrepPrint(ncrep q)
2214"USAGE:   ncrepPrint(q);
2215  q of type ncrep
2216
2217RETURN:   prints q
2218
2219NOTE:
2220      print(q);
2221  yields the same result as
2222      ncrepPrint(q);
2223
2224EXAMPLE:  example ncrepPrint;
2225  shows an example"
2226{
2227  print("lvec=");
2228  print(q.lvec);
2229  print(newline + "mat=");
2230  print(q.mat);
2231  print(newline + "rvec=");
2232  print(q.rvec);
2233}
2234example
2235{
2236  "EXAMPLE:";
2237  echo = 2;
2238  ncInit(list("x", "y", "z"));
2239  ncrat f = ncratFromString("2*x*y");
2240  ncrep q = ncrepGet(f);
2241  ncrepPrint(q);
2242  print(q);
2243}
2244
2245proc ncrepDim(ncrep q)
2246"USAGE:   ncrepDim(q);
2247  q of type ncrep
2248
2249RETURN:   dimension of q;
2250  returns 0 if q represents the zero-function
2251
2252EXAMPLE:  example ncrepDim;
2253  shows an example"
2254{
2255  int n = ncols(q.mat);
2256  // Does q represent zero?
2257  if (n == 1)
2258  {
2259    if (q.lvec == 0 or q.rvec == 0)
2260    {
2261      n = 0;
2262    }
2263  }
2264  return (n);
2265}
2266example
2267{
2268  "EXAMPLE:";
2269  echo = 2;
2270  ncInit(list("x", "y", "z"));
2271  ncrat f = ncratFromString("2*x*y");
2272  ncrep q = ncrepGet(f);
2273  print(q);
2274  ncrepDim(q);
2275}
2276
2277proc ncrepSubstitute(ncrep q, list vars, list points)
2278"USAGE:     ncrep s = ncrepSubstitute(q, l);
2279  q of type ncrep, vars = (x1, ..., xg),
2280  points = (A1, ... , Ag) with Ai matrices of the
2281  same dimension and xi of type poly are nc variables
2282
2283RETURN:     substitutes in Ai for xi in q
2284
2285EXAMPLE:  example ncrepSubstitute;
2286  shows an example"
2287{
2288  int g = size(vars);
2289  if (not(size(points) == g))
2290  {
2291    ERROR("Number of variables and points does not match!");
2292  }
2293
2294  // Lists empty
2295  if (g == 0)
2296  {
2297    return (q.mat);
2298  }
2299
2300  // Lists non-empty
2301  int i;
2302  list l = ncrepLinearPencil(q, vars);
2303  for (i = 0; i <= g; i++)
2304  {
2305    matrix Q(i) = l[i + 1];
2306  }
2307
2308  int n=1;
2309  if (typeof(points[1])!="poly") { n = ncols(points[1]);}
2310  matrix E[n][n];
2311  E = E + 1;
2312
2313  matrix M = tensor(Q(0), E);
2314  for (i = 1; i <= g; i++)
2315  {
2316    matrix A(i) = points[i];
2317    M = M + tensor(Q(i), A(i));
2318  }
2319
2320  ncrep q2;
2321  q2.mat = M;
2322  q2.lvec = tensor(q.lvec, E);
2323  q2.rvec = tensor(q.rvec, E);
2324
2325  return (q2);
2326}
2327example
2328{
2329  "EXAMPLE:";
2330  echo = 2;
2331  ncInit(list("x", "y", "z"));
2332  ncrat f = ncratFromString("x+y");
2333  ncrep q = ncrepGet(f);
2334  matrix A[2][2] = 1, 2, 3, 4;
2335  matrix B[2][2] = 5, 6, 7, 8;
2336  ncrep s = ncrepSubstitute(q, list(x, y), list(A, B));
2337  print(q);
2338  print(s);
2339}
2340
2341proc ncrepEvaluate(ncrep q)
2342"USAGE:   matrix M = ncrepEvaluate(q);
2343
2344RETURN:   for q=(u, Q, v) calculate -u*Q^(-1)*v
2345
2346EXAMPLE:  example ncrepEvaluate;
2347  shows an example"
2348{
2349  matrix QInv = inverse(q.mat);
2350  if (size(QInv) == 1 and QInv[1, 1] == 0)
2351  {
2352    ERROR("Matrix not invertible!");
2353  }
2354  matrix M = -q.lvec * QInv * q.rvec;
2355  return (M);
2356}
2357example
2358{
2359  "EXAMPLE:";
2360  echo = 2;
2361  ncInit(list("x", "y", "z"));
2362  ncrat f = ncratFromString("x+y");
2363  ncrep q = ncrepGet(f);
2364  matrix A[2][2] = 1, 2, 3, 4;
2365  matrix B[2][2] = 5, 6, 7, 8;
2366  ncrep s = ncrepSubstitute(q, list(x, y), list(A, B));
2367  matrix M = ncrepEvaluate(s);
2368  print(M);
2369}
2370
2371proc ncrepEvaluateAt(ncrep q, list vars, list point)
2372"USAGE:   matrix M = ncrepEvaluateAt(q, vars, point);
2373
2374RETURN:   For q=(u, Q, v) calculate -u*Q(point)^(-1)*v,
2375  that is to say, evaluate the ncrat represented
2376  by q at point (scalar or matrix point).
2377
2378EXAMPLE:  example ncrepEvaluateAt;
2379  shows an example"
2380{
2381  ncrep r = ncrepSubstitute(q, vars, point);
2382  matrix M = ncrepEvaluate(r);
2383  return (M);
2384}
2385example
2386{
2387  "EXAMPLE:";
2388  echo = 2;
2389  ncInit(list("x", "y"));
2390  ncrat f = ncratFromString("x+y");
2391  ncrep q = ncrepGet(f);
2392  matrix A[2][2] = 1, 2, 3, 4;
2393  matrix B[2][2] = 5, 6, 7, 8;
2394  matrix M = ncrepEvaluateAt(q, list(x, y), list(A, B));
2395  print(M);
2396}
2397
2398proc ncrepIsDefinedDim(ncrep q, int N, list vars, int n, int maxcoeff)
2399"USAGE:   list l = ncrepIsDefinedDim(q, N, vars, n, maxcoeff);
2400
2401RETURN:   list(k, list vars, list(A1, ..., Ak)), where:
2402  If k = N then there are matrices A1, ..., Ak of size N
2403  such that q is defined at A = (A1, ..., Ak), i.e.,
2404  q.mat is invertible at A.
2405  If k = 0 then no such point was found.
2406
2407NOTE:     Test whether q.mat is invertible via evaluation
2408  at random matrix points with integer coefficients
2409  in [-maxcoeff, maxcoeff]. Stops after n tries.
2410  Use square matrices of dimension N. The list vars
2411  contains the nc variables which occur in q.
2412
2413EXAMPLE:  example ncrepIsDefinedDim;
2414  shows an example"
2415{
2416  int g = size(vars);
2417  int i, k;
2418  for (i = 1; i <= n; i++)
2419  {
2420    // Substitute random matrices
2421    list points;
2422    for (k = 1; k <= g; k++)
2423    {
2424      matrix A(k) = randommat(N, N, maxideal(0), maxcoeff);
2425      points = points + list(A(k));
2426      kill(A(k));
2427    }
2428    ncrep q2 = ncrepSubstitute(q, vars, points);
2429
2430    // Check for invertibility
2431    if (mat_rk(q2.mat) == ncols(q2.mat))
2432    {
2433      list result = list(N) + list(vars) + list(points);
2434      kill(q2);
2435      kill(points);
2436      return (result);
2437    }
2438    kill(q2);
2439    kill(points);
2440  }
2441  list empty;
2442  list result = list(0) + list(vars) + list(empty);
2443  return (result);
2444}
2445example
2446{
2447  "EXAMPLE:";
2448  echo = 2;
2449  ncInit(list("x", "y"));
2450  ncrat f = ncratFromString("inv(x*y-y*x)");
2451  ncrep q = ncrepGet(f);
2452  ncrepIsDefinedDim(q, 1, list(x, y), 10, 100);
2453  ncrepIsDefinedDim(q, 2, list(x, y), 10, 100);
2454}
2455
2456proc ncrepIsDefined(ncrep q, list vars, int n, int maxcoeff)
2457"USAGE:   list l = ncrepIsDefined(q, vars, n, maxcoeff);
2458
2459RETURN:   list(dim, list vars, list(A1, ..., Ak)), where:
2460  If dim > 0 then there are matrices A1, ..., Ak of size dim
2461  such that q is defined at A = (A1, ..., Ak), i.e.,
2462  q.mat is invertible at A.
2463  If dim = 0 then no such point was found.
2464
2465NOTE:     Test whether q.mat is invertible via evaluation
2466  at random matrix points with integer coefficients
2467  in [-maxcoeff, maxcoeff]. Stops after n tries.
2468  Use ixi-matrix in i-th try. The list vars contains the
2469  nc variables which occur in q.
2470
2471EXAMPLE:  example ncrepIsDefined;
2472  shows an example"
2473{
2474  int i;
2475  list l;
2476  for (i = 1; i <= n; i++)
2477  {
2478    l = ncrepIsDefinedDim(q, i, vars, 1, maxcoeff);
2479    if (l[1] > 0)
2480    {
2481      return (l);
2482    }
2483  }
2484  return (l);
2485}
2486example
2487{
2488  "EXAMPLE:";
2489  echo = 2;
2490  ncInit(list("x", "y"));
2491  ncrat f = ncratFromString("inv(x*y-y*x)");
2492  ncrep q = ncrepGet(f);
2493  ncrepIsDefined(q, list(x, y), 5, 10);
2494  ncrat g = ncratFromString("inv(x-x)");
2495  ncrep r = ncrepGet(g);
2496  ncrepIsDefined(r, list(x), 5, 10);
2497}
2498
2499proc ncrepIsRegular(ncrep q, list vars, int n, int maxcoeff)
2500"USAGE:   list l = ncrepIsRegular(q, vars, n, maxcoeff);
2501
2502RETURN:   list(k, list vars, list(a1, ..., ak)), where:
2503  If k = 1 then there are scalars (1x1-matrices) a1, ..., ak
2504  such that q is defined at a = (a1, ..., ak), i.e.,
2505  q.mat is invertible at a.
2506  If k = 0 then no such point was found.
2507
2508NOTE:     Test whether q.mat is invertible via evaluation
2509  at random integers  in [-maxcoeff, maxcoeff].
2510  Stops after n tries. The list vars
2511  contains the nc variables which occur in q.
2512
2513EXAMPLE:  example ncrepIsRegular;
2514  shows an example"
2515{
2516  list l = ncrepIsDefinedDim(q, 1, vars, n, maxcoeff);
2517  return (l);
2518}
2519example
2520{
2521  "EXAMPLE:";
2522  echo = 2;
2523  ncInit(list("x", "y"));
2524  ncrat f = ncratFromString("inv(x*y-y*x)");
2525  ncrep q = ncrepGet(f);
2526  ncrepIsRegular(q, list(x, y), 10, 100);
2527  ncrat g = ncratFromString("inv(1+x*y-y*x)");
2528  ncrep r = ncrepGet(g);
2529  ncrepIsRegular(r, list(x, y), 10, 100);
2530}
2531
2532proc ncrepPencilGet(ncrep r, list vars)
2533"USAGE:     list pencil = ncrepPencilGet(r, vars);
2534
2535RETURN:     pencil = list(vars, matrices),
2536  where vars = list(1, x1, ..., xg) are the variables
2537  occurring in r and matrices = (Q0, ..., Qg) is a list of
2538  matrices such that
2539    r.mat = Q0 * x0 + ... + Qg * xg
2540  with x0 = 1
2541
2542NOTE:       list vars = list(x1, ..., xn) has to consist
2543  exactly of the nc variables occurring in f
2544
2545EXAMPLE:    example ncrepPencilGet;
2546  shows an example"
2547{
2548  poly p = 1;
2549  list varsNew = list(p) + vars;
2550  list matrices = ncrepLinearPencil(r, vars);
2551  list l = list(varsNew, matrices);
2552  return (l);
2553}
2554example
2555{
2556  "EXAMPLE:";
2557  echo = 2;
2558  ncInit(list("x", "y"));
2559  ncrat f = ncratFromString("x*y");
2560  ncrep r = ncrepGet(f);
2561  print(r.mat);
2562  list l = ncrepPencilGet(r, list(x, y));
2563  print(l[1]);
2564  print(l[2][1]);
2565  print(l[2][2]);
2566  print(l[2][3]);
2567}
2568
2569proc ncrepPencilCombine(list pencil)
2570"USAGE:     matrix Q = ncrepPencilCombine(pencil);
2571
2572RETURN:     matrix Q = Q0*x0 + ... + Qg*xg,
2573  where vars = list(x0, ..., xg) consists of polynomials
2574  and matrices = (Q0, ..., Qg) is a list of matrices
2575
2576EXAMPLE:    example ncrepPencilCombine;
2577  shows an example"
2578{
2579  int g = size(pencil[1]);
2580  int n = ncols(pencil[2][1]);
2581  matrix Q[n][n];
2582  int i;
2583  for (i = 1; i <= g; i++)
2584  {
2585    Q = Q + pencil[1][i] * pencil[2][i];
2586  }
2587  return (Q);
2588}
2589example
2590{
2591  "EXAMPLE:";
2592  echo = 2;
2593  ncInit(list("x", "y"));
2594  ncrat f = ncratFromString("x*y");
2595  ncrep r = ncrepGet(f);
2596  print(r.mat);
2597  list l = ncrepPencilGet(r, list(x, y));
2598  matrix Q = ncrepPencilCombine(l);
2599  print(Q);
2600}
2601
2602/*##########################################################
2603
2604   REGULAR CASE
2605
2606##########################################################*/
2607
2608proc ncrepRegularZeroMinimize(ncrep q, list #)
2609"USAGE:     ncrep s = ncrepRegularZeroMinimize(q, l);
2610
2611RETURN:     ncrep s representing the same rational
2612  function as ncrep q, where s is of minimal size
2613
2614ASSUMPTION: q is regular at zero, i.e.,
2615  if one substitutes in 0 for all nc variables in q
2616  then q.mat has to be invertible
2617
2618NOTE:       list l = list(x1, ..., xn) has to consist
2619  exactly of the nc variables occurring in q
2620
2621EXAMPLE:    example ncrepRegularZeroMinimize;
2622  shows an example"
2623{
2624  int i;
2625  int g = size(#);
2626  int n = ncols(q.mat);
2627  int offset = 0;
2628  list k = ncrepToMonicDescriptorRealization(g, n, q, #);
2629
2630  // cut down on controllable space
2631  list b = calculateControllabilitySpace(g, n, k[1], k[3]);
2632  list c = calculateComplement(n, b);
2633  n = size(b);
2634  matrix bMat = orthogonalBase(b);
2635  matrix cMat = orthogonalBase(c);
2636  k = orthogonalTransform(bMat, cMat, k[1], k[2], k[3]);
2637  k = cutdown(n, offset, k[1], k[2], k[3]);
2638
2639  // cut down on observable space
2640  n = size(b);
2641  list l;
2642
2643  // switch to adjoint system
2644  for (i = 1; i <= g; i++)
2645  {
2646    l = l + list(transpose(k[3][i]));
2647  }
2648  list ktp = list(transpose(k[2]), transpose(k[1]), l);
2649
2650  b = calculateControllabilitySpace(g, n, ktp[1], ktp[3]);
2651  c = calculateComplement(n, b);
2652  n = size(b);
2653  offset = size(c);
2654  bMat = orthogonalBase(b);
2655  cMat = orthogonalBase(c);
2656  ktp = orthogonalTransform(cMat, bMat, ktp[1], ktp[2], ktp[3]);
2657  ktp = cutdown(n, offset, ktp[1], ktp[2], ktp[3]);
2658
2659  // build ncrep
2660  n = size(b);
2661  ncrep r;
2662  r.lvec = -1 * transpose(ktp[1]);
2663  r.rvec = transpose(ktp[2]);
2664
2665  matrix Q[n][n];
2666  Q = Q + 1;
2667  for (i = 1; i <= g; i++)
2668  {
2669    Q = Q - transpose(ktp[3][i]) * #[i];
2670  }
2671  r.mat = Q;
2672
2673  return (r);
2674}
2675example
2676{
2677  "EXAMPLE:";
2678  echo = 2;
2679  ncInit(list("x", "y"));
2680  ncrat f = ncratFromString("inv(1+x*y-y*x)");
2681  ncrep q = ncrepGet(f);
2682  ncrepDim(q);
2683  ncrep s = ncrepRegularZeroMinimize(q, list(x, y));
2684  ncrepDim(s);
2685  s;
2686}
2687
2688proc ncrepRegularMinimize(ncrep q, list vars, list point)
2689"USAGE:     ncrep s = ncrepRegularMinimize(q, vars, point);
2690
2691RETURN:     ncrep s representing the same rational
2692  function as ncrep q, where s is of minimal size
2693
2694ASSUMPTION: q is regular at scalar point a, i.e.,
2695  if one substitutes in ai for all nc variables xi in q
2696  then q.mat has to be invertible
2697
2698NOTE:       list vars = list(x1, ..., xn) has to consist
2699  exactly of the nc variables occurring in q and
2700  list point = list(a1, ..., an) consists of scalars
2701
2702EXAMPLE:    example ncrepRegularMinimize;
2703  shows an example"
2704{
2705  int g = size(vars);
2706  if (not(size(point) == g))
2707  {
2708    ERROR("Lists have to be of the same size!");
2709  }
2710
2711  list shift, backshift;
2712  int i;
2713  poly p1, p2;
2714
2715  // point matrices?
2716  if (g > 0 and typeof(point[1]) == "matrix")
2717  {
2718    if (ncols(point[1]) > 1)
2719    {
2720      ERROR("Not a scalar point!");
2721    }
2722    for (i = 1; i <= g; i++)
2723    {
2724      poly z(i) = point[i][1, 1];
2725    }
2726  }
2727  // point scalars
2728  else
2729  {
2730    for (i = 1; i <= g; i++)
2731    {
2732      poly z(i) = point[i];
2733    }
2734  }
2735
2736  for (i = 1; i <= g; i++)
2737  {
2738    p1 = vars[i] - z(i);
2739    p2 = vars[i] + z(i);
2740    shift = shift + list(p1);
2741    backshift = backshift + list(p2);
2742  }
2743
2744  ncrep s = ncrepSubstitute(q, vars, shift);
2745  ncrep r = ncrepRegularZeroMinimize(s, vars);
2746  ncrep q2 = ncrepSubstitute(r, vars, backshift);
2747
2748  return (q2);
2749}
2750example
2751{
2752  "EXAMPLE:";
2753  echo = 2;
2754  ncInit(list("x", "y"));
2755  ncrat f = ncratFromString("inv(x*y)");
2756  ncrep q = ncrepGet(f);
2757  ncrepDim(q);
2758  ncrep s = ncrepRegularMinimize(q, list(x, y), list(1, 1));
2759  ncrepDim(s);
2760  s;
2761}
2762
2763proc ncrepGetRegularZeroMinimal(ncrat f, list vars)
2764"USAGE:     ncrep q = ncrepGetRegularZeroMinimal(f, vars);
2765
2766RETURN:     q is a representation of f with
2767  minimal dimension
2768
2769ASSUMPTION: f is regular at zero, i.e.,
2770  f(0) has to be defined
2771
2772NOTE:       list vars = list(x1, ..., xn) has to consist
2773  exactly of the nc variables occurring in f
2774
2775EXAMPLE:    example ncrepGetRegularZeroMinimal;
2776  shows an example"
2777{
2778  ncrep q = ncrepGet(f);
2779  ncrep q2 = ncrepRegularZeroMinimize(q, vars);
2780  return (q2);
2781}
2782example
2783{
2784  "EXAMPLE:";
2785  echo = 2;
2786  ncInit(list("x", "y"));
2787  ncrat f = ncratFromString("inv(1+x*y-y*x)");
2788  list vars = list(x, y);
2789  ncrep q = ncrepGetRegularZeroMinimal(f, vars);
2790  q;
2791}
2792
2793proc ncrepGetRegularMinimal(ncrat f, list vars, list point)
2794"USAGE:     ncrep q = ncrepGetRegularMinimal(f, vars, point);
2795
2796RETURN:     q is a representation of f with
2797  minimal dimension
2798
2799ASSUMPTION: f is regular at point, i.e.,
2800  f(point) has to be defined
2801
2802NOTE:       list vars = list(x1, ..., xn) has to consist
2803  exactly of the nc variables occurring in f and
2804  list point = (p1, ..., pn) of scalars such that
2805  f(point) is defined
2806
2807EXAMPLE:    example ncrepGetRegularMinimal;
2808  shows an example"
2809{
2810  ncrep q = ncrepGet(f);
2811  ncrep q2 = ncrepRegularMinimize(q, vars, point);
2812  return (q2);
2813}
2814example
2815{
2816  "EXAMPLE: (Hua's identity)";
2817  echo = 2;
2818  // We want to prove the Hua's identity, telling that for two
2819  // invertible elements x,y from a division ring, one has
2820  // inv(x+x*inv(y)*x)+inv(x+y) = inv(x)
2821  // where inv(t) stands for the two-sided inverse of t
2822  ncInit(list("x", "y"));
2823  ncrat f = ncratFromString("inv(x+x*inv(y)*x)+inv(x+y)-inv(x)");
2824  print(f);
2825  ncrep r = ncrepGet(f);
2826  ncrepDim(r);
2827  ncrep s = ncrepGetRegularMinimal(f, list(x, y), list(1, 1));
2828  ncrepDim(s);
2829  print(s);
2830  // since s represents the zero element, Hua's identity holds.
2831}
2832
2833/*##########################################################
2834
2835  END REGULAR CASE
2836
2837##########################################################*/
2838
2839/*##########################################################
2840
2841  END NCREP
2842
2843##########################################################*/
2844
2845/*##########################################################
2846
2847  END NON-STATIC PROCEDURES
2848
2849##########################################################*/
Note: See TracBrowser for help on using the repository browser.