Skip to content
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

implemented parsing (string -> Basic) #772

Merged
merged 19 commits into from Feb 11, 2016
Merged

Conversation

srajangarg
Copy link
Contributor

  • Implement a basic integer parser, with all basic operations
  • Add support for symbols (any token which has even one non-digit character, is considered a symbol)
  • Change styling and formatting according to symengine, comment code properly
  • Add support for symengine implemented functions
  • Add support for symengine implemented constants
  • Handle most errors, and their reporting
  • Handle entered doubles (any numerical token with exactly a single '.' is converted to RealDouble)
  • Add support for function_symbol
  • Add support for complex numbers

Addresses #559

@srajangarg srajangarg changed the title implemented Parsing of string operations [WIP] implemented parsing (string -> Basic) Jan 20, 2016
@certik
Copy link
Contributor

certik commented Jan 20, 2016

I think this looks nice and clean. My only comment is about naming conventions --- opPrecedence -> op_precedence, operatorClose -> operator_close, etc.


namespace SymEngine {

class expressionParser
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name should start with Caps.

@abinashmeher999
Copy link
Contributor

I think all source is in cpp currently. We should have one header file too at the end, if this is just for testing.


public:

RCP<const Basic> parse_string(unsigned int l, unsigned int h)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you think of any case where it might be useful to expose this by making parse_string public? I didn't see this in the tests. If not, it would be better to keep it private.

@srajangarg
Copy link
Contributor Author

Will get it done. Right now, my main focus is getting the function to work correctly, and including all features. Variable names, formatting and trivial changes, I'll make later.

@isuruf
Copy link
Member

isuruf commented Jan 21, 2016

Looks good to me. If you have any doubts, please feel free to ask.
Another item for the TODO list

  • Add support for function_symbols

if(expr == "ln") return log(param1);

if(expr == "zeta") if(s[iter+1] != ',') return zeta(param1);
if(expr == "log") if(s[iter+1] != ',') return log(param1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a linear search (i.e. a linear list of ifs), one can probably make it faster by checking std::map or something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't think anything faster than linear is possible. I have to search if 'any' of them matches, and do a unique thing on a match. I am not looking to 'find' an element in a array/map. Whatever way it is implemented, it will have to boil down to checking each the expr against each of these terms. (or something equivalent to these linear checks)

One complicated way to optimize maybe to make a search tree based on the letters of the expr. But I feel that is an overkill. Maybe do it after the main tasks?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can see how to optimize this later.

Your current solution is O(n). A faster is to use O(log(n)) or O(1) using std::map or std::unordered_map, and you store a lambda function there that will do what you need.

@srajangarg
Copy link
Contributor Author

@certik @isuruf Any ideas as to why build is failing on Windows, MinGW compiler?

@certik
Copy link
Contributor

certik commented Jan 21, 2016

The mingw is failing because it can't find std::stoi in the std namespace. I assume some header file needs to be included?

@srajangarg
Copy link
Contributor Author

http://www.cplusplus.com/reference/string/stoi/
Requires only <string>. It is a c++11 function though, "older compilers" might not support it.
What to do?

@isuruf
Copy link
Member

isuruf commented Jan 23, 2016

std::stoi is not included in MinGW. It's a known bug.
You can use std::atoi(expr.c_str())

@abhinavagarwal07
Copy link
Contributor

some function arguments can be made const

{'*', 3}, {'/', 4}, {'^', 5}
};
std::map<std::string, RCP<const Basic> > constants = {
{"e", E}, {"EulerGamma", EulerGamma}, {"pi", pi}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add I as a constant too. Then complex numbers will be supported as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh didn't think about that! Thanks!

// i am still not clear about the fundamentals of realdouble

s = "sqrt(2.0)+5";
// s = "sqrt(2)+5" this fails! (will the user add `.0` to integers to get them `computed`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this line. It's supposed to work that way. If the user just wants numerics, then they are better off using a specialized library.

@srajangarg srajangarg changed the title [WIP] implemented parsing (string -> Basic) implemented parsing (string -> Basic) Feb 6, 2016
@srajangarg
Copy link
Contributor Author

Any work to be done? @certik @isuruf

if (in[i] == ' ') {
continue;

} else if (in[i] == '*' and in[(i+1) % in.length()] == '*') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

% in.length() why is this there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If in[i] is the last character of the entered string, in[i+1] goes out of bounds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the best approach would be to check that i + 1 < in.length().

@isuruf
Copy link
Member

isuruf commented Feb 7, 2016

Looks good to me. Can you add a header file parser.h and have just one method like RCP<const Basic> parse(const std::string& s) which would call the ExpressionParser in the implementation file?

@Sumith1896
Copy link
Contributor

Looks good to me too! +1

@Sumith1896
Copy link
Contributor

@certik Can you have a final look at this?


#include <symengine/basic.h>
#include <symengine/dict.h>
#include <symengine/parser.cpp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should not include a .cpp file. Remove this include and just change

inline RCP<const Basic> parse(std::string& s) {
    ExpressionParser p;
    return p.parse_expr(s);
} 

to

RCP<const Basic> parse(const std::string& s);

and implement it in parser.cpp. Also make the input argument const, as I did.

@certik
Copy link
Contributor

certik commented Feb 10, 2016

I left some comments. Otherwise it looks good to me as well.

@srajangarg
Copy link
Contributor Author

@certik made the changes

@certik
Copy link
Contributor

certik commented Feb 10, 2016

The header change is good, thanks. Please ping me once you fix the const thing, I'll do one final review.

@srajangarg
Copy link
Contributor Author

done @certik

@certik
Copy link
Contributor

certik commented Feb 10, 2016

+1 to merge as it is, if tests pass.

@srajangarg
Copy link
Contributor Author

I'm not able to figure out what's wrong with the build. After changing all the maps to const, I'm getting a lot of error: passing ‘const '...’ as ‘this’ argument discards qualifiers [-fpermissive] on compilation.

@certik
Copy link
Contributor

certik commented Feb 10, 2016

Ok, revert the const change, just to the header file change. In general, create git commits that are logical. So the header file change should go into its own commit. Since we both approved it, you just push it in and let it be. Then we can tackle the const thing, and if it's difficult, we can do it in a future PR.

@certik
Copy link
Contributor

certik commented Feb 10, 2016

Btw, the reason it fails is because the operator[] for accessing std::map is not const, which I forgot about. See http://stackoverflow.com/questions/1474894/why-isnt-the-operator-const-for-stl-maps

Just forget about the const thing in this PR, fix the header and make sure all tests pass. Then we can merge this.

@srajangarg
Copy link
Contributor Author

@certik done

@certik
Copy link
Contributor

certik commented Feb 11, 2016

I think that this looks good. Thanks for the work!

certik added a commit that referenced this pull request Feb 11, 2016
implemented parsing (string -> Basic)
@certik certik merged commit 450ecde into symengine:master Feb 11, 2016
@srajangarg srajangarg deleted the parser branch June 6, 2016 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants