1# Copyright (c) 2011-2012, Thomas Paviot (tpaviot@gmail.com)
2# All rights reserved.
3
4# This file is part of the StepClassLibrary (SCL).
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9#   Redistributions of source code must retain the above copyright notice,
10#   this list of conditions and the following disclaimer.
11#
12#   Redistributions in binary form must reproduce the above copyright notice,
13#   this list of conditions and the following disclaimer in the documentation
14#   and/or other materials provided with the distribution.
15#
16#   Neither the name of the <ORGANIZATION> nor the names of its contributors may
17#   be used to endorse or promote products derived from this software without
18#   specific prior written permission.
19
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23# ARE DISCLAIMED.
24# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
25# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32__doc__ = "This module defines EXPRESS built in constants and functions"
33import math
34
35from SimpleDataTypes import *
36from BaseType import Aggregate
37from AggregationDataTypes import *
38
39SCL_float_epsilon = 1e-7
40# Builtin constants
41
42# EXPRESS definition:
43# ===================
44#14.1 CONST_E is a REAL constant representing the mathematical value e, the base of the natural
45#logarithm function (ln).
46CONST_E = REAL(math.pi)
47
48# EXPRESS definition:
49# ===================
50#14.2 Indeterminate
51#The indeterminate symbol (?) stands for an ambiguous value. It is compatible with all data
52#types.
53#NOTE - The most common use of indeterminate (?) is as the upper bound specication of a bag,
54#list or set. This usage represents the notion that the size of the aggregate value dened by the
55#aggregation data type is unbounded.
56# python note: indeterminate value is mapped to None in aggregate bounds
57
58# EXPRESS definition:
59# ===================
60#14.3 False
61#false is a logical constant representing the logical notion of falsehood. It is compatible with
62#the boolean and logical data types.
63FALSE = False
64
65# EXPRESS definition:
66# ===================
67#14.4 Pi
68#PI is a REAL constant representing the mathematical value , the ratio of a circle's circumference
69#to its diameter.
70PI = REAL(math.pi)
71
72# EXPRESS definition:
73# ===================
74#14.5 Self
75#SELF refers to the current entity instance or type value. self may appear within an entity
76#declaration, a type declaration or an entity constructor.
77#NOTE - sSELF is not a constant, but behaves as one in every context in which it can appear.
78# python note: SELF is not mapped to any constant, but is mapper to self
79
80# EXPRESS definition:
81# ===================
82#14.6 True
83#true is a logical constant representing the logical notion of truth. It is compatible with the
84#boolean and logical data types.
85TRUE = True
86
87# EXPRESS definition:
88# ===================
89#14.7 Unknown
90#unknown is a logical constant representing that there is insucient information available to
91#be able to evaluate a logical condition. It is compatible with the logical data type, but not
92#with the boolean data type.
93# @TODO: define UNKNOWN in python
94
95#
96# Builtin Functions
97#15 Built-in functions
98#All functions (and mathematical operations in general) are assumed to evaluate to exact results.
99#The prototype for each of the built-in functions is given to show the type of the formal parameters
100#and the result.
101#
102
103# EXPRESS definition:
104# ===================
105#15.1 Abs - arithmetic function
106#FUNCTION ABS ( V:NUMBER ) : NUMBER;
107#The abs function returns the absolute value of a number.
108#Parameters : V is a number.
109#Result : The absolute value of V. The returned data type is identical to the data type of V.
110#EXAMPLE 125 { ABS ( -10 ) --> 10
111# Python definition:
112# ==================
113# ABS is mapped to python abs builtin function
114def ABS(V):
115    if not isinstance(V,NUMBER):
116        raise TypeError("ABS function takes a NUMBER parameter")
117    return type(V)(abs(V))
118
119# EXPRESS definition:
120# ===================
121#15.2 ACos - arithmetic function
122#FUNCTION ACOS ( V:NUMBER ) : REAL;
123#The acos function returns the angle given a cosine value.
124#Parameters : V is a number which is the cosine of an angle.
125#Result : The angle in radians (0  result  ) whose cosine is V.
126#Conditions : -1.0=<V<=1.0
127#EXAMPLE 126 { ACOS ( 0.3 ) --> 1.266103...
128# Python definition:
129# ==================
130# ACOS is mapped to python math.acos builtin function
131def ACOS(V):
132    if not isinstance(V,NUMBER):
133        raise TypeError("ACOS function takes a NUMBER parameter")
134    return REAL(math.acos(V))
135
136# it's the same for ASIN and ATAN
137def ASIN(V):
138    if not isinstance(V,NUMBER):
139        raise TypeError("ASIN function takes a NUMBER parameter")
140    return REAL(math.asin(V))
141
142# EXPRESS definition:
143# ===================
144# 15.3 ATan - arithmetic function
145#FUNCTION ATAN ( V1:NUMBER; V2:NUMBER ) : REAL;
146#The atan function returns the angle given a tangent value of V , where V is given by the
147#expression V = V1/V2.
148#Parameters :
149#a) V1 is a number.
150#b) V2 is a number.
151#Result : The angle in radians (-pi/2<=result<=pi/2) whose tangent is V. If V2 is zero, the result
152#is pi/2 or -pi/2 depending on the sign of V1.
153#Conditions : Both V1 and V2 shall not be zero.
154#EXAMPLE 128 { ATAN ( -5.5, 3.0 ) --> -1.071449...
155def ATAN(V1,V2):
156    if not isinstance(V1,NUMBER) and not isinstance(V2,NUMBER):
157        raise TypeError("ATAN function takes 2 NUMBER parameters")
158    if V2 == 0:
159        if V1>0:
160            return REAL(math.pi/2)
161        elif V1<0:
162            return REAL(-math.pi/2)
163        else:
164            raise ValueError("ATAN parameters can be both equal to zero")
165    else:
166        return REAL(math.atan(float(V1)/float(V2)))
167
168# EXPRESS definition:
169# ===================
170#15.5 BLength - binary function
171#FUNCTION BLENGTH ( V:BINARY ) : INTEGER;
172#The blength function returns the number of bits in a binary.
173#Parameters : V is a binary value.
174#Result : The returned value is the actual number of bits in the binary value passed.
175#EXAMPLE 129
176#LOCAL
177#n : NUMBER;
178#x : BINARY := %01010010 ;
179#END_LOCAL;
180#...
181#n := BLENGTH ( x ); -- n is assigned the value 8
182def BLENGTH(V):
183    if not isinstance(V,BINARY):
184        raise TypeError("BLENGTH function takes one BINARY parameter")
185    return INTEGER(len(V))
186
187# EXPRESS definition:
188# ===================
189#15.6 Cos - arithmetic function
190#FUNCTION COS ( V:NUMBER ) : REAL;
191#The cos function returns the cosine of an angle.
192#Parameters : V is a number which is an angle in radians.
193#Result : The cosine of V (-1.0<=result<=1.0).
194#EXAMPLE 130 { COS ( 0.5 ) --> 8.77582...E-1
195#
196#15.21 Sin - arithmetic function
197#FUNCTION SIN ( V:NUMBER ) : REAL;
198#The sin function returns the sine of an angle.
199#Parameters : V is a number representing an angle expressed in radians.
200#Result : The sine of V (-1.0  result  1.0).
201#EXAMPLE 144 { SIN ( PI ) --> 0.0
202#
203def COS(V):
204    if not isinstance(V,NUMBER):
205        raise TypeError("COS function takes a NUMBER parameter")
206    return REAL(math.cos(V))
207def SIN(V):
208    if not isinstance(V,NUMBER):
209        raise TypeError("SIN function takes a NUMBER parameter")
210    return REAL(math.sin(V))
211
212# EXPRESS definition:
213# ===================
214#15.7 Exists - general function
215#FUNCTION EXISTS ( V:GENERIC ) : BOOLEAN;
216#The exists function returns true if a value exists for the input parameter, or false if no value
217#exists for it. The exists function is useful for checking if values have been given to optional
218#attributes, or if variables have been initialized.
219#Parameters : V is an expression which results in any type.
220#Result : true or false depending on whether V has an actual or indeterminate (?) value.
221#EXAMPLE 131 { IF EXISTS ( a ) THEN ...
222def EXISTS(V):
223    if V==None:
224        return False
225    else:
226        return True
227
228# EXPRESS definition:
229# ===================
230#15.8 Exp - arithmetic function
231#FUNCTION EXP ( V:NUMBER ) : REAL;
232#The exp function returns e (the base of the natural logarithm system) raised to the power V.
233#Parameters : V is a number.
234#Result : The value eV .
235#EXAMPLE 132 { EXP ( 10 ) --> 2.202646...E+4
236def EXP(V):
237    if not isinstance(V,NUMBER):
238        raise TypeError("EXP function takes a NUMBER parameter")
239    return REAL(math.exp(V))
240
241# EXPRESS definition:
242# ===================
243#15.9 Format - general function
244#FUNCTION FORMAT(N:NUMBER; F:STRING):STRING;
245#The format returns a formatted string representation of a number.
246#Parameters :
247#a) N is a number (integer or real).
248#b) F is a string containing formatting commands.
249#Result : A string representation of N formatted according to F. Rounding is applied to the
250#string representation if necessary.
251#The formatting string contains special characters to indicate the appearance of the result. The
252#formatting string can be written in three ways:
253#a) The formatting string can give a symbolic description of the output representation.
254#b) The formatting string can give a picture description of the output representation.
255#c) When the formatting string is empty, a standard output representation is produced.
256# Table 20:
257#Number Format Display Comment
258#10 +7I ' +10' Zero suppression
259#10 +07I '+000010' Zeros not suppressed
260#10 10.3E ' 1.000E+01'
261#123.456789 8.2F ' 123.46'
262#123.456789 8.2E '1.23E+02'
263#123.456789 08.2E '0.12E+02' Preceding zero forced
264#9.876E123 8.2E '9.88E+123' Exponent part is 3 characters
265#and width ignored
266#32.777 6I ' 33' Rounded
267# Python definition
268# =================
269# python string formatting is obtained from the val function
270# @TODO: implement a safe eval or provide another implementation
271# that avoids unsafe eval python builtin function.
272def FORMAT(N,F):
273    if not isinstance(N,NUMBER):
274        raise TypeError("FORMAT function takes a NUMBER parameter")
275    if not isinstance(F,STRING):
276        raise TypeError("FORMAT function takes a NUMBER parameter")
277    py_formatting = F.lower()
278    string_to_evaluate = "'%"
279    string_to_evaluate += "%s'"%py_formatting
280    string_to_evaluate += "%"
281    string_to_evaluate += "%s"%N
282    result = eval(string_to_evaluate).upper()
283    return STRING(result)
284
285# EXPRESS definition:
286# ===================
287#15.10 HiBound - arithmetic function
288#FUNCTION HIBOUND ( V:AGGREGATE OF GENERIC ) : INTEGER;
289#The hibound function returns the declared upper index of an array or the declared upper
290#bound of a bag, list or set.
291#Parameters : V is an aggregate value.
292#Result :
293#a) When V is an array the returned value is the declared upper index.
294#b) When V is a bag, list or set the returned value is the declared upper bound; if there
295#are no bounds declared or the upper bound is declared to be indeterminate (?) indeterminate
296#(?) is returned.
297#EXAMPLE 133 { Usage of hibound function on nested aggregate values.
298#LOCAL
299#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
300#h1, h2, h3 : INTEGER;
301#END_LOCAL;
302#...
303#a[-3][1][1] := 2; -- places a value in the list
304#...
305#h1 := HIBOUND(a); -- =19 (upper bound of array)
306#h2 := HIBOUND(a[-3]); -- = 4 (upper bound of set)
307#h3 := HIBOUND(a[-3][1]); -- = ? (upper bound of list (unbounded))
308def HIBOUND(V):
309    if not isinstance(V,Aggregate):
310        raise TypeError("HIBOUND takes an aggregate of generic")
311    return V.get_hibound()
312
313# EXPRESS definition:
314# ===================
315#15.11 HiIndex - arithmetic function
316#FUNCTION HIINDEX ( V:AGGREGATE OF GENERIC ) : INTEGER;
317#The hiindex function returns the upper index of an array or the number of elements in a bag,
318#list or set
319#Parameters : V is an aggregate value.
320#Result :
321#a) When V is an array, the returned value is the declared upper index.
322#b) When V is a bag, list or set, the returned value is the actual number of elements in
323#the aggregate value.
324#EXAMPLE 134 { Usage of hiindex function on nested aggregate values.
325#LOCAL
326#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
327#h1, h2, h3 : INTEGER;
328#END_LOCAL;
329#a[-3][1][1] := 2; -- places a value in the list
330#h1 := HIINDEX(a); -- = 19 (upper bound of array)
331#h2 := HIINDEX(a[-3]); -- = 1 (size of set) -- this is invalid with respect
332#-- to the bounds on the SET
333#h3 := HIINDEX(a[-3][1]); -- = 1 (size of list)
334def HIINDEX(V):
335    if not isinstance(V,Aggregate):
336        raise TypeError("HIINDEX takes an aggregate of generic")
337    return V.get_hiindex()
338
339# EXPRESS definition:
340# ===================
341#15.12 Length - string function
342#FUNCTION LENGTH ( V:STRING ) : INTEGER;
343#The length function returns the number of characters in a string.
344#Parameters : V is a string value.
345#Result : The returned value is the number of characters in the string and shall be greater than
346#or equal to zero.
347#EXAMPLE 135 - Usage of the length function.
348#LOCAL
349#n : NUMBER;
350#x1 : STRING := 'abc';
351#x2 : STRING := "000025FF000101B5;
352#END_LOCAL;
353#...
354#n := LENGTH ( x1 ); -- n is assigned the value 3
355#n := LENGTH ( x2 ); -- n is assigned the value 2
356def LENGTH(V):
357    if not isinstance(V,STRING):
358        raise TypeError("LENGTH take a STRING parameter")
359    return INTEGER(len(V))
360
361# EXPRESS definition:
362# ===================
363#15.13 LoBound - arithmetic function
364#FUNCTION LOBOUND ( V:AGGREGATE OF GENERIC ) : INTEGER;
365#The lobound function returns the declared lower index of an array, or the declared lower
366#bound of a bag, list or set.
367#Parameters : V is an aggregate value.
368#Result :
369#a) When V is an array the returned value is the declared lower index.
370#b) When V is a bag, list or set the returned value is the declared lower bound; if no
371#lower bound is declared, zero (0) is returned.
372#EXAMPLE 136 { Usage of lobound function on nested aggregate values.
373#LOCAL
374#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
375#h1, h2, h3 : INTEGER;
376#END_LOCAL;
377#...
378#h1 := LOBOUND(a); -- =-3 (lower index of array)
379#h2 := LOBOUND(a[-3]); -- = 2 (lower bound of set)
380#h3 := LOBOUND(a[-3][1]); -- = 0 (lower bound of list)
381def LOBOUND(V):
382    if not isinstance(V,Aggregate):
383        raise TypeError("HIBOUND takes an aggregate of generic")
384    return V.get_lobound()
385
386# EXPRESS definition:
387# ===================
388#15.14 Log - arithmetic function
389#FUNCTION LOG ( V:NUMBER ) : REAL;
390#The log function returns the natural logarithm of a number.
391#Parameters : V is a number.
392#Result : A real number which is the natural logarithm of V.
393#Conditions : V > 0:0
394#EXAMPLE 137 { LOG ( 4.5 ) --> 1.504077...E0
395#15.15 Log2 - arithmetic function
396#FUNCTION LOG2 ( V:NUMBER ) : REAL;
397#The log2 function returns the base two logarithm of a number.
398#Parameters : V is a number.
399#Result : A real number which is the base two logarithm of V.
400#Conditions : V > 0:0
401#EXAMPLE 138 { LOG2 ( 8 ) --> 3.00...E0
402#15.16 Log10 - arithmetic function
403#FUNCTION LOG10 ( V:NUMBER ) : REAL;
404#The log10 function returns the base ten logarithm of a number.
405#Parameters : V is a number.
406#Result : A real number which is the base ten logarithm of V.
407#Conditions : V > 0:0
408#EXAMPLE 139 { LOG10 ( 10 ) --> 1.00...E0
409def LOG(V):
410    if not isinstance(V,NUMBER):
411        raise TypeError("LOG function takes a NUMBER parameter")
412    return REAL(math.log(V))
413def LOG2(V):
414    if not isinstance(V,NUMBER):
415        raise TypeError("LOG2 function takes a NUMBER parameter")
416    return REAL(math.log(V,2))
417def LOG10(V):
418    if not isinstance(V,NUMBER):
419        raise TypeError("LOG10 function takes a NUMBER parameter")
420    return REAL(math.log10(V))
421
422# EXPRESS definition:
423# ===================
424#15.17 LoIndex - arithmetic function
425#FUNCTION LOINDEX ( V:AGGREGATE OF GENERIC ) : INTEGER;
426#The loindex function returns the lower index of an aggregate value.
427#Parameters : V is an aggregate value.
428#Result :
429#a) When V is an array the returned value is the declared lower index.
430#b) When V is a bag, list or set, the returned value is 1 (one).
431#EXAMPLE 140 { Usage of loindex function on nested aggregate values.
432#LOCAL
433#a : ARRAY[-3:19] OF SET[2:4] OF LIST[0:?] OF INTEGER;
434#h1, h2, h3 : INTEGER;
435#END_LOCAL;
436#...
437#h1 := LOINDEX(a); -- =-3 (lower bound of array)
438#h2 := LOINDEX(a[-3]); -- = 1 (for set)
439#h3 := LOINDEX(a[-3][1]); -- = 1 (for list)
440def LOINDEX(V):
441    if not isinstance(V,Aggregate):
442        raise TypeError("LOINDEX takes an aggregate of generic")
443    return V.get_loindex()
444
445# EXPRESS definition:
446# ===================
447#15.18 NVL - null value function
448#FUNCTION NVL(V:GENERIC:GEN1; SUBSTITUTE:GENERIC:GEN1):GENERIC:GEN1;
449#The nvl function returns either the input value or an alternate value in the case where the input
450#has a indeterminate (?) value.
451#Parameters :
452#a) V is an expression which is of any type.
453#b) SUBSTITUTE is an expression which shall not evaluate to indeterminate (?).
454#Result : When V is not indeterminate (?) that value is returned. Otherwise, SUBSTITUTE is
455#returned.
456#EXAMPLE 141 { ENTITY unit_vector;
457#x, y : REAL;
458#z : OPTIONAL REAL;
459#WHERE
460#x**2 + y**2 + NVL(z, 0.0)**2 = 1.0;
461#END_ENTITY;
462#The nvl function is used to supply zero (0.0) as the value of Z when Z is indeterminate (?).
463def NVL(V,SUBSTITUTE):
464    if V is not None:
465        return V
466    else:
467        return SUBSTITUTE
468
469# EXPRESS definition:
470# ===================
471#15.19 Odd - arithmetic function
472#FUNCTION ODD ( V:INTEGER ) : LOGICAL;
473#The odd function returns true or false depending on whether a number is odd or even.
474#Parameters : V is an integer number.
475#Result : When V MOD 2 = 1 true is returned; otherwise false is returned.
476#Conditions : Zero is not odd.
477#EXAMPLE 142 { ODD ( 121 ) --> TRUE
478def ODD(V):
479    if not isinstance(V,INTEGER):
480        raise TypeError("ODD takes an INTEGER")
481    if V%2 == 0:
482        return False
483    else:
484        return True
485
486# EXPRESS definition:
487# ===================
488#15.20 RolesOf - general function
489#FUNCTION ROLESOF ( V:GENERIC ) : SET OF STRING;
490#The rolesof function returns a set of strings containing the fully qualied names of the roles
491#played by the specied entity instance. A fully qualied name is dened to be the name of the
492#attribute qualied by the name of the schema and entity in which this attribute is declared (i.e.
493#'SCHEMA.ENTITY.ATTRIBUTE').
494#Parameters : V is any instance of an entity data type.
495#Result : A set of string values (in upper case) containing the fully qualied names of the
496#attributes of the entity instances which use the instance V.
497#When a named data type is use'd or reference'd, the schema and the name in that schema,
498#if renamed, are also returned. Since use statements may be chained, all the chained schema
499#names and the name in each schema are returned.
500#EXAMPLE 143 { This example shows that a point might be used as the centre of a circle. The
501#rolesof function determines what roles an entity instance actually plays.
502#SCHEMA that_schema;
503#ENTITY point;
504#x, y, z : REAL;
505#END_ENTITY;
506#ENTITY line;
507#start,
508#end : point;
509#END_ENTITY;
510#END_SCHEMA;
511#SCHEMA this_schema;
512#USE FROM that_schema (point,line);
513#CONSTANT
514#origin : point := point(0.0, 0.0, 0.0);
515#END_CONSTANT;
516#ENTITY circle;
517#centre : point;
518#axis : vector;
519#radius : REAL;
520#END_ENTITY;
521#...
522#LOCAL
523#p : point := point(1.0, 0.0, 0.0);
524#c : circle := circle(p, vector(1,1,1), 1.0);
525#l : line := line(p, origin);
526#END_LOCAL;
527#...
528#IF 'THIS_SCHEMA.CIRCLE.CENTRE' IN ROLESOF(p) THEN -- true
529#...
530#IF 'THIS_SCHEMA.LINE.START' IN ROLESOF(p) THEN -- true
531#...
532#IF 'THAT_SCHEMA.LINE.START' IN ROLESOF(p) THEN -- true
533#...
534#IF 'THIS_SCHEMA.LINE.END' IN ROLESOF(p) THEN -- false
535#
536# Python note:
537# @TODO: implement the ROLESOF function
538def ROLESOF(V):
539    raise NotImplemented("Function ROLESOF not implemented")
540
541# EXPRESS definition:
542# ===================
543#15.22 SizeOf - aggregate function
544#FUNCTION SIZEOF ( V:AGGREGATE OF GENERIC ) : INTEGER;
545#The sizeof function returns the number of elements in an aggregate value.
546#Parameters : V is an aggregate value.
547#Result :
548#a) When V is an array the returned value is its declared number of elements in the
549#aggregation data type.
550#b) When V is a bag, list or set, the returned value is the actual number of elements in
551#the aggregate value.
552#EXAMPLE 145 { LOCAL
553#n : NUMBER;
554#y : ARRAY[2:5] OF b;
555#END_LOCAL;
556#...
557#n := SIZEOF (y); -- n is assigned the value 4
558def SIZEOF(V):
559    if not isinstance(V,Aggregate):
560        raise TypeError("SIZEOF takes an aggregate of generic")
561    return V.get_size()
562
563# EXPRESS definition:
564# ===================
565#15.23 Sqrt - arithmetic function
566#FUNCTION SQRT ( V:NUMBER ) : REAL;
567#The sqrt function returns the non-negative square root of a number.
568#Parameters : V is any non-negative number.
569#Result : The non-negative square root of V.
570#Conditions : V  0:0
571#EXAMPLE 146 - SQRT ( 121 ) --> 11.0
572def SQRT(V):
573    if not isinstance(V,NUMBER):
574        raise TypeError("SQRT function takes a NUMBER parameter")
575    if V<0.0:
576        raise ValueError("SQRT takes a non-negative parameter")
577    return REAL(math.sqrt(V))
578
579# EXPRESS definition:
580# ===================
581#15.24 Tan - arithmetic function
582#FUNCTION TAN ( V:NUMBER ) : REAL;
583#The tan function returns the tangent of of an angle.
584#Parameters : V is a number representing an angle expressed in radians.
585#Result : The tangent of the angle. If the angle is npi/2, where n is an odd integer, indeterminate
586#(?) is returned.
587#EXAMPLE 147 - TAN ( 0.0 ) --> 0.0
588def TAN(V):
589    if not isinstance(V,NUMBER):
590        raise TypeError("TAN function takes a NUMBER parameter")
591    # check if angle is npi/2 where n is an odd integer
592    a = V/(PI/2)
593    if abs(a%2-1.) < SCL_float_epsilon :
594        return None
595    else:
596        return REAL(math.tan(V))
597
598# EXPRESS definition:
599# ===================
600#15.25 TypeOf - general function
601#FUNCTION TYPEOF ( V:GENERIC ) : SET OF STRING;
602#The typeof function returns a set of strings that contains the names of all the data types
603#of which the parameter is a member. Except for the simple data types (binary, boolean,
604#integer, logical, number, real, and string) and the aggregation data types (array, bag,
605#list, set) these names are qualied by the name of the schema which contains the denition of
606#the type.
607#NOTE 1 { The primary purpose of this function is to check whether a given value (variable, at-
608#tribute value) can be used for a certain purpose, e.g. to ensure assignment compatibility between
609#two values. It may also be used if dierent subtypes or specializations of a given type have to be
610#treated dierently in some context.
611#Parameters : V is a value of any type.
612#Result : The contents of the returned set of string values are the names (in upper case) of all
613#types the value V is a member of. Such names are qualied by the name of the schema which
614#contains the denition of the type ('SCHEMA.TYPE') if it is neither a simple data type nor an
615#aggregation data type. It may be derived by the following algorithm (which is given here for
616#specification purposes rather than to prescribe any particular type of implementation)
617def TYPEOF(V):
618    # Create the set to return
619    v_types = set()
620    # append the type of V to the set
621    try: #it's a class
622        to_add = V.__name__.upper()
623    except AttributeError: #it's an instance, first retrieve the type
624        to_add = type(V).__name__.upper()
625    if not to_add in ['FLOAT','INT','AGGREGATE']:
626        v_types.add(to_add)
627    # recursively adds the base class names
628    for base_type in type(V).__bases__:
629        #print base_type
630        if not base_type == object:
631            v_types = v_types.union(TYPEOF(base_type))
632    # finally, converts the v_types set to SET
633    return v_types
634
635# EXPRESS definition:
636# ===================
637#15.26 UsedIn - general function
638#FUNCTION USEDIN ( T:GENERIC; R:STRING) : BAG OF GENERIC;
639#The usedin function returns each entity instance that uses a specied entity instance in a
640#specied role.
641def USEDIN(T,R):
642    raise NotImplemented("USEDIN function not yet implemented.")
643
644# EXPRESS definition:
645# ===================
646#15.27 Value - arithmetic function
647#FUNCTION VALUE ( V:STRING ) : NUMBER;
648#The value function returns the numeric representation of a string.
649#Parameters : V is a string containing either a real or integer literal.
650#Result : A number corresponding to the string representation. If it is not possible to interpret
651#the string as either a real or integer literal, indeterminate (?) is returned.
652#EXAMPLE 151 { VALUE ( '1.234' ) --> 1.234 (REAL)
653#VALUE ( '20' ) --> 20 (INTEGER)
654#VALUE ( 'abc' ) --> ? null
655def VALUE(V):
656    if not isinstance(V,STRING):
657        raise TypeError("VALULE function takes a NUMBER parameter")
658    # first try to instanciate an INTEGER from the string:
659    try:
660        return INTEGER(V)
661    except:
662        pass #not possible, try to cast to REAL
663    try:
664        return REAL(V)
665    except:
666        pass
667    # else return None
668    return None
669
670# EXPRESS definition:
671# ===================
672#15.28 Value in - membership function
673#FUNCTION VALUE_IN ( C:AGGREGATE OF GENERIC:GEN; V:GENERIC:GEN ) : LOGICAL;
674#The value in function returns a logical value depending on whether or not a particular value
675#is a member of an aggregation.
676#Parameters :
677#a) C is an aggregation of any type.
678#b) V is an expression which is assignment compatible with the base type of C.
679#Result :
680#a) If either V or C is indeterminate (?), unknown is returned.
681#b) If any element of C has a value equal to the value of V, true is returned.
682#c) If any element of C is indeterminate (?), unknown is returned.
683#d) Otherwise false is returned.
684#EXAMPLE 152 { The following test ensures that there is at least one point which is positioned at
685#the origin.
686#LOCAL
687#points : SET OF point;
688#END_LOCAL;
689#...
690#IF VALUE_IN(points, point(0.0, 0.0, 0.0)) THEN ...
691def VALUE_IN(C,V):
692    if not isinstance(C,Aggregate):
693        raise TypeError("VALUE_IN method takes an aggregate as first parameter")
694    raise NotImplemented("VALUE_IN function not et implemented")
695
696# EXPRESS definition:
697# ===================
698#15.29 Value unique - uniqueness function
699#FUNCTION VALUE UNIQUE ( V:AGGREGATE OF GENERIC) : LOGICAL;
700#The value unique function returns a logical value depending on whether or not the elements
701#of an aggregation are value unique.
702#Parameters : V is an aggregation of any type.
703#Result :
704#a) If V is indeterminate (?), unknown is returned.
705#b) If any any two elements of V are value equal, false is returned.
706#c) If any element of V is indeterminate (?), unknown is returned.
707#d) Otherwise true is returned.
708#EXAMPLE 153 { The following test ensures tht each point is a set is at a dierent position, (by
709#denition they are distinct, i.e., instance unique).
710#IF VALUE_UNIQUE(points) THEN ...
711def VALUE_UNIQUE(V):
712    if not isinstance(V,Aggregate):
713        raise TypeError("VALUE_UNIQUE method takes an aggregate as first parameter")
714    return V.get_value_unique()
715
716