source: git/Singular/dyn_modules/syzextra/syzextra.h @ 266ae3

spielwiese
Last change on this file since 266ae3 was 266ae3, checked in by Hans Schoenemann <hannes@…>, 6 years ago
chg: only one definition for poly/ideal/map/matrix
  • Property mode set to 100644
File size: 17.2 KB
Line 
1// -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2/*****************************************************************************\
3 * Computer Algebra System SINGULAR
4\*****************************************************************************/
5/** @file syzextra.h
6 *
7 * Computation of Syzygies
8 *
9 * ABSTRACT: Computation of Syzygies due to Schreyer
10 *
11 * @author Oleksandr Motsak
12 *
13 **/
14/*****************************************************************************/
15
16#ifndef SYZEXTRA_H
17#define SYZEXTRA_H
18
19#include <vector>
20#include <map>
21#include <string.h>
22#include <stack>
23
24// include basic definitions
25#include "singularxx_defs.h"
26#include "kernel/ideals.h"
27
28class idrec; typedef idrec *   idhdl;
29
30class kBucket; typedef kBucket* kBucket_pt;
31
32#ifndef NOPRODUCT
33# define NOPRODUCT 1
34#endif
35
36// set to 1 if all leading coeffs are assumed to be all =1...
37// note the use of simplify on input in SSinit!
38#ifndef NODIVISION
39# define NODIVISION 1
40#endif
41
42poly leadmonom(const poly p, const ring r, const bool bSetZeroComp = true);
43
44/// return the tail of a given polynomial or vector
45/// returns NULL if input is NULL, otherwise
46/// the result is a new polynomial/vector in the ring r
47poly p_Tail(const poly p, const ring r);
48
49
50/// return the tail of a given ideal or module
51/// returns NULL if input is NULL, otherwise
52/// the result is a new ideal/module in the ring r
53/// NOTE: the resulting rank is autocorrected
54ideal id_Tail(const ideal id, const ring r);
55
56/// inplace sorting of the module (ideal) id wrt <_(c,ds)
57void Sort_c_ds(const ideal id, const ring r);
58
59
60class sBucket; typedef sBucket* sBucket_pt;
61
62/** @class SBucketFactory syzextra.h
63 *
64 * sBucket Factory
65 *
66 * Cleate/store/reuse buckets
67 *
68 */
69class SBucketFactory: private std::stack <sBucket_pt>
70{
71  private:
72    typedef std::stack <sBucket_pt> Base;
73//    typedef std::vector<Bucket> Memory;
74//    typedef std::deque <Bucket> Memory;
75//    typedef std::stack <Bucket, Memory > Base;
76
77  public:
78    typedef Base::value_type Bucket;
79
80    SBucketFactory(const ring r)
81#ifndef SING_NDEBUG
82        : m_ring(r)
83#endif
84    {
85      push ( _CreateBucket(r) ); // start with at least one sBucket...?
86      assume( top() != NULL );
87    };
88
89    ~SBucketFactory()
90    {
91      while( !empty() )
92      {
93        _DestroyBucket( top() );
94        pop();
95      }
96    }
97
98    Bucket getBucket(const ring r, const bool remove = true)
99    {
100      assume( r == m_ring );
101
102      Bucket bt = NULL;
103
104      if( !empty() )
105      {
106        bt = top();
107
108        if( remove )
109          pop();
110      }
111      else
112      {
113        bt = _CreateBucket(r);
114
115        if( !remove )
116        {
117          push(bt);
118          assume( bt == top() );
119        }
120      }
121
122      assume( bt != NULL );
123      assume( _IsBucketEmpty(bt) );
124      assume( r == _GetBucketRing(bt) );
125
126      return bt;
127    }
128
129    // TODO: this may be spared if we give-out a smart Bucket (which returns here upon its destructor!)
130    void putBucket(const Bucket & bt, const bool replace = false)
131    {
132      assume( bt != NULL );
133      assume( _IsBucketEmpty(bt) );
134      assume( m_ring == _GetBucketRing(bt) );
135
136      if( empty() )
137        push( bt );
138      else
139      {
140        if( replace )
141          top() = bt;
142        else
143        {
144          if( bt != top() )
145            push( bt );
146        }
147      }
148
149      assume( bt == top() );
150    }
151
152  private:
153
154#ifndef SING_NDEBUG
155    const ring m_ring; ///< For debugging: all buckets are over the same ring... right?!
156
157    /// get bucket ring
158    static ring _GetBucketRing(const Bucket& bt);
159
160    static bool  _IsBucketEmpty(const Bucket& bt);
161#endif
162
163    /// inital allocation for new buckets
164    static Bucket _CreateBucket(const ring r);
165
166    /// we only expect empty buckets to be left at the end for destructor
167    /// bt will be set to NULL
168    static void _DestroyBucket(Bucket & bt);
169
170  private:
171    SBucketFactory();
172    SBucketFactory(const SBucketFactory&);
173    void operator=(const SBucketFactory&);
174
175};
176
177
178
179
180
181
182
183/// Computation attribute storage
184struct SchreyerSyzygyComputationFlags
185{
186    SchreyerSyzygyComputationFlags(idhdl rootRingHdl);
187
188    SchreyerSyzygyComputationFlags(const SchreyerSyzygyComputationFlags& attr):
189        OPT__DEBUG(attr.OPT__DEBUG),
190        OPT__LEAD2SYZ(attr.OPT__LEAD2SYZ),  OPT__TAILREDSYZ(attr.OPT__TAILREDSYZ),
191        OPT__HYBRIDNF(attr.OPT__HYBRIDNF), OPT__IGNORETAILS(attr.OPT__IGNORETAILS),
192        OPT__SYZNUMBER(attr.OPT__SYZNUMBER), OPT__TREEOUTPUT(attr.OPT__TREEOUTPUT),
193        OPT__SYZCHECK(attr.OPT__SYZCHECK), OPT__PROT(attr.OPT__PROT),
194        OPT__NOCACHING(attr.OPT__NOCACHING),
195        m_rBaseRing(attr.m_rBaseRing)
196    {}
197
198  /// output all the intermediate states
199  const int OPT__DEBUG; // DebugOutput;
200
201  /// ?
202  const int OPT__LEAD2SYZ; // TwoLeadingSyzygyTerms;
203
204  /// Reduce syzygy tails wrt the leading syzygy terms
205  const int OPT__TAILREDSYZ; // TailReducedSyzygies;
206
207  /// Use the usual NF's S-poly reduction while dropping lower order terms
208  /// 2 means - smart selection!
209  const int OPT__HYBRIDNF; // UseHybridNF
210
211
212  /// ignore tails and compute the pure Schreyer frame
213  const int OPT__IGNORETAILS; // @IGNORETAILS
214
215  /// Syzygy level (within a resolution)
216  mutable int OPT__SYZNUMBER;
217
218  inline void  nextSyzygyLayer() const
219  {
220     OPT__SYZNUMBER++;
221  }
222
223  /// output lifting tree
224  const int OPT__TREEOUTPUT;
225
226  /// CheckSyzygyProperty: TODO
227  const int OPT__SYZCHECK;
228
229  /// TEST_OPT_PROT
230  const bool OPT__PROT;
231
232  /// no caching/stores/lookups
233  const int OPT__NOCACHING;
234
235  /// global base ring
236  const ring m_rBaseRing;
237};
238
239class SchreyerSyzygyComputation;
240
241class CLCM: public SchreyerSyzygyComputationFlags, public std::vector<bool>
242{
243  public:
244    CLCM(const ideal& L, const SchreyerSyzygyComputationFlags& flags);
245
246    bool Check(const poly m) const;
247
248  private:
249    bool m_compute;
250
251    const unsigned int m_N; ///< number of ring variables
252};
253
254
255class CLeadingTerm
256{
257  public:
258    CLeadingTerm(unsigned int label,  const poly lt, const ring);
259
260#ifndef SING_NDEBUG
261    ~CLeadingTerm();
262#endif
263
264#if NOPRODUCT
265    bool DivisibilityCheck(const poly multiplier, const poly t, const unsigned long not_sev, const ring r) const;
266#endif
267    bool DivisibilityCheck(const poly product, const unsigned long not_sev, const ring r) const;
268
269    bool CheckLT( const ideal & L ) const;
270
271#ifndef SING_NDEBUG
272    poly lt() const;
273    unsigned long sev() const;
274    unsigned int label() const;
275#else
276    inline poly lt() const { return m_lt; };
277    inline unsigned long sev() const { return m_sev; };
278    inline unsigned int label() const { return m_label; };
279#endif
280
281  private:
282    const unsigned long m_sev; ///< not short exp. vector
283
284    // NOTE/TODO: either of the following should be enough:
285    const unsigned int  m_label; ///< index in the main L[] + 1
286
287    const poly          m_lt; ///< the leading term itself L[label-1]
288
289#ifndef SING_NDEBUG
290    const ring _R;
291
292    const poly          m_lt_copy; ///< original copy of LEAD(lt) (only for debug!!!)
293#endif
294
295    // disable the following:
296    CLeadingTerm();
297    CLeadingTerm(const CLeadingTerm&);
298    void operator=(const CLeadingTerm&);
299};
300
301
302// TODO: needs a specialized variant without a component (hash!)
303class CReducerFinder: public SchreyerSyzygyComputationFlags
304{
305#if NOPRODUCT
306  friend class CDivisorEnumerator2;
307#endif
308  friend class CDivisorEnumerator;
309
310  public:
311    typedef long TComponentKey;
312    typedef std::vector<const CLeadingTerm*> TReducers;
313
314  private:
315    typedef std::map< TComponentKey, TReducers> CReducersHash;
316
317  public:
318    /// goes over all leading terms
319    CReducerFinder(const ideal L, const SchreyerSyzygyComputationFlags& flags);
320
321    void Initialize(const ideal L);
322
323    ~CReducerFinder();
324
325
326#if NOPRODUCT
327    poly
328        FindReducer(const poly multiplier, const poly monom, const poly syzterm, const CReducerFinder& checker) const;
329
330#endif
331    // TODO: save shortcut (syz: |-.->) LM(LM(m) * "t") -> syz?
332    poly // const_iterator // TODO: return const_iterator it, s.th: it->m_lt is the needed
333        FindReducer(const poly product, const poly syzterm, const CReducerFinder& checker) const;
334
335    bool IsDivisible(const poly q) const;
336
337
338    inline bool IsNonempty() const { return !m_hash.empty(); }
339
340    /// is the term to be "preprocessed" as lower order term or lead to only reducible syzygies...
341    int PreProcessTerm(const poly t, CReducerFinder& syzChecker) const;
342
343#ifndef SING_NDEBUG
344    void DebugPrint() const;
345    void Verify() const;
346#endif
347
348  private:
349    ideal m_L; ///< only for debug
350
351    CReducersHash m_hash; // can also be replaced with a vector indexed by components
352
353  private:
354    CReducerFinder(const CReducerFinder&);
355    void operator=(const CReducerFinder&);
356};
357
358bool my_p_LmCmp (poly, poly, const ring);
359
360typedef poly TCacheKey;
361typedef poly TCacheValue;
362
363struct CCacheCompare
364{
365  const ring & m_ring;
366
367  CCacheCompare();
368
369  CCacheCompare(const ring& r): m_ring(r) { assume(r != NULL); }
370
371  CCacheCompare(const CCacheCompare& lhs): m_ring(lhs.m_ring) { assume(m_ring != NULL); }
372  CCacheCompare& operator=(const CCacheCompare& lhs) { assume(lhs.m_ring != NULL); return (const_cast<CCacheCompare&>(lhs)); }
373
374  inline bool operator() (const TCacheKey& l, const TCacheKey& r) const { assume(m_ring != NULL); return my_p_LmCmp(l, r, m_ring); }
375};
376
377typedef std::map<TCacheKey, TCacheValue, CCacheCompare> TP2PCache; // deallocation??? !!!
378typedef std::map<int, TP2PCache> TCache;
379
380
381/** @class SchreyerSyzygyComputation syzextra.h
382 *
383 * Computing syzygies after Schreyer
384 *
385 * Storing/accumulating data during the computation requires some global
386 * object, like this class. Ideally the above global functions should not
387 * be used in favour of this class.
388 *
389 * @sa Schreyer Syzygy Computation Paper & Talk & Python prototype
390 */
391class SchreyerSyzygyComputation: public SchreyerSyzygyComputationFlags
392{
393  friend class CLCM;
394  friend class CReducerFinder;
395
396  public:
397    /// Construct a global object for given input data (separated into leads & tails)
398    SchreyerSyzygyComputation(const ideal idLeads, const ideal idTails, const SchreyerSyzygyComputationFlags setting):
399        SchreyerSyzygyComputationFlags(setting),
400        m_idLeads(idLeads), m_idTails(id_Copy(idTails, setting.m_rBaseRing)),
401        m_syzLeads(NULL), m_syzTails(NULL),
402        m_LS(NULL), m_lcm(m_idLeads, setting),
403        m_div(m_idLeads, setting), m_checker(NULL, setting), m_cache(),
404        m_sum_bucket_factory(setting.m_rBaseRing),
405        m_spoly_bucket(NULL)
406    {
407      if( UNLIKELY(OPT__PROT) ) memset( &m_stat, 0, sizeof(m_stat) );
408    }
409
410    /// Construct a global object for given input data (separated into leads & tails)
411    SchreyerSyzygyComputation(const ideal idLeads, const ideal idTails, const ideal syzLeads, const SchreyerSyzygyComputationFlags setting):
412        SchreyerSyzygyComputationFlags(setting),
413        m_idLeads(idLeads), m_idTails(id_Copy(idTails, setting.m_rBaseRing)),
414        m_syzLeads(syzLeads), m_syzTails(NULL),
415        m_LS(syzLeads), m_lcm(m_idLeads, setting),
416        m_div(m_idLeads, setting), m_checker(NULL, setting), m_cache(),
417        m_sum_bucket_factory(setting.m_rBaseRing),
418        m_spoly_bucket(NULL)
419    {
420      if( UNLIKELY(OPT__PROT) ) memset( &m_stat, 0, sizeof(m_stat) );
421
422      if( LIKELY(OPT__TAILREDSYZ && !OPT__IGNORETAILS) )
423      {
424        if (syzLeads != NULL)
425          m_checker.Initialize(syzLeads);
426//        if( idTails != NULL )
427//          SetUpTailTerms();
428      }
429    }
430
431    /// Destructor should not destruct the resulting m_syzLeads, m_syzTails.
432    ~SchreyerSyzygyComputation(){ CleanUp(); }
433
434    /// Convert the given ideal of tails into the internal representation (with reducers!)
435    /// Preprocess m_idTails as well...?
436    void SetUpTailTerms();
437
438    /// print statistics about the used heuristics
439    void PrintStats() const;
440
441    /// Read off the results while detaching them from this object
442    /// NOTE: no copy!
443    inline void ReadOffResult(ideal& syzL, ideal& syzT)
444    {
445      syzL = m_syzLeads; syzT = m_syzTails;
446
447      m_syzLeads = m_syzTails = NULL; // m_LS ?
448
449      if ( UNLIKELY(OPT__PROT) )
450        PrintStats();
451    }
452
453
454    /// The main driver function: computes
455    void ComputeSyzygy();
456
457    /// Computes Syz(leads) or only LEAD of it.
458    /// The result is stored into m_syzLeads
459    void ComputeLeadingSyzygyTerms(bool bComputeSecondTerms = true);
460
461
462
463    /// Main HybridNF == 1: poly reduce + LOT + LCM?
464    poly SchreyerSyzygyNF(const poly syz_lead, poly syz_2 = NULL) const;
465
466
467    // Main (HybridNF == 0) Tree Travers + LOT + LCM?
468    poly TraverseNF(const poly syz_lead, const poly syz_2 = NULL) const;
469
470    /// High level caching function!!!
471    poly TraverseTail(poly multiplier, const int tail) const;
472
473    // REMOVE?
474    /// called only from above and from outside (for testing)
475    poly TraverseTail(poly multiplier, poly tail) const;
476
477    /// TODO: save shortcut (syz: |-.->) LM(m) * "t" -> ? ???
478    poly ReduceTerm(poly multiplier, poly term4reduction, poly syztermCheck) const;
479
480    /// low level computation...
481    poly ComputeImage(poly multiplier, const int tail) const;
482
483
484
485  public:
486    /// just for testing via the wrapper below
487    inline poly _FindReducer(const poly product, const poly syzterm) const
488        { return m_div.FindReducer(product, syzterm, m_checker); }
489 private:
490    void CleanUp();
491  protected:
492
493
494    /// just leading terms
495    ideal Compute1LeadingSyzygyTerms();
496
497    /// leading + second terms
498    ideal Compute2LeadingSyzygyTerms();
499
500
501
502  private:
503    /// input leading terms
504    const ideal m_idLeads;
505
506    /// input tails
507    const ideal m_idTails;
508
509    /// output (syzygy) leading terms (+2nd terms?)
510    ideal m_syzLeads;
511
512    /// output (syzygy) tails
513    ideal m_syzTails;
514
515    /*mutable?*/ ideal m_LS; ///< leading syzygy terms used for reducing syzygy tails
516
517
518    /// Bitmask for variables occuring in leading terms
519    const CLCM m_lcm;
520
521    /// Divisor finder
522    const CReducerFinder m_div;
523
524    /// for checking tail-terms and makeing them irreducible (wrt m_LS!)
525    CReducerFinder m_checker;
526
527    /*
528    // need more data here:
529    // (m_idLeads : m_tailterm) = (m, pos, compl), s.th: compl * m_tailterm divides m_idLeads[pos]
530    // but resulting sysygy compl * gen(pos) should not be in
531    // Idea: extend CReducerFinder??!!
532    struct CTailTerm
533    {
534      const poly m_tailterm;
535
536      const CReducerFinder m_reducers; // positions are labels (in m_idLeads)...
537      // compl - to be computed if needed?
538
539      CTailTerm(const poly tt, const CReducerFinder reds): m_tailterm(tt), m_reducers(reds) {}
540    };
541
542    typedef std::vector<const CTailTerm*> TTail;
543    typedef std::vector<TTail> TTailTerms;
544
545    TTailTerms m_idTailTerms;
546    */
547
548    mutable TCache m_cache; // cacher comp + poly -> poly! // mutable???
549
550/// TODO: look into m_idTailTerms!!!!!!!!!!!!!!!!!!!!!!!! map? heaps???
551    // NOTE/TODO: the following globally shared buckets violate reentrance - they should rather belong to TLS!
552
553    /// used for simple summing up
554    mutable SBucketFactory m_sum_bucket_factory; // sBucket_pt
555
556    /// for S-Polynomial reductions
557    mutable kBucket_pt m_spoly_bucket; // only used inside of SchreyerSyzygyNF! destruction by CleanUp()!
558
559
560    /// Statistics:
561    ///  0..3: as in SetUpTailTerms()::PreProcessTerm() // TODO!!??
562    ///  4: number of terms discarded due to LOT heuristics
563    ///  5: number of terms discarded due to LCM heuristics
564    ///  6, 7: lookups without & with rescale, 8: stores
565    mutable unsigned long m_stat[9];
566};
567
568// The following wrappers are just for testing separate functions on highest level (within schreyer.lib)
569
570static inline void ComputeSyzygy(const ideal L, const ideal T, ideal& LL, ideal& TT, const SchreyerSyzygyComputationFlags A)
571{
572  SchreyerSyzygyComputation syz(L, T, A);
573  syz.ComputeSyzygy();
574  syz.ReadOffResult(LL, TT);
575}
576
577static inline ideal ComputeLeadingSyzygyTerms(const ideal& L, const SchreyerSyzygyComputationFlags A)
578{
579  SchreyerSyzygyComputation syz(L, NULL, A);
580  syz.ComputeLeadingSyzygyTerms(false);
581  ideal LL, TT;
582  syz.ReadOffResult(LL, TT);
583  return LL; // assume TT is NULL!
584}
585
586static inline ideal Compute2LeadingSyzygyTerms(const ideal& L, const SchreyerSyzygyComputationFlags A)
587{
588  SchreyerSyzygyComputation syz(L, NULL, A);
589  syz.ComputeLeadingSyzygyTerms(true);
590  ideal LL, TT;
591  syz.ReadOffResult(LL, TT);
592  return LL; // assume TT is NULL!
593}
594
595static inline poly FindReducer(poly product, poly syzterm,
596                               ideal L, ideal LS, const SchreyerSyzygyComputationFlags A)
597{
598  SchreyerSyzygyComputation syz(L, NULL, LS, A);
599  return syz._FindReducer(product, syzterm);
600}
601
602static inline poly TraverseTail(poly multiplier, poly tail,
603                                ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
604{
605  SchreyerSyzygyComputation syz(L, T, LS, A);
606  return syz.TraverseTail(multiplier, tail);
607}
608
609static inline poly ReduceTerm(poly multiplier, poly term4reduction, poly syztermCheck,
610                              ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
611{
612  SchreyerSyzygyComputation syz(L, T, LS, A);
613  return syz.ReduceTerm(multiplier, term4reduction, syztermCheck);
614}
615
616
617static inline poly SchreyerSyzygyNF(poly syz_lead, poly syz_2,
618                                    ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
619{
620  SchreyerSyzygyComputation syz(L, T, LS, A);
621  return syz.SchreyerSyzygyNF(syz_lead, syz_2);
622}
623
624#endif
625/* #ifndef SYZEXTRA_H */
626
627// Vi-modeline: vim: filetype=c:syntax:shiftwidth=2:tabstop=8:textwidth=0:expandtab
628
Note: See TracBrowser for help on using the repository browser.