source: git/factory/cfCharSets.cc @ bbf054

spielwiese
Last change on this file since bbf054 was bbf054, checked in by Martin Lee <martinlee84@…>, 10 years ago
chg: license stuff
  • Property mode set to 100644
File size: 36.4 KB
Line 
1/*****************************************************************************\
2 * Computer Algebra System SINGULAR
3\*****************************************************************************/
4/** @file cfCharSets.cc
5 *
6 * This file provides functions to compute characteristic sets
7 *
8 * @note some of the code is code from libfac or derived from code from libfac.
9 * Libfac is written by M. Messollen. See also COPYING for license information
10 * and README for general information on characteristic sets.
11 *
12 * ABSTRACT: Descriptions can be found in Wang "On the Parallelization of
13 * characteristic-set based algorithms" or Greuel/Pfister "A Singular
14 * Introduction to Commutative Algebra".
15 *
16 * @authors Martin Lee
17 *
18 **/
19/*****************************************************************************/
20
21#include "timing.h"
22
23#include "cfCharSets.h"
24#include "canonicalform.h"
25#include "cf_algorithm.h"
26#include "facAlgFunc.h"
27
28TIMING_DEFINE_PRINT(neworder_time)
29
30#define __ARRAY_INIT__ -1
31
32// the maximal degree of polys in PS wrt. variable x
33static int
34degpsmax (const CFList & PS, const Variable & x,
35          Intarray & A, Intarray & C)
36{
37  int varlevel= level(x);
38  if (A[varlevel] != __ARRAY_INIT__)
39    return A[varlevel];
40  int max= 0, temp, count= 0;
41 
42  for (CFListIterator i= PS; i.hasItem(); i++)
43  {
44    temp= degree (i.getItem(), x);
45    if (temp > max) 
46    {
47      max= temp;
48      count = 0;
49    }
50    if (temp == max)
51      count += max;  // we count the number of polys
52  }
53  A[varlevel]= max;
54  C[varlevel]= count;
55  return max;
56}
57
58// the minimal non-zero degree of polys in PS wrt. x
59// returns 0 if variable x doesn't occure in any of the polys
60static int
61degpsmin (const CFList & PS, const Variable & x, Intarray & A, Intarray & B,
62          Intarray & C, Intarray & D)
63{
64  int varlevel= level(x);
65  if (B[varlevel] != __ARRAY_INIT__ )
66    return B[varlevel];
67  int min= degpsmax (PS, x, A, C), temp, count= 0;
68
69  if (min == 0)
70  {
71    B[varlevel]= min;
72    D[varlevel]= min;
73    return min;
74  }
75  else
76  {
77    for (CFListIterator i= PS; i.hasItem(); i++)
78    {
79      temp= degree (i.getItem(), x);
80      if (temp < min && temp != 0)
81      {
82        min= temp;
83        count= 0;
84      }
85      if (temp == min)
86        count += min; // we count the number of polys
87    }
88  }
89  B[varlevel]= min;
90  D[varlevel]= count;
91  return min;
92}
93
94// the minimal total degree of lcoeffs of polys in PS wrt. x
95// for those polys having degree degpsmin in x.
96// F will be assigned the minimal number of terms of those lcoeffs
97static int
98Tdeg (const CFList & PS, const Variable & x, Intarray & A, Intarray & B,
99      Intarray & C, Intarray & D, Intarray & E, Intarray & F)
100{
101  int k= degpsmin (PS, x, A, B, C, D), varlevel= level(x), min= 0;
102
103  if (E[varlevel] != __ARRAY_INIT__)
104    return E [varlevel];
105  if (k == 0)
106  {
107    E[varlevel]= 0;
108    F[varlevel]= 0;
109  }
110  else
111  {
112    int nopslc= 0;
113    CFList LCdegList;
114    CanonicalForm elem;
115    CFListIterator i;
116
117    for (i= PS; i.hasItem(); i++)
118    {
119      elem= i.getItem();
120      if (degree (elem, x) == k)
121        LCdegList.append (LC (elem, x));
122    }
123   
124    if (LCdegList.length() > 0)
125    {
126      CFList TermList;
127      int newmin, newnopslc;
128
129      min= totaldegree (LCdegList.getFirst());
130      TermList= get_Terms (LCdegList.getFirst()); 
131      nopslc= TermList.length();
132      for (i= LCdegList; i.hasItem(); i++)
133      {
134        elem= i.getItem();
135        newmin= totaldegree(elem);
136        TermList= get_Terms(elem);
137        newnopslc= TermList.length();
138        if (newmin < min)
139          min= newmin; 
140        if (newnopslc < nopslc)
141          nopslc= newnopslc;
142      }
143     
144    }
145    E[varlevel]= min;
146    F[varlevel]= nopslc;
147  }
148  return min;
149}
150
151// The number of the poly in which Variable x first occures
152static int
153nr_of_poly( const CFList & PS, const Variable & x, Intarray & G)
154{
155  int min= 0, varlevel= level(x);
156  if (G[varlevel] != __ARRAY_INIT__)
157    return G[varlevel];
158  for (CFListIterator i= PS; i.hasItem(); i++)
159  {
160    min += 1;
161    if (degree (i.getItem(), x) > 0)
162      break;
163  }
164  G[varlevel]= min;
165  return min;
166}
167
168static int
169degord (const Variable & x, const Variable & y, const CFList & PS,
170        Intarray & A, Intarray & B, Intarray & C, Intarray & D,
171        Intarray & E, Intarray & F, Intarray & G)
172{
173  int xlevel= level(x), ylevel= level(y);
174
175  if      (degpsmax(PS,y,A,C) < degpsmax(PS,x,A,C))         return 1;
176  else if (degpsmax(PS,x,A,C) < degpsmax(PS,y,A,C) )        return 0;
177  else if (C[ylevel] < C[xlevel])                           return 1;
178  else if (C[xlevel] < C[ylevel])                           return 0;
179  else if (degpsmin(PS,x,A,B,C,D) < degpsmin(PS,y,A,B,C,D)) return 1;
180  else if (degpsmin(PS,y,A,B,C,D) < degpsmin(PS,x,A,B,C,D)) return 0;
181  else if (D[ylevel] < D[xlevel])                           return 1;
182  else if (D[xlevel] < D[ylevel])                           return 0;
183  else if (Tdeg(PS,y,A,B,C,D,E,F) < Tdeg(PS,x,A,B,C,D,E,F)) return 1;
184  else if (Tdeg(PS,x,A,B,C,D,E,F) < Tdeg(PS,y,A,B,C,D,E,F)) return 0;
185  else if (F[ylevel] < F[xlevel])                           return 1;
186  else if (F[xlevel] < F[ylevel])                           return 0;
187  else if (nr_of_poly(PS,x,G) <= nr_of_poly(PS,y,G))        return 1;
188  else return 0;
189}
190
191// determine the highest variable of all involved Variables in PS
192// NOTE:
193//    this doesn't give always the correct answer:
194//    If a variable is assigned the highest level in the definition of the
195//    original ring, but doesn't occure in any of the
196//    polynomials, get_max_var returns the variable with a level lower than
197//    the highest level.
198//    Is there a workaround?
199// But for the redefinition of the ring this doesn't matter due to the
200// implementation of neworder().
201
202static Variable
203get_max_var(const CFList & PS)
204{
205  Variable x= PS.getFirst().mvar(), y;
206  for (CFListIterator i= PS; i.hasItem(); i++)
207  {
208    y= i.getItem().mvar();
209    if (y > x)
210      x= y;
211  }
212  return x;
213}
214
215
216// determine if variable x is in one and only one of the polynomials in PS
217// first criterion for neworder
218static CFList
219only_in_one (const CFList & PS, const Variable & x)
220{
221  CFList output;
222
223  for (CFListIterator i= PS; i.hasItem(); i++ )
224  {
225    if (degree (i.getItem(), x) >= 1)
226      output.insert (i.getItem());
227    if (output.length() >= 2)
228      break;
229  }
230  return output;
231}
232
233// initialize all Arrays (of same range) with __ARRAY_INIT__
234static void
235initArray (const int highest_level, Intarray & A, Intarray & B, Intarray & C,
236           Intarray & D, Intarray & E, Intarray & F, Intarray & G)
237{
238  for (int i=1 ; i <= highest_level; i ++)
239  {
240    A[i]= __ARRAY_INIT__;
241    B[i]= __ARRAY_INIT__;
242    C[i]= __ARRAY_INIT__;
243    D[i]= __ARRAY_INIT__;
244    E[i]= __ARRAY_INIT__;
245    F[i]= __ARRAY_INIT__;
246    G[i]= __ARRAY_INIT__;
247  }
248}
249
250// now for the second criterion; a little more complex
251//
252// idea: set up seven arrays of lenth highest_level
253//       (of which some entries may be empty, because of only_in_one!)
254//   A saves maxdegree of Variable x in A(level(x))
255//   B saves mindegree of Variable x in B(level(x))
256//   C saves the number of polys in PS which have degree A(level(x)) in
257//     D(level(x))
258//   D saves the number of polys in PS which have degree B(level(x)) in
259//     D(level(x))
260//   E saves the minimal total degree of lcoeffs of polys wrt x in E(level(x))
261//   F saves the minimal number of terms of lcoeffs of E(level(x)) in F(~)
262//   G saves nr of poly Variable x has first deg <> 0
263
264#define __INIT_GAP__ 3
265static Varlist
266reorderb (const Varlist & difference, const CFList & PS,
267          const int highest_level)
268{
269  Intarray A(1, highest_level), B(1, highest_level), C(1, highest_level),
270           D(1, highest_level), E(1, highest_level), F(1, highest_level),
271           G(1, highest_level);
272  initArray (highest_level, A, B, C, D, E, F, G);
273  int i= 0, j, n= difference.length(), gap= 1 + __INIT_GAP__;
274  Variable temp;
275  Array<Variable> v(0, n);
276  VarlistIterator J;
277
278  for (J= difference; J.hasItem(); J++ )
279  {
280    v[i]= J.getItem();
281    i++;
282  }
283 
284  while (gap <= n)
285    gap = __INIT_GAP__ * gap + 1;
286  gap /= __INIT_GAP__;
287 
288  while (gap > 0)
289  {
290    for (i= gap; i <= n - 1; i++)
291    {
292      temp= v[i];
293      for (j= i - gap; j >=0 ; j -= gap)
294      {
295        if (degord (v[j], temp, PS, A, B, C, D, E, F, G))
296          break;
297        v[j + gap]= v[j];
298      }
299      v[j + gap]= temp;
300    }
301    gap /= __INIT_GAP__;
302  }
303  Varlist output;
304  for (i= 0; i <= n - 1; i++)
305    output.append (v[i]);
306  return output;
307}
308
309// set up a new orderd list of Variables.
310// we try to reorder the variables heuristically optimal.
311Varlist
312neworder( const CFList & PolyList )
313{
314  CFList PS= PolyList, PS1=PolyList;
315  Varlist oldorder, reorder, difference;
316
317  TIMING_START(neworder_time);
318
319  int highest_level= level(get_max_var(PS));
320
321  // set up oldorder and first criterion: only_in_one
322  for (int i= highest_level; i>=1; i--)
323  {
324    oldorder.insert (Variable(i));
325    CFList is_one= only_in_one (PS1, Variable(i)); 
326    if (is_one.length() == 1)
327    {
328      reorder.insert (Variable(i));
329      PS1= Difference (PS1, is_one);
330    }
331    else if (is_one.length() == 0)
332    {
333      reorder.append (Variable (i)); // assigne it the highest level
334      PS1= Difference (PS1, is_one); 
335    }
336  }
337  difference= Difference (oldorder, reorder);
338
339  // rearrange the ordering of the variables!
340  difference= reorderb (difference, PS, highest_level);
341  reorder= Union (reorder, difference);
342  TIMING_END(neworder_time);
343
344  TIMING_PRINT(neworder_time, "\ntime used for neworder   : ");
345
346  return Union (reorder, Difference (oldorder, reorder));
347}
348
349// the same as above, only returning a list of CanonicalForms
350CFList
351newordercf(const CFList & PolyList )
352{
353  Varlist reorder= neworder (PolyList);
354  CFList output;
355
356  for (VarlistIterator i=reorder; i.hasItem(); i++)
357    output.append (CanonicalForm (i.getItem()));
358
359  return output;
360}
361
362// the same as above, only returning a list of ints
363IntList
364neworderint(const CFList & PolyList )
365{
366  Varlist reorder= neworder (PolyList);
367  IntList output;
368
369  for (VarlistIterator i= reorder; i.hasItem(); i++)
370    output.append (level (i.getItem()));
371
372  return output;
373}
374
375// swapvar a whole list of CanonicalForms
376static CFList
377swapvar( const CFList & PS, const Variable & x, const Variable & y)
378{
379  CFList ps;
380
381  for (CFListIterator i = PS; i.hasItem(); i++)
382    ps.append (swapvar (i.getItem(), x, y));
383  return ps;
384}
385
386static CFFList
387swapvar( const CFFList & PS, const Variable & x, const Variable & y)
388{
389  CFFList ps;
390
391  for (CFFListIterator i= PS; i.hasItem(); i++)
392    ps.append (CFFactor(swapvar (i.getItem().factor(), x, y), i.getItem().exp()));
393  return ps;
394}
395
396// a library function: we reorganize the global variable ordering
397CFList
398reorder (const Varlist & betterorder, const CFList & PS)
399{
400  int i= 1, n= betterorder.length();
401  Intarray v (1, n);
402  CFList ps= PS;
403
404  //initalize:
405  for (VarlistIterator j= betterorder; j.hasItem(); j++)
406  {
407    v[i]= level (j.getItem());
408    i++;
409  }
410  // reorder:
411  for (i= 1; i <= n; i++)
412    ps= swapvar (ps, Variable (v[i]), Variable (n + i));
413  return ps;
414}
415
416CFFList
417reorder( const Varlist & betterorder, const CFFList & PS)
418{
419  int i= 1, n= betterorder.length();
420  Intarray v (1, n);
421  CFFList ps= PS;
422
423  //initalize:
424  for (VarlistIterator j= betterorder; j.hasItem(); j++)
425  {
426    v[i]= level (j.getItem());
427    i++;
428  }
429
430  // reorder:
431  for (i= 1; i <= n; i++)
432    ps= swapvar (ps, Variable (v[i]), Variable (n + i));
433  return ps;
434}
435
436ListCFList
437reorder (const Varlist & betterorder, const ListCFList & Q)
438{
439  ListCFList Q1;
440
441  for (ListCFListIterator i= Q; i.hasItem(); i++)
442    Q1.append (reorder (betterorder, i.getItem()));
443  return Q1;
444}
445
446static bool
447lowerRank (const CanonicalForm & F, const CanonicalForm & G, int & ind)
448{
449  int degF, degG, levelF, levelG;
450
451  levelF= F.level();
452  levelG= G.level();
453  if (F.inCoeffDomain())
454  {
455    if (G.inCoeffDomain())
456      ind= 1;
457    return true;
458  }
459  else if (G.inCoeffDomain())
460    return false;
461  else if (levelF < levelG)
462    return true;
463  else if (levelF == levelG)
464  {
465    degF= degree(F);
466    degG= degree(G);
467    if (degF < degG)
468      return true;
469    else if (degF == degG)
470      return lowerRank (LC (F), LC (G), ind);
471    else
472      return false;
473  }
474  return false;
475}
476
477static
478CanonicalForm
479lowestRank (const CFList & L)
480{
481  CFListIterator i= L;
482  CanonicalForm f;
483  int ind= 0;
484  if (!i.hasItem())
485    return f;
486
487  f= i.getItem();
488  i++;
489
490  while (i.hasItem())
491  {
492    if (lowerRank (i.getItem(), f, ind))
493    {
494      if (ind)
495      {
496        if (size (i.getItem()) < size (f))
497          f= i.getItem();
498        ind= 0;
499      }
500      else
501        f= i.getItem();
502    }
503    i++;
504  }
505  return f;
506}
507
508CFList initials (const CFList& L)
509{
510  CFList result;
511  for (CFListIterator iter= L; iter.hasItem(); iter++)
512  {
513    if (!LC(iter.getItem()).inCoeffDomain())
514      result.append (LC (iter.getItem()));
515  }
516  return result;
517}
518
519// sort in descending order of length of elements
520void
521sortListCFList (ListCFList& list)
522{
523  int l= 1;
524  int k= 1;
525  CFList buf;
526  ListCFListIterator m;
527  for (ListCFListIterator i= list; l <= list.length(); i++, l++)
528  {
529    for (ListCFListIterator j= list; k <= list.length() - l; k++)
530    {
531      m= j;
532      m++;
533      if (j.getItem().length() < m.getItem().length())
534      {
535        buf= m.getItem();
536        m.getItem()= j.getItem();
537        j.getItem()= buf;
538        j++;
539        j.getItem()= m.getItem();
540      }
541      else
542        j++;
543    }
544    k= 1;
545  }
546}
547
548
549// sort in descending order of level of elements
550void
551sortCFListByLevel (CFList& list)
552{
553  int l= 1;
554  int k= 1;
555  CanonicalForm buf;
556  CFListIterator m;
557  for (CFListIterator i= list; l <= list.length(); i++, l++)
558  {
559    for (CFListIterator j= list; k <= list.length() - l; k++)
560    {
561      m= j;
562      m++;
563      if ((size (j.getItem()) < size (m.getItem())) ||
564          ((size (j.getItem()) == size (m.getItem()))
565            && (j.getItem().level() < m.getItem().level())))
566      {
567        buf= m.getItem();
568        m.getItem()= j.getItem();
569        j.getItem()= buf;
570        j++;
571        j.getItem()= m.getItem();
572      }
573      else
574        j++;
575    }
576    k= 1;
577  }
578}
579
580static bool
581member (const CanonicalForm& f, const CFList& F)
582{
583  for (CFListIterator i= F; i.hasItem(); i++)
584  {
585    if (i.getItem().mapinto() == f.mapinto())
586      return 1;
587  }
588  return 0;
589}
590
591// are list A and B the same?
592static bool
593same (const CFList& A, const CFList& B)
594{
595  if (A.length() != B.length())
596    return 0;
597
598  CFListIterator i;
599
600  for (i= A; i.hasItem(); i++)
601  {
602    if (!member (i.getItem(), B))
603      return 0;
604  }
605  for (i= B; i.hasItem(); i++)
606  {
607    if (!member (i.getItem(), A))
608      return 0;
609  }
610  return 1;
611}
612
613
614// is List cs contained in List of lists pi?
615static bool
616member (const CFList& cs, const ListCFList& pi)
617{
618  if (pi.isEmpty())
619    return 0;
620
621  ListCFListIterator i;
622
623  for (i= pi; i.hasItem(); i++)
624  {
625    if (i.getItem().length() != cs.length())
626      continue;
627    if (same (cs, i.getItem()))
628      return 1;
629  }
630  return 0;
631}
632
633// is PS a subset of Cset ?
634static bool
635subset (const CFList &PS, const CFList& Cset)
636{
637  for (CFListIterator i= PS; i.hasItem(); i++)
638  {
639    if (!member (i.getItem(), Cset))
640      return 0;
641  }
642  return 1;
643}
644
645// Union of two List of Lists
646static ListCFList
647MyUnion (const ListCFList& a, const ListCFList& b)
648{
649  if (a.isEmpty())
650    return b;
651  if (b.isEmpty())
652    return a;
653
654  ListCFList output;
655  ListCFListIterator i;
656  CFList elem;
657
658  for (i= a; i.hasItem(); i++)
659  {
660    elem= i.getItem();
661    if ((!elem.isEmpty()) && (!member (elem, output)))
662      output.append(elem);
663  }
664
665  for (i= b; i.hasItem(); i++)
666  {
667    elem= i.getItem();
668    if ((!elem.isEmpty()) && (!member (elem, output)))
669      output.append(elem);
670  }
671  return output;
672}
673
674// Union of a and b stored in b
675void
676MyUnion2 (const ListCFList& a, ListCFList& b)
677{
678  if (a.isEmpty())
679    return;
680  if (b.isEmpty())
681  {
682    b= a;
683    return;
684  }
685
686  ListCFListIterator i;
687  CFList elem;
688
689  for (i= a; i.hasItem(); i++)
690  {
691    elem= i.getItem();
692    if ((!elem.isEmpty()) && (!member (elem, b)))
693      b.insert(elem);
694  }
695}
696
697//if list b is member of the list of lists remove b and return the rest
698static ListCFList
699MyDifference (const ListCFList& a, const CFList& b)
700{
701  ListCFList output;
702  ListCFListIterator i;
703  CFList elem;
704
705  for (i= a; i.hasItem(); i++)
706  {
707    elem= i.getItem();
708    if ((!elem.isEmpty()) && (!same (elem, b)))
709      output.append (elem);
710  }
711  return output;
712}
713
714// remove all elements of b from list of lists a and return the rest
715static ListCFList
716Minus( const ListCFList& a, const ListCFList& b)
717{
718  ListCFList output= a;
719
720  for (ListCFListIterator i=b; i.hasItem(); i++)
721    output = MyDifference (output, i.getItem());
722
723  return output;
724}
725
726static ListCFList
727adjoin (const CFList& is, const CFList& qs, const ListCFList& qh)
728{
729  ListCFList iss, qhi;
730  ListCFListIterator j;
731  CFList iscopy, itt;
732  CFListIterator i;
733  int ind, length;
734
735  for (i= is; i.hasItem(); i++)
736  {
737    if (i.getItem().level() > 0)
738      iscopy= Union (CFList (i.getItem()), iscopy);
739  }
740  if (iscopy.isEmpty())
741    return iss;
742
743  qhi= MyDifference (qh, qs);
744  length= qhi.length();
745
746  for (i= iscopy; i.hasItem(); i++)
747  {
748    itt= Union (qs, CFList (i.getItem()));
749    ind= 0;
750    if (length > 0)
751    {
752      for (j= qhi; j.hasItem(); j++)
753      {
754        if (subset (j.getItem(), itt))
755          ind= 1;
756      }
757    }
758    if (ind == 0)
759      iss.append (itt);
760  }
761  return iss;
762}
763
764static ListCFList
765adjoinb (const CFList & is, const CFList & qs, const ListCFList & qh ,const CFList & cs)
766{
767  ListCFList iss, qhi;
768  ListCFListIterator j;
769  CFList iscopy, itt;
770  CFListIterator i;
771  int ind, length;
772
773  for (i= is ; i.hasItem(); i++)
774  {
775    if (i.getItem().level() > 0)
776      iscopy= Union (CFList (i.getItem()), iscopy);
777  }
778  if (iscopy.isEmpty())
779    return iss;
780  qhi= MyDifference (qh, qs);
781  length= qhi.length();
782  for (i= iscopy; i.hasItem(); i++)
783  {
784    itt= Union (Union (qs, CFList (i.getItem())), cs);
785    ind= 0;
786    if (length > 0)
787    {
788      for (j= qhi; j.hasItem(); j++)
789      {
790        if (subset (j.getItem(), itt))
791          ind= 1;
792      }
793    }
794    if (ind == 0)
795      iss.append(itt);
796  }
797  return iss;
798}
799
800static void
801select (const ListCFList& ppi, int length, ListCFList& ppi1, ListCFList& ppi2)
802{
803  CFList elem;
804  for (ListCFListIterator i=ppi; i.hasItem(); i++)
805  {
806    elem = i.getItem();
807    if (!elem.isEmpty())
808    {
809      if (length <= elem.length())
810        ppi2.append(elem);
811      else
812        ppi1.append(elem);
813    }
814  }
815}
816
817CanonicalForm normalize (const CanonicalForm& F)
818{
819  if (F.isZero())
820    return F;
821  if (getCharacteristic() == 0)
822  {
823    CanonicalForm G;
824    bool isRat= isOn (SW_RATIONAL);
825    if (!isRat)
826      On (SW_RATIONAL);
827    G= F;
828    G *= bCommonDen (G);
829    if (!isRat)
830      Off (SW_RATIONAL);
831    if (isRat)
832      Off (SW_RATIONAL);
833    G= F/icontent (F);
834    if (isRat)
835      On (SW_RATIONAL);
836    return G;
837  }
838
839  return F/lc (F);
840}
841
842static
843CanonicalForm
844Prem (const CanonicalForm& F, const CanonicalForm& G)
845{
846  CanonicalForm f, g, l, test, lu, lv, t, retvalue;
847  int degF, degG, levelF, levelG;
848  bool reord;
849  Variable v, vg= G.mvar();
850
851  if ( (levelF= F.level()) < (levelG= G.level()))
852    return F;
853  else
854  {
855    if ( levelF == levelG )
856    {
857      f= F;
858      g= G;
859      reord= false;
860      v= F.mvar();
861    }
862    else
863    {
864      v= Variable (levelF + 1);
865      f= swapvar (F, vg, v);
866      g= swapvar (G, vg, v);
867      reord= true;
868    }
869    degG= degree (g, v );
870    degF= degree (f, v );
871    if (degG <= degF)
872    {
873      l= LC (g);
874      g= g - l*power (v, degG);
875    }
876    else
877      l= 1;
878    while ((degG <= degF) && (!f.isZero()))
879    {
880      test= gcd (l, LC(f));
881      lu= l / test;
882      lv= LC(f) / test;
883      t= g*lv*power (v, degF - degG);
884
885      if (degF == 0)
886        f= 0;
887      else
888        f= f - LC (f)*power (v, degF);
889
890      f= f*lu - t;
891      degF= degree (f, v);
892    }
893
894    if (reord)
895      retvalue= swapvar (f, vg, v);
896    else
897      retvalue= f;
898
899    return retvalue;
900  }
901}
902
903static
904CanonicalForm
905Premb (const CanonicalForm &f, const CFList &L)
906{
907  CanonicalForm rem= f;
908  CFList l= L;
909  l.removeFirst();
910  CFListIterator i= l;
911
912  for (i.lastItem(); i.hasItem(); i--)
913    rem= normalize (Prem (rem, i.getItem()));
914
915  CanonicalForm tmp= L.getFirst()/content (L.getFirst());
916
917  bool isRat= isOn (SW_RATIONAL);
918  if (getCharacteristic() == 0 && !isRat)
919    On (SW_RATIONAL);
920  if (fdivides (tmp, rem))
921  {
922    if (getCharacteristic() == 0 && !isRat)
923      Off (SW_RATIONAL);
924    return 0;
925  }
926
927  if (getCharacteristic() == 0 && !isRat)
928    Off (SW_RATIONAL);
929
930  rem= normalize (Prem (rem, L.getFirst()));
931
932  return rem;
933}
934
935static
936CanonicalForm
937Prem (const CanonicalForm &f, const CFList &L)
938{
939  CanonicalForm rem= f;
940  CFListIterator i= L;
941
942  for (i.lastItem(); i.hasItem(); i--)
943    rem= normalize (Prem (rem, i.getItem()));
944
945  return rem;
946}
947
948CFList uniGcd (const CFList& L)
949{
950  CFList tmp;
951  CanonicalForm g;
952  CFListIterator i;
953  for (i= L; i.hasItem(); i++)
954  {
955    if (i.getItem().isUnivariate() && i.getItem().level() == 1)
956      tmp.append (i.getItem());
957  }
958  if (tmp.length() <= 2)
959    return L;
960  i= tmp;
961  g= i.getItem();
962  i++;
963  g= gcd (g,i.getItem());
964  i++;
965  for (; i.hasItem(); i++)
966    g= gcd (g, i.getItem());
967  return Union (Difference (L, tmp), CFList (g));
968}
969
970
971CFList
972factorsOfInitials(const CFList & L)
973{
974  CFList result;
975  CFFList factors;
976  CanonicalForm tmp;
977
978  for (CFListIterator i= L; i.hasItem(); i++)
979  {
980    factors= factorize (LC (i.getItem()));
981    for (CFFListIterator j= factors; j.hasItem(); j++)
982    {
983      tmp= j.getItem().factor();
984      if (!tmp.inCoeffDomain())
985        result= Union (result, CFList (normalize (tmp)));
986    }
987  }
988
989  return result;
990}
991
992void
993removeContent (CanonicalForm& F, CanonicalForm& cF)
994{
995  if (size (F) == 1)
996  {
997    CanonicalForm tmp= F;
998    F= F.mvar();
999    cF= tmp/F;
1000    if (!cF.inCoeffDomain())
1001      cF= normalize (cF);
1002    else
1003      cF= 0;
1004
1005    return;
1006  }
1007
1008  cF= content (F);
1009
1010  if (cF.inCoeffDomain())
1011    cF= 0;
1012  else
1013  {
1014    cF= normalize (cF);
1015    F /= cF;
1016    F= normalize (F);
1017  }
1018}
1019
1020CFList
1021factorPSet (const CFList& PS)
1022{
1023  CFList result;
1024  CFFList factors;
1025  CFFListIterator j;
1026
1027  for (CFListIterator i= PS; i. hasItem(); i++)
1028  {
1029    factors= factorize (i.getItem());
1030    if (factors.getFirst().factor().inCoeffDomain())
1031      factors.removeFirst();
1032    for (j= factors; j.hasItem(); j++ )
1033      result= Union (result, CFList (normalize (j.getItem().factor())));
1034  }
1035  return result;
1036}
1037
1038void
1039removeFactors (CanonicalForm& r, StoreFactors& StoredFactors,
1040               CFList& removedFactors)
1041{
1042  CanonicalForm quot;
1043  CFList testlist;
1044  int n= level(r);
1045  bool divides;
1046  CFListIterator j;
1047
1048  for (int i=1; i<= n; i++)
1049    testlist.append (CanonicalForm (Variable (i)));
1050
1051  for (j= StoredFactors.FS1; j.hasItem(); j++)
1052  {
1053    while (fdivides (j.getItem(), r, quot))
1054    {
1055      if (!quot.inCoeffDomain())
1056        r= quot;
1057      else
1058        break;
1059    }
1060  }
1061
1062  // remove already removed factors
1063  for (j= StoredFactors.FS2; j.hasItem(); j++)
1064  {
1065    divides= false;
1066    while (fdivides (j.getItem(), r, quot))
1067    {
1068      if (!quot.inCoeffDomain())
1069      {
1070        divides= true;
1071        r= quot;
1072      }
1073      else
1074        break;
1075    }
1076    if (divides)
1077      removedFactors= Union (removedFactors, CFList (j.getItem()));
1078  }
1079  r= normalize (r);
1080
1081  // remove variables
1082  for (j= testlist; j.hasItem() && !r.isOne(); j++)
1083  {
1084    while (fdivides (j.getItem(), r, quot))
1085    {
1086      if (!quot.inCoeffDomain())
1087        r= quot;
1088      else
1089        break;
1090      removedFactors= Union (removedFactors, CFList (j.getItem()));
1091    }
1092  }
1093}
1094
1095CFList
1096removeContent (const CFList & PS, StoreFactors & StoredFactors)
1097{
1098  CFListIterator i= PS;
1099  if ((!i.hasItem()) || (PS.getFirst().level() == 0 ))
1100    return PS;
1101
1102  CFList output;
1103  CanonicalForm cc,elem;
1104
1105  for (; i.hasItem(); i++)
1106  {
1107    elem= i.getItem();
1108    cc= content (elem, elem.mvar());
1109    if (cc.level() > 0 )
1110    {
1111      output.append (elem / cc);
1112      StoredFactors.FS1 = Union (CFList (cc), StoredFactors.FS1);
1113    }
1114    else
1115      output.append(elem);
1116  }
1117  return output;
1118}
1119
1120static bool
1121contractsub (const CFList& cs1, const CFList& cs2)
1122{
1123  CFListIterator i;
1124
1125  CanonicalForm r;
1126  for (i= cs1; i.hasItem(); i++)
1127  {
1128    if (Prem (i.getItem(), cs2) != 0)
1129      return false;
1130  }
1131
1132  CFList is= factorsOfInitials (cs1);
1133
1134  for (i= is; i.hasItem(); i++)
1135  {
1136    if (Prem (i.getItem(), cs2) == 0)
1137      return false;
1138  }
1139  return true;
1140}
1141
1142static ListCFList
1143contract (const ListCFList& cs)
1144{
1145  ListCFList mem, ts;
1146  CFList iitem, jitem;
1147
1148  if (cs.length() < 2)
1149    return cs;
1150
1151  int l= cs.length();
1152  int ii= 1;
1153  ListCFListIterator j;
1154  for (ListCFListIterator i= cs; i.hasItem() && ii < l; i++, ii++)
1155  {
1156    iitem= i.getItem();
1157    if (!member (iitem, mem))
1158    {
1159      j= i;
1160      j++;
1161      for (; j.hasItem(); j++)
1162      {
1163        jitem= j.getItem();
1164        if (!member (jitem, mem))
1165        {
1166          if (contractsub (iitem, jitem))
1167          {
1168            ts.append (jitem);
1169            mem.append (jitem);
1170          }
1171          else
1172          {
1173            if (contractsub (jitem, iitem))
1174              ts.append (iitem); // no mem.append (item) because we assume cs does not contain duplicate entries
1175          }
1176        }
1177      }
1178    }
1179  }
1180  return Minus (cs,ts);
1181}
1182
1183
1184CFList
1185basicSet (const CFList &PS)
1186{
1187  CFList QS= PS, BS, RS;
1188  CanonicalForm b;
1189  int cb, degb;
1190
1191  if (PS.length() < 2)
1192    return PS;
1193
1194  CFListIterator i;
1195
1196  while (!QS.isEmpty())
1197  {
1198    b= lowestRank (QS);
1199    cb= b.level();
1200
1201    BS= Union(CFList (b), BS);
1202
1203    if (cb <= 0)
1204      return CFList();
1205    else
1206    {
1207      degb= degree (b);
1208      RS= CFList();
1209      for (i= QS; i.hasItem(); i++)
1210      {
1211        if (degree (i.getItem(), cb) < degb)
1212          RS= Union (CFList (i.getItem()), RS);
1213      }
1214      QS= RS;
1215    }
1216  }
1217
1218  return BS;
1219}
1220
1221CFList
1222charSet (const CFList &PS)
1223{
1224  CFList QS= PS, RS= PS, CSet, tmp;
1225  CFListIterator i;
1226  CanonicalForm r;
1227
1228  while (!RS.isEmpty())
1229  {
1230    CSet= basicSet (QS);
1231
1232    RS= CFList();
1233    if (CSet.length() > 0 && CSet.getFirst().level() > 0)
1234    {
1235      tmp= Difference (QS, CSet);
1236      for (i= tmp; i.hasItem(); i++)
1237      {
1238        r= Prem (i.getItem(), CSet);
1239        if (r != 0)
1240          RS= Union (RS, CFList (r));
1241      }
1242      QS= Union (QS, RS);
1243    }
1244  }
1245
1246  return CSet;
1247}
1248
1249/// medial set
1250CFList
1251charSetN (const CFList &PS)
1252{
1253  CFList QS= PS, RS= PS, CSet, tmp;
1254  CFListIterator i;
1255  CanonicalForm r;
1256
1257  while (!RS.isEmpty())
1258  {
1259    QS= uniGcd (QS);
1260    CSet= basicSet (QS);
1261
1262    RS= CFList();
1263    if (CSet.length() > 0 && CSet.getFirst().level() > 0)
1264    {
1265      tmp= Difference (QS, CSet);
1266      for (i= tmp; i.hasItem(); i++)
1267      {
1268        r= Prem (i.getItem(), CSet);
1269        if (!r.isZero())
1270          RS= Union (RS, CFList (r));
1271      }
1272      QS= Union (CSet, RS);
1273    }
1274  }
1275
1276  return CSet;
1277}
1278
1279/// compute a characteristic set via medial set
1280CFList
1281charSetViaCharSetN (const CFList& PS)
1282{
1283  CFList L;
1284  CFFList sqrfFactors;
1285  CanonicalForm sqrf;
1286  CFFListIterator iter2;
1287  for (CFListIterator iter= PS; iter.hasItem(); iter++)
1288  {
1289    sqrf= 1;
1290    sqrfFactors= sqrFree (iter.getItem());
1291    for (iter2= sqrfFactors; iter2.hasItem(); iter2++)
1292      sqrf *= iter2.getItem().factor();
1293    L= Union (L, CFList (normalize (sqrf)));
1294  }
1295
1296  CFList result= charSetN (L);
1297
1298  if (result.isEmpty() || result.getFirst().inCoeffDomain())
1299    return CFList(1);
1300
1301  CanonicalForm r;
1302  CFList RS;
1303  CFList tmp= Difference (L, result);
1304
1305  for (CFListIterator i= tmp; i.hasItem(); i++)
1306  {
1307    r= Premb (i.getItem(), result);
1308    if (!r.isZero())
1309      RS= Union (RS, CFList (r));
1310  }
1311  if (RS.isEmpty())
1312    return result;
1313
1314  return charSetViaCharSetN (Union (L, Union (RS, result)));
1315}
1316
1317/// modified medial set
1318CFList
1319modCharSet (const CFList& L, StoreFactors& StoredFactors, bool removeContents)
1320{
1321  CFList QS= L, RS= L, CSet, tmp, contents, initial, removedFactors;
1322  CFListIterator i;
1323  CanonicalForm r, cF;
1324  bool noRemainder= true;
1325  StoreFactors StoredFactors2;
1326
1327  QS= uniGcd (L);
1328
1329  while (!RS.isEmpty())
1330  {
1331    noRemainder= true;
1332    CSet= basicSet (QS);
1333
1334    initial= factorsOfInitials (CSet);
1335
1336    StoredFactors2.FS1= StoredFactors.FS1;
1337    StoredFactors2.FS2= Union (StoredFactors2.FS2, initial);
1338
1339    RS= CFList();
1340
1341    if (CSet.length() > 0 && CSet.getFirst().level() > 0)
1342    {
1343      tmp= Difference (QS, CSet);
1344
1345      for (i= tmp; i.hasItem(); i++)
1346      {
1347        r= Prem (i.getItem(), CSet);
1348        if (!r.isZero())
1349        {
1350          noRemainder= false;
1351          if (removeContents)
1352          {
1353            removeContent (r, cF);
1354
1355            if (!cF.isZero())
1356              contents= Union (contents, factorPSet (CFList(cF))); //factorPSet maybe too much it should suffice to do a squarefree factorization instead
1357          }
1358
1359          removeFactors (r, StoredFactors2, removedFactors);
1360          StoredFactors2.FS1= Union (StoredFactors2.FS1, removedFactors);
1361          StoredFactors2.FS2= Difference (StoredFactors2.FS2, removedFactors);
1362
1363          removedFactors= CFList();
1364
1365          RS= Union (RS, CFList (r));
1366        }
1367      }
1368
1369      if (removeContents && !noRemainder)
1370      {
1371        StoredFactors.FS1= Union (StoredFactors2.FS1, contents);
1372        StoredFactors.FS2= StoredFactors2.FS2;
1373      }
1374      else
1375        StoredFactors= StoredFactors2;
1376
1377      QS= Union (CSet, RS);
1378
1379      contents= CFList();
1380      removedFactors= CFList();
1381    }
1382    else
1383      StoredFactors= StoredFactors2;
1384  }
1385
1386  return CSet;
1387}
1388
1389/// characteristic set via modified medial set
1390CFList
1391charSetViaModCharSet (const CFList& PS, StoreFactors& StoredFactors, bool removeContents)
1392{
1393  CFList L;
1394  CFFList sqrfFactors;
1395  CanonicalForm sqrf;
1396  CFFListIterator iter2;
1397  for (CFListIterator iter= PS; iter.hasItem(); iter++)
1398  {
1399    sqrf= 1;
1400    sqrfFactors= sqrFree (iter.getItem());
1401    for (iter2= sqrfFactors; iter2.hasItem(); iter2++)
1402      sqrf *= iter2.getItem().factor();
1403    L= Union (L, CFList (normalize (sqrf)));
1404  }
1405
1406  L= uniGcd (L);
1407
1408  CFList result= modCharSet (L, StoredFactors, removeContents);
1409
1410  if (result.isEmpty() || result.getFirst().inCoeffDomain())
1411    return CFList(1);
1412
1413  CanonicalForm r;
1414  CFList RS;
1415  CFList tmp= Difference (L, result);
1416
1417  for (CFListIterator i= tmp; i.hasItem(); i++)
1418  {
1419    r= Premb (i.getItem(), result);
1420    if (!r.isZero())
1421      RS= Union (RS, CFList (r));
1422  }
1423  if (RS.isEmpty())
1424    return result;
1425
1426  return charSetViaModCharSet (Union (L, Union (RS, result)), StoredFactors, removeContents);
1427}
1428
1429CFList
1430charSetViaModCharSet (const CFList& PS, bool removeContents)
1431{
1432  StoreFactors tmp;
1433  return charSetViaModCharSet (PS, tmp, removeContents);
1434}
1435
1436ListCFList
1437charSeries (const CFList& L)
1438{
1439  ListCFList tmp, result, tmp2, ppi1, ppi2, qqi, ppi, alreadyConsidered;
1440  CFList l, charset, ini;
1441
1442  int count= 0;
1443  int highestLevel= 1;
1444  CFListIterator iter;
1445
1446  StoreFactors StoredFactors;
1447
1448  l= L;
1449
1450  for (iter= l; iter.hasItem(); iter++)
1451  {
1452    iter.getItem()= normalize (iter.getItem());
1453    if (highestLevel < iter.getItem().level())
1454      highestLevel= iter.getItem().level();
1455  }
1456
1457  tmp= ListCFList (l);
1458
1459  while (!tmp.isEmpty())
1460  {
1461    sortListCFList (tmp);
1462
1463    l= tmp.getFirst();
1464
1465    tmp= MyDifference (tmp, l);
1466
1467    select (ppi, l.length(), ppi1, ppi2);
1468
1469    MyUnion2 (ppi2, qqi);
1470
1471    if (count > 0)
1472      ppi= MyUnion (ListCFList (l), ppi1);
1473    else
1474      ppi= ListCFList();
1475
1476    if (l.length() - 3 < highestLevel)
1477      charset= charSetViaModCharSet (l, StoredFactors);
1478    else
1479      charset= charSetViaCharSetN (l);
1480
1481    if (charset.length() > 0 && charset.getFirst().level() > 0)
1482    {
1483      result= MyUnion (result, ListCFList (charset));
1484      ini= factorsOfInitials (charset);
1485
1486      ini= Union (ini, factorPSet (StoredFactors.FS1));
1487      sortCFListByLevel (ini);
1488    }
1489    else
1490    {
1491      ini= factorPSet (StoredFactors.FS1);
1492      sortCFListByLevel (ini);
1493    }
1494
1495    tmp2= adjoin (ini, l, qqi);
1496    tmp= MyUnion (tmp, tmp2);
1497
1498    StoredFactors.FS1= CFList();
1499    StoredFactors.FS2= CFList();
1500
1501    ppi1= ListCFList();
1502    ppi2= ListCFList();
1503
1504    count++;
1505  }
1506
1507  //TODO need to remove superflous components
1508
1509  return result;
1510}
1511
1512static bool
1513irreducible (const CFList & AS)
1514{
1515// AS is given by AS = { A1, A2, .. Ar }, d_i = degree(Ai)
1516
1517// 1) we test: if d_i > 1, d_j =1 for all j<>i, then AS is irreducible.
1518  bool deg1= true;
1519  for (CFListIterator i= AS ; i.hasItem(); i++)
1520  {
1521    if (degree (i.getItem()) > 1)
1522    {
1523      if (deg1)
1524        deg1= false;
1525      else
1526        return false; // found 2nd poly with deg > 1
1527    }
1528  }
1529  return true;
1530}
1531
1532static CFList
1533irredAS (CFList & AS, int & indexRed, CanonicalForm & reducible)
1534{
1535  CFFList qs;
1536  CFList ts, as;
1537  CanonicalForm elem;
1538  bool ind= true;
1539  int nr= 0, success= -1;
1540  CFListIterator i;
1541
1542  indexRed= 0;
1543  for (i= AS; i.hasItem(); i++ )
1544  {
1545    nr += 1;
1546    if (degree (i.getItem()) > 1)
1547    {
1548      qs= factorize (i.getItem());
1549      if (qs.getFirst().factor().inCoeffDomain())
1550        qs.removeFirst();
1551    }
1552    else
1553      qs= CFFList (CFFactor (i.getItem(), 1));
1554
1555    if ((qs.length() >= 2 ) || (qs.getFirst().exp() > 1))
1556    {
1557      indexRed= nr;
1558      ind= false;
1559      reducible= i.getItem();
1560      break;
1561    }
1562  }
1563
1564  if (ind)
1565  {
1566    if (irreducible (AS))  // as quasilinear? => irreducible!
1567      indexRed= 0;
1568    else
1569    {
1570      i= AS;
1571      for (nr= 1; nr< AS.length(); nr++)
1572      {
1573        as.append (i.getItem());
1574        i++;
1575        if (degree (i.getItem()) > 1)
1576        {  // search for a non linear elem
1577          qs= newfactoras (i.getItem(), as, success);
1578          if (qs.getFirst().factor().inCoeffDomain())
1579            qs.removeFirst();
1580          if (qs.length() > 1 || qs.getFirst().exp() > 1)
1581          { //found elem is reducible
1582            reducible= i.getItem();
1583            indexRed= nr + 1;
1584            break;
1585          }
1586        }
1587      }
1588    }
1589  }
1590  for (CFFListIterator k= qs; k.hasItem(); k++)
1591    ts.append (k.getItem().factor());
1592  return ts;
1593}
1594
1595ListCFList
1596irrCharSeries (const CFList & PS)
1597{
1598  CanonicalForm reducible, reducible2;
1599  CFList qs, cs, factorset, is, ts, L;
1600  CanonicalForm sqrf;
1601  CFFList sqrfFactors;
1602  CFFListIterator iter2;
1603  for (CFListIterator iter= PS; iter.hasItem(); iter++)
1604  {
1605    sqrf= 1;
1606    sqrfFactors= sqrFree (iter.getItem());
1607    if (sqrfFactors.getFirst().factor().inCoeffDomain())
1608      sqrfFactors.removeFirst();
1609    for (iter2= sqrfFactors; iter2.hasItem(); iter2++)
1610      sqrf *= iter2.getItem().factor();
1611    sqrf= normalize (sqrf);
1612    L= Union (L, CFList (sqrf));
1613  }
1614
1615  ListCFList pi, ppi, qqi, qsi, iss, qhi= ListCFList(L);
1616
1617  int nr_of_iteration= 0, indexRed, highestlevel= 0;
1618
1619  for (CFListIterator iter= PS; iter.hasItem(); iter++)
1620  {
1621    if (level (iter.getItem()) > highestlevel)
1622      highestlevel= level(iter.getItem());
1623  }
1624
1625  while (!qhi.isEmpty())
1626  {
1627    sortListCFList (qhi);
1628
1629    qs= qhi.getFirst();
1630
1631    ListCFList ppi1,ppi2;
1632    select (ppi, qs.length(), ppi1, ppi2);
1633
1634    MyUnion2 (ppi2, qqi);
1635
1636    if (nr_of_iteration == 0)
1637    {
1638      nr_of_iteration += 1;
1639      ppi= ListCFList();
1640    }
1641    else
1642    {
1643      nr_of_iteration += 1;
1644      ppi= MyUnion (ListCFList(qs), ppi1);
1645    }
1646
1647    StoreFactors StoredFactors;
1648    cs= charSetViaModCharSet (qs, StoredFactors);
1649    cs= removeContent (cs, StoredFactors);
1650
1651    factorset= StoredFactors.FS1;
1652
1653    if (cs.getFirst().level() > 0)
1654    {
1655      ts= irredAS (cs, indexRed, reducible);
1656
1657      if (indexRed <= 0) // irreducible
1658      {
1659        if (!subset (cs,qs))
1660          cs= charSetViaCharSetN (Union (qs,cs));
1661        if (!member (cs, pi))
1662        {
1663          pi= MyUnion (pi, ListCFList (cs));
1664          if (cs.getFirst().level() > 0)
1665          {
1666            ts= irredAS (cs, indexRed, reducible);
1667
1668            if (indexRed <= 0) //irreducible
1669            {
1670              qsi= MyUnion (qsi, ListCFList(cs));
1671              if (cs.length() == highestlevel)
1672                is= factorPSet (factorset);
1673              else
1674                is= Union (factorsOfInitials (cs), factorPSet (factorset));
1675              iss= adjoin (is, qs, qqi);
1676            }
1677          }
1678          else
1679            iss= adjoin (factorPSet (factorset), qs, qqi);
1680        }
1681        else
1682          iss= adjoin (factorPSet (factorset), qs, qqi);
1683      }
1684
1685      if (indexRed > 0)
1686      {
1687        is= factorPSet (factorset);
1688        if (indexRed > 1)
1689        {
1690          CFList cst;
1691          for (CFListIterator i= cs ; i.hasItem(); i++)
1692          {
1693            if (i.getItem() == reducible)
1694              break;
1695            else 
1696              cst.append (i.getItem());
1697          }
1698          is= Union (factorsOfInitials (cst), is);
1699          iss= MyUnion (adjoin (is, qs, qqi), adjoinb (ts, qs, qqi, cst));
1700        }
1701        else
1702          iss= adjoin (Union (is, ts), qs, qqi);
1703      }
1704    }
1705    else
1706      iss= adjoin (factorPSet (factorset), qs, qqi);
1707    if (qhi.length() > 1)
1708    {
1709      qhi.removeFirst();
1710      qhi= MyUnion (qhi, iss);
1711    }
1712    else
1713      qhi= iss;
1714  }
1715  if (!qsi.isEmpty())
1716    return contract (qsi);
1717  return ListCFList(CFList (1)) ;
1718}
1719
Note: See TracBrowser for help on using the repository browser.