home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 02 Useful Techniques / 08 Zarozinski / src / ffllapi / FuzzySetBase.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-13  |  12.8 KB  |  600 lines

  1. //
  2. // File:    FuzzySetBase.cpp
  3. //
  4. // Purpose:    This file contains code for the FuzzySetBase class
  5. //
  6. // Copyright ⌐ 1999-2001 Louder Than A Bomb! Software
  7. //
  8. // This file is part of the FFLL (Free Fuzzy Logic Library) project (http://ffll.sourceforge.net)
  9. // It is released under the BSD license, see http://ffll.sourceforge.net/license.txt for the full text.
  10. // 
  11.  
  12. #include "FuzzySetBase.h"
  13. #include "MemberFuncTri.h"
  14. #include "MemberFuncTrap.h"
  15. #include "MemberFuncSCurve.h"
  16. #include "MemberFuncSingle.h"
  17.  
  18. #include "FuzzyVariableBase.h"
  19.  
  20. #include <math.h>
  21.  
  22. #ifdef _DEBUG
  23. #undef THIS_FILE
  24. static char THIS_FILE[]=__FILE__;
  25. #endif
  26.  
  27.  
  28. //
  29. // Function:    FuzzySetBase()
  30. // 
  31. // Purpose:        Constructor
  32. //
  33. // Arguments:
  34. //
  35. //        FuzzyVariableBase* par - variable that this set is part of
  36. //
  37. // Returns:
  38. //
  39. //        none
  40. //
  41. // Author:    Michael Zarozinski
  42. // Date:    6/99
  43. // 
  44. // Modification History
  45. // Author    Date        Modification
  46. // ------    ----        ------------
  47. //
  48. //
  49. FuzzySetBase::FuzzySetBase(FuzzyVariableBase* par) : FFLLBase(par) 
  50. {    
  51.     rule_index = 0;
  52.     index = 255; 
  53.     id = L"";
  54.     member_func = NULL;
  55. }; 
  56.  
  57. //
  58. // Function:    ~FuzzySetBase()
  59. // 
  60. // Purpose:        Destructor
  61. //
  62. // Arguments:
  63. //
  64. //        none
  65. //
  66. // Returns:
  67. //
  68. //        none
  69. //
  70. // Author:    Michael Zarozinski
  71. // Date:    6/99
  72. // 
  73. // Modification History
  74. // Author    Date        Modification
  75. // ------    ----        ------------
  76. //
  77. //
  78. FuzzySetBase::~FuzzySetBase()
  79. {
  80.     if (member_func != NULL)
  81.         delete member_func;
  82. };
  83.  
  84.  
  85. //
  86. // Function: init()
  87. // 
  88. // Purpose:    Initialize set object
  89. // 
  90. // Arguments:
  91. //
  92. //        wchar_t*        n            -    identifier of the variable
  93. //        short            idx            -    index of this set in the variable
  94. //        int                mid_pt_x    -    middle 'x' point for this set
  95. //        int                set_width    -    width of the set
  96. //        int                type        -    type of membership function for this set. It should be one of
  97. //                                        the enum values MemberFuncBase::TYPE (default is trangle)
  98. //
  99. // Returns:
  100. //
  101. //        0    - success
  102. //        -1    - error
  103. // 
  104. // Author:    Michael Zarozinski    
  105. // Date:    1/21/99
  106. // 
  107. // Modification History
  108. // Author        Date        Modification
  109. // ------        ----        ------------
  110. //
  111. //
  112.  
  113.  // 
  114. int FuzzySetBase::init(const wchar_t* n, int mid_pt_x, short idx, int set_width, int type /* =  MemberFuncBase::TRIANGLE*/)
  115. {
  116.   
  117.     // set_id() will verify unique for this variable.
  118.     if (set_id(n))
  119.         return -1; // id was not unique
  120.  
  121.     // perform some sanity checks on the mid point and width
  122.  
  123.     int var_width = FuzzyVariableBase::get_x_array_max_idx();
  124.  
  125.     if (set_width > var_width)
  126.         {
  127.         set_width = var_width / 4;
  128.         mid_pt_x = var_width / 2;
  129.         }
  130.  
  131.     index = idx;
  132.     rule_index = 0;
  133.  
  134.     int ret_val = new_member_func(type, mid_pt_x, set_width); 
  135.  
  136.     if (ret_val)
  137.         return ret_val;
  138.  
  139.     calc();
  140.  
  141.     return 0;
  142.  
  143. } // end FuzzySetBase::init()
  144.  
  145.  
  146.  
  147.  
  148.  
  149. //
  150. // Function:    new_member_func()
  151. // 
  152. // Purpose:        Create a membership function for this set and perform some initialization
  153. //
  154. // Arguments:
  155. //
  156. //        int        type    -    type of membership function for this set. It should be one of
  157. //                            the enum values MemberFuncBase::TYPE (default is trangle)
  158. //        int        mid_x    -    mid point for this membership function
  159. //        int        width    -    width of the set
  160. //
  161. // Returns:
  162. //
  163. //        0 - success
  164. //        non-zero - failure
  165. //
  166. // Author:    Michael Zarozinski
  167. // Date:    7/99
  168. // 
  169. // Modification History
  170. // Author    Date        Modification
  171. // ------    ----        ------------
  172. //
  173. //
  174. int FuzzySetBase::new_member_func(int type, int mid_x, int width)
  175. {
  176.  
  177.     // create the object...
  178.     int ret_val = new_member_func(type);
  179.  
  180.     if (ret_val)
  181.         return ret_val;
  182.     
  183.     // fill in relavent info...
  184.     assert(member_func != NULL);
  185.      member_func->init_nodes(mid_x, width);
  186.  
  187.     // perform any calculations...
  188.     calc();
  189.  
  190.     return 0;
  191.  
  192. } // end FuzzySetBase::new_member_func()
  193.  
  194. //
  195. // Function:    new_member_func()
  196. // 
  197. // Purpose:        Create the appropriate membership function for this set
  198. //
  199. // Arguments:
  200. //
  201. //        int type -    type of membership function to create. This should be one
  202. //                    of the enum TYPE values in MemberFuncBase
  203. //
  204. // Returns:
  205. //
  206. //        0 - success
  207. //        non-zero - failure
  208. //
  209. // Author:    Michael Zarozinski
  210. // Date:    6/00
  211. // 
  212. // Modification History
  213. // Author    Date        Modification
  214. // ------    ----        ------------
  215. //
  216. //
  217. int FuzzySetBase::new_member_func(int type)
  218. {
  219.  
  220.     switch (type)
  221.             {
  222.             case MemberFuncBase::TYPE::TRIANGLE:
  223.  
  224.                  member_func = new MemberFuncTri(this);
  225.  
  226.                 break;
  227.  
  228.             case MemberFuncBase::TYPE::TRAPEZOID:
  229.  
  230.                 member_func = new MemberFuncTrap(this);
  231.                 break;
  232.  
  233.             case MemberFuncBase::TYPE::S_CURVE:
  234.  
  235.                 member_func = new MemberFuncSCurve(this);
  236.  
  237.                 break;
  238.  
  239.             case MemberFuncBase::TYPE::SINGLETON:
  240.  
  241.                 member_func = new MemberFuncSingle(this);
  242.  
  243.                 break;
  244.  
  245.             default:
  246.                 // default to a triangle
  247.                 member_func = new MemberFuncTri(this);
  248.         
  249.                 break;
  250.  
  251.             } // end switch on member_func_type;
  252.          
  253.     if (!member_func)
  254.         {
  255.         // problem allocating memory
  256.         // NOTE: in MSVC new returns NULL if there's not enough memory. If this is ported
  257.         // to a diff platform new may throw a std::bad_alloc exception it it can't alloc the memory.
  258.          set_msg_text(ERR_ALLOC_MEM);
  259.         assert(member_func != NULL);
  260.         return -1;
  261.         } // end if error allocating memory
  262.  
  263.     member_func->init();    // perform any initialization
  264.     calc();
  265.  
  266.     return 0;
  267.  
  268. } // end FuzzySetBase::new_member_func()
  269.  
  270. //
  271. // Function:    set_id()
  272. // 
  273. // Purpose:        Set the identifier for this set, making sure it's unique
  274. //                if we don't allow duplicated ids.
  275. //
  276. // Arguments:
  277. //
  278. //        const wchar_t*    _id            -    identifier for the set
  279. //        bool            allow_dup    -    if true, allow duplicate identifiers within the variable (default is false)
  280. //
  281. // Returns:
  282. //
  283. //        0  - set id
  284. //        -1 - identifier is not unique
  285. //
  286. // Author:    Michael Zarozinski
  287. // Date:    
  288. // 
  289. // Modification History
  290. // Author    Date        Modification
  291. // ------    ----        ------------
  292. //
  293. //
  294. int FuzzySetBase::set_id(const wchar_t* _id, bool allow_dup /* = false*/)
  295. {
  296.     // if parent is null just assign the id
  297.  
  298.     // only check if the id is unique if we don't allow duplicates
  299.     if (!allow_dup)
  300.         {
  301.         FuzzyVariableBase* par = get_parent();
  302.  
  303.         assert(par != NULL);
  304.     
  305.         if (!(par->is_set_id_unique(_id, index)))
  306.             {
  307.             // read the error from the parent and set it for 'this'
  308.             set_msg_text(par->get_msg_text());
  309.              return -1;  
  310.             }        
  311.         } // if don't allow duplicates
  312.  
  313.     id = _id;    // only set if unique
  314.     return 0;
  315.  
  316. }; // end FuzzySetBase::set_id() 
  317.  
  318.  
  319. //
  320. // Function:    copy()
  321. // 
  322. // Purpose:        Copy all values from the set passed in to this set
  323. //
  324. // Arguments:
  325. //
  326. //        const FuzzySetBase& copy_from - set to copy information from
  327. //
  328. // Returns:
  329. //
  330. //        0 - success
  331. //        non-zero - failure    
  332. //
  333. // Author:    Michael Zarozinski
  334. // Date:    5/00
  335. // 
  336. // Modification History
  337. // Author    Date        Modification
  338. // ------    ----        ------------
  339. //
  340. //
  341.  
  342. int FuzzySetBase::copy(const FuzzySetBase& copy_from)
  343.     // set this set's index to be the next for the variable we're part of
  344.     index = get_parent()->get_num_of_sets();
  345.  
  346.     // don't copy rule_index - that's calculated
  347.  
  348.      set_id(copy_from.get_id(), true); // true allows us to have a duplicate id 
  349.  
  350.     // create the member function
  351.  
  352.     int ret_val = new_member_func(copy_from.get_func_type());
  353.  
  354.     if (ret_val)
  355.         return ret_val;
  356.  
  357.     // initialize all the nodes to reasonable values before moving to the specific
  358.     // values. This helps get around any problems we may have with validation when we
  359.     // call set_node() below.
  360.      member_func->init_nodes(copy_from.member_func->get_center_x(), 
  361.         copy_from.member_func->get_end_x() - copy_from.member_func->get_start_x());
  362.  
  363.     // copy the nodes...
  364.     for (int i = 0; i < copy_from.get_node_count(); i++)
  365.         {
  366.         NodePoint node = copy_from.member_func->get_node(i);
  367.          member_func->set_node (i, node.x,  node.y);
  368.         } // end loop through nodes
  369.  
  370.     return 0;
  371.  
  372. } // end  FuzzySetBase::copy()
  373.  
  374.  
  375. //
  376. // Function:    save_to_fcl_file()
  377. // 
  378. // Purpose:        Write out the FCL (Fuzzy Control Language) for this set. This is written
  379. //                inside a FUZZIFY block and has the format (as defined by the
  380. //                IEC 61131-7 International Standard):
  381. //
  382. //                    TERM term_name:= membership_function;
  383. //
  384. //                Where membership_function is the point that define the membership function curve.
  385. //
  386. // Arguments:
  387. //
  388. //        std::ofstream& file_contents - STL stream to write out to a file
  389. //
  390. // Returns:
  391. //
  392. //        void
  393. //
  394. // Author:    Michael Zarozinski
  395. // Date:    9/01
  396. // 
  397. // Modification History
  398. // Author    Date        Modification
  399. // ------    ----        ------------
  400. //
  401. //
  402.  
  403. void FuzzySetBase::save_to_fcl_file(std::ofstream& file_contents)
  404. {
  405.     // we save all points.  The FCL allows for assumptions for ramps so you
  406.     // don't have to specifiy start/end points.  The IEC 61131-7 says:
  407.     // If the value of a linguistic variable is less than the first base point in the look-up table, all
  408.     // values below the first point in the look-up table shall have the same membership degree as    
  409.     // defined at the first point.
  410.  
  411.     // convert id to ascii version replacing any spaces with underscores
  412.      char* aid = convert_to_ascii(get_id(), '_');
  413.  
  414.     file_contents << "\tTERM " << aid << " := ";
  415.  
  416.     delete[] aid;
  417.  
  418.     member_func->save_to_fcl_file(file_contents);
  419.  
  420. } // end FuzzySetBase::save_to_fcl_file()
  421.  
  422. /////////////////////////////////////////////////////////////////////
  423. ////////// Trivial Functions That Don't Require Headers /////////////
  424. /////////////////////////////////////////////////////////////////////
  425.  
  426. FuzzyModelBase* FuzzySetBase::get_rule_block()
  427. {
  428.     FuzzyVariableBase* var = get_parent();
  429.  
  430.     assert(var != NULL);
  431.  
  432.     return (FuzzyModelBase*)(var->get_parent());
  433. }
  434.  
  435. bool FuzzySetBase::is_set_id_unique() const
  436. {
  437.     // make sure we're part of a variable
  438.     assert(get_parent() != NULL);
  439.     int ret_val = get_parent()->is_set_id_unique(id.data(), index);
  440.  
  441.     if (ret_val)
  442.         {
  443.         // read the error from the parent and set it for 'this'
  444.         set_msg_text(get_parent()->get_msg_text());
  445.         }
  446.  
  447.     return (ret_val) ? true : false;
  448. };
  449.  
  450. bool FuzzySetBase::is_output() const
  451. {
  452.     return get_parent()->is_output();
  453. }
  454.   
  455. RealType  FuzzySetBase::get_left_x() const
  456. {
  457.     return get_parent()->get_left_x();
  458. };
  459. RealType FuzzySetBase::get_idx_multiplier() const
  460. {
  461.     return get_parent()->get_idx_multiplier();
  462. };
  463.  
  464. std::string FuzzySetBase::get_model_name() const
  465. {
  466.     return get_parent()->get_model_name();    
  467. };
  468. int FuzzySetBase::get_var_index() const
  469.     return get_parent()->get_index();
  470. };
  471.  
  472. DOMType FuzzySetBase::get_dom(int idx) const
  473. {
  474.     return(member_func->get_value(idx));
  475. };
  476. DOMType FuzzySetBase::get_index() const 
  477. {
  478.     return index;
  479. };
  480. void FuzzySetBase::set_index(int _idx)
  481. {
  482.     index = _idx;
  483. };
  484. int FuzzySetBase::get_node_x(int node_idx) const
  485. {
  486.     return member_func->get_node_x(node_idx);
  487. };
  488. DOMType FuzzySetBase::get_value(int idx) const
  489. {
  490.     return(member_func->get_value(idx));
  491. };
  492. void FuzzySetBase::calc()
  493. {
  494.     if (member_func)
  495.         member_func->calc();
  496. };
  497.         
  498. FuzzyVariableBase* FuzzySetBase::get_parent() const
  499. {
  500.     return static_cast<FuzzyVariableBase*>(FFLLBase::get_parent());
  501. };
  502.  
  503. const wchar_t* FuzzySetBase::get_id(void) const
  504. {
  505.     return((id == L"") ? NULL :  (id.data()));
  506. }; 
  507.  
  508. int FuzzySetBase::get_end_x(void) const
  509. {
  510.     return member_func->get_end_x();
  511. };
  512.  
  513.  
  514. int FuzzySetBase::get_start_x(void) const
  515. {
  516.     return member_func->get_start_x();
  517. };
  518. int FuzzySetBase::get_func_type() const 
  519. {
  520.     return member_func->get_func_type();
  521. };
  522.  
  523. void FuzzySetBase::move_node(int  idx, int x, int y)
  524. {
  525.     member_func->move_node(idx, x, y);
  526.     calc(); 
  527. };
  528. void FuzzySetBase::move_node(int anchor_idx, _point pt)
  529. {
  530.     move_node(anchor_idx, pt.x, pt.y); 
  531.  
  532. };
  533.  void FuzzySetBase::move(int x_delta)
  534. {
  535.     member_func->move(x_delta);
  536.     calc();
  537. };
  538. void FuzzySetBase::set_ramp(int hi_lo_ind, int left_right_ind)
  539. {
  540.     member_func->set_ramp(hi_lo_ind, left_right_ind);
  541.     calc();
  542. };
  543. int FuzzySetBase::get_ramp()
  544. {
  545.     return member_func->get_ramp();
  546. };
  547.  
  548. FuzzySetBase& FuzzySetBase::operator=(const FuzzySetBase& copy_from)
  549. {
  550.     return *this;
  551. };
  552.  
  553. RealType FuzzySetBase::convert_idx_to_value(int idx) const
  554. {
  555.     assert(idx >= 0);
  556.     assert(idx <= FuzzyVariableBase::get_x_array_count());
  557.  
  558.     return get_parent()->convert_idx_to_value(idx);
  559.  
  560. };  
  561.  
  562. void FuzzySetBase::expand(int x_delta)
  563. {
  564.     member_func->expand(x_delta);
  565.     calc();
  566. }; 
  567. void FuzzySetBase::shrink(int x_delta  )
  568. {
  569.     member_func->shrink(x_delta );
  570.     calc();
  571. }; 
  572. void FuzzySetBase::set_member_func(void* new_func)
  573. {
  574.      delete member_func; member_func = static_cast<MemberFuncBase*>(new_func);
  575. }; 
  576. void FuzzySetBase::set_rule_index(int idx)
  577. {
  578.     rule_index = idx;
  579. };  
  580. int FuzzySetBase::get_rule_index() const 
  581.     return rule_index;
  582. };  
  583. int FuzzySetBase::get_node_count() const 
  584.     return member_func->get_node_count();
  585. };
  586.  
  587. NodePoint FuzzySetBase::get_node(int idx)
  588. {
  589.     return member_func->get_node(idx);
  590. };
  591.     
  592. void FuzzySetBase::set_node(int idx, int x, int y, bool validate /* = true */)
  593.     member_func->set_node(idx, x, y, validate);
  594. };
  595.