## May 27, 2020

#### Faisal Riyaz (friyaz): Google Summer of Code with SymPy

My proposal to SymPy has been selected for GSoC. My project is to add the support of vector integration over Curves, Lines, and Surfaces to SymPy. My mentors are Francesco Bonazzi and DivyanshuThakur. I am very excited to learn from them and contribute to SymPy.

Google Summer of Code or GSoC is a three-month program to bring student developers into open source development. Students contribute to an open project for three months. Students apply by submitting proposals to organizations. Students can submit up to 3 proposals. I only submitted one as most students do.

When I started contributing to SymPy, I was new to Open-source. I looked through many projects. SymPy was a great fit for my skills and interests. The Introduction to contributing and development workflow pages are great and helpful. SymPy has nice documentation and the codebase is well maintained. I received continuous feedback from the community on my Pull Requests. SymPy is a great project to get started with the open-source if you are familiar with Python and comfortable with mathematics.

# SymPy

SymPy is a python library for symbolic mathematics. Symbolic computations are useful when we want to represent any mathematical quantity exactly.

SymPy is free software and is licensed under New BSD license.

Perhaps, the best way to get started with SymPy is to go through the SymPy tutorial. We can compute complicated math expressions, solve equations, perform integration, and do many more things.

>>> from sympy import *
>>>
>>> eq = 9*x - 2*x*y + y**2
>>> eq = eq - x
>>> eq
-2*x*y + 8*x + y**2
>>>
>>> eqdash = eq/x
>>> eqdash.expand()
-2*y + 8 + y**2/x
>>> factor(eqdash)
-(2*x*y - 8*x - y**2)/x
>>>
>>> diff(eq,x)
-2*y + 8
>>> Integral(eq,y)
Integral(-2*x*y + 8*x + y**2, y)
>>> Integral(eq,y).doit()
-x*y**2 + 8*x*y + y**3/3
>>>
>>> solve(sin(x)*x, x)
[0, pi]


# My project

SymPy has a vector module. It provides tools for basic vector maths.

To get started with vectors, we first have to define a coordinate system. The module supports Cartesian, spherical, and curvilinear coordinate systems.

>>> from sympy.vector import CoordSys3D, divergence, gradient
>>> C = CoordSys3D('C')


We can access the unit vectors of the Coordinate System using C.i, C.j an C.k. C.x, C.y and C.z represent . Any vector expression can be created by performing basic mathematical operations like *,-,+ or / on base scalars and base vectors. We can also calculate gradient, curl and divergence.

>>> v = 3*C.i + 5*C.j - 2*C.k
>>> s = 3*C.x*C.y
>>> vdash = C.i - 8*C.j + 11*C.k
>>> v + vdash
4*C.i + (-3)*C.j + 9*C.k
>>> v.cross(vdash)
39*C.i + (-35)*C.j + (-29)*C.k
>>> gradient(s)
3*C.y*C.i + 3*C.x*C.j


SymPy does not support integration of vector/scalar fields over curves, surfaces and volume elements. But Vector instances can be integrated with respect to a single variable using Integral class.

>>> from sympy import Integral
>>> Integral(v, C.x)
(Integral(3, C.x))*C.i + (Integral(5, C.x))*C.j + (Integral(-2, C.x))*C.k
>>> Integral(v, C.x).doit()
3*C.x*C.i + 5*C.x*C.j + (-2*C.x)*C.k


Vector calculus has many applications in the field of physics and mathematics, especially in the description of electromagnetic fields, gravitational fields, and fluid flow. The integrals of these fields represent important physical quantities. Vector Calculus plays a significant role in the study of partial differential equations.

Let’s look at some problems of such integrals.

1. Integrate a scalar field f(x,y,z) = x2yz over the circle centered at x = 2 and radius r = 3.
2. Calculate the flux of the vector field v across the surface x2 + y2 + z2 = 4 and z > 0.
3. Calculate the mass of the body of Volume V bounded by x2 + y2 + z2 = 1 and z2 = (x2 + y2)/2. The desnity is given as rho = z.

To solve such integrals using Sympy, one first has to represent these integrals into multiple integrals and then use Integral class to get the result. Other Computer Algebra Systems like Mathematica and Maple already provides the functionality to perform such Integrals.

# Community Bonding Period

Community Bonding Period is the first phase of the program. Students try to get familiar with the community and the codebase. I have contributed to SymPy in the past so I was comfortable with the development workflow.

I submitted my proposal just before the deadline. Therefore, I could not discuss the proposal with the community. I wanted to use this period to discuss the API with the community and find any possible problem which can arise. I also wanted to get familiar with the vector module. SymPy, require that all student-mentor interactions happen on a public channel like a mailing list or Gitter. The Gitter room for discussion related to vectors is sympy/vector. If you have any ideas or suggestions or just want to check out the progress, do lurk around there.

## The API

In my proposal, I suggested a possible API. But there were some obvious problems with that API which Francesco highlighted. The API must be easy to use and intuitive for SymPy users. It has to be close to the mathematical representation in textbooks. This reduces the difficulty of learning a new API and allows the user to focus. I have started an issue for discussing the API with the rest of the community. I also looked at other CAS to get inspiration. Mathematica seems to do a good job of calculating vector integrals.

I proposed separate classes for different types of integrals(Line, Surface, Volume). Francesco suggested that the classes should represent the way an integral is displayed, not what kind of integral it is. SymPy should distinguish what these integrals are. Integral equations will be represented using subclasses of Integral. Then, we can write algorithms to perform computation.

We discussed about the separate classes to represent special surfaces. Many problems involve integrating over geometric objects like Circle, Sphere, Rectangle, Disk, etc. It can be helpful to the users if SymPy provides classes to represent such geometric entities. This saves the user from defining these objects using their parametric or implicit equation. We have decided to leave this part for later.

Another problem is determining the orientation of a surface. A surface can have two normals. The surface integral of scalar fields does not depend on the orientation. A surface integral of a vector field(flux) depends on the orientation. The result differs in sign. We decided that SymPy should always return the magnitude of the integral and it should be left to the user to decide the sign using the dot product.

## Defining regions using implicit equations

Many curves and surfaces are easy to describe using their implicit equations. As an example, a problem involves calculating integral over S where S is the portion of y = 3sx2 + 3z2 that lies behind y=6. It will be tiresome for the user to first get the parametric representation of this surface and then use SymPy to solve the integral. I believe that a major part of the problem is finding the parametric representation. The rest of the calculation can be easily performed.

But handling such integrals is a difficult problem. To calculate the integral, we generally need the parametric representation of the curve/surface. We can then reduce the integral to multiple integrals and use SymPy integral class to get the result.

One approach to handle implicit equations is to write an algorithm to get the parametric representation from the implicit equation. This approach requires significant effort. We have decided to handle implicit integrals after we have completed the work on parametric integrals.

## Conclusion

We have decided to first handle integrals over parametric regions. I will implement a class which will represent a parametric region in space. Another class will be implemented to represent an integral over a parametric region.

>>> circle = ParametricCurve(r*cos(theta), r*sin(theta), (theta, 0, 2*pi), (r, 0, 1))
>>> ParametricIntegral(f(x, y), (x, y), circle)


We will handle implicit regions later. I plan to complete this work in the first phase hopefully and get started with implicit integrals from the next phase.

I wanted to start coding early but due to midsemester exams, I could not. Most probably, the end-semester exams will not be conducted this summer. They will get conducted along with next semester’s exams. So, I do not have any other major commitments for the next 3 months.

## May 24, 2020

#### Smit Lunagariya (Smit-create): Week 1-GSoC 2020

This blog discribes the first official implementation week of the program. One of the advantage of Community Bonding period, I experienced during this week was that it saves a lot of time of designing new APIs. Since, it was all decided earlier on the APIs in the previous week, it made easy to maintain the timeline and add significant features.

## May 20, 2020

#### Abhinav Anand (abhinav28071999): Google Summer of Code 2020 with Sympy!

From my first year i always wanted to get selected for Gsoc and do some exiciting projects, but never took it seriously. When i reached my third year i made up my mind that it is a high time for preparig for Gsoc. For Gsoc 2020 i choose to apply to Sympy as i found this community very intresting. I took a head start and started contributing for four months before the application period. It was a really nice experience and i meet some really interesting people. I am glad that i made the right decision of choosing this organization.

## May 17, 2020

#### Smit Lunagariya (Smit-create): Community Bonding Period-GSoC 2020

This is the first official blog associated with GSoC 2020. I will be sharing the experience of the Community Bonding Period and work during this period after selection.

## May 07, 2020

#### Sachin Agarwal (sachin-4099): GSoC 2020 Acceptance

The results of Google Summer of Code were out on 04 May 2020 and I am pleased to share with you that my proposal with Sympy was accepted.

I would like to thank all the members of the organisation especially Kalevi Suominen for guiding me in my proposal and PR’s. I am really excited to work for such an amazing organization.

I will be working on my project, Amendments to Limit Evaluation and Series Expansion, during a period of 3 months spanning from June to August, under the mentorship of Kalevi Suominen and Sartaj Singh.

My primary focus will be to work on the series module and make it more robust as it is the backbone of all the limit evaluations performed by the library.

Looking forward for a really productive and wonderful summer ahead.

## May 06, 2020

#### Smit Lunagariya (Smit-create): About ME

Name: Smit Lunagariya

## May 05, 2020

#### Smit Lunagariya (Smit-create): Pre GSoC 2020

I will be sharing my Pre-GSoC journey in this blog. I started exploring about the GSoC program around November 2019 and was quite interested in the open source. I began to look for the organisations and came across a Math and Physics library in python, SymPy.

## March 31, 2020

#### Aaron Meurer (asmeurer): Verifying the Riemann Hypothesis with SymPy and mpmath

Like most people, I've had a lot of free time recently, and I've spent some of it watching various YouTube videos about the Riemann Hypothesis. I've collected the videos I've watched into YouTube playlist. The playlist is sorted with the most mathematically approachable videos first, so even if you haven't studied complex analysis before, you can watch the first few. If you have studied complex analysis, all the videos will be within your reach (none of them are highly technical with proofs). Each video contains parts that aren't in any of the other videos, so you will get something out of watching each of them.

One of the videos near the end of the playlist is a lecture by Keith Conrad. In it, he mentioned a method by which one could go about verifying the Riemann Hypothesis with a computer. I wanted to see if I could do this with SymPy and mpmath. It turns out you can.

## Background Mathematics

$cat mymod/a.py # mymod/a.py from .b import y def func(x): return x + y  The -i flag causes it to edit a.py in-place. Without it, it would just print a diff to the terminal. For implicit star imports and explicit star imports from the same module, removestar works statically, making use of pyflakes. This means none of the code is actually executed. For external imports, it is not possible to work statically as external imports may include C extension modules, so in that case, it imports the names dynamically. removestar can be installed with pip or conda: pip install removestar  or if you use conda conda install -c conda-forge removestar  ### sphinx-math-dollar In SymPy, we make heavy use of LaTeX math in our documentation. For example, in our special functions documentation, most special functions are defined using a LaTeX formula, like However, the source for this math in the docstring of the function uses RST syntax: class besselj(BesselBase): """ Bessel function of the first kind. The Bessel J function of order \nu is defined to be the function satisfying Bessel's differential equation .. math :: z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2} + z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 - \nu^2) w = 0, with Laurent expansion .. math :: J_\nu(z) = z^\nu \left(\frac{1}{\Gamma(\nu + 1) 2^\nu} + O(z^2) \right), if :math:\nu is not a negative integer. If :math:\nu=-n \in \mathbb{Z}_{<0} *is* a negative integer, then the definition is .. math :: J_{-n}(z) = (-1)^n J_n(z).  Furthermore, in SymPy's documentation we have configured it so that text between single backticks is rendered as math. This was originally done for convenience, as the alternative way is to write :math:\nu every time you want to use inline math. But this has lead to many people being confused, as they are used to Markdown where single backticks produce code. A better way to write this would be if we could delimit math with dollar signs, like $\nu$. This is how things are done in LaTeX documents, as well as in things like the Jupyter notebook. With the new sphinx-math-dollar Sphinx extension, this is now possible. Writing $\nu$ produces$\nu$, and the above docstring can now be written as class besselj(BesselBase): """ Bessel function of the first kind. The Bessel$J$function of order$\nu$is defined to be the function satisfying Bessel's differential equation .. math :: z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2} + z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 - \nu^2) w = 0, with Laurent expansion .. math :: J_\nu(z) = z^\nu \left(\frac{1}{\Gamma(\nu + 1) 2^\nu} + O(z^2) \right), if$\nu$is not a negative integer. If$\nu=-n \in \mathbb{Z}_{<0}\$
*is* a negative integer, then the definition is

.. math ::
J_{-n}(z) = (-1)^n J_n(z).


We also plan to add support for $$double dollars$$ for display math so that .. math :: is no longer needed either .

For end users, the documentation on docs.sympy.org will continue to render exactly the same, but for developers, it is much easier to read and write.

This extension can be easily used in any Sphinx project. Simply install it with pip or conda:

pip install sphinx-math-dollar


or

conda install -c conda-forge sphinx-math-dollar


Then enable it in your conf.py:

extensions = ['sphinx_math_dollar', 'sphinx.ext.mathjax']


### Google Season of Docs

The above work on sphinx-math-dollar is part of work I have been doing to improve the tooling around SymPy's documentation. This has been to assist our technical writer Lauren Glattly, who is working with SymPy for the next three months as part of the new Google Season of Docs program. Lauren's project is to improve the consistency of our docstrings in SymPy. She has already identified many key ways our docstring documentation can be improved, and is currently working on a style guide for writing docstrings. Some of the issues that Lauren has identified require improved tooling around the way the HTML documentation is built to fix. So some other SymPy developers and I have been working on improving this, so that she can focus on the technical writing aspects of our documentation.

Lauren has created a draft style guide for documentation at https://github.com/sympy/sympy/wiki/SymPy-Documentation-Style-Guide. Please take a moment to look at it and if you have any feedback on it, comment below or write to the SymPy mailing list.

## August 23, 2019

#### Nikhil Maan (Sc0rpi0n101): Week 12: The Final Week

“Software is like entropy: It is difficult to grasp, weighs nothing, and obeys the Second Law of Thermodynamics; i.e., it always increases.” — Norman Augustine Welcome everyone, this is your host Nikhil Maan aka Sc0rpi0n101 and this week will be the last week of coding for GSoC 2019. It is time to finish work now. The C Parser Travis Build Tests Documentation The C Parser I completed the C Parser last week along with the documentation for the module.

## August 22, 2019

#### Nikhil Maan (Sc0rpi0n101): Week 11: The Other Parser

Welcome everyone, this is your host Nikhil Maan aka Sc0rpi0n101 and this week we’re talking about the C parser. The Fortran Parser The C Parser Documentation Travis Build The Fortran Parser The Fortran Parser is complete. The Pull Request has also been merged. The parser is merged in master and will be a part of the next SymPy release. You can check out the source code for the Parser at the Pull Request.

## August 20, 2019

#### Shubham Kumar Jha (ShubhamKJha): GSoC 2019: Week 12 (The Final Week)

The last week of coding period is officially over. A summary of the work done during this week is:

• #17379 is now complete and currently under review. I will try to get it merged within this week.
• #17392 still needs work. I will try to put a closure to this by the end of week.
• #17440 was started. It attempts to add a powerful (but optional) SAT solving engine to SymPy (pycosat). The performance gain for SAT solver is also subtle here: Using this
1
2
3
4
from sympy import *
from sympy.abc import x
r = random_poly(x, 100, -100, 100)
ans = ask(Q.positive(r), Q.positive(x))


The performance is like

1
2
3
4
5
6
7
8
# In master
|  - 0.631 check_satisfiability  sympy/assumptions/satask.py:30
|     - 0.607 satisfiable  sympy/logic/inference.py:38
|        - 0.607 dpll_satisfiable  sympy/logic/algorithms/dpll2.py:21
# With pycosat
|  - 0.122 check_satisfiability  sympy/assumptions/satask.py:30
|     - 0.098 satisfiable  sympy/logic/inference.py:39
|        - 0.096 pycosat_satisfiable  sympy/logic/algorithms/pycosat_wrapper.py:11


It is finished and under review now.

Also, with the end of GSoC 2019, final evaluations have started. I will be writing a final report to the whole project by the end of this week.

So far it has been a great and enriching experience for me. It was my first attempt at GSoC and I am lucky to get such an exposure. I acknowledge that I started with an abstract idea of the project but I now understand both the need and the code of New Assumptions pretty well (thanks to Aaron who wrote the most of it). The system is still in its early phases and needs a lot more work. I am happy to be a part of it and I will be available to work on it.

This is the last weekly report but I will still be contributing to SymPy and open source in general. I will try to write more of such experiences through this portal. Till then, Good bye and thank you!

#### Ishan Joshi (ishanaj): GSoC’19: Week-12 – The Final wrap-up

This was the last week of the coding period. With not much of work left, the goal was to wrap-up the PR’s.

The week started with the merge of  PR #17001 which implemented a method cut_section() in the polygon class, in order to get two new polygons when a polygon is cut via a line. After this a new method first_moment_of_area() was added in PR #17153. This method used cut_section() for its implementation. Tests for the same were added in this PR. Also the existing documentation was improved. I also renamed the polar_modulus() function to polar_second_moment_of_area() which was a more general term as compared to the previous name. This PR also got merged later on.

Now, we are left with two more PR’s to go. PR #17122 (Column Buckling) and PR #17345 (Beam diagram). The column buckling probably requires a little more documentation. I will surely look into it and add some more explanations and references to it. Also, the beam diagram PR has been completed and documented. A few more discussions to be done on its working and we will be ready with it.

I believe that by the end of this week both of these will finally get a merge.

Another task that remains is the implementation of the Truss class. Some rigorous debate and discussion is still needed to be done before we start its implementation. Once we agree on the implementation needs and API it won’t be a difficult task to write it through.

Also, since the final evaluations have started I will be writing the project report which I have to submit before the next week ends.

Since officially the coding period ends here, there would be no ToDo’s for the next week, just the final wrapping up and will surely try to complete the work that is still left.

Will keep you updated!

Thanks!

#### Arighna Chakrabarty (arighnaiitg): GSoC Week 12 !!

Week 12 ends.. - So, finally after a long summer GSoC has come to an end!! It has been a great experience, and something which I will cherish for the rest of my life. I would like to thank my mentor Sartaj, who has been guiding me through the thick and thin of times....

## August 19, 2019

#### Divyanshu Thakur (divyanshu132): GSoC 2019 - Week 11 and 12 - Phase-III Completion

We’ve reached to the end of GSoC 2019, end to the really productive and wonderful summer. In the last two weeks I worked on documenting polycyclic groups which got merged as well, here is the PR sympy/sympy#17399.

Also, the PR on Induced-pcgs and exponent vector for polycyclic subgroups got merged sympy/sympy#17317.

Let’s have a look at some of the highlights of documentation.

• The parameters of both the classes(PolycyclicGroup and Collector) has been discussed in detail.
• Conditions for a word to be collected or uncollected is highlighted.
• Computation of polycyclic presentation has been explained in detail highlighting the sequence in which presentation is computed with the corresponding pcgs and and polycyclic series elements used.
• Other methods like subword_index, exponent_vector, depth, etc are also documented.

An example is provided for every functionality. For more details one can visit: https://docs.sympy.org/dev/modules/combinatorics/pc_groups.html

Now, I’m supposed to prepare a final report presenting all the work done. Will update with report next week. In addition to the report preparation I’ll try to add Parameters section in the docstrings for various classes and methods of pc_groups.

## August 18, 2019

#### Jogi Miglani (jmig5776): Final report for GSoC 2019 (Week 12)

It’s finally the last week of the Google Summer of Code 2019. Before I start discussing my work over the summer I would like to highlight my general experience with the GSoC program.

GSoC gives students all over the world the opportunity to connect and collaborate with some of the best programmers involved in open source from around the world. I found the programme tremendusly enriching both in terms of the depth in which I got to explore some of the areas involved in my project and also gave me exxposure to some areas I had no previous idea about. The role of a mentor in GSoC is the most important and I consider myself very lucky to have got Yathartha Anirudh Joshi and Amit Kumar as my mentors. Amit and Yathartha has been tremendously encouraging and helpful throughout the summer. I would also like to mention the importance of the entire community involved, just being part of the SymPy community.

### Work Completed

Here is a list of PRs which were opened during the span of GSoC:

Here is a list of PRs merged:

Here is all the brief description about the PRs merged:

In this PR a new solver _solve_modular was made for solving modular equations.

### What type of equations to be considered and what domain?

A - Mod(B, C) = 0

A -> This can or cannot be a function specifically(Linear, nth degree single
Pow, a**f_x and Add and Mul) of symbol.(But currently its not a
function of x)
B -> This is surely a function of symbol.
C -> It is an integer.
And domain should be a subset of S.Integers.


### Filtering out equations

A check is being applied named _is_modular which verifies that only above mentioned type equation should return True.

### Working of _solve_modular

In the starting of it there is a check if domain is a subset of Integers.

domain.is_subset(S.Integers)


Only domain of integers and it subset are being considered while solving these equations. Now after this it separates out a modterm and the rest term on either sides by this code.

modterm = list(f.atoms(Mod))[0]
rhs = -(S.One)*(f.subs(modterm, S.Zero))
if f.as_coefficients_dict()[modterm].is_negative:
# f.as_coefficient(modterm) was returning None don't know why
# checks if coefficient of modterm is negative in main equation.
rhs *= -(S.One)


Now the equation is being inverted with the helper routine _invert_modular like this.

n = Dummy('n', integer=True)
f_x, g_n = _invert_modular(modterm, rhs, n, symbol)


I am defining n in _solve_modular because _invert_modular contains recursive calls to itself so if define the n there then it was going to have many instances which of no use. Thats y I am defining it in _solve_modular.

Now after the equation is inverted now solution finding takes place.

if f_x is modterm and g_n is rhs:
return unsolved_result


First of all if _invert_modular fails to invert then a ConditionSet is being returned.

    if f_x is symbol:
if domain is not S.Integers:
return domain.intersect(g_n)
return g_n


And if _invert_modular is fully able to invert the equation then only domain intersection needs to takes place. _invert_modular inverts the equation considering S.Integers as its default domain.

    if isinstance(g_n, ImageSet):
lamda_expr = g_n.lamda.expr
lamda_vars = g_n.lamda.variables
base_set = g_n.base_set
sol_set = _solveset(f_x - lamda_expr, symbol, S.Integers)
if isinstance(sol_set, FiniteSet):
tmp_sol = EmptySet()
for sol in sol_set:
tmp_sol += ImageSet(Lambda(lamda_vars, sol), base_set)
sol_set = tmp_sol
return domain.intersect(sol_set)


In this case when g_n is an ImageSet of n and f_x is not symbol so the equation is being solved by calling _solveset (this will not lead to recursion because equation to be entered is free from Mod) and then the domain intersection takes place.

### What does _invert_modular do?

This function helps to convert the equation A - Mod(B, C) = 0 to a form (f_x, g_n). First of all it checks the possible instances of invertible cases if not then it returns the equation as it is.

a, m = modterm.args
if not isinstance(a, (Dummy, Symbol, Add, Mul, Pow)):
return modterm, rhs


Now here is the check for complex arguments and returns the equation as it is if somewhere it finds I.

if rhs.is_real is False or any(term.is_real is False \
for term in list(_term_factors(a))):
# Check for complex arguments
return modterm, rhs


Now after this we check of emptyset as a solution by checking range of both sides of equation. As modterm can have values between [0, m - 1] and if rhs is out of this range then emptySet is being returned.

if (abs(rhs) - abs(m)).is_positive or (abs(rhs) - abs(m)) is S.Zero:
# if rhs has value greater than value of m.
return symbol, EmptySet()


Now the equation haveing these types are being returned as the following

if a is symbol:
return symbol, ImageSet(Lambda(n, m*n + rhs), S.Integers)

if a.is_Add:
# g + h = a
g, h = a.as_independent(symbol)
if g is not S.Zero:
return _invert_modular(Mod(h, m), (rhs - Mod(g, m)) % m, n, symbol)

if a.is_Mul:
# g*h = a
g, h = a.as_independent(symbol)
if g is not S.One:
return _invert_modular(Mod(h, m), (rhs*invert(g, m)) % m, n, symbol)


The more peculiar case is of a.is_Pow which is handled as following.

if a.is_Pow:
# base**expo = a
base, expo = a.args
if expo.has(symbol) and not base.has(symbol):
# remainder -> solution independent of n of equation.
# m, rhs are made coprime by dividing igcd(m, rhs)
try:
remainder = discrete_log(m / igcd(m, rhs), rhs, a.base)
except ValueError: # log does not exist
return modterm, rhs
# period -> coefficient of n in the solution and also referred as
# the least period of expo in which it is repeats itself.
# (a**(totient(m)) - 1) divides m. Here is link of theoram:
# (https://en.wikipedia.org/wiki/Euler's_theorem)
period = totient(m)
for p in divisors(period):
# there might a lesser period exist than totient(m).
if pow(a.base, p, m / igcd(m, a.base)) == 1:
period = p
break
return expo, ImageSet(Lambda(n, period*n + remainder), S.Naturals0)
elif base.has(symbol) and not expo.has(symbol):
remainder_list = nthroot_mod(rhs, expo, m, all_roots=True)
if remainder_list is None:
return symbol, EmptySet()
g_n = EmptySet()
for rem in remainder_list:
g_n += ImageSet(Lambda(n, m*n + rem), S.Integers)
return base, g_n


Two cases are being created based of a.is_Pow

1. x**a
2. a**x

x**a - It is being handled by the helper function nthroot_mod which returns required solution. I am not going into very mch detail for more information you can read the documentation of nthroot_mod.

a**x - For this totient is being used in the picture whose meaning can be find on this Wikipedia page. And then its divisors are being checked to find the least period of solutions.

This PR went through many up and downs and nearly made to the most commented PR. And with the help of @smichr it was successfully merged. It mainly solved the bug for not returning all solutions of lambert.

## Explaining the function _solve_lambert (main function to solve lambert equations)

Input - f, symbol, gens
OutPut - Solution of f = 0 if its lambert type expression else NotImplementedError


This function separates out cases as below based on the main function present in the main equation.

For the first ones:
1a1) B**B = R != 0 (when 0, there is only a solution if the base is 0,
but if it is, the exp is 0 and 0**0=1
comes back as B*log(B) = log(R)
1a2) B*(a + b*log(B))**p = R or with monomial expanded or with whole
thing expanded comes back unchanged
log(B) + p*log(a + b*log(B)) = log(R)
lhs is Mul:
expand log of both sides to give:
log(B) + log(log(B)) = log(log(R))
1b) d*log(a*B + b) + c*B = R
lhs is Add:
isolate c*B and expand log of both sides:
log(c) + log(B) = log(R - d*log(a*B + b))


If the equation are of type 1a1, 1a2 and 1b then the mainlog of the equation is taken into concern as the deciding factor lies in the main logarithmic term of equation.

For the next two,
collect on main exp
2a) (b*B + c)*exp(d*B + g) = R
lhs is mul:
log to give
log(b*B + c) + d*B = log(R) - g
2b) -b*B + g*exp(d*B + h) = R
lhs is add:
add b*B
log and rearrange
log(R + b*B) - d*B = log(g) + h


If the equation are of type 2a and 2b then the mainexp of the equation is taken into concern as the deciding factor lies in the main exponential term of equation.

3) d*p**(a*B + b) + c*B = R
collect on main pow
log(R - c*B) - a*B*log(p) = log(d) + b*log(p)


If the equation are of type 3 then the mainpow of the equation is taken into concern as the deciding factor lies in the main power term of equation.

Eventually from all of the three cases the equation is meant to be converted to this form:-

f(x, a..f) = a*log(b*X + c) + d*X - f = 0 which has the
solution,  X = -c/b + (a/d)*W(d/(a*b)*exp(c*d/a/b)*exp(f/a)).


And the solution calculation process is done by _lambert function.

Everything seems flawless?? You might be thinking no modification is required. Lets see what loopholes are there in it.

## What does PR #16890 do?

There are basically two flaws present with the this approach.

1. Not considering all branches of equation while taking log both sides.
2. Calculation of roots should consider all roots in case having rational power.

### 1. Not considering all branches of equation while taking log both sides.

Let us consider this equation to be solved by _solve_lambert function.

-1/x**2 + exp(x/2)/2 = 0


So what the old _solve_lambert do is to convert this equation to following.

2*log(x) + x/2 = 0


and calculates its roots from _lambert. But it missed this branch of equation while taking log on main equation.

2*log(-x) + x/2 = 0


Yeah you can reproduce the original equation from this equation.So basically the problem was that it missed the branches of equation while taking log. And when does the main equation have more than one branch?? The terms having even powers of variable x leads to two different branches of equation.

So how it is solved? What I has done is that before actually gets into solving I preprocess the main equation and if it has more than one branches of equation while converting taking log then I consider all the equations generated from them.(with the help of _solve_even_degree_expr)

How I preprocess the equation? So what I do is I replace all the even powers of x present with even powers of t(dummy variable).

Code for targeted replacement
lhs = lhs.replace(
lambda i:  # find symbol**even
i.is_Pow and i.base == symbol and i.exp.is_even,
lambda i:  # replace t**even
t**i.exp)
Example:-
Main equation -> -1/x**2 + exp(x/2)/2 = 0
After replacement -> -1/t**2 + exp(x/2)/2 = 0


Now I take logarithms on both sides and simplify it.

After simplifying -> 2*log(t) + x/2 = 0


Now I call function _solve_even_degree_expr to replace the t with +/-x to generate two equations.

Replacing t with +/-x
1. 2*log(x) + x/2 = 0
2. 2*log(-x) + x/2 = 0


And consider the solutions of both of the equations to return all lambert real solutions of -1/x**2 + exp(x/2)/2 = 0.

Hope you could understand the logic behind this work.

### 2. Calculation of roots should consider all roots in case having rational power.

This flaw is in the calculation of roots in function _lambert. Earlier the function_lambert has the working like :-

1. Find all the values of a, b, c, d, e in the required loagrithmic equation
2. Then it defines a solution of the form
-c/b + (a/d)*l where l = LambertW(d/(a*b)*exp(c*d/a/b)*exp(-f/a), k)


and then it included that solution. I agree everything seems flawless here. but try to see the step where we are defining l.

Let us suppose a hypothetical algorithm just like algorithm used in _lambert in which equation to be solved is

x**3 - 1 = 0


and in which we define solution of the form

x = exp(I*2*pi/n) where n is the power of x in equation


so the algorithm will give solution

x = exp(I*2*pi/3) # but expected was [1, exp(I*2*pi/3), exp(-I*2*pi/3)]


which can be found by finding all solutions of

x**n - exp(2*I*pi) = 0


by a different correct algorithm. Thats y it was wrong. The above algorithm would have given correct values for x - 1 = 0.

And the question in your mind may arise that why only exp() because the possiblity of having more than one roots is in exp(), because if the algorithm would have been like x = a, where a is some real constant then there is not any possiblity of further roots rather than solution like x = a**(1/n). And its been done in code like this:

code
num, den = ((c*d-b*f)/a/b).as_numer_denom()
p, den = den.as_coeff_Mul()
e = exp(num/den)
t = Dummy('t')
args = [d/(a*b)*t for t in roots(t**p - e, t).keys()]


### Work under development

This PR tends to define a unifying algorithm for linear relations.

### Future Work

Here is a list that comprises of all the ideas (which were a part of my GSoC Proposal and/or thought over during the SoC) which can extend my GSoC project.

1. Integrating helper solvers within solveset: linsolve, solve_decomposition, nonlinsolve

2. Handle nested trigonometric equations.

## August 13, 2019

#### Ishan Joshi (ishanaj): GSoC’19: Week-11- Heading to the final week

With the end of this week the draw() function has been completely implemented. The work on PR #17345 has been completed along with the documentations.

As mentioned in the previous blog this PR was an attempt to make the draw() function use SymPy’s own plot() rather than importing matplotlib externally to plot the diagram. The idea was to plot the load equation which is in terms of singularity function. This would directly plot uniformly distributed load, uniformly varying load and other higher order loads except for point loads and moment loads.
The task was now to plot the remaining parts of the diagram which were:

• A rectangle for drawing the beam
• Arrows for point loads
• Markers for moment loads and supports
• Colour filling to fill colour in inside the higher order loads (order >=0).

Instead of making temporary hacks to implement these, I went a step further to give the plotting module some additional functionalities. Apart from helping in implementing the draw() function,  this would also enhance the plotting module.

The basic idea was to have some additional keyworded arguments in the plot() function. Every keyworded argument would be a list of dictionaries where each dictionary would represent the arguments (or parameters) that would have been passed in the corresponding matplotlib functions.

These are the functions of matplotlib that can now be accessed using sympy’s plot(), along with where there are used in our current situation:

Another thing which is worth mentioning is that to use fill_between() we would require numpy’s arange() for sure. Although it might be better if we could avoid using an external module directly, but I guess this is unavoidable for now.

Also, I have added an option for the user to scale the plot and get a pictorial view of it in case where the plotting with the exact dimensions doesn’t produce a decent diagram. For eg. If the magnitude of the load (order >= 0) is relatively higher to other applied loads or to the length of the beam, the load plot might get out of the final plot window.

Here is an example:

>>> R1, R2 = symbols('R1, R2')
>>> E, I = symbols('E, I')

>>> b1 = Beam(50, 20, 30)

>>> b1.apply_load(10, 2, -1)
>>> b1.apply_load(R1, 10, -1)
>>> b1.apply_load(R2, 30, -1)
>>> b1.apply_load(90, 5, 0, 23)
>>> b1.apply_load(10, 30, 1, 50)
>>> b1.apply_support(50, "pin")
>>> b1.apply_support(0, "fixed")
>>> b1.apply_support(20, "roller")
# case 1 on the left
>>> p = b1.draw()
>>> p.show()

# case 2 on the right
>>> p1 = b1.draw(pictorial=True)
>>> p1.show()


## Next Week:

• Getting leftover PR’s merged
• Initiating implementation of Truss class

Will keep you updated!

Thanks!

## August 12, 2019

#### Shubham Kumar Jha (ShubhamKJha): GSoC 2019: Week 10 and 11

So, the second last week of the official coding period is over now. During the last two weeks, I was mostly occupied with on-campus placement drives, hence I couldn’t put up a blog earlier. A summary of my work during these weeks is as follows:

• First of all, #17144 is merged 😄. This was a large PR and hence took time to get fully reviewed. With this, the performance of New assumptions comes closer to that of the old system. Currently, queries are evaluated about 20X faster than before.

• #17379 attempts to remove SymPy’s costly rcall() from the whole assumptions mechanism. It’s a follow-up from #17144 and the performance gain is subtle for large queries. E.g.
1
2
3
from sympy import *
p = random_poly(x, 50, -50, 50)
print(ask(Q.positive(p), Q.positive(x)))


In the master it takes 4.292 s, out of this 2.483 s is spent in rcall. With this, the time spent is 1.929 s and 0.539 s respectively.

• #17392 attempts to make the New Assumptions able to handle queries which involve Relationals. Currently, it works only with simple queries (e.g. ask(x>y, Q.positive(x) & Q.negative(y)) now evaluates True) just like the way old system works. This is a much-awaited functionality for the new system. Also, during this I realized that sathandlers lack many necessary facts. This PR also adds many new facts to the system.

For the last week of coding, my attempt would be to complete both of these PRs and get them merged. Also, I will try to add new facts to sathandlers.

#### Arighna Chakrabarty (arighnaiitg): GSoC Week 11 !!

Week 11 ends.. - The second last week has also come to an end. We are almost there at the end of the ride. Me and Sartaj had a meeting on 13th of August about the final leftovers to be done, and wrapping up the GSoC work successfully. Here are the works which have...

## August 11, 2019

#### Jogi Miglani (jmig5776): GSoC 2019 - Week 11

This was the eleventh week meeting with the GSoC mentors which was scheduled on Sunday 11th August, 2019 between 11:30 - 12:30 PM (IST). Me, Yathartha and Amit were the attendees of the meeting. _solve_modular was discussed in this meeting.

Here is all the brief description about new solver _solve_modular for solving modular equations.

### What type of equations to be considered and what domain?

A - Mod(B, C) = 0

A -> This can or cannot be a function specifically(Linear, nth degree single
Pow, a**f_x and Add and Mul) of symbol.(But currently its not a
function of x)
B -> This is surely a function of symbol.
C -> It is an integer.
And domain should be a subset of S.Integers.


### Filtering out equations

A check is being applied named _is_modular which verifies that only above mentioned type equation should return True.

### Working of _solve_modular

In the starting of it there is a check if domain is a subset of Integers.

domain.is_subset(S.Integers)


Only domain of integers and it subset are being considered while solving these equations. Now after this it separates out a modterm and the rest term on either sides by this code.

modterm = list(f.atoms(Mod))[0]
rhs = -(S.One)*(f.subs(modterm, S.Zero))
if f.as_coefficients_dict()[modterm].is_negative:
# f.as_coefficient(modterm) was returning None don't know why
# checks if coefficient of modterm is negative in main equation.
rhs *= -(S.One)


Now the equation is being inverted with the helper routine _invert_modular like this.

n = Dummy('n', integer=True)
f_x, g_n = _invert_modular(modterm, rhs, n, symbol)


I am defining n in _solve_modular because _invert_modular contains recursive calls to itself so if define the n there then it was going to have many instances which of no use. Thats y I am defining it in _solve_modular.

Now after the equation is inverted now solution finding takes place.

if f_x is modterm and g_n is rhs:
return unsolved_result


First of all if _invert_modular fails to invert then a ConditionSet is being returned.

    if f_x is symbol:
if domain is not S.Integers:
return domain.intersect(g_n)
return g_n


And if _invert_modular is fully able to invert the equation then only domain intersection needs to takes place. _invert_modular inverts the equation considering S.Integers as its default domain.

    if isinstance(g_n, ImageSet):
lamda_expr = g_n.lamda.expr
lamda_vars = g_n.lamda.variables
base_set = g_n.base_set
sol_set = _solveset(f_x - lamda_expr, symbol, S.Integers)
if isinstance(sol_set, FiniteSet):
tmp_sol = EmptySet()
for sol in sol_set:
tmp_sol += ImageSet(Lambda(lamda_vars, sol), base_set)
sol_set = tmp_sol
return domain.intersect(sol_set)


In this case when g_n is an ImageSet of n and f_x is not symbol so the equation is being solved by calling _solveset (this will not lead to recursion because equation to be entered is free from Mod) and then the domain intersection takes place.

### What does _invert_modular do?

This function helps to convert the equation A - Mod(B, C) = 0 to a form (f_x, g_n). First of all it checks the possible instances of invertible cases if not then it returns the equation as it is.

a, m = modterm.args
if not isinstance(a, (Dummy, Symbol, Add, Mul, Pow)):
return modterm, rhs


Now here is the check for complex arguments and returns the equation as it is if somewhere it finds I.

if rhs.is_real is False or any(term.is_real is False \
for term in list(_term_factors(a))):
# Check for complex arguments
return modterm, rhs


Now after this we check of emptyset as a solution by checking range of both sides of equation. As modterm can have values between [0, m - 1] and if rhs is out of this range then emptySet is being returned.

if (abs(rhs) - abs(m)).is_positive or (abs(rhs) - abs(m)) is S.Zero:
# if rhs has value greater than value of m.
return symbol, EmptySet()


Now the equation haveing these types are being returned as the following

if a is symbol:
return symbol, ImageSet(Lambda(n, m*n + rhs), S.Integers)

if a.is_Add:
# g + h = a
g, h = a.as_independent(symbol)
if g is not S.Zero:
return _invert_modular(Mod(h, m), (rhs - Mod(g, m)) % m, n, symbol)

if a.is_Mul:
# g*h = a
g, h = a.as_independent(symbol)
if g is not S.One:
return _invert_modular(Mod(h, m), (rhs*invert(g, m)) % m, n, symbol)


The more peculiar case is of a.is_Pow which is handled as following.

if a.is_Pow:
# base**expo = a
base, expo = a.args
if expo.has(symbol) and not base.has(symbol):
# remainder -> solution independent of n of equation.
# m, rhs are made coprime by dividing igcd(m, rhs)
try:
remainder = discrete_log(m / igcd(m, rhs), rhs, a.base)
except ValueError: # log does not exist
return modterm, rhs
# period -> coefficient of n in the solution and also referred as
# the least period of expo in which it is repeats itself.
# (a**(totient(m)) - 1) divides m. Here is link of theoram:
# (https://en.wikipedia.org/wiki/Euler's_theorem)
period = totient(m)
for p in divisors(period):
# there might a lesser period exist than totient(m).
if pow(a.base, p, m / igcd(m, a.base)) == 1:
period = p
break
return expo, ImageSet(Lambda(n, period*n + remainder), S.Naturals0)
elif base.has(symbol) and not expo.has(symbol):
remainder_list = nthroot_mod(rhs, expo, m, all_roots=True)
if remainder_list is None:
return symbol, EmptySet()
g_n = EmptySet()
for rem in remainder_list:
g_n += ImageSet(Lambda(n, m*n + rem), S.Integers)
return base, g_n


Two cases are being created based of a.is_Pow

1. x**a
2. a**x

x**a - It is being handled by the helper function nthroot_mod which returns required solution. I am not going into very mch detail for more information you can read the documentation of nthroot_mod.

a**x - For this totient is being used in the picture whose meaning can be find on this Wikipedia page. And then its divisors are being checked to find the least period of solutions.

Hope I am able to clear out everything!!

Code improvement takes time!!

## August 06, 2019

#### Ankit Pandey (anpandey): Google Summer of Code Week 10: Matrix Wildcard Redux

For this week, I’ve made some more minor changes to the Indexed pull request from last week, in addition to filing a new matrix wildcard pull request.

### Matrix Wildcards (again)

Since #17223 was merged this week, I started with an implementation of matrix wildcards that takes advantage of the functionality included in the pull request. I thought that this would be relatively straightforward, with an implementation of the matches method for the MatrixWild subclass being enough. There was one problem though: the underlying matching implementation assumes that all powers in the expression are an instance of the Pow class. However, this isn’t true for matrix expressions: the MatPow class, which represents matrix powers, is a subclass of its own. I’m not exactly sure what the reason for this is, since a quick change of MatPow to inherit from Pow doesn’t seem to break anything. I’ll probably look into this a bit more, since I think this might have something to do with the fact that Matrix exponents can also include other matrices.

My solution for this was to allow temporarily allow expansion of powers by recursing through the expression tree and setting the is_Pow field of each matrix power to True and later reverting these states later. It doesn’t look pretty, but it does seem to work (you can see the code here).

## Next Steps

I’ll try to get started with some optimizations that utilize this wildcard class once the pull request gets merged.

#### Nikhil Maan (Sc0rpi0n101): Week 10: The Finished Parser

“Software is like entropy: It is difficult to grasp, weighs nothing, and obeys the Second Law of Thermodynamics; i.e., it always increases.” — Norman Augustine Welcome everyone, this is your host Nikhil Maan aka Sc0rpi0n101 and we will talk all about the Fortran Parser this week. I have passed the second evaluation and Fortran Parser pull request is complete. The Week Fortran Parser SymPy Expression Travis Builds The C Parser The Meeting The Week This week began with me working on the C parser to finalize that.

## August 05, 2019

#### Ishan Joshi (ishanaj): GSoC’19: Week-10- An alternative to the draw() function

This was the end of the tenth week, and we have entered the final phase of the project.

For the last phase we have Truss calculations to be implemented in the continuum_mechanics module. I had initiated a discussion regarding what needs to be done and how the implementation will move forward in an issue #17302. We will have to analyse a bit more about making Truss calculations symbolic and what benefits one might get in solving it symbolically. We have some good packages to compare from like this. I guess a bit more discussion is needed before we go ahead with it.

Besides this, I had worked on improving the draw() function implemented in the previous week in PR #17240. I modified it to use the _backend attribute for plotting the beam diagram. This could have worked until I realised that using the _backend attribute doesn’t really has affect the Plot object. To understand the last statement, lets go to how sympy.plot() works.

In simple terms, the equations that we pass through the plot() function as arguments are actually stored in _series attribute. So we can indirectly say that the basic data of the plot is stored in this attribute. But using the _backend attribute wouldn’t alter _series at all and if _series remains empty at the start it would end up storing nothing.

But we are of course getting a decent plot at the end, so shouldn’t we probably ignore this? No, it would surely give the plot but we won’t be getting a fully defined Plot object which we can further use with PlotGrid to get a subplot which includes all the five plots related to the beam.

Keeping this in mind, I tried an alternative way to directly use sympy.plot()  to give the plot. Although a bit hard and time taking to do, I have intiated this in a draft PR #17345. This PR perfectly plots a rectangular beam and loads (except point and moment loads). Only things that are left here are to plot supports and arrows denoting the direction of the load.

The example below shows how it functions: (keep in mind it just plots the basic structure of the intended beam diagram, it hasn’t been completed yet)

>>> E, I = symbols('E, I')
>>> b = Beam(9, E, I)
>>> b.apply_load(-12, 9, -1)  # gets skipped
>>> b.apply_load(50, 5, -2)  # gets skipped
>>> b.apply_load(3, 6, 1, end=8)
>>> b.apply_load(4, 0, 0, end=5)
>>> b.draw()


I also tried to complete the leftover PR’s in this week, but still some work is left.

## Next week:

• Completing the draw() function
• Documentation and testing
• Starting Truss implementations

Will keep you updated!

Thanks!

#### Arighna Chakrabarty (arighnaiitg): GSoC Week 10 !!

Week 10 ends.. - Phase 3 of the GSoC coding period is traversong smoothly. !! I and Sartaj had a meeting on the 05th of August, about the timeline of the next 2 weeks. Here are the deliverables that have been completed in this week, including the minutes of the meeting. The second aseries...

#### Divyanshu Thakur (divyanshu132): GSoC 2019 - Week 10 - Induced Pcgs for polycyclic subgroups

The tenth week of coding period has ended and a new PRsympy/sympy#17317 has been introduced. The PR implements induced Pcgs and exponent vector for polycyclic subgroups with respect to the original pcgs of the group. Below is an example to show the functionality.

>>> from sympy.combinatorics import *
>>> S = SymmetricGroup(8)
>>> G = S.sylow_subgroup(2)
>>> gens = [G[0], G[1]]
>>> PcGroup = G.polycyclic_group()
>>> collector = PcGroup.collector
>>> ipcgs = collector.induced_pcgs(gens)
>>> [gen.order() for gen in ipcgs]
[2, 2, 2]



Further it can also be used to implement Canonical polycyclic sequence which can be used to check if two subgroups of polycyclic presented group G are equal or not.

For the next week I’ll try to complete the documentation work on polycyclic groups and open a PR for the same.

Till then, good byee..

## August 04, 2019

#### Jogi Miglani (jmig5776): GSoC 2019 - Week 10

This was the tenth week meeting with the GSoC mentors which was scheduled on Sunday 4th August, 2019 between 1:00 - 2:00 PM (IST). Me, Yathartha were the attendees of the meeting.

• Discussing previous week’s progress
1. Progress of _solve_modular:- In PR #16976 After discussing with Yathartha, I decided to change the basic model of the _solve_modular  such that I should be able to target equations more efficiently and also the rest of the types of equation should return ConditionSet. Cases like Mod(a**x, m) - rhs = 0 are special type and will be handled differently with the helper functions of ntheory module.

2. Progress of ImageSet Union:- In PR #17079 This PR is currently been left for review.

• Next week goals

• Work upon _solve_modular
• In the following week I will be changing the domain of solving equations to Integers only.

Code improvement takes time!!

## August 01, 2019

#### Arighna Chakrabarty (arighnaiitg): GSoC Week 9 !!

Week 9 ends.. - The last phase of this journey has started. I am happy to let you know that I have passed Phase 2 successfully. Phase 3 will include merging of some important code written in Phase 2, and also implementation of some other useful code. I had a meeting with Sartaj in...

## July 30, 2019

#### Shubham Kumar Jha (ShubhamKJha): GSoC 2019: Week 9

I spent most of this week getting #17144 ready to be merged. I had to change a lot of things from the last attempt. One of such was an attempt on early encoding, I had tried it on Literals. They were eventually going to be encoded so I tried to do this when Literals were created only. But as Aaron suggested, my approach had left encodings in the global space and hence could leak memory. During the week, I tried to attach encoding to the CNF object itself but it would have needed a lot of refactoring, since CNF objects interacted with other such objects. So, after some attempts, at the end I left the encoding to be done at last in EncodedCNF object. Currently, this is ready to be merged.

For the coming weeks, I would try to improve over this.

This was also the week for second monthly evaluation and I feel happy to announce that I passed it. From this week my college has also started but I am still able to give the required time to this project and complete it.

Will keep you updated. Thank you !

## July 29, 2019

#### Ishan Joshi (ishanaj): GSoC’19: Week-9- Analyzing the draw() function

With the end of this week the third phase officially ends.

There has been some discussions in the PR #17240 which implements the draw() function. We might change the name of the function to plot() which is more consistent with the previous beam methods plot_shear_force(), plot_bending_moment(), etc.

Another discussion was about making this beam diagram a part of the plot_loading_results(), which basically intends to plot all the beam related plots. Although currently the beam diagram uses matplotlib as an external module, whereas the plot_loading_results() uses PlotGrid which is Sympy’s internal functionality. So it would be a bit tricky to merge those two.

We also discussed the idea or rather the possibility of directly making use of SymPy’s own plot to create a beam diagram. SymPy’s plot() is capable to plotting Singularity functions, so the load applied on the beam can also be plotted using sympy.plot() as beam.load is indeed in terms of singularity function. But there is a problem when it comes to point loads and moment loads as the are in terms singularity function of negative order (or exponent). Not sure whether the sympy plot for singularity functions of negative order is plotted correctly, but the current plot won’t help us in drawing point loads and moment loads. We might have to deal with it separately.

I have opened a discussion in the mailing list regarding whether the plot is correct for singularity functions of negative order, or what else should be done in order to get it corrected.

Also, it will be difficult to plot a rectangle (for making beam) and markers (for making supports) via sympy.plot(). One idea is to go with the _backend attribute of sympy.plot() which helps in directly using the backend (i.e. matplotlib backend). I will have a look over it.

Of course if the beam diagram is made using SymPy’s own plot it would surely be preferred but for that we also need work on sympy.plot() as currently it is limited to certain functionalities.

From the next week I will be starting with the last phase of implementing a Truss structure and its respective calculations.

Since only last few weeks are left, I think I will be able to make a draft PR for the last phase implementation by the end of the next week. And then we would only be left with minor things and leftovers of the previous phases.

Also, I am glad to share that I was able to pass the second evaluations. So once again thank you mentors for all your support and guidance!

## Next Week:

• Starting phase-IV  implementations
• Simultaneously working and discussing previous PR’s.

Will keep you updated!

Thanks!

Planet SymPy is made from the blogs of SymPy's contributors. The opinions it contains are those of the contributor. This site is powered by Rawdog and Rawdog RSS. Feed readers can read Planet SymPy with RSS, FOAF or OPML.