source: git/libfac/charset/charset.cc @ 456842

spielwiese
Last change on this file since 456842 was 456842, checked in by Hans Schönemann <hannes@…>, 22 years ago
*hannes: Dan's HAVE_SINGULAR_ERROR git-svn-id: file:///usr/local/Singular/svn/trunk@5573 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 17.8 KB
Line 
1/* Copyright 1996 Michael Messollen. All rights reserved. */
2////////////////////////////////////////////////////////////
3// emacs edit mode for this file is -*- C++ -*-
4static char * rcsid = "$Id: charset.cc,v 1.9 2001-08-08 14:26:54 Singular Exp $";
5/////////////////////////////////////////////////////////////
6// FACTORY - Includes
7#include <factory.h>
8// Factor - Includes
9#include <SqrFree.h>
10#include <Factor.h>
11#include <interrupt.h>
12// Charset - Includes
13#include "csutil.h"
14#include "algfactor.h"
15#include "alg_factor.h"
16// Some CC's need this:
17#include "charset.h"
18
19#ifdef BASICSETDEBUG
20#  define DEBUGOUTPUT
21#else
22#  undef DEBUGOUTPUT
23#endif
24
25#include "debug.h"
26#include "timing.h"
27TIMING_DEFINE_PRINT(subfactorize_time);
28
29
30// forward declarations:
31static CFList     irras(CFList & AS, int &ja, CanonicalForm & reducible);
32
33#ifdef BASICSETDEBUG
34#  define DEBUGOUTPUT
35#else
36#  undef DEBUGOUTPUT
37#endif
38#include "debug.h"
39
40#ifdef SINGULAR
41#define HAVE_SINGULAR_ERROR
42#endif
43
44#ifdef HAVE_SINGULAR_ERROR
45   extern "C" { void WerrorS(char *); }
46   extern "C" { void WarnS(const char *); }
47#endif
48
49// the next computes a characteristic set (a basic set in Wang's sense)
50CFList
51BasicSet( const CFList &PS )
52{
53    CFList QS = PS, BS, RS;
54    CanonicalForm b;
55    int cb;
56
57    DEBOUTLN(cout, "BasicSet: called with ps= ", PS);
58    if ( PS.length() < 2 ) return PS;
59    while ( ! QS.isEmpty() ) {
60        b = lowestRank( QS );
61        cb = rank( b );
62        DEBOUTLN(cout, "BasicSet: choose b  = ", b);
63        DEBOUTLN(cout, "BasicSet: it's rank = ", cb);
64        BS=Union(CFList(b),BS);//BS.append( b );
65        if ( rank( b ) == 0 )
66            return Union(PS, CFList(b)) ; // b should be the first elem!
67        else {
68            RS = CFList();
69            // QS:= {q \in QS -{B} | q is reduced wrt b}
70            // We can process whole QS, because b is not reduced wrt. b
71            for ( CFListIterator i = QS; i.hasItem(); ++i )
72                if ( degree( i.getItem(), cb ) < degree( b ) )
73                    //RS.append( i.getItem() );
74                    RS = Union(CFList(i.getItem()),RS);
75            QS = RS;
76        }
77    }
78    DEBOUTLN(cout, "BasicSet: returning bs= ", BS);
79    return BS;
80}
81
82int
83checkok( const CFList & PS, CFList & FS2){
84  CanonicalForm elem;
85
86  for ( CFListIterator i=PS; i.hasItem(); i++){
87    elem= i.getItem();
88    for (CFListIterator j=FS2; j.hasItem(); j++){
89      if (elem == j.getItem()){
90         //        FS2= Difference(FS2,CFList(elem));
91         return 0;
92      }
93    }
94  }
95  return 1;
96}
97
98#ifdef MCHARSETNDEBUG
99#  define DEBUGOUTPUT
100#else
101#  undef DEBUGOUTPUT
102#endif
103#include "debug.h"
104
105// The modified CharSet (an extended characteristic set with certain factors
106// canceled; this is a characteristic set in Wang's sense)
107CFList
108MCharSetN( const CFList &PS, PremForm & Remembern ){
109  CFList QS = PS, RS = PS, CS, OLDCS;
110
111  DEBOUTLN(cout, "MCharSetN: called with ps= ", PS);
112  while ( ! RS.isEmpty() ) {
113    CS = BasicSet( QS );
114    OLDCS=CS;
115    DEBOUTLN(cout, "MCharSetN: CS= ", CS);
116//     if ( getNumVars(CS.getFirst()) > 1 ){
117//       //CS = removecontent(CS, Remembern);
118// #ifdef MCHARSETNDEBUG
119//       cout << "MCharSetN: CS= " << CS << endl;
120// #endif
121//     }
122    Remembern.FS1 = Union(Remembern.FS1, initalset1(CS));
123    DEBOUTLN(cout, "MCharSetN: Remembern.FS1= ", Remembern.FS1);
124    DEBOUTLN(cout, "MCharSetN: Remembern.FS2= ", Remembern.FS2);
125    RS = CFList();
126    if ( rank( CS.getFirst() ) != 0 ) {
127      CFList D = Difference( QS, CS );
128      DEBOUT(cout, "MCharSetN: Difference( ", QS);
129      DEBOUT(cout, " , ", CS);
130      DEBOUTLN(cout, " ) = ", D);
131//cout << "MCharSetN: Difference( " << QS << " , " << CS << " ) = " << D << endl;
132      //PremForm Oldremember=Remembern;
133      //PremForm Newremember=Remembern;
134      for ( CFListIterator i = D; i.hasItem(); ++i ) {
135        CanonicalForm r = Prem( i.getItem(), CS );
136        DEBOUT(cout,"MCharSetN: Prem(", i.getItem()  );
137        DEBOUT(cout, ",", CS);
138        DEBOUTLN(cout,") = ", r);
139//cout << "MCharSetN: Prem("<< i.getItem() << "," << CS << ") = " << r << endl;
140        if ( r != 0 ){
141          //removefactor( r, Newremember );
142          removefactor( r, Remembern );
143          //Remembern.FS2 = Union(Remembern.FS2, Newremember.FS2);
144          //Newremember = Oldremember;
145          //if ( cls(r) > 0 )
146            //RS=Union(CFList(r),RS);//RS.append( r );
147            RS=Union(RS,CFList(r));
148        }
149      }
150      if ( ! checkok(RS,Remembern.FS2)) return CFList(CanonicalForm(1));
151      DEBOUTLN(cout, "MCharSetN: RS= ", RS);
152      //QS = Union( QS, RS );
153      QS = Union(OLDCS,RS);
154      DEBOUTLN(cout, "MCharSetN: QS= Union(QS,RS)= ", QS);
155    }
156    else{ return CFList(CanonicalForm(1)); }
157  }
158  DEBOUTLN(cout, "MCharSetN: Removed factors: ", Remembern.FS2);
159  DEBOUTLN(cout, "MCharSetN: Remembern.FS1: ", Remembern.FS1);
160
161  return CS;
162}
163
164
165CFList
166mcharset( const CFList &PS, PremForm & Remembern ){
167  CFList cs= MCharSetN(PS, Remembern );
168  CFList rs= remsetb(Difference(PS,cs),cs);
169
170  DEBOUTLN(cout, "mcharset: cs= ", cs);
171  DEBOUTLN(cout, "mcharset: rs= ", rs);
172  if ( rs.length() > 0 )
173    cs= mcharset(Union(PS,Union(cs,rs)), Remembern);
174  return cs;
175}
176
177// the "original" extended characteristic set
178CFList
179CharSet( const CFList &PS ){
180  CFList QS = PS, RS = PS, CS;
181
182  while ( ! RS.isEmpty() ) {
183    CS = BasicSet( QS );
184    DEBOUTLN(cout, "CharSet: CS= ", CS);
185    RS = CFList();
186    if ( rank( CS.getFirst() ) != 0 ) {
187      CFList D = Difference( QS, CS );
188      for ( CFListIterator i = D; i.hasItem(); ++i ) {
189        CanonicalForm r = Prem( i.getItem(), CS );
190        if ( r != 0 )  RS=Union(CFList(r),RS);//RS.append( r );
191      }
192      QS = Union( QS, RS );
193    }
194  }
195  return CS;
196}
197
198static CFList
199charseta( const CFList & PS ){
200  CFList QS = PS, RS = PS, CS;
201
202  while ( ! RS.isEmpty() ) {
203    CS = CharSet( QS );
204    RS = CFList();
205    if ( rank( CS.getFirst() ) != 0 ) {
206      CFList D = Difference( QS, CS );
207      for ( CFListIterator i = D; i.hasItem(); ++i ) {
208        CanonicalForm r = Prem( i.getItem(), CS );
209        if ( r != 0 )  RS=Union(CFList(r),RS);//RS.append( r );
210      }
211      QS = Union(CS,Union( QS, RS ));
212    }
213    else return CFList(CanonicalForm(1));
214  }
215  return CS;
216}
217
218static bool
219contractsub( const CFList & cs1, const CFList & cs2 ){
220  CFListIterator i;
221
222  for ( i=cs1; i.hasItem(); i++ )
223    if ( Prem(i.getItem(),cs2 ) != 0 ) return false;
224  CFList is=initalset1(cs1);
225  for ( i=is; i.hasItem(); i++ )
226    if ( Prem(i.getItem(),cs2 ) == 0 ) return false;
227  return true;
228}
229
230static ListCFList
231contract( const ListCFList & cs){
232  ListCFList mem,ts;
233  CFList iitem,jitem;
234
235  if ( cs.length() < 2 ) return cs;
236
237  for ( ListCFListIterator i=cs; i.hasItem(); i++ ){
238    iitem=i.getItem();
239    if ( ! member(iitem, mem))
240      for ( ListCFListIterator j=i; j.hasItem(); j++){
241        jitem=j.getItem();
242        if ( ! same( iitem, jitem ) )
243          if ( ! member(jitem, mem))
244            if ( contractsub(iitem, jitem) ){
245              ts.append(jitem); mem.append(jitem);
246            }
247            else
248              if ( contractsub(jitem, iitem) ){
249                ts.append(iitem);
250              }
251      }
252  }
253  return Minus(cs,ts);
254}
255
256static ListCFList
257adjoin(const CFList & is, const CFList & qs, const ListCFList & qh ){
258  ListCFList iss,qhi;
259  ListCFListIterator j;
260  CFList iscopy,itt;
261  CFListIterator i;
262  CanonicalForm elem;
263  int ind, length;
264
265  for ( i=is ; i.hasItem(); i++ ){
266    elem=i.getItem();
267    if ( cls(elem) > 0 ) iscopy=Union(CFList(elem),iscopy);
268  }
269  if ( iscopy.isEmpty() ) return iss;
270  qhi = MyDifference(qh,qs);
271  length = qhi.length();
272  for ( i =iscopy; i.hasItem(); i++){
273    itt = Union(qs,CFList(i.getItem()));
274    ind = 0;
275    if ( length > 0 )
276      for ( j=qhi; j.hasItem(); j++ )
277        if ( subset(j.getItem(),itt )) ind=1;
278    if ( ind == 0 ) iss.append(itt);
279  }
280  return iss;
281}
282
283static ListCFList
284adjoinb(const CFList & is, const CFList & qs, const ListCFList & qh ,const CFList & cs){
285  ListCFList iss,qhi;
286  ListCFListIterator j;
287  CFList iscopy,itt;
288  CFListIterator i;
289  CanonicalForm elem;
290  int ind, length;
291
292  for ( i=is ; i.hasItem(); i++ ){
293    elem=i.getItem();
294    if ( cls(elem) > 0 ) iscopy=Union(CFList(elem),iscopy);
295  }
296  if ( iscopy.isEmpty() ) return iss;
297  qhi = MyDifference(qh,qs);
298  length = qhi.length();
299  for ( i =iscopy; i.hasItem(); i++){
300    itt = Union(Union(qs,CFList(i.getItem())),cs);
301    ind = 0;
302    if ( length > 0 )
303      for ( j=qhi; j.hasItem(); j++ )
304        if ( subset(j.getItem(),itt )) ind=1;
305    if ( ind == 0 ) {iss.append(itt);}
306  }
307  return iss;
308}
309
310static ListCFList
311sort( const ListCFList & list_to_sort ){
312  ListCFList output,copy=list_to_sort;
313  CFList l,qs1,elem;
314
315  l = copy.getLast(); copy.removeLast();
316  if ( copy.length() == 0 ){ return ListCFList(l); }
317  for ( ListCFListIterator i=copy ; i.hasItem(); i++ ){
318    elem = i.getItem();
319    if ( elem.length() > l.length() ) {
320      output = MyUnion( ListCFList(l), output);
321      l= elem;
322    }
323    else{ output = MyUnion(output, ListCFList(elem) ); }
324  }
325  //output = MyUnion(ListCFList(l),sort(output));
326  output = MyUnion(ListCFList(l),output);
327  return output;
328}
329
330#ifdef EXPERIMENTAL
331static CFList
332getItemNr( int nr, const ListCFList & copy){
333  int i =1;
334  CFList elem;
335
336  for ( ListCFListIterator j=copy; j.hasItem(); j++ )
337    if ( i == nr ) { elem=j.getItem(); break; }
338    else { i+= 1; }
339  return elem;
340}
341
342static int
343choosefrom(){
344int choice;
345    cout << "choose from qhi! ->";
346    cin >> choice;
347return choice;
348}
349
350static ListCFList
351msort( const ListCFList & list_to_sort ){
352  int nr, number = list_to_sort.length();
353  ListCFList output;
354
355  cout << "Sort: list to sort is: " <<  list_to_sort << endl;
356  for (int i=1; i<= number; i++){
357    cout << " Next elem = "; cin >> nr;
358    output.append(getItemNr(nr,list_to_sort));
359  }
360  return output;
361}
362#endif
363
364#ifdef IRRCHARSERIESDEBUG
365#  define DEBUGOUTPUT
366#else
367#  undef DEBUGOUTPUT
368#endif
369#include "debug.h"
370
371ListCFList
372IrrCharSeries( const CFList &PS, int opt ){
373  CanonicalForm reducible,reducible2;
374  CFList qs,cs,factorset,is,ts;
375  ListCFList pi,ppi,qqi,qsi,iss,qhi= ListCFList(PS);
376  int nr_of_iteration=0,ts2,highestlevel=0;
377#ifdef EXPERIMENTAL
378  int choice=1;;
379#endif
380
381  DEBOUTMSG(cout, rcsid);
382//  cout << getCharacteristic() << endl;
383  for ( CFListIterator Ps=PS; Ps.hasItem(); Ps++ )
384    if ( level(Ps.getItem() ) > highestlevel ) highestlevel = level(Ps.getItem()) ;
385//  for ( int xx=1; xx <= highestlevel; xx++)
386//   cout << Variable(xx) ;
387//  cout << endl;
388//  for ( CFListIterator Ps=PS; Ps.hasItem(); Ps++ )
389//    cout << Ps.getItem() << ", " ;//<< endl;
390//  cout <<  endl;
391  while ( ! qhi.isEmpty() ) {
392    qhi=sort(qhi);
393    DEBOUTLN(cout, "qhi is: ", qhi);
394#ifdef EXPERIMENTAL
395    choice=choosefrom();
396    cout <<"/n Choose " << choice << endl;
397    qs= getItemNr(choice, qhi);
398#else
399    qs=qhi.getFirst();
400#endif
401    DEBOUTLN(cout, "qs  is: ", qs);
402    DEBOUTLN(cout, "ppi is: ", ppi);
403    ListCFList ppi1,ppi2;
404    select(ppi,qs.length(),ppi1,ppi2);
405    DEBOUTLN(cout, "ppi1 is: ", ppi1);
406    DEBOUTLN(cout, "ppi2 is: ", ppi2);
407    qqi = MyUnion(ppi2,qqi);
408    DEBOUTLN(cout, "qqi is: ", qqi);
409    if ( nr_of_iteration == 0 ){ nr_of_iteration += 1; ppi = ListCFList(); }
410    else{ nr_of_iteration += 1; ppi = MyUnion(ListCFList(qs),ppi1); }
411    DEBOUTLN(cout,"ppi is: ", ppi);
412    PremForm Remembern;
413    cs = MCharSetN(qs,Remembern);
414    DEBOUTLN(cout, "cs is: ", cs);
415    DEBOUTLN(cout, "factorset is: ", Remembern.FS2);
416    cs = removecontent(cs,Remembern);
417    factorset=Remembern.FS2;
418    DEBOUTLN(cout, "cs (after removecontent) is: ", cs);
419    DEBOUTLN(cout, "factorset is: ", factorset);
420    // Hier: removecontent einfuegen!!!!
421    if ( cls(cs.getFirst()) > 0 ){
422      ts = irras(cs,ts2, reducible);
423
424      // INTERRUPTHANDLER
425      if ( interrupt_handle() ) return ListCFList() ;
426      // INTERRUPTHANDLER
427
428      DEBOUTLN(cout, "ts is: ", ts);
429      DEBOUTLN(cout, "ts2 is: ", ts2);
430      // next is preliminary: should be ==0
431      if ( ts2 <= 0 ){ //irreducible
432        if ( ! subset(cs,qs) ){
433          DEBOUTMSG(cout, "cs is not a subset of qs");
434          cs = charseta(Union(qs,cs));
435          DEBOUTLN(cout, "new cs is: ", cs);
436        }
437        if ( ! member(cs,pi) ){
438          pi = MyUnion(pi, ListCFList(cs));
439          DEBOUTMSG(cout, "cs is not a member of pi");
440          DEBOUTLN(cout, "pi is: ", pi);
441          if ( cls(cs.getFirst()) > 0 ){
442            ts = irras(cs,ts2,reducible);
443
444            // INTERRUPTHANDLER
445            if ( interrupt_handle() ) return ListCFList() ;
446            // INTERRUPTHANDLER
447
448            DEBOUTLN(cout, "ts is: ", ts);
449            DEBOUTLN(cout, "ts2 is: ", ts2);
450            // next is preliminary: should be ==0
451            if ( ts2 <= 0 ){ //irreducible
452              qsi = MyUnion(qsi,ListCFList(cs));
453              DEBOUTLN(cout, "qsi is: ", qsi);
454              if ( cs.length() == highestlevel ){
455                DEBOUTLN(cout, "cs.length() == nops(ord) :", cs.length());
456                is = factorps(factorset);
457              }
458              else{
459                DEBOUT(cout,"cs.length() != nops(ord) :", cs.length());
460                DEBOUTLN(cout, "  nops(ord)= ", highestlevel);
461                is = Union(initalset1(cs),factorps(factorset));
462              }
463              DEBOUTLN(cout, "is is: ", is);
464              iss = adjoin(is,qs,qqi);
465              DEBOUTLN(cout, "iss is: ", iss);
466            }
467          }
468          else{ iss = adjoin(factorps(factorset),qs,qqi); }
469        }
470        else{
471          DEBOUTMSG(cout, "cs is a member of pi");
472          iss = adjoin(factorps(factorset),qs,qqi); }
473        DEBOUTLN(cout, "iss is: ", iss);
474        DEBOUTLN(cout, "   factorps(factorset)= ", factorps(factorset));
475        DEBOUTLN(cout, "   qs= ", qs);
476        DEBOUTLN(cout, "   qqi= ", qqi);
477      }
478      // next is preliminary: should be !=0
479      if ( ts2 > 0 ){
480        is = factorps(factorset);
481        DEBOUTLN(cout, "is is: ", is);
482        if ( ts2 > 1 ){
483          // setup cst: need it later for adjoinb
484          CFList cst;
485          for ( CFListIterator i=cs ; i.hasItem(); i++){
486            if ( i.getItem() == reducible ) { break; }
487            else { cst.append(i.getItem()); }
488          }
489          is = Union(initalset1(cst), is);
490          iss = MyUnion(adjoin(is,qs,qqi), adjoinb(ts,qs,qqi,cst));
491        }
492        else{ iss = adjoin(Union(is,ts),qs,qqi); }
493        DEBOUTLN(cout, "iss is: ", iss);
494      }
495    }
496    else{
497      iss = adjoin(factorps(factorset),qs,qqi);
498      DEBOUTMSG(cout, "case: cs is a constant.");
499      DEBOUTLN(cout, "  qs = ", qs);
500      DEBOUTLN(cout, "  qqi = ", qqi);
501      DEBOUTLN(cout, "  iss = adjoin(factorps(factorset),qs,qqi) = ",iss);
502    }
503    if ( qhi.length() > 1 ){ qhi.removeFirst(); qhi = MyUnion(qhi,iss); }
504    else{ qhi = iss; }
505    DEBOUTLN(cout, "iss is: ", iss);
506  }
507  if ( ! qsi.isEmpty() ){
508    DEBOUTLN(cout, "qsi before contract= ", qsi);
509    if ( opt == 0 ){
510       return contract( qsi );
511    }
512    else { return qsi; }
513  }
514  else{ return ListCFList() ; }
515}
516
517// tests for characteristic sets
518//////////////////////////////////
519#ifdef IRRASDEBUG
520#  define DEBUGOUTPUT
521#else
522#  undef DEBUGOUTPUT
523#endif
524
525#include "debug.h"
526
527static CFList
528irras( CFList & AS, int & ja, CanonicalForm & reducible){
529  CFFList qs;
530  CFList ts,as;
531  CanonicalForm elem;
532  int ind=1,nr=0, success=-1;
533  CFListIterator i;
534
535  ja = 0;
536  DEBOUTLN(cout, "irras: called with: AS= ", AS);
537  for ( i=AS; i.hasItem(); i++ ){
538    elem = i.getItem();
539    nr += 1;
540    DEBOUT(cout, "irras: factoring: ", elem);
541    if ( degree(elem) > 1 ) // linear poly's are irreduzible
542      qs = Factorize(elem);
543    else{
544      qs=(CFFactor(elem,1));
545      qs.insert(CFFactor(CanonicalForm(1),1));
546    }
547    DEBOUTLN(cout, "  = ", qs);
548    // INTERRUPTHANDLER
549    if ( interrupt_handle() ) return CFList() ;
550    // INTERRUPTHANDLER
551    qs.removeFirst();
552    if ( (qs.length() >= 2 ) || (qs.getFirst().exp() > 1)){
553      DEBOUTLN(cout, "irras: Setting ind=0, ja= ", nr);
554      ja=nr; ind=0; reducible= elem;
555      break;
556    }
557    //    else{ as.append(elem) ; }
558  }
559  //  cout << "ind= " << ind << endl;
560  if ( (ind == 1) ){ //&& ( as.length() > 1) ){
561    if ( irreducible(AS) ){ // as quasilinear? => irreducible!
562      ja = 0;
563      DEBOUTLN(cout, "as is irreducible. as= ", AS);
564    }
565    else {
566      i=AS;
567      for ( nr=1; nr< AS.length(); nr++){
568        as.append(i.getItem());
569        i++;
570        if ( degree(i.getItem()) > 1 ){// search for a non linear elem
571          elem=i.getItem();
572//          cout << "f=  " << elem << endl;
573//        cout << "as= " << as << endl;
574          qs= newfactoras(elem,as,success);
575//          cout << "irras:newfactoras    qs= " << qs << endl;
576//          qs= factoras(elem,as,success);
577//          cout << "irras:factoras qs= " << qs << endl;
578          if ( qs.length() > 1 || qs.getFirst().exp() > 1 ){ //found elem is reducible
579            reducible=elem;
580            ja=nr+1;
581            break;
582          }
583          else
584          {
585#ifdef HAVE_SINGULAR_ERROR
586            WarnS("libfac: Factoring over algebraic function field required!");
587#else
588#ifndef NOSTREAMIO
589            cerr << "libfac: Factoring over algebraic function field!" << endl;
590#endif
591#endif
592          }
593        }
594      }
595    }
596  }
597  for ( CFFListIterator k=qs; k.hasItem();k++)
598    ts.append(k.getItem().factor());
599  return ts;
600}
601///////////////////////////////////////////////////////////////////////////////
602/*
603$Log: not supported by cvs2svn $
604Revision 1.8  2001/08/06 08:32:53  Singular
605* hannes: code cleanup
606
607Revision 1.7  2001/06/27 13:58:06  Singular
608*hannes/GP: debug newfactoras, char_series, ...
609
610Revision 1.6  2000/03/08 12:54:35  obachman
611 * comment out warning "libfac: Factoring over algebraic function
612   field required!"
613
614Revision 1.5  2000/03/08 12:45:41  obachman
615* fixed Singular includes
616
617Revision 1.4  1999/06/15 12:54:54  Singular
618* hannes: debug fixes for Singular-interface
619
620Revision 1.3  1997/09/12 07:19:40  Singular
621* hannes/michael: libfac-0.3.0
622
623Revision 1.2  1997/04/25 22:52:28  michael
624changed cerr and cout messages for use with Singular
625Version for libfac-0.2.1
626
627*/
Note: See TracBrowser for help on using the repository browser.