Learning PyQt

One of my recent undertakings has been, to extend my knowledge of Python, which I was previously only capable of writing procedural code for, to include, how to write Object-Oriented Python.

In the process, I began to think of what advantages I might now have, with that ability. And one answer which presented itself was of the form, ‘I already know enough about the Qt Library, to use it for some C++ programs. It has a Python binding referred to sometimes as PyQt. With the ability to write Object-Oriented Python, I should also gain the ability to write GUI applications in Python – eventually.’

The result of my recent exercise can be found at this URL:

https://dirkmittler.homeip.net/binaries/

The compressed files which contain my first project using PyQt are named ‘PyQt_Test_1_s.gz‘ and ‘PyQt_Test_1_s.zip‘. Those compressed archives need to be unzipped to a folder, in which there should be a total of 4 Python scripts. Python 3 would need to be run on the script named ‘AppStart.py’.

I’m sorry to start so small.

Oh, yes… In order for these scripts to run, the reader’s Python installation must include PyQt. Not all do.

Dirk

A little cheat-sheet, on how to wrap Python mpmath procedurals inside regular SageMath expressions.

The following link should not be taken, as the complete solution to anybody else’s computing task, in which my readers might want to wrap Python code for use in SageMath. In fact, I don’t even consider myself an expert in either of these subjects.

For people who do not know, “SageMath” is a combination of “Computer Algebra System” – ‘CAS’ – and ‘Numerical Toolbox’. SageMath is written using multiple languages, mainly Python. And, the ‘Maxima’ CAS back-end was written in LISP. ‘mpmath’ is a specific Python package, that allows Multi-Precision Arithmetic.

The integration of ‘mpmath’ is particularly straightforward, because Sage already uses this package. But the principles that would be used for other Python packages are similar. An interface must be established, by which Sage objects can be translated into the objects specific to the external Python packages, and back into objects that Sage can recognize again. Objects that Sage finds particularly useful, are ‘Symbolic Functions’ – that are to be manipulated algebraically – and ditto for ‘Symbolic Expressions’.

If worse comes to worst, then the data generated by the external, ‘wrapped’ code, may be converted into native Python objects such as ~Strings~. However, Sage does not recognize strings as valid Symbolic Expressions. So, one way around that could be, to call Sage’s ‘sage_eval()‘ function on the strings. (:1)

 

http://dirkmittler.homeip.net/LambertW%20Test%203%20–%20Sage.html

 

(Updated 7/28/2021, 12h15… )

Continue reading A little cheat-sheet, on how to wrap Python mpmath procedurals inside regular SageMath expressions.

Proof that FreeFem allows a Simple Integral, to be restated as a PDE, and then solved over 1 axis.

My recent postings have rambled at some length, about the open-source program ‘FreeFem’, the purpose of which is, to solve Partial Differential Equations, which are strictly defined, but which often won’t have exact, analytical solutions. FreeFem approximates their solutions numerically.

My own formal background doesn’t extend much beyond Calculus 2, such that I wasn’t even taught “Ordinary Differential Equations” – aka ‘ODE’s – in a classroom. But what that really means, is just, that I can’t solve one manually. I can still comprehend what problem is being defined, and, given computers that can solve those, can also feed them to my computers to solve.

Of course, ‘PDE’s are more difficult than ODEs, because PDEs are multi-variable.

Long story short, my recent postings have had two main subjects: They have asserted that real-world PDEs, like real-world ODEs, are usually more complicated, than just a form that can be converted directly into an integral. And secondly, I’ve mused over how, then, FreeFem will go about solving them anyway. That second part is speculative.

But, just to make my point, the following is a PDE, which only makes full use of 1 out of its 2 available variables, and which happens to be simple enough, to state a simple integral, but to state it implicitly. Here the FreeFem script:

 

// For label definition.
int Bottom=1;
int Right=2;
int Top=3;
int Left=4;

// The triangulated domain Th is on the left side of its boundary.
mesh Th = square(10, 10, [(x*2)-1., (y*2)-1.]);
plot(Th, ps="ThRectX.eps", wait = true);

// Define a function f.
func f = x * y;

// The finite element space defined over Th is called Vh here.
fespace Vh(Th, P2);
Vh u, v;	// Declare u and v as piecewise P2-continuous functions.

// Get the clock in seconds.
real cpu=clock();

// Define a PDE, that just integrates f with respect to Y...
solve SimpleXInt(u, v)
	= int2d(Th)(
		dy(u) * v			// Let this be valid syntax.
	)
	- int2d(Th)(
		f*v
	)
	+ on(Bottom, u=0);		// The boundary condition at the start of the integral.

// Plot the result...
plot(u, cmm="Is this an example of the Poisson Equation? f=x*y",
	ps="SimpIntX.eps", value=true, wait = true);

// Display the total computational time.
cout << "CPU time = " << (clock()-cpu) << endl;

 

The way this script works hinges on a simple idea: ‘dx(u)‘ can accurately be computed by FreeFem as ‘the derivative of (u) with respect to (x)’, and evaluates to a real number. Since it was possible just to multiply a function that also evaluates to a real number by ‘v‘, and thus form the RHS of the equation, it should be just as easy, to write ‘dx(u) * v‘ as the LHS. And, after having fixed some minor technicalities peculiar to computing first-order integrals, one can see that this valid syntax computes ‘f(x,y):=x*y‘, and then integrates it once, in the direction that the Y-axis is positive.

 

ImplInt_1

 

SimpIntX

 

Predictable.

(Updated 7/25/2021, 22h00… )

Continue reading Proof that FreeFem allows a Simple Integral, to be restated as a PDE, and then solved over 1 axis.

Proving that FreeFem is capable of solving PDEs, in which a boundary’s values exist as a function, and not as a constant.

One of the subjects which have been fascinating me in recent days and weeks, has been the program ‘FreeFem’, which is an open-source program, that approximates solutions to “Partial Differential Equations” – ‘PDE’s – such that the solutions result as Finite Element functions, the interpolations of which are also continuous.

A stipulation is to be solved for each time, that an equation that subtracts some sort of ‘regular function’ from the gradients of the solution-function, results in values that converge on zero. Presumably, one of the many strategies which FreeFem applies, to achieve this result, is successive approximation. I’ve written in numerous postings, what my hypotheses are, as to the detailed calculations which FreeFem might be performing. But in reality, the program achieves its goals so well, that the underlying Math can be difficult if not impossible to reveal, in a scripting language which is supposed to solve the PDE instead, in such a way that evidence of the methodology cancels out, on the solution. Thus, I have no real proof for most of my hypotheses.

One recent observation which I did want to follow up my own postings about, was, that the default situation for the PDEs is one, in which a Test Function is to be matched by the gradients of the solution, and, that Dirichlet Boundaries are defined, at which the value of the solution must be one exact value for each boundary. In contrast with this situation, FreeFem allows PDEs to be defined using the ‘- int1d(...) (...)‘ expression, which then replaces such a Test Function, and which effectively tells the solver, ‘Please don’t integrate this function.’

And, because the developers became ambitious with their goal, that very complicated meshes can be constructed and then solved over, that have numerous boundaries and not just 2 or 4, I suppose this also means that a PDE of the sort which I just described will receive values of some sort, as long as at least 1 boundary receives a Dirichlet value.

The following script generates and then plots such a PDE:

 

// Load Cubic polynomial interpolator
load "Element_P3";

// Caution:
// Cubic interpolations are often unneccessary, and may
// overshoot their endpoints.
// They're usually only needed, for second-degree
// Derivatives, which lead to second-order Differential Equations.

// A P3-derived fespace will nevertheless be used here.

// For label definition.
int Outer = 1;
int Inner = 2;

// Define mesh boundary.
border C1(t=0, 2*pi){x=cos(t); y=sin(t); label=Outer;}
border C2(t=0, 2*pi){x=cos(t) * 0.5 + 0.2; y=sin(t) * 0.5 + 0.2;
						label=Inner;}

// The triangulated domain Th is on the left side of its boundary.
mesh Th = buildmesh(C1(100) + C2(-40));
plot(Th, ps="ThWithHole.eps", wait = true);

// Define a function f.
real Pi = 3.1415926536;
func f = sin(Pi * x) * cos(Pi * y);

// The finite element space defined over Th is called Vh here.
fespace Vh(Th, P3);
Vh u, v;	// Declare u and v as piecewise P3-continuous functions.

// Get the clock in seconds.
real cpu=clock();

// Define a PDE, in which the values of the outer boundary are defined by f...
solve Poisson(u, v, solver=LU)
	= int2d(Th)(    	// The bilinear part
		  (dx(u) * dx(v))
		+ (dy(u) * dy(v))
	)
	- int1d(Th, Outer)(	// Applying the 1-D boundary function.
		f * v
	)
	+ on(Inner, u=0);   // The Dirichlet boundary condition

// Plot the result...
plot(u, ps="VariableBoundaries.eps", value = true);

// Display the total computational time.
cout << "CPU time = " << (clock()-cpu) << endl;

 

(Revised 7/19/2021, 19h30. )

And, the following is the relevant plot that results:

 

VariableBoundaries

 

(Update 7/21/2021, 16h40: )

If I combine this observation, with what I wrote in a previous posting, I surmise that the solver will first process the boundary ‘Outer‘, by applying function ‘f()‘, with interpolation weights, over all of (v), negatively, but in a way that ultimately depends on what ‘f()‘ was on that boundary. And then, when the boundary ‘Inner‘ is to be processed, the solver will apply the value (0.) over (u) as well as (v), using the same methodology, that involves a new set of weights specific to ‘Inner‘.

Then, (u) will be adjusted, by multiplying the values of the expression with ‘sign(sign(dx(v) + dy(v)) + 0.5)‘, and subtracting (the values of the expression) from (u), until those values become sufficiently close to zero, for all combinations of (x,y).

Why not?


 

(Update 7/20/2021, 11h30: )

In order for changes which are being written to (u), to cause ‘the values of the expression’ to converge on zero, the contribution which the term starting on Line 38 makes to the value of the expression, must still be an integral.

Presumably, FreeFem stores the values of the expression, as two hidden properties of the mesh, which the user, who is writing and testing the script, has no access to. One of those properties would simply act as ‘a temporary buffer’, which allows interpolation between actual, computed values, while the other will receive the result from the interpolation.

If the optimization is desired, that the term starting on Line 42 is only to be computed once, since what is being computed there does not, itself, depend on (u), the mesh would need to possess a third hidden property, where that can be stored (or, which constant values from multiple, Linear terms in the expression can be added to).

And, it’s because Line 38 is still being computed as an integral, that the boundary values of (u) in the upper-right-hand quadrant of the plot (along the non-constant boundary ‘Outer‘), do not quite reach the (negative) amplitudes, which the boundary-values of (u), in the lower-right-hand quadrant of the plot, reach.


 

(Update 7/20/2021, 20h50… )

Note:

Throughout this blog, I’ve been referring to PDE boundaries that have a constant value as ‘the Dirichlet Boundaries’, while in this posting, referring to ‘the boundary that has a non-constant value’, as such. This is really just an arbitrary way I have of differentiating between two types of FreeFem syntax, that does not have much formal validity.

Be that as it may, FreeFem requires at least 1 boundary to have a constant value, in order to generate values for the plot, since this is also its starting point of an integration.

 

 

Enjoy,
Dirk