00001 #ifndef BALL_STRUCTURE_ASSIGNBONDORDERPROCESSOR_H
00002 #define BALL_STRUCTURE_ASSIGNBONDORDERPROCESSOR_H
00003
00004 #ifndef BALL_CONCEPT_PROCESSOR_H
00005 #include <BALL/CONCEPT/processor.h>
00006 #endif
00007
00008 #ifndef BALL_KERNEL_ATOMCONTAINER_H
00009 #include <BALL/KERNEL/atomContainer.h>
00010 #endif
00011
00012 #ifndef BALL_DATATYPE_HASHMAP_H
00013 #include <BALL/DATATYPE/hashMap.h>
00014 #endif
00015
00016 #ifndef BALL_DATATYPE_HASHSET_H
00017 #include <BALL/DATATYPE/hashSet.h>
00018 #endif
00019
00020
00021 #ifndef BALL_KERNEL_BOND_H
00022 #include <BALL/KERNEL/bond.h>
00023 #endif
00024
00025 #ifndef BALL_DATATYPE_OPTIONS_H
00026 # include <BALL/DATATYPE/options.h>
00027 #endif
00028
00029 #ifndef BALL_COMMON_LIMITS_H
00030 # include <BALL/COMMON/limits.h>
00031 #endif
00032
00033 #ifndef BALL_COMMON_EXCEPTION_H
00034 # include <BALL/COMMON/exception.h>
00035 #endif
00036
00037 #ifndef BALL_SYSTEM_TIMER_H
00038 #include <BALL/SYSTEM/timer.h>
00039 #endif
00040
00041 #include <map>
00042 #include <vector>
00043 #include <queue>
00044
00045 #ifdef BALL_HAS_LPSOLVE
00046 struct _lprec;
00047 typedef struct _lprec lprec;
00048 #endif
00049
00050 namespace BALL
00051 {
00085 class BALL_EXPORT AssignBondOrderProcessor
00086 : public UnaryProcessor<AtomContainer>
00087 {
00088 protected:
00089 class Solution_;
00090 friend class Solution;
00091 class PQ_Entry_;
00092 friend class PQ_Entry_;
00093
00094 public:
00095
00099
00100 struct BALL_EXPORT Option
00101 {
00105 static const char* OVERWRITE_SINGLE_BOND_ORDERS;
00106
00110 static const char* OVERWRITE_DOUBLE_BOND_ORDERS;
00111
00115 static const char* OVERWRITE_TRIPLE_BOND_ORDERS;
00116
00125 static const char* OVERWRITE_SELECTED_BONDS;
00126
00130 static const char* ADD_HYDROGENS;
00131
00136 static const char* COMPUTE_ALSO_CONNECTIVITY;
00137
00142 static const char* CONNECTIVITY_CUTOFF;
00143
00146 static const char* USE_FINE_PENALTY;
00147
00150 static const char* KEKULIZE_RINGS;
00151
00154 static const char* ALGORITHM;
00155
00161 static const char* HEURISTIC;
00162
00165 static const char* INIFile;
00166
00169 static const char* MAX_BOND_ORDER;
00170
00175 static const char* MAX_NUMBER_OF_SOLUTIONS;
00176
00181 static const char* COMPUTE_ALSO_NON_OPTIMAL_SOLUTIONS;
00182
00188 static const char* BOND_LENGTH_WEIGHTING;
00189
00193 static const char* APPLY_FIRST_SOLUTION;
00194
00201 static const char* GREEDY_K_SIZE;
00202
00209 static const char* BRANCH_AND_BOUND_CUTOFF;
00210
00211
00212 };
00213
00215 struct BALL_EXPORT Default
00216 {
00217 static const bool OVERWRITE_SINGLE_BOND_ORDERS;
00218 static const bool OVERWRITE_DOUBLE_BOND_ORDERS;
00219 static const bool OVERWRITE_TRIPLE_BOND_ORDERS;
00220 static const bool OVERWRITE_SELECTED_BONDS;
00221 static const bool ADD_HYDROGENS;
00222 static const bool COMPUTE_ALSO_CONNECTIVITY;
00223 static const float CONNECTIVITY_CUTOFF;
00224 static const bool USE_FINE_PENALTY;
00225 static const bool KEKULIZE_RINGS;
00226 static const String ALGORITHM;
00227 static const String HEURISTIC;
00228 static const String INIFile;
00229 static const int MAX_BOND_ORDER;
00230 static const int MAX_NUMBER_OF_SOLUTIONS;
00231 static const bool COMPUTE_ALSO_NON_OPTIMAL_SOLUTIONS;
00232 static const float BOND_LENGTH_WEIGHTING;
00233 static const bool APPLY_FIRST_SOLUTION;
00234 static const int GREEDY_K_SIZE;
00235 static const float BRANCH_AND_BOUND_CUTOFF;
00236 };
00237
00238 struct BALL_EXPORT Algorithm
00239 {
00240 static const String A_STAR;
00241 static const String ILP;
00242 static const String K_GREEDY;
00243 static const String BRANCH_AND_BOUND;
00244 };
00245
00246 struct BALL_EXPORT Heuristic
00247 {
00248 static const String SIMPLE;
00249 static const String MEDIUM;
00250 static const String TIGHT;
00251 };
00252
00254
00258
00260 AssignBondOrderProcessor();
00261
00262
00263
00264
00266 virtual ~AssignBondOrderProcessor();
00268
00272
00274 virtual bool start();
00275
00280 void clear();
00281
00294 virtual Processor::Result operator ()(AtomContainer& ac);
00295
00297 virtual bool finish();
00298
00300
00304
00311 Size getNumberOfAddedHydrogens(Position i)
00312 {
00313 if (i >= solutions_.size())
00314 {
00315 Log.error() << "AssignBondOrderProcessor: No solution with index " << i << std::endl;
00316 return 0;
00317 }
00318 int num_hydrogens = 0;
00319
00320 HashMap<Atom*, int>::Iterator it = solutions_[i].number_of_virtual_hydrogens.begin();
00321 for (; it != solutions_[i].number_of_virtual_hydrogens.end(); it++)
00322 num_hydrogens += it->second;
00323 return num_hydrogens;
00324 }
00325
00335 Size getNumberOfComputedSolutions() {return solutions_.size();}
00336
00337
00340 AtomContainer* getAtomContainer() {return ac_;}
00341
00344 AtomContainer const* getAtomContainer() const {return ac_;}
00345
00354 const System& getSolution(Position i) throw(Exception::IndexOverflow);
00355
00361 float getTotalCharge(Position i)
00362 {
00363 if (i >= solutions_.size())
00364 {
00365 Log.error() << "AssignBondOrderProcessor: No solution with index " << i << std::endl;
00366
00367 return Limits<float>::max();
00368 }
00369 else
00370 return getTotalCharge_(solutions_[i]);
00371
00372 }
00373
00380 float getTotalPenalty(Position i=0)
00381 {
00382 if (i >= solutions_.size())
00383 {
00384 Log.error() << "AssignBondOrderProcessor: No solution with index " << i << std::endl;
00385
00386 return Limits<float>::max();
00387 }
00388 else
00389 return getTotalPenalty_(solutions_[i]);
00390 }
00391
00392
00393
00394
00395
00396
00397 int getNumberOfNodeExpansions(Position i)
00398 {
00399 if (i >= solutions_.size())
00400 {
00401 Log.error() << "AssignBondOrderProcessor: No solution with index " << i << std::endl;
00402
00403 return -1;
00404 }
00405 else
00406 return getNumberOfNodeExpansions_(solutions_[i]);
00407 }
00408
00409
00410
00411
00412
00413
00414 int getQueueSize(Position i)
00415 {
00416 if (i >= solutions_.size())
00417 {
00418 Log.error() << "AssignBondOrderProcessor: No solution with index " << i << std::endl;
00419
00420 return -1;
00421 }
00422 else
00423 return getQueueSize_(solutions_[i]);
00424 }
00425
00438 bool apply(Position i);
00439
00445 void resetBondOrders();
00446
00453 bool computeNextSolution(bool apply_solution = true);
00454
00457 void setDefaultOptions();
00458
00465 float evaluatePenalty(AtomContainer* ac);
00467
00471
00472 Options options;
00473
00475
00476 protected:
00477
00478
00479 class Solution_
00480 {
00481 friend class AssignBondOrderProcessor;
00482
00483 public:
00484
00485 Solution_();
00486
00487
00488 Solution_(PQ_Entry_& entry ,AssignBondOrderProcessor* abop,
00489 int number_of_node_expansions, int search_queue_size);
00490
00491
00492 virtual ~Solution_();
00493
00494
00495 void clear();
00496
00497
00498 int getNumberOfNodeExpansions() const {return node_expansions;}
00499
00500
00501 int getQueueSize() const {return queue_size;}
00502
00503
00504 bool valid;
00505
00506
00507 HashMap<Bond*, int> bond_orders;
00508
00509
00510 HashMap<Atom*, int> number_of_virtual_hydrogens;
00511
00512
00513
00514 vector<Atom*> atoms_to_delete;
00515
00516
00517
00518 float atom_type_penalty;
00519 float bond_length_penalty;
00520 float total_charge;
00521 int node_expansions;
00522 int queue_size;
00523 AssignBondOrderProcessor* parent;
00524 AtomContainer* ac;
00525 };
00526
00527
00528 class PQ_Entry_
00529 {
00530 friend class AssignBondOrderProcessor;
00531
00532 public:
00533
00534
00535 PQ_Entry_();
00536
00537
00538 ~PQ_Entry_();
00539
00540
00541 void clear();
00542
00543
00544
00545 bool operator < (const PQ_Entry_& b) const;
00546
00547
00548 float coarsePenalty(float atom_type_penalty, float bond_length_penalty) const
00549 {
00550 return ( ( ( (atom_type_normalization_factor < 0.0001)
00551 || (bond_length_normalization_factor < 0.0001)
00552 || (alpha < 0.0001)) ?
00553 atom_type_penalty :
00554 ((1.-alpha) * (atom_type_penalty / atom_type_normalization_factor)
00555 + (alpha* bond_length_penalty / bond_length_normalization_factor))));
00556 }
00557
00558
00559 float coarsePenalty() const
00560 {
00561 return coarsePenalty(estimated_atom_type_penalty, estimated_bond_length_penalty);
00562 }
00563
00564
00565 float finePenalty() const {return estimated_bond_length_penalty;}
00566
00567
00568 float estimated_atom_type_penalty;
00569
00570 float estimated_bond_length_penalty;
00571
00572
00573
00574
00575 vector<short> bond_orders;
00576
00577
00578 Position last_bond;
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 static float alpha;
00590 static float atom_type_normalization_factor;
00591 static float bond_length_normalization_factor;
00592 static bool use_fine_penalty;
00593 };
00594
00600 bool readOptions_();
00601
00602
00607 bool readAtomPenalties_() throw(Exception::FileNotFound());
00608
00617 bool preassignPenaltyClasses_();
00618
00625 int getPenaltyClass_(Atom* atom);
00626
00627
00643 bool precomputeBondLengthPenalties_();
00644
00656 float computeVirtualHydrogens_(Atom* atom);
00657
00660 bool apply_(Solution_& solution);
00661
00664 void storeOriginalConfiguration_();
00665
00666
00667
00668
00669
00670
00671 int getQueueSize_(const Solution_& sol){return sol.getQueueSize();}
00672
00679 float getTotalCharge_(const Solution_& sol)
00680 {
00681 if (sol.valid)
00682 {
00683 return sol.total_charge;
00684 }
00685 else
00686 {
00687 return 0;
00688 }
00689 }
00690
00697 float getTotalPenalty_(const Solution_& sol)
00698 {
00699 if ( (atom_type_normalization_factor_ < 0.00001)
00700 || (bond_length_normalization_factor_ < 0.00001)
00701 || (alpha_ < 0.0001))
00702 {
00703 return sol.atom_type_penalty;
00704 }
00705 else
00706 {
00707 return ( (1.-alpha_) * (sol.atom_type_penalty/atom_type_normalization_factor_)
00708 + (alpha_*sol.bond_length_penalty/bond_length_normalization_factor_));
00709 }
00710 }
00711
00712
00713
00714
00715
00716
00717 int getNumberOfNodeExpansions_(const Solution_& sol){return sol.getNumberOfNodeExpansions();}
00718
00719
00720 #ifdef BALL_HAS_LPSOLVE
00721
00723 bool createILP_();
00724
00727 bool solveILP_();
00728 #endif
00729
00731 bool valid_;
00732
00734 bool evaluation_mode_;
00735
00736
00737
00738 std::map<Bond*, short> bond_fixed_;
00739
00740
00741 std::vector<Bond*> free_bonds_;
00742
00743
00744 HashMap<Bond*, Index> bond_to_index_;
00745
00746
00747 std::vector<Bond*> index_to_bond_;
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757 HashMap<Atom*, int> number_of_virtual_hydrogens_;
00758
00759
00760 std::vector<int> virtual_bond_index_to_number_of_virtual_hydrogens_;
00761
00762
00763 Size num_of_virtual_bonds_;
00764
00765
00766 vector<Atom*> virtual_bond_index_to_atom_;
00767 HashMap<Atom*, int> atom_to_virtual_bond_index_;
00768
00769
00770
00771 Bond* virtual_bond_;
00772
00773
00774
00775
00776
00777
00778
00779 std::vector<Bond*> ilp_index_to_free_bond_;
00780
00781
00782 Position ilp_number_of_free_bonds_;
00783
00784
00785 float ilp_const_penalty_;
00786
00787
00788
00789
00790 Position total_num_of_bonds_;
00791
00792
00793 int num_of_free_bonds_;
00794
00795
00796 std::vector<Position> fixed_val_;
00797
00798
00799 vector<Solution_> solutions_;
00800
00801
00802
00803 vector<Solution_> starting_configuration_;
00804
00805
00806 float atom_type_normalization_factor_;
00807
00808
00809 float bond_length_normalization_factor_;
00810
00811
00812
00813 int last_applied_solution_;
00814
00815
00816 AtomContainer* ac_;
00817
00818
00819 int max_bond_order_;
00820
00821
00822 float alpha_;
00823
00824
00825 int max_number_of_solutions_;
00826
00827
00828 bool compute_also_non_optimal_solutions_;
00829
00830
00831 bool add_missing_hydrogens_;
00832
00833
00834 bool compute_also_connectivity_;
00835
00836
00837 bool use_fine_penalty_;
00838
00839
00840 enum HEURISTIC_INDEX
00841 {
00842 SIMPLE,
00843 MEDIUM,
00844 TIGHT
00845 };
00846
00847 HEURISTIC_INDEX heuristic_index_;
00848
00849
00850 bool performBranchAndBound_();
00851 float greedy_atom_type_penalty_;
00852 float greedy_bond_length_penalty_;
00853
00854
00855 vector<PQ_Entry_> performGreedy_(PQ_Entry_& entry, Size greedy_k = 10);
00856 int greedy_node_expansions_;
00857
00858
00860 bool performAStarStep_();
00861
00862
00863
00864
00866 std::priority_queue<PQ_Entry_> queue_;
00867
00875 bool estimatePenalty_(PQ_Entry_& entry, bool include_heuristic_term = true);
00876
00878 float estimateAtomTypePenalty_(Atom* atom,
00879 Index atom_index,
00880 int fixed_valence,
00881 int fixed_virtual_order,
00882 int num_free_bonds,
00883 PQ_Entry_& entry);
00885
00886 float estimateBondLengthPenalty_(Index atom_index,
00887 const vector<Bond*>& free_bonds,
00888 int fixed_virtual_order,
00889 int fixed_valence,
00890 int num_free_bonds);
00891
00892
00893
00894
00895
00896
00897
00898 vector<int> penalties_;
00899 vector<Position> block_to_start_idx_;
00900 vector<Size> block_to_length_;
00901 vector<int> block_to_start_valence_;
00902
00903 vector<std::pair<String, String> > block_definition_;
00904
00905
00906
00907
00908
00909
00910 vector< vector<int> > atom_to_block_;
00911
00912
00913 HashMap<Bond*, vector<float> > bond_lengths_penalties_;
00914
00915
00916
00917 int step_;
00918
00919 Timer timer_;
00920 #ifdef BALL_HAS_LPSOLVE
00921 lprec* ilp_;
00922 #endif
00923 AssignBondOrderProcessor(const AssignBondOrderProcessor& abop);
00924 AssignBondOrderProcessor& operator = (const AssignBondOrderProcessor& abop);
00925 };
00926
00927 }
00928
00929
00930 #endif // BALL_STRUCTURE_ASSIGNBONDORDERPROCESSOR_H