source: git/Singular/dyn_modules/syzextra/syzextra.h @ 349ee0c

spielwiese
Last change on this file since 349ee0c was 349ee0c, checked in by Hans Schoenemann <hannes@…>, 6 years ago
removed more debug stuff from syzextra
  • Property mode set to 100644
File size: 15.4 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
74  public:
75    typedef Base::value_type Bucket;
76
77    SBucketFactory(const ring r)
78    {
79      push ( _CreateBucket(r) ); // start with at least one sBucket...?
80      assume( top() != NULL );
81    };
82
83    ~SBucketFactory()
84    {
85      while( !empty() )
86      {
87        _DestroyBucket( top() );
88        pop();
89      }
90    }
91
92    Bucket getBucket(const ring r, const bool remove = true)
93    {
94      Bucket bt = NULL;
95
96      if( !empty() )
97      {
98        bt = top();
99
100        if( remove )
101          pop();
102      }
103      else
104      {
105        bt = _CreateBucket(r);
106
107        if( !remove )
108        {
109          push(bt);
110          assume( bt == top() );
111        }
112      }
113
114      assume( bt != NULL );
115
116      return bt;
117    }
118
119    // TODO: this may be spared if we give-out a smart Bucket (which returns here upon its destructor!)
120    void putBucket(const Bucket & bt, const bool replace = false)
121    {
122      assume( bt != NULL );
123
124      if( empty() )
125        push( bt );
126      else
127      {
128        if( replace )
129          top() = bt;
130        else
131        {
132          if( bt != top() )
133            push( bt );
134        }
135      }
136
137      assume( bt == top() );
138    }
139
140  private:
141    /// inital allocation for new buckets
142    static Bucket _CreateBucket(const ring r);
143
144    /// we only expect empty buckets to be left at the end for destructor
145    /// bt will be set to NULL
146    static void _DestroyBucket(Bucket & bt);
147
148  private:
149    SBucketFactory();
150    SBucketFactory(const SBucketFactory&);
151    void operator=(const SBucketFactory&);
152
153};
154
155
156
157
158
159
160
161/// Computation attribute storage
162struct SchreyerSyzygyComputationFlags
163{
164    SchreyerSyzygyComputationFlags(idhdl rootRingHdl);
165
166    SchreyerSyzygyComputationFlags(const SchreyerSyzygyComputationFlags& attr):
167        OPT__DEBUG(attr.OPT__DEBUG),
168        OPT__LEAD2SYZ(attr.OPT__LEAD2SYZ),  OPT__TAILREDSYZ(attr.OPT__TAILREDSYZ),
169        OPT__HYBRIDNF(attr.OPT__HYBRIDNF), OPT__IGNORETAILS(attr.OPT__IGNORETAILS),
170        OPT__SYZNUMBER(attr.OPT__SYZNUMBER), OPT__TREEOUTPUT(attr.OPT__TREEOUTPUT),
171        OPT__SYZCHECK(attr.OPT__SYZCHECK), OPT__PROT(attr.OPT__PROT),
172        OPT__NOCACHING(attr.OPT__NOCACHING),
173        m_rBaseRing(attr.m_rBaseRing)
174    {}
175
176  /// output all the intermediate states
177  const int OPT__DEBUG; // DebugOutput;
178
179  /// ?
180  const int OPT__LEAD2SYZ; // TwoLeadingSyzygyTerms;
181
182  /// Reduce syzygy tails wrt the leading syzygy terms
183  const int OPT__TAILREDSYZ; // TailReducedSyzygies;
184
185  /// Use the usual NF's S-poly reduction while dropping lower order terms
186  /// 2 means - smart selection!
187  const int OPT__HYBRIDNF; // UseHybridNF
188
189
190  /// ignore tails and compute the pure Schreyer frame
191  const int OPT__IGNORETAILS; // @IGNORETAILS
192
193  /// Syzygy level (within a resolution)
194  mutable int OPT__SYZNUMBER;
195
196  inline void  nextSyzygyLayer() const
197  {
198     OPT__SYZNUMBER++;
199  }
200
201  /// output lifting tree
202  const int OPT__TREEOUTPUT;
203
204  /// CheckSyzygyProperty: TODO
205  const int OPT__SYZCHECK;
206
207  /// TEST_OPT_PROT
208  const bool OPT__PROT;
209
210  /// no caching/stores/lookups
211  const int OPT__NOCACHING;
212
213  /// global base ring
214  const ring m_rBaseRing;
215};
216
217class SchreyerSyzygyComputation;
218
219class CLCM: public SchreyerSyzygyComputationFlags, public std::vector<bool>
220{
221  public:
222    CLCM(const ideal& L, const SchreyerSyzygyComputationFlags& flags);
223
224    bool Check(const poly m) const;
225
226  private:
227    bool m_compute;
228
229    const unsigned int m_N; ///< number of ring variables
230};
231
232
233class CLeadingTerm
234{
235  public:
236    CLeadingTerm(unsigned int label,  const poly lt, const ring);
237
238#if NOPRODUCT
239    bool DivisibilityCheck(const poly multiplier, const poly t, const unsigned long not_sev, const ring r) const;
240#endif
241    bool DivisibilityCheck(const poly product, const unsigned long not_sev, const ring r) const;
242
243    bool CheckLT( const ideal & L ) const;
244
245    inline poly lt() const { return m_lt; };
246    inline unsigned long sev() const { return m_sev; };
247    inline unsigned int label() const { return m_label; };
248  private:
249    const unsigned long m_sev; ///< not short exp. vector
250
251    // NOTE/TODO: either of the following should be enough:
252    const unsigned int  m_label; ///< index in the main L[] + 1
253
254    const poly          m_lt; ///< the leading term itself L[label-1]
255
256    // disable the following:
257    CLeadingTerm();
258    CLeadingTerm(const CLeadingTerm&);
259    void operator=(const CLeadingTerm&);
260};
261
262
263// TODO: needs a specialized variant without a component (hash!)
264class CReducerFinder: public SchreyerSyzygyComputationFlags
265{
266#if NOPRODUCT
267  friend class CDivisorEnumerator2;
268#endif
269  friend class CDivisorEnumerator;
270
271  public:
272    typedef long TComponentKey;
273    typedef std::vector<const CLeadingTerm*> TReducers;
274
275  private:
276    typedef std::map< TComponentKey, TReducers> CReducersHash;
277
278  public:
279    /// goes over all leading terms
280    CReducerFinder(const ideal L, const SchreyerSyzygyComputationFlags& flags);
281
282    void Initialize(const ideal L);
283
284    ~CReducerFinder();
285
286
287#if NOPRODUCT
288    poly
289        FindReducer(const poly multiplier, const poly monom, const poly syzterm, const CReducerFinder& checker) const;
290
291#endif
292    // TODO: save shortcut (syz: |-.->) LM(LM(m) * "t") -> syz?
293    poly // const_iterator // TODO: return const_iterator it, s.th: it->m_lt is the needed
294        FindReducer(const poly product, const poly syzterm, const CReducerFinder& checker) const;
295
296    bool IsDivisible(const poly q) const;
297
298
299    inline bool IsNonempty() const { return !m_hash.empty(); }
300
301    /// is the term to be "preprocessed" as lower order term or lead to only reducible syzygies...
302    int PreProcessTerm(const poly t, CReducerFinder& syzChecker) const;
303
304  private:
305    ideal m_L; ///< only for debug
306
307    CReducersHash m_hash; // can also be replaced with a vector indexed by components
308
309  private:
310    CReducerFinder(const CReducerFinder&);
311    void operator=(const CReducerFinder&);
312};
313
314bool my_p_LmCmp (poly, poly, const ring);
315
316typedef poly TCacheKey;
317typedef poly TCacheValue;
318
319struct CCacheCompare
320{
321  const ring & m_ring;
322
323  CCacheCompare();
324
325  CCacheCompare(const ring& r): m_ring(r) { assume(r != NULL); }
326
327  CCacheCompare(const CCacheCompare& lhs): m_ring(lhs.m_ring) { assume(m_ring != NULL); }
328  CCacheCompare& operator=(const CCacheCompare& lhs) { assume(lhs.m_ring != NULL); return (const_cast<CCacheCompare&>(lhs)); }
329
330  inline bool operator() (const TCacheKey& l, const TCacheKey& r) const { assume(m_ring != NULL); return my_p_LmCmp(l, r, m_ring); }
331};
332
333typedef std::map<TCacheKey, TCacheValue, CCacheCompare> TP2PCache; // deallocation??? !!!
334typedef std::map<int, TP2PCache> TCache;
335
336
337/** @class SchreyerSyzygyComputation syzextra.h
338 *
339 * Computing syzygies after Schreyer
340 *
341 * Storing/accumulating data during the computation requires some global
342 * object, like this class. Ideally the above global functions should not
343 * be used in favour of this class.
344 *
345 * @sa Schreyer Syzygy Computation Paper & Talk & Python prototype
346 */
347class SchreyerSyzygyComputation: public SchreyerSyzygyComputationFlags
348{
349  friend class CLCM;
350  friend class CReducerFinder;
351
352  public:
353    /// Construct a global object for given input data (separated into leads & tails)
354    SchreyerSyzygyComputation(const ideal idLeads, const ideal idTails, const SchreyerSyzygyComputationFlags setting):
355        SchreyerSyzygyComputationFlags(setting),
356        m_idLeads(idLeads), m_idTails(id_Copy(idTails, setting.m_rBaseRing)),
357        m_syzLeads(NULL), m_syzTails(NULL),
358        m_LS(NULL), m_lcm(m_idLeads, setting),
359        m_div(m_idLeads, setting), m_checker(NULL, setting), m_cache(),
360        m_sum_bucket_factory(setting.m_rBaseRing),
361        m_spoly_bucket(NULL)
362    {
363      if( UNLIKELY(OPT__PROT) ) memset( &m_stat, 0, sizeof(m_stat) );
364    }
365
366    /// Construct a global object for given input data (separated into leads & tails)
367    SchreyerSyzygyComputation(const ideal idLeads, const ideal idTails, const ideal syzLeads, const SchreyerSyzygyComputationFlags setting):
368        SchreyerSyzygyComputationFlags(setting),
369        m_idLeads(idLeads), m_idTails(id_Copy(idTails, setting.m_rBaseRing)),
370        m_syzLeads(syzLeads), m_syzTails(NULL),
371        m_LS(syzLeads), m_lcm(m_idLeads, setting),
372        m_div(m_idLeads, setting), m_checker(NULL, setting), m_cache(),
373        m_sum_bucket_factory(setting.m_rBaseRing),
374        m_spoly_bucket(NULL)
375    {
376      if( UNLIKELY(OPT__PROT) ) memset( &m_stat, 0, sizeof(m_stat) );
377
378      if( LIKELY(OPT__TAILREDSYZ && !OPT__IGNORETAILS) )
379      {
380        if (syzLeads != NULL)
381          m_checker.Initialize(syzLeads);
382//        if( idTails != NULL )
383//          SetUpTailTerms();
384      }
385    }
386
387    /// Destructor should not destruct the resulting m_syzLeads, m_syzTails.
388    ~SchreyerSyzygyComputation(){ CleanUp(); }
389
390    /// Convert the given ideal of tails into the internal representation (with reducers!)
391    /// Preprocess m_idTails as well...?
392    void SetUpTailTerms();
393
394    /// print statistics about the used heuristics
395    void PrintStats() const;
396
397    /// Read off the results while detaching them from this object
398    /// NOTE: no copy!
399    inline void ReadOffResult(ideal& syzL, ideal& syzT)
400    {
401      syzL = m_syzLeads; syzT = m_syzTails;
402
403      m_syzLeads = m_syzTails = NULL; // m_LS ?
404
405      if ( UNLIKELY(OPT__PROT) )
406        PrintStats();
407    }
408
409
410    /// The main driver function: computes
411    void ComputeSyzygy();
412
413    /// Computes Syz(leads) or only LEAD of it.
414    /// The result is stored into m_syzLeads
415    void ComputeLeadingSyzygyTerms(bool bComputeSecondTerms = true);
416
417
418
419    /// Main HybridNF == 1: poly reduce + LOT + LCM?
420    poly SchreyerSyzygyNF(const poly syz_lead, poly syz_2 = NULL) const;
421
422
423    // Main (HybridNF == 0) Tree Travers + LOT + LCM?
424    poly TraverseNF(const poly syz_lead, const poly syz_2 = NULL) const;
425
426    /// High level caching function!!!
427    poly TraverseTail(poly multiplier, const int tail) const;
428
429    // REMOVE?
430    /// called only from above and from outside (for testing)
431    poly TraverseTail(poly multiplier, poly tail) const;
432
433    /// TODO: save shortcut (syz: |-.->) LM(m) * "t" -> ? ???
434    poly ReduceTerm(poly multiplier, poly term4reduction, poly syztermCheck) const;
435
436    /// low level computation...
437    poly ComputeImage(poly multiplier, const int tail) const;
438
439
440
441  public:
442    /// just for testing via the wrapper below
443    inline poly _FindReducer(const poly product, const poly syzterm) const
444        { return m_div.FindReducer(product, syzterm, m_checker); }
445 private:
446    void CleanUp();
447  protected:
448
449
450    /// just leading terms
451    ideal Compute1LeadingSyzygyTerms();
452
453    /// leading + second terms
454    ideal Compute2LeadingSyzygyTerms();
455
456
457
458  private:
459    /// input leading terms
460    const ideal m_idLeads;
461
462    /// input tails
463    const ideal m_idTails;
464
465    /// output (syzygy) leading terms (+2nd terms?)
466    ideal m_syzLeads;
467
468    /// output (syzygy) tails
469    ideal m_syzTails;
470
471    /*mutable?*/ ideal m_LS; ///< leading syzygy terms used for reducing syzygy tails
472
473
474    /// Bitmask for variables occuring in leading terms
475    const CLCM m_lcm;
476
477    /// Divisor finder
478    const CReducerFinder m_div;
479
480    /// for checking tail-terms and makeing them irreducible (wrt m_LS!)
481    CReducerFinder m_checker;
482
483    mutable TCache m_cache; // cacher comp + poly -> poly! // mutable???
484
485    /// used for simple summing up
486    mutable SBucketFactory m_sum_bucket_factory; // sBucket_pt
487
488    /// for S-Polynomial reductions
489    mutable kBucket_pt m_spoly_bucket; // only used inside of SchreyerSyzygyNF! destruction by CleanUp()!
490
491
492    /// Statistics:
493    ///  0..3: as in SetUpTailTerms()::PreProcessTerm() // TODO!!??
494    ///  4: number of terms discarded due to LOT heuristics
495    ///  5: number of terms discarded due to LCM heuristics
496    ///  6, 7: lookups without & with rescale, 8: stores
497    mutable unsigned long m_stat[9];
498};
499
500// The following wrappers are just for testing separate functions on highest level (within schreyer.lib)
501
502static inline void ComputeSyzygy(const ideal L, const ideal T, ideal& LL, ideal& TT, const SchreyerSyzygyComputationFlags A)
503{
504  SchreyerSyzygyComputation syz(L, T, A);
505  syz.ComputeSyzygy();
506  syz.ReadOffResult(LL, TT);
507}
508
509static inline ideal ComputeLeadingSyzygyTerms(const ideal& L, const SchreyerSyzygyComputationFlags A)
510{
511  SchreyerSyzygyComputation syz(L, NULL, A);
512  syz.ComputeLeadingSyzygyTerms(false);
513  ideal LL, TT;
514  syz.ReadOffResult(LL, TT);
515  return LL; // assume TT is NULL!
516}
517
518static inline ideal Compute2LeadingSyzygyTerms(const ideal& L, const SchreyerSyzygyComputationFlags A)
519{
520  SchreyerSyzygyComputation syz(L, NULL, A);
521  syz.ComputeLeadingSyzygyTerms(true);
522  ideal LL, TT;
523  syz.ReadOffResult(LL, TT);
524  return LL; // assume TT is NULL!
525}
526
527static inline poly FindReducer(poly product, poly syzterm,
528                               ideal L, ideal LS, const SchreyerSyzygyComputationFlags A)
529{
530  SchreyerSyzygyComputation syz(L, NULL, LS, A);
531  return syz._FindReducer(product, syzterm);
532}
533
534static inline poly TraverseTail(poly multiplier, poly tail,
535                                ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
536{
537  SchreyerSyzygyComputation syz(L, T, LS, A);
538  return syz.TraverseTail(multiplier, tail);
539}
540
541static inline poly ReduceTerm(poly multiplier, poly term4reduction, poly syztermCheck,
542                              ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
543{
544  SchreyerSyzygyComputation syz(L, T, LS, A);
545  return syz.ReduceTerm(multiplier, term4reduction, syztermCheck);
546}
547
548
549static inline poly SchreyerSyzygyNF(poly syz_lead, poly syz_2,
550                                    ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
551{
552  SchreyerSyzygyComputation syz(L, T, LS, A);
553  return syz.SchreyerSyzygyNF(syz_lead, syz_2);
554}
555
556#endif
557/* #ifndef SYZEXTRA_H */
558
559// Vi-modeline: vim: filetype=c:syntax:shiftwidth=2:tabstop=8:textwidth=0:expandtab
560
Note: See TracBrowser for help on using the repository browser.