Line data Source code
1 : /* -------------------------------------------------------------------------- * 2 : * lepton * 3 : * -------------------------------------------------------------------------- * 4 : * This is part of the lepton expression parser. * 5 : * See https://openmm.org/development. * 6 : * * 7 : * Portions copyright (c) 2009-2021 Stanford University and the Authors. * 8 : * Authors: Peter Eastman * 9 : * Contributors: * 10 : * * 11 : * Permission is hereby granted, free of charge, to any person obtaining a * 12 : * copy of this software and associated documentation files (the "Software"), * 13 : * to deal in the Software without restriction, including without limitation * 14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 15 : * and/or sell copies of the Software, and to permit persons to whom the * 16 : * Software is furnished to do so, subject to the following conditions: * 17 : * * 18 : * The above copyright notice and this permission notice shall be included in * 19 : * all copies or substantial portions of the Software. * 20 : * * 21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 22 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 24 : * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 25 : * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 26 : * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 27 : * USE OR OTHER DEALINGS IN THE SOFTWARE. * 28 : * -------------------------------------------------------------------------- */ 29 : 30 : #include "ExpressionTreeNode.h" 31 : #include "Exception.h" 32 : #include "Operation.h" 33 : #include <utility> 34 : 35 : namespace PLMD { 36 : using namespace lepton; 37 : using namespace std; 38 : 39 548671 : ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const vector<ExpressionTreeNode>& children) : operation(operation), children(children) { 40 548671 : if (operation->getNumArguments() != children.size()) 41 0 : throw Exception("wrong number of arguments to function: "+operation->getName()); 42 548671 : } 43 : 44 75776 : ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child1, const ExpressionTreeNode& child2) : operation(operation) { 45 75776 : children.push_back(child1); 46 75776 : children.push_back(child2); 47 75776 : if (operation->getNumArguments() != children.size()) 48 0 : throw Exception("wrong number of arguments to function: "+operation->getName()); 49 75776 : } 50 : 51 42064 : ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child) : operation(operation) { 52 42064 : children.push_back(child); 53 42064 : if (operation->getNumArguments() != children.size()) 54 0 : throw Exception("wrong number of arguments to function: "+operation->getName()); 55 42064 : } 56 : 57 2123861 : ExpressionTreeNode::ExpressionTreeNode(Operation* operation) : operation(operation) { 58 2123861 : if (operation->getNumArguments() != children.size()) 59 0 : throw Exception("wrong number of arguments to function: "+operation->getName()); 60 2123861 : } 61 : 62 15104236 : ExpressionTreeNode::ExpressionTreeNode(const ExpressionTreeNode& node) : operation(node.operation == NULL ? NULL : node.operation->clone()), children(node.getChildren()) { 63 15104236 : } 64 : 65 264078 : ExpressionTreeNode::ExpressionTreeNode(ExpressionTreeNode&& node) : operation(node.operation), children(std::move(node.children)) { 66 264078 : node.operation = NULL; 67 264078 : node.children.clear(); 68 264078 : } 69 : 70 3199697 : ExpressionTreeNode::ExpressionTreeNode() : operation(NULL) { 71 3199697 : } 72 : 73 21358383 : ExpressionTreeNode::~ExpressionTreeNode() { 74 21358383 : if (operation != NULL) 75 18262827 : delete operation; 76 21358383 : } 77 : 78 2955660 : bool ExpressionTreeNode::operator!=(const ExpressionTreeNode& node) const { 79 2955660 : if (node.getOperation() != getOperation()) 80 : return true; 81 912862 : if (getOperation().isSymmetric() && getChildren().size() == 2) { 82 310799 : if (getChildren()[0] == node.getChildren()[0] && getChildren()[1] == node.getChildren()[1]) 83 : return false; 84 230036 : if (getChildren()[0] == node.getChildren()[1] && getChildren()[1] == node.getChildren()[0]) 85 : return false; 86 230036 : return true; 87 : } 88 876265 : for (int i = 0; i < (int) getChildren().size(); i++) 89 430906 : if (getChildren()[i] != node.getChildren()[i]) 90 : return true; 91 : return false; 92 : } 93 : 94 2524754 : bool ExpressionTreeNode::operator==(const ExpressionTreeNode& node) const { 95 2524754 : return !(*this != node); 96 : } 97 : 98 550932 : ExpressionTreeNode& ExpressionTreeNode::operator=(const ExpressionTreeNode& node) { 99 550932 : if (operation != NULL) 100 87305 : delete operation; 101 550932 : operation = node.getOperation().clone(); 102 550932 : children = node.getChildren(); 103 550932 : return *this; 104 : } 105 : 106 2831221 : ExpressionTreeNode& ExpressionTreeNode::operator=(ExpressionTreeNode&& node) { 107 2831221 : if (operation != NULL) 108 95408 : delete operation; 109 2831221 : operation = node.operation; 110 2831221 : children = std::move(node.children); 111 2831221 : node.operation = NULL; 112 2831221 : node.children.clear(); 113 2831221 : return *this; 114 : } 115 : 116 29913044 : const Operation& ExpressionTreeNode::getOperation() const { 117 29913044 : return *operation; 118 : } 119 : 120 62463123 : const vector<ExpressionTreeNode>& ExpressionTreeNode::getChildren() const { 121 62463123 : return children; 122 : } 123 : 124 745679 : void ExpressionTreeNode::assignTags(vector<const ExpressionTreeNode*>& examples) const { 125 : // Assign tag values to all nodes in a tree, such that two nodes have the same 126 : // tag if and only if they (and all their children) are equal. This is used to 127 : // optimize other operations. 128 : 129 745679 : int numTags = examples.size(); 130 1432282 : for (const ExpressionTreeNode& child : getChildren()) 131 686603 : child.assignTags(examples); 132 745679 : if (numTags == examples.size()) { 133 : // All the children matched existing tags, so possibly this node does too. 134 : 135 17057588 : for (int i = 0; i < examples.size(); i++) { 136 16885916 : const ExpressionTreeNode& example = *examples[i]; 137 16885916 : bool matches = (getChildren().size() == example.getChildren().size() && getOperation() == example.getOperation()); 138 18497544 : for (int j = 0; matches && j < getChildren().size(); j++) 139 1611628 : if (getChildren()[j].tag != example.getChildren()[j].tag) 140 : matches = false; 141 16885916 : if (matches) { 142 309003 : tag = i; 143 309003 : return; 144 : } 145 : } 146 : } 147 : 148 : // This node does not match any previous node, so assign a new tag. 149 : 150 436676 : tag = examples.size(); 151 436676 : examples.push_back(this); 152 : } 153 : 154 : } // namespace PLMD