python experiment

Headers, Bindings, Libraries for use with FreeBASIC, Please include example of use to help ensure they are tested and usable.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: python experiment

Post by caseih »

Correct. ctypes is, in Python 3 at least, a built-in module.

Python 3 is definitely faster than Python 2. If you're trying to do a lot of intensive math calculations in Python, you will be disappointed compared to compiled FB performance. However in the scientific and math community Python is often used because expressivity (the algorithm) is often more important than raw speed. That said, compiled extensions like numpy, provide Python with certain kinds of super-fast math tools. When speed is needed, it's necessary to dip into C (compiled languages anyway). Although Python can be easily extended with C (and maybe FB if enough interfaces are converted), a lot of people use a tool called Cython, which is a subset of the Python syntax that compiles via gcc to a binary Python extension. There is also work being done on implementing a Python interpreter with Python, using advanced JIT compiling techniques. And indeed an integer math program executed in PyPy can be achieve speeds of nearly 50% of a compiled C equivalent. Pretty impressive, honestly. And also there is a guy who's made an actual Python compiler, which he calls nuitka. For some code it is nearly as fast a C binary. For others (most), not nearly as much, due to the dynamic nature of Python.

I can see how FB would be nice for writing Python extensions. What kinds of things would you use embedded Python inside of FB to do? Use it as a scripting language like how games use Lua? FreeCAD does this.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: python experiment

Post by dodicat »

Hi casieh
You obviously know a little bit about python.
It is a language which seems to be creeping into modern day computing.
My niece is doing a course in computing and python is their chosen route.
It is supposed to be easy learn, easy on the eye (readability).
I would agree up to a point, but writing scripts inside a freebasic string is a bit of a spoiler.
Anyway, this thread is just an experiment to run python within one working folder, for those few who do not have or want python installed in windows.
Any new imported (libraries) in the form of a .py file can be popped into the folder and called.
Python then automatically creates the .pyc import in folder __pycache__ (which it also creates).
I think other languages can embed python in this manner, so why not try fb.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: python experiment

Post by jj2007 »

Python is slow - if you use native Python code in a speed-critical loop. If, however, you let its internal routines (coded in C or Assembly) do their job, it can by faster than anything else. Google fastest sort algorithm python to see what I mean.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: python experiment

Post by dodicat »

Hi jj2007.
Thank you.
The code as it stands in your link (timsort) is very slow and seems in error.
Also it chokes at a larger array.
here is psort.py (which is the timsort function in your link)

Code: Select all

# based off of this code https://gist.github.com/nandajavarma/a3a6b62f34e74ec4c31674934327bbd3
# Brandon Skerritt
# https://skerritt.tech

def binary_search(the_array, item, start, end):
    if start == end:
        if the_array[start] > item:
            return start
        else:
            return start + 1
    if start > end:
        return start

    mid = round((start + end)/ 2)

    if the_array[mid] < item:
        return binary_search(the_array, item, mid + 1, end)

    elif the_array[mid] > item:
        return binary_search(the_array, item, start, mid - 1)

    else:
        return mid

"""
Insertion sort that timsort uses if the array size is small or if
the size of the "run" is small
"""
def insertion_sort(the_array):
    l = len(the_array)
    for index in range(1, l):
        value = the_array[index]
        pos = binary_search(the_array, value, 0, index - 1)
        the_array = the_array[:pos] + [value] + the_array[pos:index] + the_array[index+1:]
    return the_array

def merge(left, right):
    """Takes two sorted lists and returns a single sorted list by comparing the
    elements one at a time.
    [1, 2, 3, 4, 5, 6]
    """
    if not left:
        return right
    if not right:
        return left
    if left[0] < right[0]:
        return [left[0]] + merge(left[1:], right)
    return [right[0]] + merge(left, right[1:])

def timsort(the_array):
    runs, sorted_runs = [], []
    length = len(the_array)
    new_run = [the_array[0]]

    # for every i in the range of 1 to length of array
    for i in range(1, length):
        # if i is at the end of the list
        if i == length - 1:
            new_run.append(the_array[i])
            runs.append(new_run)
            break
        # if the i'th element of the array is less than the one before it
        if the_array[i] < the_array[i-1]:
            # if new_run is set to None (NULL)
            if not new_run:
                runs.append([the_array[i]])
                new_run.append(the_array[i])
            else:
                runs.append(new_run)
                new_run = []
        # else if its equal to or more than
        else:
            new_run.append(the_array[i])

    # for every item in runs, append it using insertion sort
    for item in runs:
        sorted_runs.append(insertion_sort(item))
    
    # for every run in sorted_runs, merge them
    sorted_array = []
    for run in sorted_runs:
        sorted_array = merge(sorted_array, run)
    #print("infile ",sorted_array)
    return(sorted_array)

#timsort([2, 3, 1, 5, 6, 7]) 
and here is the test code

Code: Select all

#inclib "python37"
#include "file.bi"
'=====================================
Declare Sub  Pyinit Cdecl  Alias "Py_Initialize"()
Declare Function runstring Cdecl Alias "PyRun_SimpleString"(Byval s As zstring Ptr) As Integer
Declare Sub setname Cdecl Alias "Py_SetProgramName"(As String)
Declare Function PyMain Cdecl Alias "Py_Main"(As Long=0,Byref As zstring Ptr =0) As Long
Declare Sub Pyfinish Cdecl Alias "Py_Finalize"()

Sub runfile(filename As String)
    runstring("exec(open('"+filename+"').read())") 
End Sub

Sub runfileex(filename As String,flag As boolean=true)
    runstring( "fp=open('"+filename+"','r')")
    runstring("codestring=fp.read()")
    If flag Then runstring("print(codestring)")
    runstring("exec(codestring)")
End Sub

Sub savefile(filename As String,file_content As String)
    Dim As Integer n
    n=Freefile
    If Open (filename For Binary Access Write As #n)=0 Then
        Put #n,,file_content
        Close
    Else
        Print "Unable to save " + filename
    End If
End Sub

Function loadfile(file As String) As String
    If Fileexists(file)=0 Then Print file;" not found":Sleep:End
    Var  f=Freefile
    Open file For Binary Access Read As #f
    Dim As String text
    If Lof(f) > 0 Then
        text = String(Lof(f), 0)
        Get #f, , text
    End If
    Close #f
    Return text
End Function


#macro pysort(a)
scope
     Dim As String s="L=["
    For n As Long=Lbound(a) To Ubound(a)
        s+=Str(a(n))+","
    Next
    s=Rtrim(s,",")
    s+="]"
    dim as string script
    script ="import psort"+Chr(10)
    script+=s+Chr(10)
    script+="result=(psort.timsort(L))"+Chr(10)
    script+="fp=open('sortedlist.txt','w')"+chr(10)
    script+="for z in result:"+chr(10)
    script+=" fp.write(str(z)+chr(10))"+chr(10)
    script+="fp.close"
    Pyinit
    runstring script
    Pyfinish
    end scope
#endmacro

dim as integer d(1 to ...)={2,3,1,5,6,7}
pysort(d)
print loadfile("sortedlist.txt")
print "Press a key to continue . . ."
sleep
redim as double x(1400)
for n as long=0 to ubound(x)
    x(n)= rnd*2000
next
dim as double t=timer
pysort(x)
dim as double t2=timer-t
print loadfile("sortedlist.txt")
print
print "time taken = ";t2;" seconds"
kill "sortedlist.txt"
if fileexists("sortedlist.txt") then print "Delete sortedlist.txt manually"

 
psort.py goes into the working folder along with the test code.
Of course the full code in the link (3376 lines) will probably be the ticket.
I'll mess around with it later.
Post Reply