Evocosm - A C++ Framework for Evolutionary Computing

Main Index

Created by Scott Robert Ladd at Coyote Gulch Productions.


fuzzy_machine.h
1 //---------------------------------------------------------------------
2 // Algorithmic Conjurings @ http://www.coyotegulch.com
3 // Evocosm -- An Object-Oriented Framework for Evolutionary Algorithms
4 //
5 // fuzzy_machine.h
6 //---------------------------------------------------------------------
7 //
8 // Copyright 1996, 1999, 2002, 2003, 2004, 2005, 2006, 2007 Scott Robert Ladd
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the
22 // Free Software Foundation, Inc.
23 // 59 Temple Place - Suite 330
24 // Boston, MA 02111-1307, USA.
25 //
26 //-----------------------------------------------------------------------
27 //
28 // For more information on this software package, please visit
29 // Scott's web site, Coyote Gulch Productions, at:
30 //
31 // http://www.coyotegulch.com
32 //
33 //-----------------------------------------------------------------------
34 
35 #if !defined(LIBEVOCOSM_FUZZY_MACHINE_H)
36 #define LIBEVOCOSM_FUZZY_MACHINE_H
37 
38 // Standard C++ Library
39 #include <cstddef>
40 #include <stack>
41 #include <stdexcept>
42 #ifdef DEBUG
43 #include <iostream>
44 #include <iomanip>
45 #endif
46 using namespace std;
47 
48 // libevocosm
49 #include "evocommon.h"
50 #include "fsm_tools.h"
51 
52 namespace libevocosm
53 {
55 
68  template <size_t InSize, size_t OutSize>
69  class fuzzy_machine : protected globals, protected fsm_tools
70  {
71  public:
73  struct tranout_t
74  {
77 
80 
82  tranout_t(double * state_weights, size_t num_states, double * output_weights)
83  : m_new_state(state_weights, num_states),
84  m_output(output_weights, OutSize)
85  {
86  // nada
87  }
88 
90  tranout_t(const tranout_t & source)
91  : m_new_state(source.m_new_state),
92  m_output(source.m_output)
93  {
94  // nada
95  }
96 
98  tranout_t & operator = (const tranout_t & source)
99  {
100  m_new_state = source.m_new_state;
101  m_output = source.m_output;
102  return *this;
103  }
104  };
105 
107 
117  fuzzy_machine(size_t a_size,
118  double a_output_base,
119  double a_output_range,
120  double a_state_base,
121  double a_state_range);
122 
124 
128  fuzzy_machine(size_t a_size);
129 
131 
136  fuzzy_machine(const fuzzy_machine<InSize,OutSize> & a_parent1, const fuzzy_machine<InSize,OutSize> & a_parent2);
137 
139 
144 
146 
150  virtual ~fuzzy_machine();
151 
152  // Assignment
158  fuzzy_machine & operator = (const fuzzy_machine<InSize,OutSize> & a_source);
159 
161 
173  void mutate(double a_rate);
174 
176 
182  static void set_mutation_weight(mutation_id a_type, double a_weight);
183 
185 
191  size_t transition(size_t a_input);
192 
194 
197  void reset();
198 
200 
204  size_t size() const;
205 
207 
213  const tranout_t & get_transition(size_t a_state, size_t a_input) const;
214 
216 
220  size_t num_input_states() const;
221 
223 
227  size_t num_output_states() const;
228 
230 
234  size_t init_state() const;
235 
237 
241  size_t current_state() const;
242 
244 
255  {
256  return m_state_table;
257  }
258 
259  #ifdef DEBUG
260  void dump(const char * description, ostream & a_stream = cerr) const;
261  #endif
262 
263  private:
264  // release resources
265  void release();
266 
267  // deep copy
268  void deep_copy(const fuzzy_machine<InSize,OutSize> & a_source);
269 
270  protected:
273 
275  size_t m_size;
276 
278  size_t m_init_state;
279 
282 
285 
288 
290  double m_state_base;
291 
294 
297  };
298 
299  // Static initializer
300  template <size_t InSize, size_t OutSize>
302 
303  // release resources
304  template <size_t InSize, size_t OutSize>
306  {
307  for (size_t s = 0; s < m_size; ++s)
308  {
309  for (size_t i = 0; i < InSize; ++i)
310  delete m_state_table[s][i];
311 
312  delete [] m_state_table[s];
313  }
314 
315  delete [] m_state_table;
316  }
317 
318  // deep copy
319  template <size_t InSize, size_t OutSize>
320  void fuzzy_machine<InSize,OutSize>::deep_copy(const fuzzy_machine<InSize,OutSize> & a_source)
321  {
322  // allocate state table
323  m_state_table = new tranout_t ** [m_size];
324 
325  for (size_t s = 0; s < m_size; ++s)
326  {
327  // allocate an array corresponding to inputs
328  m_state_table[s] = new tranout_t * [InSize];
329 
330  // set transition values
331  for (size_t i = 0; i < InSize; ++i)
332  m_state_table[s][i] = new tranout_t(*(a_source.m_state_table[s][i]));
333  }
334  }
335 
336  // Creation constructor
337  template <size_t InSize, size_t OutSize>
339  double a_output_base,
340  double a_output_range,
341  double a_state_base,
342  double a_state_range)
343  : m_state_table(NULL),
344  m_size(a_size),
345  m_init_state(0),
346  m_current_state(0),
347  m_output_base(a_output_base),
348  m_output_range(a_output_range),
349  m_state_base(a_state_base),
350  m_state_range(a_state_range)
351  {
352  // verify parameters
353  if (m_size < 2)
354  throw std::runtime_error("invalid fuzzy_machine creation parameters");
355 
356  // allocate state table
357  m_state_table = new tranout_t ** [m_size];
358 
359  // tables of weights for roulette wheels
360  double * output_weights = new double[OutSize];
361  double * state_weights = new double[m_size];
362 
363  for (size_t s = 0; s < m_size; ++s)
364  {
365  // allocate an array corresponding to inputs
366  m_state_table[s] = new tranout_t * [InSize];
367 
368  for (size_t i = 0; i < InSize; ++i)
369  {
370  // define weights
371  size_t n;
372 
373  for (n = 0; n < OutSize; ++n)
374  output_weights[n] = g_random.get_real() * a_output_range + a_output_base;
375 
376  for (n = 0; n < m_size; ++n)
377  state_weights[n] = g_random.get_real() * a_state_range + a_state_base;
378 
379  // set transition values
380  m_state_table[s][i] = new tranout_t(state_weights,m_size,output_weights);
381  }
382  }
383 
384  delete [] output_weights;
385  delete [] state_weights;
386 
387  // set initial state and start there
388  m_init_state = rand_index(m_size);
390  }
391 
392  // Creation constructor
393  template <size_t InSize, size_t OutSize>
395  : m_state_table(NULL),
396  m_size(a_size),
397  m_init_state(0),
398  m_current_state(0),
399  m_output_base(1.0),
400  m_output_range(100.0),
401  m_state_base(1.0),
402  m_state_range(100.0)
403  {
404  // verify parameters
405  if (m_size < 2)
406  throw std::runtime_error("invalid fuzzy_machine creation parameters");
407 
408  // allocate state table
409  m_state_table = new tranout_t ** [m_size];
410 
411  // tables of weights for roulette wheels
412  double * output_weights = new double[OutSize];
413  double * state_weights = new double[m_size];
414 
415  for (size_t s = 0; s < m_size; ++s)
416  {
417  // allocate an array corresponding to inputs
418  m_state_table[s] = new tranout_t * [InSize];
419 
420  for (size_t i = 0; i < InSize; ++i)
421  {
422  // define weights
423  size_t n;
424 
425  for (n = 0; n < OutSize; ++n)
426  output_weights[n] = 1.0;
427 
428  output_weights[rand_index(OutSize)] = 100.0;
429 
430  for (n = 0; n < m_size; ++n)
431  state_weights[n] = 1.0;
432 
433  state_weights[rand_index(m_size)] = 100.0;
434 
435  // set transition values
436  m_state_table[s][i] = new tranout_t(state_weights,m_size,output_weights);
437  }
438  }
439 
440  delete [] output_weights;
441  delete [] state_weights;
442 
443  // set initial state and start there
444  m_init_state = rand_index(m_size);
446  }
447 
448  // Construct via bisexual crossover
449  template <size_t InSize, size_t OutSize>
451  : m_state_table(NULL),
452  m_size(a_parent1.m_size),
453  m_init_state(0),
454  m_current_state(0),
455  m_output_base(a_parent1.m_output_base),
456  m_output_range(a_parent1.m_output_range),
457  m_state_base(a_parent1.m_state_base),
458  m_state_range(a_parent1.m_state_range)
459  {
460  #ifdef DEBUG
461  cerr << "\n<< crossover operation >>\n";
462  a_parent1.dump("PARENT1");
463  a_parent2.dump("PARENT2");
464  #endif
465 
466  // copy first parent
467  deep_copy(a_parent1);
468 
469  // don't do anything else if fsms differ is size
470  if ((a_parent1.m_size != a_parent2.m_size) || (&a_parent1 == &a_parent2))
471  return;
472 
473  // pick a crossover point
474  size_t x = rand_index(m_size);
475 
476  #ifdef DEBUG
477  cerr << "crossover at " << x << "\n";
478  #endif
479 
480  for (size_t n = x; n < m_size; ++n)
481  {
482  // set transition values
483  for (size_t i = 0; i < InSize; ++i)
484  {
485  delete m_state_table[n][i];
486  m_state_table[n][i] = new tranout_t(*a_parent2.m_state_table[n][i]);
487  }
488  }
489 
490  // randomize the initial state (looks like mom and dad but may act like either one!)
491  if (g_random.get_real() < 0.5)
492  m_init_state = a_parent1.m_init_state;
493  else
494  m_init_state = a_parent2.m_init_state;
495 
496  // reset for start
498 
499  #ifdef DEBUG
500  dump("CHILD");
501  #endif
502  }
503 
504  // Copy constructor
505  template <size_t InSize, size_t OutSize>
507  : m_state_table(NULL),
508  m_size(a_source.m_size),
509  m_init_state(a_source.m_init_state),
510  m_current_state(a_source.m_current_state),
511  m_output_base(a_source.m_output_base),
512  m_output_range(a_source.m_output_range),
513  m_state_base(a_source.m_state_base),
514  m_state_range(a_source.m_state_range)
515  {
516  // copy first parent
517  deep_copy(a_source);
518  }
519 
520  // Virtual destructor
521  template <size_t InSize, size_t OutSize>
523  {
524  release();
525  }
526 
527  // Assignment
528  template <size_t InSize, size_t OutSize>
530  {
531  // release resources
532  release();
533 
534  // set values
535  m_init_state = a_source.m_init_state;
536  m_current_state = a_source.m_current_state;
537  m_size = a_source.m_size;
538  m_output_base = a_source.m_output_base;
539  m_output_range = a_source.m_output_range;
540  m_state_base = a_source.m_state_base;
541  m_state_range = a_source.m_state_range;
542 
543  // copy source
544  deep_copy(a_source);
545 
546  return *this;
547  }
548 
550  template <size_t InSize, size_t OutSize>
552  {
553  g_selector.set_weight(a_type,a_weight);
554  }
555 
556  // Mutation
557  template <size_t InSize, size_t OutSize>
559  {
560  // the number of chances for mutation is based on the number of states in the machine;
561  // larger machines thus encounter more mutations
562  #ifdef DEBUG
563  cerr << "\n<< mutation operation >>\n";
564  dump("BEFORE");
565  #endif
566 
567  for (size_t n = 0; n < m_size; ++n)
568  {
569  if (g_random.get_real() < a_rate)
570  {
571  // pick a mutation
572  switch (g_selector.get_index())
573  {
574  case MUTATE_OUTPUT_SYMBOL:
575  {
576  // mutate output symbol
577  size_t state = rand_index(m_size);
578  size_t input = rand_index(InSize);
579  size_t index = rand_index(OutSize);
580 
581  #ifdef DEBUG
582  cerr << "MUTATE_OUTPUT_SYMBOL, state " << state << ", input " << input << ", index " << index << "\n";
583  #endif
584 
585  double new_weight = m_output_base + m_output_range * g_random.get_real();
586  m_state_table[state][input]->m_output.set_weight(index,new_weight);
587  break;
588  }
589  case MUTATE_TRANSITION:
590  {
591  // mutate state transition
592  size_t state = rand_index(m_size);
593  size_t input = rand_index(InSize);
594  size_t index = rand_index(m_size);
595 
596  #ifdef DEBUG
597  cerr << "MUTATE_TRANSITION, state " << state << ", input " << input << ", index " << index << "\n";
598  #endif
599 
600  double new_weight = m_state_base + m_state_range * g_random.get_real();
601  m_state_table[state][input]->m_new_state.set_weight(index,new_weight);
602  break;
603  }
604  case MUTATE_REPLACE_STATE:
605  {
606  // select mutated state
607  size_t state = rand_index(m_size);
608 
609  #ifdef DEBUG
610  cerr << "REPLACE_STATE, state " << state << "\n";
611  #endif
612 
613  // allocate an array corresponding to inputs
614  delete [] m_state_table[state];
615  m_state_table[state] = new tranout_t * [InSize];
616 
617  // tables of weights for roulette wheels
618  double * output_weights = new double[OutSize];
619  double * state_weights = new double[m_size];
620 
621  for (size_t i = 0; i < InSize; ++i)
622  {
623  // define weights
624  size_t n;
625 
626  for (n = 0; n < OutSize; ++n)
627  output_weights[n] = 1.0;
628 
629  output_weights[rand_index(OutSize)] = 100.0;
630 
631  for (n = 0; n < m_size; ++n)
632  state_weights[n] = 1.0;
633 
634  state_weights[rand_index(m_size)] = 100.0;
635 
636  // set transition values
637  m_state_table[state][i] = new tranout_t(state_weights,m_size,output_weights);
638  }
639 
640  delete [] output_weights;
641  delete [] state_weights;
642 
643  break;
644  }
645  case MUTATE_SWAP_STATES:
646  {
647  // swap two states (by swapping pointers)
648  size_t state1 = rand_index(m_size);
649  size_t state2;
650 
651  do
652  state2 = static_cast<size_t>(rand_index(m_size));
653  while (state2 == state1);
654 
655  #ifdef DEBUG
656  cerr << "MUTATE_SWAP_STATES, " << state1 << " with " << state2 << "\n";
657  #endif
658 
659  for (size_t i = 0; i < InSize; ++i)
660  {
661  tranout_t * temp = m_state_table[state1][i];
662  m_state_table[state1][i] = m_state_table[state2][i];
663  m_state_table[state2][i] = temp;
664  }
665 
666  break;
667  }
668  case MUTATE_INIT_STATE:
669  {
670  // change initial state
671  #ifdef DEBUG
672  cerr << "MUTATE_INIT_STATE\n";
673  #endif
674  m_init_state = rand_index(m_size);
675  break;
676  }
677  #ifdef DEBUG
678  default:
679  cerr << "UNKNOWN MUTATION!\n";
680  #endif
681  }
682  }
683  }
684 
685  // reset current state because init state may have changed
686 
687  m_current_state = m_init_state;
688  #ifdef DEBUG
689  dump("AFTER");
690  #endif
691  }
692 
693  // Cause state transition
694  template <size_t InSize, size_t OutSize>
695  inline size_t fuzzy_machine<InSize,OutSize>::transition(size_t a_input)
696  {
697  // get output symbol for given input for current state
698  size_t output = m_state_table[m_current_state][a_input]->m_output.get_index();
699 
700  // change to new state
701  m_current_state = m_state_table[m_current_state][a_input]->m_new_state.get_index();
702 
703  // return output symbol
704  return output;
705  }
706 
707  // Reset to start-up state
708  template <size_t InSize, size_t OutSize>
710  {
711  m_current_state = m_init_state;
712  }
713 
714  // Get size
715  template <size_t InSize, size_t OutSize>
717  {
718  return m_size;
719  }
720 
721  // Get a copy of the internal table
722  template <size_t InSize, size_t OutSize>
723  inline const typename fuzzy_machine<InSize,OutSize>::tranout_t & fuzzy_machine<InSize,OutSize>::get_transition(size_t a_state, size_t a_input) const
724  {
725  return *m_state_table[a_state][a_input];
726  }
727 
728  // Get number of input states
729  template <size_t InSize, size_t OutSize>
731  {
732  return InSize;
733  }
734 
735  // Get number of output states
736  template <size_t InSize, size_t OutSize>
738  {
739  return OutSize;
740  }
741 
742  // Get initial state
743  template <size_t InSize, size_t OutSize>
745  {
746  return m_init_state;
747  }
748 
749  // Get current state
750  template <size_t InSize, size_t OutSize>
752  {
753  return m_current_state;
754  }
755 
756  #ifdef DEBUG
757  template <size_t InSize, size_t OutSize>
758  void fuzzy_machine<InSize,OutSize>::dump(const char * description, ostream & a_stream) const
759  {
760  a_stream << "----------\nDumping machine " << description << " (" << hex << this
761  << ")\ninitial state = " << m_init_state
762  << "\ncurrent state = " << m_current_state << "\n\n";
763 
764  for (size_t s = 0; s < m_size; ++s)
765  {
766  a_stream << "state " << s;
767 
768  for (size_t i = 0; i < InSize; ++i)
769  {
770  size_t n;
771 
772  a_stream << "\n output weights:";
773 
774  for (n = 0; n < OutSize; ++n)
775  a_stream << " " << m_state_table[s][i]->m_output.get_weight(n);
776 
777  a_stream << "\n state weights:";
778 
779  for (n = 0; n < m_size; ++n)
780  a_stream << " " << m_state_table[s][i]->m_new_state.get_weight(n);
781 
782  a_stream << endl;
783  }
784  }
785 
786  a_stream << "----------" << endl;
787  }
788  #endif
789 };
790 
791 #endif
double m_output_base
base value for output weights
Definition: fuzzy_machine.h:284
size_t m_current_state
Current state.
Definition: fuzzy_machine.h:281
size_t init_state() const
Get initial state.
Definition: fuzzy_machine.h:744
size_t m_size
Number of states.
Definition: fuzzy_machine.h:275
Wraps a roulette wheel for selecting mutations.
Definition: fsm_tools.h:77
void mutate(double a_rate)
Mutation.
Definition: fuzzy_machine.h:558
void reset()
Reset to start-up state.
Definition: fuzzy_machine.h:709
double m_state_base
base value for state weights
Definition: fuzzy_machine.h:290
static size_t rand_index(size_t n)
Static function to allow use of g_random function pointer in random_shuffle.
Definition: evocommon.h:119
tranout_t *** state_table()
Get current transition table.
Definition: fuzzy_machine.h:254
A set of common tools for finite state machines.
Definition: fsm_tools.h:47
roulette_wheel m_new_state
The state to be transitioned to.
Definition: fuzzy_machine.h:76
fuzzy_machine(size_t a_size, double a_output_base, double a_output_range, double a_state_base, double a_state_range)
Creation constructor.
Definition: fuzzy_machine.h:338
double m_state_range
range for state weights
Definition: fuzzy_machine.h:293
double get_real()
get the next value in the range [0,1)
Definition: evocommon.h:104
roulette_wheel m_output
The output value.
Definition: fuzzy_machine.h:79
static mutation_selector g_selector
Global mutation selector.
Definition: fuzzy_machine.h:296
const tranout_t & get_transition(size_t a_state, size_t a_input) const
Get a transition from the internal state table.
Definition: fuzzy_machine.h:723
tranout_t(double *state_weights, size_t num_states, double *output_weights)
Creation Constructor.
Definition: fuzzy_machine.h:82
static void set_mutation_weight(mutation_id a_type, double a_weight)
Set a mutation weight.
Definition: fuzzy_machine.h:551
static prng g_random
A shared random number generator.
Definition: evocommon.h:125
size_t transition(size_t a_input)
Cause state transition.
Definition: fuzzy_machine.h:695
double m_output_range
range for output weights
Definition: fuzzy_machine.h:287
size_t m_init_state
Initial state.
Definition: fuzzy_machine.h:278
virtual ~fuzzy_machine()
Virtual destructor.
Definition: fuzzy_machine.h:522
A toolkit and framework for implementing evolutionary algorithms.
Definition: evocommon.h:60
size_t current_state() const
Get current state.
Definition: fuzzy_machine.h:751
Defines a transition and output state pair.
Definition: fuzzy_machine.h:73
size_t size() const
Get size.
Definition: fuzzy_machine.h:716
Elements shared by all classes in Evocosm.
Definition: evocommon.h:115
tranout_t *** m_state_table
State table (the machine definition)
Definition: fuzzy_machine.h:272
tranout_t(const tranout_t &source)
Copy constructor.
Definition: fuzzy_machine.h:90
mutation_id
Types of mutation supported.
Definition: fsm_tools.h:51
A simulated roulette wheel for weighted selection.
Definition: roulette.h:71
size_t num_output_states() const
Get number of output states.
Definition: fuzzy_machine.h:737
fuzzy_machine & operator=(const fuzzy_machine< InSize, OutSize > &a_source)
Definition: fuzzy_machine.h:529
size_t num_input_states() const
Get number of input states.
Definition: fuzzy_machine.h:730
A finite state machine.
Definition: fuzzy_machine.h:69

© 1996-2005 Scott Robert Ladd. All rights reserved.
HTML documentation generated by Dimitri van Heesch's excellent Doxygen tool.