-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
POEM_096 Research and Pseudocode #196
Closed
Closed
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
abf3ead
Create POEM_96.md
jsrogan 4885658
Update POEM_96.md
jsrogan 623c1ff
Associated POEM_96 File
jsrogan dedc834
Create fake
jsrogan ae28d2c
Delete POEM_96.md
jsrogan 0fd1b7a
Update and rename fake to POEM_096.md
jsrogan 98a57e8
Delete backtrack.py
jsrogan 2e50c14
Create poem096.py
jsrogan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
POEM ID: 096 | ||
|
||
Title: Research and Pseudocode of Manual Reverse Mode differentiation | ||
|
||
authors: jsrogan, coleyoung5 | ||
|
||
Competing POEMs: N/A | ||
|
||
Related POEMs: N/A | ||
|
||
Associated implementation PR: N/A | ||
|
||
|
||
Status: | ||
|
||
- [x] Active | ||
- [ ] Requesting decision | ||
- [ ] Accepted | ||
- [ ] Rejected | ||
- [ ] Integrated | ||
|
||
|
||
|
||
## Motivation | ||
Considering the fact that private optimization libraries such as SNOPT offer the ability to find a feasible starting point, it makes sense that OPENMdao should also have that functionality. Aditionally OPENMdao's current components do not calculate reverse derivatives, so the implementation of this is also necessary (and still ongoing). | ||
|
||
|
||
|
||
## Description | ||
In order to implement this we researched helpful libraries to implement a tree like structure which would allow us to perform reverse mode differentation while backtracking, and wrote pseudocode which explains our choices and our insights into the problem. While not a full solution by any means, hopefully this provides a strong starting point for others who are looking to implement this problem. | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
#we went with anytree because we saw feasible start as a backtracking problem, and anytree seemed like it would be an effective | ||
#method of constructing a tree to backtrack through, well documented, high functionality, etc. | ||
from anytree import Node, RenderTree | ||
from sympy import symbols, diff | ||
import re | ||
|
||
def problem_to_tree(problem): | ||
""" | ||
Based on this line of code from parabaloid example: | ||
prob.model.add_subsystem('paraboloid', om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3')) | ||
|
||
We assume 'problem' as it is passed is an OpenMDAO problem, and we constructing the tree from the equation stored in the subsystem | ||
|
||
|
||
Level 1 is the initial problem (represented by a function) and the left hand sign of the equation, in this case single variable Y | ||
|
||
1 Y = A*B + C*D | ||
/ \ | ||
/ \ | ||
2 AB CD | ||
/ \ / \ | ||
/ \ / \ | ||
3 A B C D | ||
|
||
Gradients: the gradient list ends up being all leaf nodes at the end of the tree's formation | ||
|
||
Partial Dervivative: Compute the partial derivative of each parent with respect to all it's children | ||
eg, the PARTIAL of A would be partial_derivative(parent, child) or partial of AB with respect to A, which is B | ||
|
||
All nodes link to both their parent and all children (lead nodes and root nodes only link 1 way) | ||
|
||
|
||
per prob.model.add_subsystem('paraboloid', om.ExecComp('f = (x-3)**2 + x*y + (y+4)**2 - 3')), | ||
subsystem was assumed to be tuple of name and om.ExecComp and that ExecComp was stored as a string | ||
""" | ||
equation = problem.model.subsystem[1] #abstraction, unsure how to access the equation string stored in subsystem | ||
|
||
equation = equation.split('=') | ||
|
||
lhs = equation[0] | ||
lhs = lhs.strip(' ') | ||
root = Node(lhs, gradients=[]) #gradients starts empty, and is filled during back propagation | ||
|
||
rhs = equation[1] | ||
terms_list = re.split(r'\D', rhs) #rough idea, does not take into account full order of operations | ||
|
||
for each term in terms_list: | ||
""" | ||
construct an anytree node (as outlined for the root) and | ||
store which operation (+, -, /, *, etc.) took you from parent to child | ||
|
||
Example Node AB would be (from level 2 in diagram above): | ||
node_ab = Node(AB, parent=root, gradients=[], operation='*') | ||
|
||
- AB is the node's name | ||
- the parent node is the root of the tree in this case | ||
- gradients are empty until back propagation | ||
- the operation which forms AB's children is multiplication. Operation of leaf node is null | ||
""" | ||
|
||
|
||
return RenderTree(root) | ||
|
||
|
||
def find_feasible_start(problem): | ||
tree = problem_to_tree(problem) | ||
|
||
equation = problem.model.subsystem[1] #abstraction, unsure how to access the equation string stored in subsystem | ||
equation = equation.split('=') | ||
rhs = equation[1] | ||
exclude = {'*', '/', '+', '-', '0', '1', '2', | ||
'3', '4', '5', '6', '7', '8', '9'} #characters we don't differentiate with respect to | ||
|
||
symbols = [] #each symbol (eg variable) we want to differentiate with respect to | ||
for char in rhs: | ||
if char not in exclude: | ||
symbols.append(char) | ||
|
||
|
||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenMDAO computes partials at the component level, either through specification of a jacobian matrix - or through a "matrix-free" API (the component.compute_jacvec_prod method) in it will compute a forward JVP or a reverse VJP. The framework then assembles these calculations into a graph for efficient computation and assembly of the total derivatives. The notion of reverse derivatives just aren't relevant to the implementation of a feasible starting point.