source: git/Singular/dyn_modules/syzextra/syzextra.h @ 0f9b03

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