Modernized GAlib  3.0.0 current
GAAllele.h
1 /* ----------------------------------------------------------------------------
2  mbwall 21mar95
3  Copyright (c) 1995 Massachusetts Institute of Technology
4  all rights reserved
5 ---------------------------------------------------------------------------- */
6 
7 #pragma once
8 
9 #include "gaconfig.h"
10 #include <garandom.h>
11 
12 #include <GAAllele.h>
13 #include <cstring>
14 #include <gaerror.h>
15 #include <istream>
16 #include <ostream>
17 #include <vector>
18 
19 constexpr auto GA_ALLELE_CHUNK = 10;
20 
26 class GAAllele
27 {
28  public:
29  enum class Type
30  {
31  ENUMERATED = 1,
32  BOUNDED = 2,
33  DISCRETIZED
34  };
35  enum class BoundType
36  {
37  NONE,
38  INCLUSIVE,
39  EXCLUSIVE
40  };
41 };
42 
43 /* ----------------------------------------------------------------------------
44  This object contains a set of alleles for use with a similarly typed genome.
45  This object can be used with any type that has operator= defined for it. If
46 you use the remove member then you must have operator== defined for it.
47  This should be implemented as a derivative of the Array class? But I don't
48 want that overhead at this point. Also, behaviour is not the same.
49  The allele set uses the envelope/message structure. The core allele object
50 is a reference-counted structure that contains all of the guts of an allele
51 set. The outer shell, the allele set itself, is what users actually see. It
52 defines the interface. With this setup you can create a single allele set then
53 each genome does not have to make its own copy. And we don't have to worry
54 about an allele set going out of scope then leaving genomes hanging (a problem
55 if we just used a pointer to a single alleleset with no reference counting).
56  You can link an allele set to another so that they share the same core. Use
57 the 'link' member function (this is typically used within the GAlib to reduce
58 the number of actual alleleset instances when cloning populations of genomes).
59  There is no way to 'resize' an allele set. You must add to it or remove
60 elements from it.
61  The base template class assumes that the objects in the allele set are
62 complex, i.e. it is not OK to do a bit-copy of each object. We should do
63 specializations for non-complex objects (or perhaps a separate class that does
64 bit-copies rather than logical-copies?)
65  When you clone an allele set, the new one has its own core.
66  Why didn't I do this as a couple of objects (enumerated set, bounded set,
67 discretized set, etc)? I wanted to be able to have an array that uses sets of
68 many different types. I suppose the allele set should be completely
69 polymorphic like the rest of the GAlib objects, but for now we'll do it as
70 a single object with multiple personalities (and a state).
71  There is no error checking. You should check the type before you try to
72 call any of the member functions. In particular, if you try to get the
73 bounds on an enumerated set of one element, it will break.
74 
75 *** should the assignment operator check to be sure that no allele is
76  duplicated, or is it OK to have duplicate alleles in a set? For now we
77  allow duplicates (via either the add or assignemnt ops).
78 ---------------------------------------------------------------------------- */
79 template <class T> class GAAlleleSetCore
80 {
81  public:
83  : csz(GA_ALLELE_CHUNK),
84  a(std::vector<T>())
85  {
86  lowerb = GAAllele::BoundType::NONE;
87  upperb = GAAllele::BoundType::NONE;
88 
89  cnt = 1;
90  }
91 
92  GAAlleleSetCore(unsigned int n, const T array[])
93  : type(GAAllele::Type::ENUMERATED), csz(GA_ALLELE_CHUNK), sz(n),
94  SZ(GA_ALLELE_CHUNK)
95  {
96  while (SZ < sz)
97  SZ += csz;
98  a = std::vector<T>(SZ);
99  for (unsigned int i = 0; i < sz; i++)
100  a.at(i) = *(array + i);
101  lowerb = GAAllele::BoundType::NONE;
102  upperb = GAAllele::BoundType::NONE;
103 
104  cnt = 1;
105  }
106 
107  GAAlleleSetCore(const T &lower, const T &upper,
108  GAAllele::BoundType lb = GAAllele::BoundType::INCLUSIVE,
109  GAAllele::BoundType ub = GAAllele::BoundType::INCLUSIVE)
110  : type(GAAllele::Type::BOUNDED), csz(GA_ALLELE_CHUNK), sz(2), SZ(2),
111  a(std::vector<T>(2))
112  {
113  a.at(0) = lower;
114  a.at(1) = upper;
115  lowerb = lb;
116  upperb = ub;
117 
118  cnt = 1;
119  }
120 
121  GAAlleleSetCore(const T &lower, const T &upper, const T &increment,
122  GAAllele::BoundType lb = GAAllele::BoundType::INCLUSIVE,
123  GAAllele::BoundType ub = GAAllele::BoundType::INCLUSIVE)
124  : type(GAAllele::Type::DISCRETIZED), csz(GA_ALLELE_CHUNK), sz(3), SZ(3),
125  a(std::vector<T>(3))
126  {
127  a.at(0) = lower;
128  a.at(1) = upper;
129  a.at(2) = increment;
130  lowerb = lb;
131  upperb = ub;
132 
133  cnt = 1;
134  }
135 
136  // We do not copy the original's reference count!
138  : csz(orig.csz), sz(orig.sz), SZ(orig.SZ), a(std::vector<T>(orig.SZ))
139  {
140  for (unsigned int i = 0; i < sz; i++)
141  a.at(i) = orig.a.at(i);
142  lowerb = orig.lowerb;
143  upperb = orig.upperb;
144  type = orig.type;
145 
146  cnt = 1;
147  }
148 
149  // This just trashes everything. This shouldn't get called before the count
150  // reaches zero, so if it does, we post an error.
151  ~GAAlleleSetCore()
152  {
153  if (cnt > 0)
154  GAErr(GA_LOC, "GAAlleleSetCore", "destructor", GAError::RefsRemain);
155  }
156 
157  // Copying the contents of another allele set core does NOT change the
158  // current count of the allele set core!
159  GAAlleleSetCore<T>& operator=(const GAAlleleSetCore<T> &orig)
160  {
161  if (this == &orig)
162  return *this;
163 
164  if (SZ < orig.sz)
165  {
166  while (SZ < orig.sz)
167  SZ += csz;
168  a = std::vector<T>(SZ);
169  }
170 
171  for (unsigned int i = 0; i < orig.sz; i++)
172  a.at(i) = orig.a.at(i);
173 
174  sz = orig.sz;
175  lowerb = orig.lowerb;
176  upperb = orig.upperb;
177  type = orig.type;
178 
179  return *this;
180  }
181 
182  GAAllele::Type type{GAAllele::Type::ENUMERATED}; // is this an ennumerated or bounded set?
183  GAAllele::BoundType lowerb, upperb; // what kind of limit is the bound?
184  unsigned int cnt; // how many objects are using us?
185  unsigned int csz; // how big are the chunks to allocate?
186  unsigned int sz{0}; // number we have
187  unsigned int SZ{0}; // how many have we allocated?
188  std::vector<T> a;
189 };
190 
191 template <class T> class GAAlleleSet
192 {
193  public:
194  GAAlleleSet() : core(nullptr) {}
195  GAAlleleSet(unsigned int n, const T a[])
196  : core(new GAAlleleSetCore<T>(n, a))
197  {
198  }
199  GAAlleleSet(const T &lower, const T &upper,
200  GAAllele::BoundType lb = GAAllele::BoundType::INCLUSIVE,
201  GAAllele::BoundType ub = GAAllele::BoundType::INCLUSIVE)
202  : core(new GAAlleleSetCore<T>(lower, upper, lb, ub))
203  {
204  }
205  GAAlleleSet(const T &lower, const T &upper, const T &increment,
206  GAAllele::BoundType lb = GAAllele::BoundType::INCLUSIVE,
207  GAAllele::BoundType ub = GAAllele::BoundType::INCLUSIVE)
208  : core(new GAAlleleSetCore<T>(lower, upper, increment, lb, ub))
209  {
210  }
211  GAAlleleSet(const GAAlleleSet<T> &set)
212  : core(new GAAlleleSetCore<T>(*(set.core)))
213  {
214  }
215  virtual ~GAAlleleSet()
216  {
217  if (core != nullptr)
218  {
219  core->cnt -= 1;
220  if (core->cnt == 0)
221  {
222  delete core;
223  }
224  }
225  }
226  GAAlleleSet<T> &operator=(const GAAlleleSet<T> &set)
227  {
228  if (this == &set)
229  {
230  return *this;
231  }
232  if (core)
233  {
234  *core = *set.core;
235  }
236  else
237  {
238  core = new GAAlleleSetCore<T>(*(set.core));
239  }
240  return *this;
241  }
242  GAAlleleSet<T> *clone() const { return new GAAlleleSet<T>(*this); }
243 
244  // When we link to another allele set, we point our core to that one. Be
245  // sure that we have a core. If not, just point. If so, trash as needed.
246  // TODO check, if this wokrs now as it is now a std::vector
247  void link(GAAlleleSet<T> set)
248  {
249  if (&set != this)
250  {
251  if (core != nullptr)
252  {
253  core->cnt -= 1;
254  if (core->cnt == 0)
255  delete core;
256  }
257  core = set.core;
258  core->cnt += 1;
259  }
260  }
261 
262  void unlink()
263  {
264  if (core == nullptr)
265  return; // nothing to unlink
266  if (core->cnt > 1)
267  {
268  core->cnt -= 1;
269  core = new GAAlleleSetCore<T>(*core);
270  }
271  }
272 
273  int size() const { return core->sz; } // only meaninful for enumerated sets
274 
275  // If everthing goes OK, return 0. If there's an error, we return -1. I
276  // really wish there were enough compilers doing exceptions to use them...
277  int add(const T &alle)
278  {
279  if (core == nullptr)
280  core = new GAAlleleSetCore<T>;
281  if (core->type != GAAllele::Type::ENUMERATED)
282  return 1;
283  if (core->sz >= core->SZ)
284  {
285  core->SZ += core->csz;
286  auto tmp = core->a;
287  core->a = std::vector<T>(core->SZ);
288  for (unsigned int i = 0; i < core->sz; i++)
289  core->a.at(i) = tmp.at(i);
290  }
291  core->a.at(core->sz) = alle;
292  core->sz += 1;
293  return 0;
294  }
295 
296  int remove(const T &allele)
297  {
298  if (core == nullptr)
299  core = new GAAlleleSetCore<T>;
300  if (core->type != GAAllele::Type::ENUMERATED)
301  return 1;
302  for (unsigned int i = 0; i < core->sz; i++)
303  {
304  if (core->a[i] == allele)
305  {
306  for (unsigned int j = i; j < core->sz - 1; j++)
307  core->a[j] = core->a[j + 1];
308  // memmove(&(core->a[i]), &(core->a[i+1]),
309  //(core->sz-i-1)*sizeof(T));
310  core->sz -= 1;
311  i = core->sz; // break out of the loop
312  }
313  }
314  return 0;
315  }
316 
317  int remove(unsigned int x)
318  {
319  for (unsigned int j = x; j < core->sz - 1; j++)
320  core->a[j] = core->a[j + 1];
321  // memmove(&(core->a[i]), &(core->a[i+1]), (core->sz-i-1)*sizeof(T));
322  core->sz -= 1;
323  return 0;
324  }
325 
326  // When returning an allele from the set, we have to know what type we are.
327  // The allele that we return depends on the type. If we're an enumerated
328  // set then just pick randomly from the list of alleles. If we're a bounded
329  // set then pick randomly from the bounds, and respect the bound types. If
330  // we're a discretized set then we do much as we would for the bounded set,
331  // but we respect the discretization.
332  // Be sure to specialize this member function (see the real genome for an
333  // example of how to do this)
334  T allele() const
335  {
336  if (core->type == GAAllele::Type::ENUMERATED)
337  return core->a[GARandomInt(0, core->sz - 1)];
338  else if (core->type == GAAllele::Type::DISCRETIZED)
339  {
340  GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)",
341  GAError::OpUndef);
342  return core->a[0];
343  }
344  else
345  {
346  GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)",
347  GAError::OpUndef);
348  return core->a[0];
349  }
350  }
351 
352  // This works only for enumerated sets. If someone tries to use this on a
353  // non-enumerated set then we post an error message. No bounds checking on
354  // the value that was passed to us, but we do modulo it so that we'll never
355  // break. Also, this means you can wrap an allele set around an array that
356  // is significantly larger than the allele set that defines its contents.
357  T allele(unsigned int i) const
358  {
359  if (core->type == GAAllele::Type::ENUMERATED)
360  return core->a[i % core->sz];
361  else if (core->type == GAAllele::Type::DISCRETIZED)
362  {
363  GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)",
364  GAError::OpUndef);
365  return core->a[0];
366  }
367  else
368  {
369  GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)",
370  GAError::NoAlleleIndex);
371  return core->a[0];
372  }
373  }
374 
375  T lower() const { return core->a[0]; } // only for bounded sets
376  T upper() const { return core->a[1]; }
377  T inc() const { return core->a[2]; }
378  GAAllele::BoundType lowerBoundType() const { return core->lowerb; }
379  GAAllele::BoundType upperBoundType() const { return core->upperb; }
380  GAAllele::Type type() const { return core->type; }
381 
382  int read(std::istream &)
383  {
384  GAErr(GA_LOC, "GAAlleleSet", "read", GAError::OpUndef);
385  return 1;
386  }
387 
388  int write(std::ostream &) const
389  {
390  GAErr(GA_LOC, "GAAlleleSet", "write", GAError::OpUndef);
391  return 1;
392  }
393 
394  template <class U>
395  friend int operator==(const GAAlleleSet<U>&, const GAAlleleSet<U>&);
396  template <class U>
397  friend int operator!=(const GAAlleleSet<U>&, const GAAlleleSet<U>&);
398 
399  protected:
400  GAAlleleSetCore<T> *core;
401 };
402 
403 template <class T> class GAAlleleSetArray
404 {
405  public:
406  GAAlleleSetArray() : csz(GA_ALLELE_CHUNK), aset(nullptr) {}
407 
409  : csz(GA_ALLELE_CHUNK), sz(1), SZ(GA_ALLELE_CHUNK),
410  aset(new GAAlleleSet<T> *[GA_ALLELE_CHUNK])
411  {
412  aset[0] = new GAAlleleSet<T>(s);
413  }
414 
416  : csz(orig.csz), sz(orig.sz), SZ(orig.SZ),
417  aset(new GAAlleleSet<T> *[orig.SZ])
418  {
419  for (unsigned int i = 0; i < sz; i++)
420  aset[i] = new GAAlleleSet<T>(orig.set(i));
421  }
422 
424  {
425  for (unsigned int i = 0; i < sz; i++)
426  delete aset[i];
427  delete[] aset;
428  }
429 
430  GAAlleleSetArray<T>& operator=(const GAAlleleSetArray<T> &orig)
431  {
432  if (this == &orig)
433  return *this;
434  unsigned int i;
435  for (i = 0; i < sz; i++)
436  delete aset[i];
437 
438  if (SZ < orig.sz)
439  {
440  while (SZ < orig.sz)
441  SZ += csz;
442  delete[] aset;
443  aset = new GAAlleleSet<T> *[SZ];
444  }
445  for (i = 0; i < orig.sz; i++)
446  aset[i] = new GAAlleleSet<T>(orig.set(i));
447 
448  sz = orig.sz;
449 
450  return *this;
451  }
452 
453  int size() const { return sz; }
454  const GAAlleleSet<T> &set(unsigned int i) const { return *(aset[i]); }
455 
456  // Return 0 if everything goes OK, otherwise return -1
457  int add(const GAAlleleSet<T> &s)
458  {
459  if (sz + 1 > SZ)
460  {
461  SZ += csz;
462  GAAlleleSet<T> **tmp = aset;
463  aset = new GAAlleleSet<T> *[SZ];
464  memcpy(aset, tmp, sz * sizeof(GAAlleleSet<T> *));
465  delete[] tmp;
466  }
467  aset[sz] = new GAAlleleSet<T>(s);
468  sz++;
469  return 0;
470  }
471 
472  int add(unsigned int n, const T a[])
473  {
474  if (sz + 1 > SZ)
475  {
476  SZ += csz;
477  GAAlleleSet<T> **tmp = aset;
478  aset = new GAAlleleSet<T> *[SZ];
479  memcpy(aset, tmp, sz * sizeof(GAAlleleSet<T> *));
480  delete[] tmp;
481  }
482  aset[sz] = new GAAlleleSet<T>(n, a);
483  sz++;
484  return 0;
485  }
486 
487  int add(const T &lower, const T &upper,
488  GAAllele::BoundType lb = GAAllele::BoundType::INCLUSIVE,
489  GAAllele::BoundType ub = GAAllele::BoundType::INCLUSIVE)
490  {
491  if (sz + 1 > SZ)
492  {
493  SZ += csz;
494  GAAlleleSet<T> **tmp = aset;
495  aset = new GAAlleleSet<T> *[SZ];
496  memcpy(aset, tmp, sz * sizeof(GAAlleleSet<T> *));
497  delete[] tmp;
498  }
499  aset[sz] = new GAAlleleSet<T>(lower, upper, lb, ub);
500  sz++;
501  return 0;
502  }
503 
504  int add(const T &lower, const T &upper, const T &increment,
505  GAAllele::BoundType lb = GAAllele::BoundType::INCLUSIVE,
506  GAAllele::BoundType ub = GAAllele::BoundType::INCLUSIVE)
507  {
508  if (sz + 1 > SZ)
509  {
510  SZ += csz;
511  GAAlleleSet<T> **tmp = aset;
512  aset = new GAAlleleSet<T> *[SZ];
513  memcpy(aset, tmp, sz * sizeof(GAAlleleSet<T> *));
514  delete[] tmp;
515  }
516  aset[sz] = new GAAlleleSet<T>(lower, upper, increment, lb, ub);
517  sz++;
518  return 0;
519  }
520 
521  int remove(unsigned int n)
522  {
523  if (n >= sz)
524  return 1;
525  delete aset[n];
526  for (unsigned int i = n; i < sz - 1; i++)
527  aset[i] = aset[i + 1];
528  sz--;
529  return 0;
530  }
531 
532  protected:
533  unsigned int csz;
534  unsigned int sz{0};
535  unsigned int SZ{0};
536  GAAlleleSet<T> **aset;
537 };
538 
539 // could do these with a memcmp if the type is simple...
540 template <class T>
541 int operator==(const GAAlleleSet<T>& a, const GAAlleleSet<T>& b)
542 {
543  if (a.core == b.core)
544  return 1;
545  if (a.core == 0 || b.core == 0)
546  return 0;
547  if (a.core->sz != b.core->sz)
548  return 0;
549  // return((memcmp(a.core, b.core, a.core->sz * sizeof(T)) == 0) ? 1 :
550  // 0);
551  unsigned int i;
552  for (i = 0; i < a.core->sz && a.core->a[i] == b.core->a[i]; i++)
553  ;
554  return ((i == a.core->sz) ? 1 : 0);
555 }
556 
557 template <class T>
558 int operator!=(const GAAlleleSet<T>& a, const GAAlleleSet<T>& b)
559 {
560  if (a.core == b.core)
561  return 0;
562  if (a.core == 0 || b.core == 0)
563  return 1;
564  if (a.core->sz != b.core->sz)
565  return 1;
566  // return((memcmp(a.core, b.core, a.core->sz * sizeof(T)) == 0) ? 0 :
567  // 1);
568  unsigned int i;
569  for (i = 0; i < a.core->sz && a.core->a[i] == b.core->a[i]; i++)
570  ;
571  return ((i == a.core->sz) ? 0 : 1);
572 }
573 
574 template <class T>
575 std::ostream &operator<<(std::ostream &os, const GAAlleleSet<T> &arg)
576 {
577  arg.write(os);
578  return os;
579 }
580 template <class T>
581 std::istream &operator>>(std::istream &is, GAAlleleSet<T> &arg)
582 {
583  arg.read(is);
584  return is;
585 }
Definition: GAAllele.h:404
Definition: GAAllele.h:80
Definition: GAAllele.h:192
Allele.
Definition: GAAllele.h:27