Skip to content

Latest commit

 

History

History
475 lines (402 loc) · 17.2 KB

symbolicModuleTest.rst

File metadata and controls

475 lines (402 loc) · 17.2 KB

symbolicModuleTest.py

You can view and download this file on Github: symbolicModuleTest.py

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# This is an EXUDYN example
#
# Details:  Tests for symbolic scalar, vector and matrix
#
# Author:   Johannes Gerstmayr
# Date:     2023-12-14
#
# Copyright:This file is part of Exudyn. Exudyn is free software. You can redistribute it and/or modify it under the terms of the Exudyn license. See 'LICENSE.txt' for more details.
#
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
import exudyn as exu
from exudyn.utilities import * #includes itemInterface and rigidBodyUtilities
import exudyn.graphics as graphics #only import if it does not conflict

useGraphics = False #without test
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#you can erase the following lines and all exudynTestGlobals related operations if this is not intended to be used as TestModel:
try: #only if called from test suite
    from modelUnitTests import exudynTestGlobals #for globally storing test results
    useGraphics = exudynTestGlobals.useGraphics
except:
    class ExudynTestGlobals:
        pass
    exudynTestGlobals = ExudynTestGlobals()
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

esym = exu.symbolic
import numpy as np
import math

#reset counters:
esym.Real.__newCount = 0
esym.Real.__deleteCount = 0
esym.Vector.__newCount = 0
esym.Vector.__deleteCount = 0
esym.Matrix.__newCount = 0
esym.Matrix.__deleteCount = 0

SymReal = esym.Real

def Not(value):
    return not value

def PyRealName(name, value):
    return value

def PyNamedVector(name, value):
    return np.array(value)

def Evaluate(value):
    #print(str(value))
    if (type(value) == esym.Real
        or type(value) == esym.Vector
        or type(value) == esym.Matrix
        ):
        return value.Evaluate()
    if type(value) == np.ndarray:
        value = value.copy() #requires copy, to store results!
    return value

def Min(a,b):
    return a if a<b else b
def Max(a,b):
    return a if a>b else b

math.sign = np.sign #to have function in math
math.Not = Not
math.abs = np.abs
math.mod = math.fmod
math.min = Min
math.max = Max
math.round = np.round
math.ceil = np.ceil
math.floor = np.floor
math.acosh=np.arccosh #numpy agrees to 16 digits with std::acosh, math.acosh not


scalarTests = True
vectorTests = True
debug = False
caseSymbolic = 0   #exudyn.symbolic
casePython = 1     #Python

listFunctions = ['abs', 'sign', 'Not',
                 'round', 'ceil', 'floor', 'exp',
                 'sqrt', 'log',
                 'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
                 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh',]

listBinFunctions = ['pow', 'atan2', 'mod', 'min', 'max']


# some integers, zeros, Reals, etc.
listNumbers = [-3,0,2,-0.13157932734543,0.,0.2345473645342,math.pi]
# listNumbers = [-0.13157932734543,0.,math.pi]
listResults = []
currentResult = [] #0=symbolic, 1=math/numpy
cntWrong = 0
cntTests = 0
sumResults = 0.
if scalarTests:
    #for recording in []:
    for recording in [True,False]:
    # for recording in [True]:
        if debug: exu.Print('***********')
        if recording:
            if debug: exu.Print('WITH RECORDING')
        else:
            if debug: exu.Print('WITHOUT RECORDING')
        for number in listNumbers:
            if debug: exu.Print('NUMBER=',number)

            esym.SetRecording(recording)

            result = [[],[]]
            for case in [0,1]:
                if case == 0:
                    Real = SymReal
                    NamedReal = SymReal
                    lib = esym
                else:
                    Real = float
                    NamedReal = PyRealName
                    lib = math

                a = Real(number)
                b = NamedReal("b",math.pi)
                c = NamedReal("c",-0.1)
                result[case] += [Evaluate(a)]
                result[case] += [Evaluate(b)]
                result[case] += [Evaluate(c)]

                d = a+lib.sin(a/b)**2+lib.tan(a)*lib.cos(a)*c*3
                result[case] += [Evaluate(d)]
                result[case] += [Evaluate(a+b)]
                result[case] += [Evaluate(b+a)]
                result[case] += [Evaluate(b-a)]
                result[case] += [Evaluate(a-b)]
                result[case] += [Evaluate(b*a)]
                result[case] += [Evaluate(a*b)]
                result[case] += [Evaluate(a/b)]
                result[case] += [Evaluate(a/3)]
                result[case] += [Evaluate(-a)]
                result[case] += [Evaluate(+a)]
                result[case] += [Evaluate(b**a)]
                # result[case] += [Evaluate(1**a)] #does not WORK!

                # +=,-=
                d = Real(0)
                result[case] += [Evaluate(d)]
                d += a
                result[case] += [Evaluate(d)]
                #Real delete count wrong from here:
                d -= a*b
                result[case] += [Evaluate(d)]
                d *= a
                result[case] += [Evaluate(d)]
                if (float(a) != 0.):
                    d /= a
                    result[case] += [Evaluate(d)]

                f = a < b
                result[case] += [Evaluate(f)]
                f = a <= b
                result[case] += [Evaluate(f)]
                f = a > b
                result[case] += [Evaluate(f)]
                f = a >= b
                result[case] += [Evaluate(f)]
                f = a == b
                result[case] += [Evaluate(f)]
                f = a != b
                result[case] += [Evaluate(f)]

                #functions
                for funcStr in listFunctions:
                    if funcStr=='log':
                        if number <= 0: continue
                    if funcStr=='sqrt':
                        if number < 0: continue
                    if funcStr=='acosh':
                        if number < 1 : continue
                    if funcStr=='atanh':
                        if abs(number) >= 1 : continue
                    if funcStr=='acos' or funcStr=='asin':
                        if abs(number) > 1 : continue

                    func = getattr(lib, funcStr)
                    # if debug: exu.Print(funcStr)
                    d = func(a)
                    if debug: exu.Print('  '+funcStr+'('+str(Evaluate(a))+')=',Evaluate(d))
                    result[case] += [Evaluate(d)]

                #binary functions
                for funcStr in listBinFunctions:
                    func = getattr(lib, funcStr)
                    #if debug: exu.Print(funcStr)
                    d = func(a,2)
                    if debug: exu.Print('  '+funcStr+'('+str(Evaluate(a))+','+str(Evaluate(b))+')=',Evaluate(d))
                    result[case] += [Evaluate(d)]

                #ifthenelse
                if case==0:
                    f = lib.IfThenElse(a, a+1, b+a)
                else:
                    f = a+1 if a else b+a
                result[case] += [Evaluate(f)]


            result = np.array(result).T.tolist()
            cntTests += len(result)

            for res in result:
                s = 'correct'
                sumResults += res[0]
                if res[0] != res[1]:
                    s = 'WRONG:'
                    s += str(res[0]-res[1])
                    cntWrong+=1
                if debug: exu.Print('. res sym:',res[0], ', res Py:', res[1], s)

#%%++++++++++++++++++++++++++++++++++++++++++++++++++++
#Vector-Matrix
SymVector = esym.Vector
SymMatrix = esym.Matrix

if vectorTests:
    for recording in [False,True]:
    # for recording in [True]:
        if debug: exu.Print('***********')
        if recording:
            if debug: exu.Print('WITH RECORDING')
        else:
            if debug: exu.Print('WITHOUT RECORDING')

        esym.SetRecording(recording)

        result = [[],[]]
        for case in [1,0]:
            if debug: exu.Print('*********\ncase:',case)
            if case == 0:
                Real = SymReal
                NamedReal = SymReal
                lib = esym
                Vector = esym.Vector
                NamedVector = esym.Vector
                Matrix = esym.Matrix
            else:
                Real = float
                NamedReal = PyRealName
                lib = math
                Vector = np.array
                NamedVector = PyNamedVector
                Matrix = np.array

            a = NamedReal("a",0.5)
            b = NamedReal("b",math.pi)

            v = Vector([1.3])
            w = Vector([4.2])
            result[case] += [Evaluate(v+w)]

            v = NamedVector('vv',[1,2])
            w = Vector([4.2-1,-1.2-1])
            x = Vector([0.,0.])

            if case == 0:
                w.SetVector([4.2,-1.2])
                d = 3.3*v+a*w+(v*w)*v
                x[0] += d.NormL2()
                x[1] += Evaluate(v == v )
                x[1] += Evaluate(v == Vector([1,2.1]) )
                x[1] += Evaluate(v != Vector([1,2.1]) )
                x[1] += Evaluate(v == Vector([1,2.]) )
                x[1] += Evaluate(v != Vector([1,2.]) )
            else:
                w = np.array([4.2,-1.2])
                d = 3.3*v+a*w+(v@w)*v
                x[0] += np.linalg.norm(d)
                x[1] += (v == v ).all()
                x[1] += (v == Vector([1,2.1]) ).all()
                x[1] += (v != Vector([1,2.1]) ).any()
                x[1] += (v == Vector([1,2.]) ).all()
                x[1] += (v != Vector([1,2.]) ).any()

            result[case] += [Evaluate(x)]

            result[case] += [Evaluate(d)]
            result[case] += [Evaluate(v+w)]
            result[case] += [Evaluate(v-w)]
            if case==0:
                n = w.NumberOfItems()
                result[case] += [Evaluate(v*w)]
                # print('v0:',x)
            if case==1:
                n = len(w)
                result[case] += [Evaluate(v@w)]
                # print('v1:',x)
            x = Vector([n,1.1])

            result[case] += [Evaluate(x)]
            result[case] += [Evaluate(v)]
            result[case] += [Evaluate(-v)]
            result[case] += [Evaluate(a*v)]
            result[case] += [Evaluate(v*a)]
            result[case] += [Evaluate(3.3*v)]
            result[case] += [Evaluate(v*3.3)]

            v = Vector([-0.33,0.347,1.5])
            w = Vector([4.2,-1.2+10,7.7])
            w[1] = -1.2
            result[case] += [Evaluate(w)]

            result[case] += [Evaluate(d)]
            result[case] += [Evaluate(v+w)]
            result[case] += [Evaluate(v-w)]

            if case==0:
                result[case] += [Evaluate(v*w)]
                result[case] += [Evaluate(v.MultComponents(w))]

            if case==1:
                result[case] += [Evaluate(v@w)]
                result[case] += [Evaluate(v*w)]

            result[case] += [Evaluate(v)]
            result[case] += [Evaluate(-v)]
            result[case] += [Evaluate(a*v)]
            result[case] += [Evaluate(v*a)]
            result[case] += [Evaluate(3.3*v)]
            result[case] += [Evaluate(v*3.3)]

            u = Vector([0.,0.,0.])
            u += 2*v
            # print('case'+str(case)+': 2*v=',Evaluate(2*v),', v=',v,', u=',u)
            u = u + 2*v
            result[case] += [Evaluate(u)]
            u -= v
            result[case] += [Evaluate(u)]
            result[case] += [Evaluate(u==v)]
            result[case] += [Evaluate(u!=v)]
            u *= a
            result[case] += [Evaluate(u)]
            u *= 1/3
            result[case] += [Evaluate(u)]
            result[case] += [Evaluate(u==v)]
            result[case] += [Evaluate(u!=v)]

            #MATRIX MATRIX MATRIX
            M = Matrix(np.array([[2.,0.1,0.33],
                                 [-0.1,2.3,0.7],
                                 [0,0.34,1.8]]))
            N = Matrix(np.array([[1.,0.3,-0.33],
                                 [-0.9,1.3,-0.7],
                                 [0,0.64,-1.8]]))
            result[case] += [Evaluate(N)]

            if case==0:
                M02 = M[0,2].Evaluate()
                M20 = M[2,0].Evaluate()

                if (M02 != M.Get(0,2).Evaluate()):
                    M02 = -1000
                    #print('*****************ERROR')
                nr = M.NumberOfRows()
                nc = M.NumberOfColumns()

                N.SetMatrix(np.array([[(nr+nc)/6,0.3,-M02],
                                     [-0.9,1.3,-0.7],
                                     [M20,0.64+100,-1.8]]))
                N[2,1] = 0.64

            result[case] += [Evaluate(N)]

            result[case] += [Evaluate(M)]
            result[case] += [Evaluate(a*M)]
            result[case] += [Evaluate(0.5*M)]
            result[case] += [Evaluate(M*a)]
            result[case] += [Evaluate(M*0.5)]
            result[case] += [Evaluate(M+N)]
            result[case] += [Evaluate(M-N)]
            if case==0:
                result[case] += [Evaluate(M*N)]
                result[case] += [Evaluate(M*v)]
                result[case] += [Evaluate(v*M)]
            if case==1:
                result[case] += [Evaluate(M@N)]
                result[case] += [Evaluate(M@v)]
                result[case] += [Evaluate(v@M)]

            P = 0.*M
            result[case] += [Evaluate(P)]

            #matrix delete counts wrong starting here:
            P += N
            result[case] += [Evaluate(P)]
            P -= M
            result[case] += [Evaluate(P)]
            P *= 1.3
            result[case] += [Evaluate(P)]


        # result = np.array(result).T.tolist() #doesnt work for mixed components
        cntTests += len(result[0])
        for i in range(len(result[0])):
            res = [result[0][i],result[1][i]]
            s = 'correct'
            sumResults += np.linalg.norm(res[0])
            #if (res[0] != res[1]).any():  #problem with 1e-16 errors
            wrong = False
            if np.linalg.norm(res[0] - res[1]) > 1e-15:
                s = '\\diff:\n'
                s += str(res[0]-res[1])
                cntWrong+=1
                wrong=True
            if debug or wrong:
                exu.Print('. res sym:\n',res[0], ',\n  res Py:\n', res[1], s)

#%%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#cleanup and check new/delete
if True:
    del a,b,c,d,f
    del u,v,w,x
    del M,N,P

    #check sum of new/delete
    newDelSum = 0
    newDelSum += esym.Real.__newCount-esym.Real.__deleteCount
    newDelSum += esym.Vector.__newCount-esym.Vector.__deleteCount
    newDelSum += esym.Matrix.__newCount-esym.Matrix.__deleteCount
    if newDelSum != 0:
        exu.Print('*******************')
        exu.Print('*  WARNING        *')
        exu.Print('New-Del=',newDelSum)
        exu.Print('*******************')
    sumResults += newDelSum

exu.Print('Real.newCount=',esym.Real.__newCount)
exu.Print('Real.deleteCount=',esym.Real.__deleteCount)

exu.Print('Vector.newCount=',esym.Vector.__newCount)
exu.Print('Vector.deleteCount=',esym.Vector.__deleteCount)

exu.Print('Matrix.newCount=',esym.Matrix.__newCount)
exu.Print('Matrix.deleteCount=',esym.Matrix.__deleteCount)

#%%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

exu.Print('\nfinished',cntTests,'tests')
exu.Print('WRONG results (after vectorTests):',cntWrong,'\n')

#
u = sumResults/1000
exu.Print('u=',u)
exu.Print('solution of symbolicModuleTest=',u)

# result for 10000 steps; identical for both UF cases
exudynTestGlobals.testError = u - (0.9480053738744615)
exudynTestGlobals.testResult = u