Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tsoc
openmm
Commits
8b3bfc92
Commit
8b3bfc92
authored
Oct 16, 2013
by
peastman
Browse files
Lots of optimizations to Lepton, including creating CompiledExpression class.
parent
d389e504
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
301 additions
and
14 deletions
+301
-14
libraries/lepton/include/Lepton.h
libraries/lepton/include/Lepton.h
+1
-0
libraries/lepton/include/lepton/CompiledExpression.h
libraries/lepton/include/lepton/CompiledExpression.h
+91
-0
libraries/lepton/include/lepton/ExpressionProgram.h
libraries/lepton/include/lepton/ExpressionProgram.h
+1
-3
libraries/lepton/include/lepton/Operation.h
libraries/lepton/include/lepton/Operation.h
+25
-2
libraries/lepton/include/lepton/ParsedExpression.h
libraries/lepton/include/lepton/ParsedExpression.h
+6
-1
libraries/lepton/src/CompiledExpression.cpp
libraries/lepton/src/CompiledExpression.cpp
+149
-0
libraries/lepton/src/ExpressionProgram.cpp
libraries/lepton/src/ExpressionProgram.cpp
+7
-8
libraries/lepton/src/ParsedExpression.cpp
libraries/lepton/src/ParsedExpression.cpp
+5
-0
tests/TestParser.cpp
tests/TestParser.cpp
+16
-0
No files found.
libraries/lepton/include/Lepton.h
View file @
8b3bfc92
...
...
@@ -32,6 +32,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "lepton/CompiledExpression.h"
#include "lepton/CustomFunction.h"
#include "lepton/ExpressionProgram.h"
#include "lepton/ExpressionTreeNode.h"
...
...
libraries/lepton/include/lepton/CompiledExpression.h
0 → 100644
View file @
8b3bfc92
#ifndef LEPTON_COMPILED_EXPRESSION_H_
#define LEPTON_COMPILED_EXPRESSION_H_
/* -------------------------------------------------------------------------- *
* Lepton *
* -------------------------------------------------------------------------- *
* This is part of the Lepton expression parser originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "ExpressionTreeNode.h"
#include "windowsIncludes.h"
#include <map>
#include <set>
#include <string>
#include <vector>
namespace
Lepton
{
class
Operation
;
class
ParsedExpression
;
/**
* A CompiledExpression is a highly optimized representation of an expression for cases when you want to evaluate
* it many times as quickly as possible. You should treat it as an opaque object; none of the internal representation
* is visible.
*
* A CompiledExpression is created by calling createCompiledExpression() on a ParsedExpression.
*/
class
LEPTON_EXPORT
CompiledExpression
{
public:
CompiledExpression
();
CompiledExpression
(
const
CompiledExpression
&
expression
);
~
CompiledExpression
();
CompiledExpression
&
operator
=
(
const
CompiledExpression
&
expression
);
/**
* Get the names of all variables used by this expression.
*/
const
std
::
set
<
std
::
string
>&
getVariables
()
const
;
/**
* Get a reference to the memory location where the value of a particular variable is stored. This can be used
* to set the value of the variable before calling evaluate().
*/
double
&
getVariableReference
(
const
std
::
string
&
name
);
/**
* Evaluate the expression. The values of all variables should have been set before calling this.
*/
double
evaluate
()
const
;
private:
friend
class
ParsedExpression
;
CompiledExpression
(
const
ParsedExpression
&
expression
);
void
compileExpression
(
const
ExpressionTreeNode
&
node
,
std
::
vector
<
std
::
pair
<
ExpressionTreeNode
,
int
>
>&
temps
);
int
findTempIndex
(
const
ExpressionTreeNode
&
node
,
std
::
vector
<
std
::
pair
<
ExpressionTreeNode
,
int
>
>&
temps
);
std
::
vector
<
std
::
vector
<
int
>
>
arguments
;
std
::
vector
<
int
>
target
;
std
::
vector
<
Operation
*>
operation
;
std
::
map
<
std
::
string
,
int
>
variableIndices
;
std
::
set
<
std
::
string
>
variableNames
;
mutable
std
::
vector
<
double
>
workspace
;
mutable
std
::
vector
<
double
>
argValues
;
std
::
map
<
std
::
string
,
double
>
dummyVariables
;
};
}
// namespace Lepton
#endif
/*LEPTON_COMPILED_EXPRESSION_H_*/
libraries/lepton/include/lepton/ExpressionProgram.h
View file @
8b3bfc92
...
...
@@ -48,9 +48,7 @@ class ParsedExpression;
* evaluated and the result is pushed back onto the stack. At the end, the stack contains a single value,
* which is the value of the expression.
*
* An ExpressionProgram is created by calling createProgram() on a ParsedExpression. It can generally be evaluated
* more quickly than the ParsedExpression itself, so when you need to evaluate an expression many times, it is
* most efficient to create an ExpressionProgram from it.
* An ExpressionProgram is created by calling createProgram() on a ParsedExpression.
*/
class
LEPTON_EXPORT
ExpressionProgram
{
...
...
libraries/lepton/include/lepton/Operation.h
View file @
8b3bfc92
...
...
@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009 Stanford University and the Authors.
*
* Portions copyright (c) 2009
-2013
Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
...
...
@@ -965,6 +965,8 @@ private:
class
LEPTON_EXPORT
Operation
::
PowerConstant
:
public
Operation
{
public:
PowerConstant
(
double
value
)
:
value
(
value
)
{
intValue
=
(
int
)
value
;
isIntPower
=
(
intValue
==
value
);
}
std
::
string
getName
()
const
{
std
::
stringstream
name
;
...
...
@@ -981,6 +983,25 @@ public:
return
new
PowerConstant
(
value
);
}
double
evaluate
(
double
*
args
,
const
std
::
map
<
std
::
string
,
double
>&
variables
)
const
{
if
(
isIntPower
)
{
// Integer powers can be computed much more quickly by repeated multiplication.
int
exponent
=
intValue
;
double
base
=
args
[
0
];
if
(
exponent
<
0
)
{
exponent
=
-
exponent
;
base
=
1.0
/
base
;
}
double
result
=
1.0
;
while
(
exponent
!=
0
)
{
if
((
exponent
&
1
)
==
1
)
result
*=
base
;
base
*=
base
;
exponent
=
exponent
>>
1
;
}
return
result
;
}
else
return
std
::
pow
(
args
[
0
],
value
);
}
ExpressionTreeNode
differentiate
(
const
std
::
vector
<
ExpressionTreeNode
>&
children
,
const
std
::
vector
<
ExpressionTreeNode
>&
childDerivs
,
const
std
::
string
&
variable
)
const
;
...
...
@@ -996,6 +1017,8 @@ public:
}
private:
double
value
;
int
intValue
;
bool
isIntPower
;
};
class
LEPTON_EXPORT
Operation
::
Min
:
public
Operation
{
...
...
libraries/lepton/include/lepton/ParsedExpression.h
View file @
8b3bfc92
...
...
@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009 Stanford University and the Authors.
*
* Portions copyright (c) 2009
=2013
Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
...
...
@@ -39,6 +39,7 @@
namespace
Lepton
{
class
CompiledExpression
;
class
ExpressionProgram
;
/**
...
...
@@ -97,6 +98,10 @@ public:
* Create an ExpressionProgram that represents the same calculation as this expression.
*/
ExpressionProgram
createProgram
()
const
;
/**
* Create a CompiledExpression that represents the same calculation as this expression.
*/
CompiledExpression
createCompiledExpression
()
const
;
/**
* Create a new ParsedExpression which is identical to this one, except that the names of some
* variables have been changed.
...
...
libraries/lepton/src/CompiledExpression.cpp
0 → 100644
View file @
8b3bfc92
/* -------------------------------------------------------------------------- *
* Lepton *
* -------------------------------------------------------------------------- *
* This is part of the Lepton expression parser originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "lepton/CompiledExpression.h"
#include "lepton/Operation.h"
#include "lepton/ParsedExpression.h"
#include <utility>
using
namespace
Lepton
;
using
namespace
std
;
CompiledExpression
::
CompiledExpression
()
{
}
CompiledExpression
::
CompiledExpression
(
const
ParsedExpression
&
expression
)
{
ParsedExpression
expr
=
expression
.
optimize
();
// Just in case it wasn't already optimized.
vector
<
pair
<
ExpressionTreeNode
,
int
>
>
temps
;
compileExpression
(
expr
.
getRootNode
(),
temps
);
}
CompiledExpression
::~
CompiledExpression
()
{
for
(
int
i
=
0
;
i
<
(
int
)
operation
.
size
();
i
++
)
if
(
operation
[
i
]
!=
NULL
)
delete
operation
[
i
];
}
CompiledExpression
::
CompiledExpression
(
const
CompiledExpression
&
expression
)
{
*
this
=
expression
;
}
CompiledExpression
&
CompiledExpression
::
operator
=
(
const
CompiledExpression
&
expression
)
{
arguments
=
expression
.
arguments
;
target
=
expression
.
target
;
variableIndices
=
expression
.
variableIndices
;
variableNames
=
expression
.
variableNames
;
workspace
.
resize
(
expression
.
workspace
.
size
());
argValues
.
resize
(
expression
.
argValues
.
size
());
operation
.
resize
(
expression
.
operation
.
size
());
for
(
int
i
=
0
;
i
<
(
int
)
operation
.
size
();
i
++
)
operation
[
i
]
=
expression
.
operation
[
i
]
->
clone
();
return
*
this
;
}
void
CompiledExpression
::
compileExpression
(
const
ExpressionTreeNode
&
node
,
vector
<
pair
<
ExpressionTreeNode
,
int
>
>&
temps
)
{
if
(
findTempIndex
(
node
,
temps
)
!=
-
1
)
return
;
// We have already processed a node identical to this one.
// Process the child nodes.
vector
<
int
>
args
;
for
(
int
i
=
0
;
i
<
node
.
getChildren
().
size
();
i
++
)
{
compileExpression
(
node
.
getChildren
()[
i
],
temps
);
args
.
push_back
(
findTempIndex
(
node
.
getChildren
()[
i
],
temps
));
}
// Process this node.
if
(
node
.
getOperation
().
getId
()
==
Operation
::
VARIABLE
)
{
variableIndices
[
node
.
getOperation
().
getName
()]
=
workspace
.
size
();
variableNames
.
insert
(
node
.
getOperation
().
getName
());
}
else
{
int
stepIndex
=
arguments
.
size
();
arguments
.
push_back
(
vector
<
int
>
());
target
.
push_back
(
workspace
.
size
());
operation
.
push_back
(
node
.
getOperation
().
clone
());
if
(
args
.
size
()
==
0
)
arguments
[
stepIndex
].
push_back
(
0
);
// The value won't actually be used. We just need something there.
else
{
// If the arguments are sequential, we can just pass a pointer to the first one.
bool
sequential
=
true
;
for
(
int
i
=
1
;
i
<
args
.
size
();
i
++
)
if
(
args
[
i
]
!=
args
[
i
-
1
]
+
1
)
sequential
=
false
;
if
(
sequential
)
arguments
[
stepIndex
].
push_back
(
args
[
0
]);
else
{
arguments
[
stepIndex
]
=
args
;
if
(
args
.
size
()
>
argValues
.
size
())
argValues
.
resize
(
args
.
size
(),
0.0
);
}
}
}
temps
.
push_back
(
make_pair
(
node
,
workspace
.
size
()));
workspace
.
push_back
(
0.0
);
}
int
CompiledExpression
::
findTempIndex
(
const
ExpressionTreeNode
&
node
,
vector
<
pair
<
ExpressionTreeNode
,
int
>
>&
temps
)
{
for
(
int
i
=
0
;
i
<
(
int
)
temps
.
size
();
i
++
)
if
(
temps
[
i
].
first
==
node
)
return
i
;
return
-
1
;
}
const
set
<
string
>&
CompiledExpression
::
getVariables
()
const
{
return
variableNames
;
}
double
&
CompiledExpression
::
getVariableReference
(
const
string
&
name
)
{
map
<
string
,
int
>::
iterator
index
=
variableIndices
.
find
(
name
);
if
(
index
==
variableIndices
.
end
())
throw
Exception
(
"getVariableReference: Unknown variable '"
+
name
+
"'"
);
return
workspace
[
index
->
second
];
}
double
CompiledExpression
::
evaluate
()
const
{
// Loop over the operations and evaluate each one.
for
(
int
step
=
0
;
step
<
operation
.
size
();
step
++
)
{
const
vector
<
int
>&
args
=
arguments
[
step
];
if
(
args
.
size
()
==
1
)
workspace
[
target
[
step
]]
=
operation
[
step
]
->
evaluate
(
&
workspace
[
args
[
0
]],
dummyVariables
);
else
{
for
(
int
i
=
0
;
i
<
args
.
size
();
i
++
)
argValues
[
i
]
=
workspace
[
args
[
i
]];
workspace
[
target
[
step
]]
=
operation
[
step
]
->
evaluate
(
&
argValues
[
0
],
dummyVariables
);
}
}
return
workspace
[
workspace
.
size
()
-
1
];
}
libraries/lepton/src/ExpressionProgram.cpp
View file @
8b3bfc92
...
...
@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009 Stanford University and the Authors.
*
* Portions copyright (c) 2009
-2013
Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
...
...
@@ -93,14 +93,13 @@ double ExpressionProgram::evaluate() const {
}
double
ExpressionProgram
::
evaluate
(
const
std
::
map
<
std
::
string
,
double
>&
variables
)
const
{
vector
<
double
>
args
(
max
(
maxArgs
,
1
));
vector
<
double
>
stack
(
stackSize
);
int
stackPointer
=
0
;
vector
<
double
>
stack
(
stackSize
+
1
);
int
stackPointer
=
stackSize
;
for
(
int
i
=
0
;
i
<
(
int
)
operations
.
size
();
i
++
)
{
int
numArgs
=
operations
[
i
]
->
getNumArguments
();
for
(
int
j
=
0
;
j
<
numArgs
;
j
++
)
args
[
j
]
=
stack
[
--
stackPointer
]
;
stack
[
stackPointer
++
]
=
operations
[
i
]
->
evaluate
(
&
args
[
0
],
variables
)
;
double
result
=
operations
[
i
]
->
evaluate
(
&
stack
[
stackPointer
],
variables
);
stackPointer
+=
numArgs
-
1
;
stack
[
stackPointer
]
=
result
;
}
return
stack
[
0
];
return
stack
[
stackSize
-
1
];
}
libraries/lepton/src/ParsedExpression.cpp
View file @
8b3bfc92
...
...
@@ -30,6 +30,7 @@
* -------------------------------------------------------------------------- */
#include "lepton/ParsedExpression.h"
#include "lepton/CompiledExpression.h"
#include "lepton/ExpressionProgram.h"
#include "lepton/Operation.h"
#include <limits>
...
...
@@ -294,6 +295,10 @@ ExpressionProgram ParsedExpression::createProgram() const {
return
ExpressionProgram
(
*
this
);
}
CompiledExpression
ParsedExpression
::
createCompiledExpression
()
const
{
return
CompiledExpression
(
*
this
);
}
ParsedExpression
ParsedExpression
::
renameVariables
(
const
map
<
string
,
string
>&
replacements
)
const
{
return
ParsedExpression
(
renameNodeVariables
(
getRootNode
(),
replacements
));
}
...
...
tests/TestParser.cpp
View file @
8b3bfc92
...
...
@@ -56,6 +56,12 @@ void verifyEvaluation(const string& expression, double expectedValue) {
ExpressionProgram
program
=
parsed
.
createProgram
();
value
=
program
.
evaluate
();
ASSERT_EQUAL_TOL
(
expectedValue
,
value
,
1e-10
);
// Create a CompiledExpression and see if that also gives the same result.
CompiledExpression
compiled
=
parsed
.
createCompiledExpression
();
value
=
compiled
.
evaluate
();
ASSERT_EQUAL_TOL
(
expectedValue
,
value
,
1e-10
);
}
/**
...
...
@@ -86,6 +92,16 @@ void verifyEvaluation(const string& expression, double x, double y, double expec
value
=
program
.
evaluate
(
variables
);
ASSERT_EQUAL_TOL
(
expectedValue
,
value
,
1e-10
);
// Create a CompiledExpression and see if that also gives the same result.
CompiledExpression
compiled
=
parsed
.
createCompiledExpression
();
if
(
compiled
.
getVariables
().
find
(
"x"
)
!=
compiled
.
getVariables
().
end
())
compiled
.
getVariableReference
(
"x"
)
=
x
;
if
(
compiled
.
getVariables
().
find
(
"y"
)
!=
compiled
.
getVariables
().
end
())
compiled
.
getVariableReference
(
"y"
)
=
y
;
value
=
compiled
.
evaluate
();
ASSERT_EQUAL_TOL
(
expectedValue
,
value
,
1e-10
);
// Make sure that variable renaming works.
variables
.
clear
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment