DGCV 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of DGCV might be problematic. Click here for more details.
- DGCV/CRGeometry.py +175 -0
- DGCV/DGCVFormatter.py +215 -0
- DGCV/DGCV_display.py +198 -0
- DGCV/RiemannianGeometry.py +873 -0
- DGCV/__init__.py +90 -0
- DGCV/_safeguards.py +187 -0
- DGCV/assets/__init__.py +0 -0
- DGCV/assets/fonts/Orbitron-Black.ttf +0 -0
- DGCV/assets/fonts/Orbitron-Bold.ttf +0 -0
- DGCV/assets/fonts/Orbitron-ExtraBold.ttf +0 -0
- DGCV/assets/fonts/Orbitron-Medium.ttf +0 -0
- DGCV/assets/fonts/Orbitron-Regular.ttf +0 -0
- DGCV/assets/fonts/Orbitron-SemiBold.ttf +0 -0
- DGCV/assets/fonts/PatrickHand-Regular.ttf +0 -0
- DGCV/assets/fonts/fonts.css +55 -0
- DGCV/classesAndVariables.py +7032 -0
- DGCV/combinatorics.py +579 -0
- DGCV/complexGeometry.py +301 -0
- DGCV/config.py +133 -0
- DGCV/coordinateMaps.py +209 -0
- DGCV/polynomials.py +265 -0
- DGCV/reformatted_styles.py +726 -0
- DGCV/styles.py +695 -0
- DGCV/vectorFieldsAndDifferentialForms.py +1252 -0
- DGCV-0.1.0.dist-info/LICENSE.txt +19 -0
- DGCV-0.1.0.dist-info/METADATA +22 -0
- DGCV-0.1.0.dist-info/RECORD +29 -0
- DGCV-0.1.0.dist-info/WHEEL +5 -0
- DGCV-0.1.0.dist-info/top_level.txt +1 -0
DGCV/CRGeometry.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
############## dependencies
|
|
2
|
+
from sympy import eye, expand, Matrix, numer, poly_from_expr, solve, Transpose, Symbol
|
|
3
|
+
from functools import reduce
|
|
4
|
+
from .config import _cached_caller_globals
|
|
5
|
+
from .combinatorics import *
|
|
6
|
+
from .classesAndVariables import *
|
|
7
|
+
from .vectorFieldsAndDifferentialForms import *
|
|
8
|
+
from .polynomials import *
|
|
9
|
+
from ._safeguards import retrieve_passkey
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
############## CR geometry
|
|
13
|
+
|
|
14
|
+
def tangencyObstruction(arg1,arg2,arg3,*args):
|
|
15
|
+
"""
|
|
16
|
+
Computes the Lie derivative of a holomorphic vector field's real part applied to a graph defining a CR hypersurface, then substitutes the defining equation into the result.
|
|
17
|
+
|
|
18
|
+
Returns 0 (up to simplification) if and only if the vector field is a symmetry of the hypersurface.
|
|
19
|
+
|
|
20
|
+
Arguments must be expressions w.r.t. a complex coordinate system initialized by *complexVarProc*
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
arg1: VFClass class instance in the form of a holomorphic vector field (for example, a VF initialized by *assembleFromHolVFC*)
|
|
24
|
+
arg2: Defining function of CR hypersurface in holomorphic or real variables format (i.e., a real-valued function of the complex parameter space depending on some but not all of the real and imaginaray parts of the complex variables)
|
|
25
|
+
arg3: The real variable that when set equal to the defining function defines the CR hypersurface.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
A sympy expression.
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
NA
|
|
32
|
+
"""
|
|
33
|
+
if isinstance(arg1,VFClass):
|
|
34
|
+
if arg1.DGCVType == 'standard':
|
|
35
|
+
raise TypeError('`tangencyObstruction` requires its first argument `vf` to be VFClass with vf.DGCVType=\'complex\'')
|
|
36
|
+
else:
|
|
37
|
+
raise TypeError('`tangencyObstruction` requires its first argument `vf` to be VFClass with vf.DGCVType=\'complex\'')
|
|
38
|
+
arg1=allToReal(arg1)
|
|
39
|
+
evaluationLoc=allToReal(realPartOfVF(arg1)(holToReal(arg3-arg2))).subs(holToReal(symToReal(arg3)),symToReal(arg2))
|
|
40
|
+
return simplify(symToReal(evaluationLoc))
|
|
41
|
+
|
|
42
|
+
def weightedHomogeneousVF(arg1,arg2,arg3,arg4,degreeCap=0,_tempVar=None,assumeReal=None):
|
|
43
|
+
"""
|
|
44
|
+
Creates a general weighted homogeneous vector field (i.e., VFClass instance) in the coordinate space of variables in *arg1* of weight *arg2* w.r.t. weights in *arg3*. Variables for the coefficients in the vector field are created with the label *arg4*.
|
|
45
|
+
|
|
46
|
+
If variable weights assigned are nonzero then the returned vector field is truly general. Otherwise the returned vector field is the general one with polynomial degree in the zero-weight variables bounded by *degreeCap* which can be set to any integer. If *degreeCap* is not specified then it defaults to zero.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
arg1: a tuple/list of variables initialized by either *varWithVF* or *complexVarProc*
|
|
50
|
+
arg2: int
|
|
51
|
+
arg3: list of non-negative integer weights corresponding to the variables in *arg1* (must have the same length as *arg1*). If 0 is among the weights, then then proceedure will only test polynomial vector fields with polynomial degree in the weight zero variables up to the weight specified in *degreeCap*. By default, degreeCap=0, and can be set to any positive integer.
|
|
52
|
+
arg4: str
|
|
53
|
+
_tempVar: (optional keyword) internal key
|
|
54
|
+
assumeReal: (optional keyword) True or False
|
|
55
|
+
degreeCap: (optional keyword) set this keyword argument equal to any positive integer. If not specified, it defaults to zero.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
A vector field (i.e., VFClass instance)
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
NA
|
|
63
|
+
"""
|
|
64
|
+
pListLoc=[]
|
|
65
|
+
for j in range(len(arg3)):
|
|
66
|
+
pListLoc.append(createPolynomial(arg4+'_'+str(j)+'_',arg2+arg3[j],arg1,degreeCap=degreeCap,weightedHomogeneity=arg3,_tempVar=_tempVar,assumeReal=assumeReal))
|
|
67
|
+
return reduce(addVF,[scaleVF(pListLoc[j],eval('D_'+str(arg1[j]),_cached_caller_globals)) for j in range(len(arg1))])
|
|
68
|
+
def findWeightedCRSymmetries(arg1,arg2,arg3,arg4,arg5,arg6,degreeCap=0,returnVectorFieldBasis=False,applyNumer=False,simplifyingFactor=None):
|
|
69
|
+
"""
|
|
70
|
+
***This function's algorithm will be revised in future updates***
|
|
71
|
+
|
|
72
|
+
Attempts to find all infinitesimal symmetries of a rigid CR hypersurface given by setting one variable *arg5* equal to a defining function *arg1* in the variable space *arg2* with weighted homogeneity *arg3* w.r.t. to non-negative integer weights in *arg4*. Variables in the returned vector field's coefficients are labeled by *arg6*.
|
|
73
|
+
|
|
74
|
+
Only polynomial vector fields are searched for, so if a variable is assigned weight zero, the function cannot search across general symmetries. In such cases, it rather searches all possible symmetries with polynomial degree in the zero-weighted variables up to the specified bound *degreeCap*. If *degreeCap* is not specified, then it defaults to zero.
|
|
75
|
+
|
|
76
|
+
The algorithm is most succesful when the function *arg1* must be a polynomial.
|
|
77
|
+
|
|
78
|
+
The function *arg1* should not depend on the variable *arg5* (i.e., the algorithm is not intended for implicit defining equations). If there is such dependence *findWeightedCRSymmetries* may still find some but not all symmetries.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
arg1: Defining function of a rigid CR hypersurface.
|
|
83
|
+
arg2: a tuple or list of complex variables parameterizing the space that the above CR hypersurface is defined in (not including the transverse direction symmetry).
|
|
84
|
+
arg3: list of non-negative integer weights corresponding to the variables in *arg1* (must have the same length as *arg1*). If 0 is among the weights, then then proceedure will only test polynomial vector fields with polynomial degree in the weight zero variables up to the weight specified in *degreeCap*. By default, degreeCap=0, and can be set to any positive integer.
|
|
85
|
+
arg4: int
|
|
86
|
+
arg5: The real variable that when set equal to the defining function defines the CR hypersurface.
|
|
87
|
+
arg6: str
|
|
88
|
+
degreeCap: (optional keyword) set this keyword argument equal to any positive integer. If not specified, it defaults to zero.
|
|
89
|
+
applyNumer: (optional keyword) True or False. Set equal to true if defining equation is rational but not polynomial. It can help the internal solvers.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
coefficient list for a holomorphic vector field containing variables, and any set real value for these variables defines an infinitesimal symmetry. **Note, indeed only real values for the variables define actual symmetries**
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
NA
|
|
96
|
+
"""
|
|
97
|
+
def extractRIVar(arg1):
|
|
98
|
+
return sum([list(holToReal(j).atoms(Symbol)) for j in arg1],[])
|
|
99
|
+
VFLoc=addVF(weightedHomogeneousVF(arg2,arg4,arg3,'ALoc',_tempVar=retrieve_passkey(),degreeCap=degreeCap,assumeReal=True),scaleVF(I,weightedHomogeneousVF(arg2,arg4,arg3,'BLoc',_tempVar=retrieve_passkey(),degreeCap=degreeCap,assumeReal=True)))
|
|
100
|
+
tOLoc=tangencyObstruction(VFLoc,arg1,arg5,arg2)
|
|
101
|
+
varLoc=tOLoc.atoms(Symbol)
|
|
102
|
+
varLoc1={j for j in varLoc}
|
|
103
|
+
varComp=set(extractRIVar(arg2))
|
|
104
|
+
varLoc.difference_update(varComp)
|
|
105
|
+
varLoc1.difference_update(varLoc)
|
|
106
|
+
varComp.difference_update(varLoc1)
|
|
107
|
+
variableProcedure(arg6,len(varLoc),assumeReal=True)
|
|
108
|
+
if applyNumer==True:
|
|
109
|
+
if varLoc1==set():
|
|
110
|
+
varLoc1=set(arg2)
|
|
111
|
+
coefListLoc=poly_from_expr(expand(numer(tOLoc)),*varLoc1)[0].coeffs()
|
|
112
|
+
solLoc=solve(coefListLoc,varLoc)
|
|
113
|
+
elif simplifyingFactor==None:
|
|
114
|
+
if varLoc1==set():
|
|
115
|
+
varLoc1=set(arg2)
|
|
116
|
+
coefListLoc=poly_from_expr(expand(tOLoc),*varLoc1)[0].coeffs()
|
|
117
|
+
solLoc=solve(coefListLoc,varLoc)
|
|
118
|
+
else:
|
|
119
|
+
if varLoc1==set():
|
|
120
|
+
varLoc1=set(arg2)
|
|
121
|
+
coefListLoc=poly_from_expr(expand(simplify(symToReal(simplifyingFactor)*tOLoc)),*varLoc1)[0].coeffs()
|
|
122
|
+
solLoc=solve(coefListLoc,varLoc)
|
|
123
|
+
if solLoc==[]:
|
|
124
|
+
clearVar(*listVar(temporary_only=True),report=False)
|
|
125
|
+
return 'no solution'
|
|
126
|
+
elif type(solLoc)==dict:
|
|
127
|
+
VFCLoc=[j.subs(solLoc) for j in holVF_coeffs(VFLoc,arg2)]
|
|
128
|
+
subVar=sum(VFCLoc).atoms(Symbol)
|
|
129
|
+
subVar.difference_update(set(arg2))
|
|
130
|
+
variableProcedure(arg6,len(subVar),assumeReal=True)
|
|
131
|
+
VFCLoc=[j.subs(dict(zip(subVar,eval(arg6,_cached_caller_globals)))) for j in VFCLoc]
|
|
132
|
+
clearVar(*listVar(temporary_only=True),report=False)
|
|
133
|
+
if returnVectorFieldBasis==True:
|
|
134
|
+
VFListLoc=[]
|
|
135
|
+
for j in eval(arg6,_cached_caller_globals):
|
|
136
|
+
VFCLocTemp=[k.subs(j,1).subs([(l,0) for l in eval(arg6,_cached_caller_globals)]) for k in VFCLoc]
|
|
137
|
+
VFListLoc.append(assembleFromHolVFC(VFCLocTemp,arg2))
|
|
138
|
+
clearVar(arg6,report=False)
|
|
139
|
+
return VFListLoc, VFCLoc
|
|
140
|
+
else:
|
|
141
|
+
return VFCLoc
|
|
142
|
+
else:
|
|
143
|
+
VFCLoc=holVF_coeffs(VFLoc,arg2)
|
|
144
|
+
subVar=sum(VFCLoc).atoms(Symbol)
|
|
145
|
+
subVar.difference_update(set(arg2))
|
|
146
|
+
variableProcedure(arg6,len(subVar),assumeReal=True)
|
|
147
|
+
VFCLoc=[j.subs(dict(zip(subVar,eval(arg6,_cached_caller_globals)))) for j in VFCLoc]
|
|
148
|
+
clearVar(*listVar(temporary_only=True),report=False)
|
|
149
|
+
return VFCLoc,solLoc
|
|
150
|
+
|
|
151
|
+
def model2Nondegenerate(arg1,arg2,arg3,arg4):
|
|
152
|
+
"""
|
|
153
|
+
Builds the defining equation for a 2-nondegnerate model hypersurface using the general formula from the arXiv preprint arXiv:2404.06525.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
arg1: nondegenerate s-by-s hermitian matrix
|
|
157
|
+
arg2: s-by-s symmetric matrix valued function of some complex variables whose differential at zero is injective, and whose value at zero is zero.
|
|
158
|
+
arg3: a length s tuple of complex variables, different from those appearing in *arg2*
|
|
159
|
+
arg4: a single complex variable, different from those appearing in *arg2* and *arg3*
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
A sympy expression. Setting this expression equal to zero defines the 2-nondegenerate model.
|
|
163
|
+
|
|
164
|
+
Raises:
|
|
165
|
+
NA
|
|
166
|
+
"""
|
|
167
|
+
BARSLoc=conjugate(arg2)
|
|
168
|
+
zVecLoc=Matrix(arg3)
|
|
169
|
+
bzVecLoc=Matrix([conjugate(j) for j in arg3])
|
|
170
|
+
sizeLoc=arg1.shape[0]
|
|
171
|
+
hFun=(Rational(1,2))*((arg1*(eye(sizeLoc)-(BARSLoc*Transpose(arg1)*arg2*arg1))**(-1))+((eye(sizeLoc)-(arg1*BARSLoc*Transpose(arg1)*arg2))**(-1)*arg1))
|
|
172
|
+
sFun=arg1*((eye(sizeLoc)-(BARSLoc*Transpose(arg1)*arg2*arg1))**(-1))*BARSLoc*Transpose(arg1)
|
|
173
|
+
bsFun=Transpose(arg1)*((eye(sizeLoc)-(arg2*arg1*BARSLoc*Transpose(arg1)))**(-1))*arg2*arg1
|
|
174
|
+
return simplify((Transpose(zVecLoc)*hFun*bzVecLoc+(Rational(1,2))*(Transpose(zVecLoc)*sFun*zVecLoc+Transpose(bzVecLoc)*bsFun*bzVecLoc))[0])-im(arg4)
|
|
175
|
+
|
DGCV/DGCVFormatter.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from pandas import DataFrame, MultiIndex
|
|
3
|
+
from .config import get_variable_registry, greek_letters
|
|
4
|
+
from .styles import get_style
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Modular function to collect data for complex, standard, and algebra variables
|
|
8
|
+
def collect_variable_data(variable_registry, use_latex):
|
|
9
|
+
data = [['Number of Var.', 'Real Part', 'Imaginary Part', 'Vector Fields', 'Differential Forms']]
|
|
10
|
+
index = []
|
|
11
|
+
|
|
12
|
+
complex_vars = sorted(variable_registry.get('complex_variable_systems', {}).keys())
|
|
13
|
+
standard_vars = sorted(variable_registry.get('standard_variable_systems', {}).keys())
|
|
14
|
+
finite_algebra_vars = sorted(variable_registry.get('finite_algebra_systems', {}).keys())
|
|
15
|
+
|
|
16
|
+
# Process complex variables
|
|
17
|
+
for var_name in complex_vars:
|
|
18
|
+
process_variable(var_name, 'complex', variable_registry, data, index, use_latex)
|
|
19
|
+
|
|
20
|
+
# Process standard variables
|
|
21
|
+
for var_name in standard_vars:
|
|
22
|
+
process_variable(var_name, 'standard', variable_registry, data, index, use_latex)
|
|
23
|
+
|
|
24
|
+
# Process finite algebra systems
|
|
25
|
+
for var_name in finite_algebra_vars:
|
|
26
|
+
process_algebra(var_name, variable_registry, data, index, use_latex)
|
|
27
|
+
|
|
28
|
+
return data, index
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Function to process complex and standard variables
|
|
32
|
+
def process_variable(var_name, system_type, variable_registry, data, index, use_latex):
|
|
33
|
+
# Common logic for both standard and complex variable systems
|
|
34
|
+
family_type = variable_registry[f'{system_type}_variable_systems'][var_name].get('family_type', 'single')
|
|
35
|
+
family_names = variable_registry[f'{system_type}_variable_systems'][var_name]['family_names']
|
|
36
|
+
initial_index = variable_registry[f'{system_type}_variable_systems'][var_name].get('initial_index', 1)
|
|
37
|
+
|
|
38
|
+
# Logic to process tuple or single variables and append to data
|
|
39
|
+
tuple_len = len(family_names)
|
|
40
|
+
real_part, imaginary_part, vf_str, df_str = format_variable_details(var_name, family_names, initial_index, tuple_len, system_type, use_latex)
|
|
41
|
+
|
|
42
|
+
# Append to data
|
|
43
|
+
data.append([
|
|
44
|
+
tuple_len,
|
|
45
|
+
real_part,
|
|
46
|
+
imaginary_part,
|
|
47
|
+
vf_str,
|
|
48
|
+
df_str
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
# Update the index
|
|
52
|
+
formatted_name = format_variable_name(var_name, system_type, use_latex)
|
|
53
|
+
index.append((formatted_name, ''))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Function to process algebra systems
|
|
57
|
+
def process_algebra(var_name, variable_registry, data, index, use_latex):
|
|
58
|
+
system_data = variable_registry['finite_algebra_systems'][var_name]
|
|
59
|
+
algebra_family_names = system_data.get('family_names', [])
|
|
60
|
+
|
|
61
|
+
# Format algebra label and basis
|
|
62
|
+
formatted_str = format_algebra_name(var_name, algebra_family_names, use_latex)
|
|
63
|
+
|
|
64
|
+
# Append to data
|
|
65
|
+
data.append([len(algebra_family_names), '----', '----', '----', '----'])
|
|
66
|
+
|
|
67
|
+
# Update the index
|
|
68
|
+
index.append((formatted_str, ''))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Function to build the table
|
|
72
|
+
def build_table(data, index, style):
|
|
73
|
+
# Build and return the final styled table
|
|
74
|
+
columns = MultiIndex.from_product([['Initialized Coordinate Systems and Algebras'], ['', '', '', '', '']])
|
|
75
|
+
table = DataFrame(data=data, index=index, columns=columns)
|
|
76
|
+
|
|
77
|
+
# Apply styles and return the table
|
|
78
|
+
table_styles = get_style(style)
|
|
79
|
+
return table.style.set_table_styles(table_styles)
|
|
80
|
+
|
|
81
|
+
# Helper function to format variable details (real part, imaginary part, vector fields, differential forms)
|
|
82
|
+
def format_variable_details(var_name, family_names, initial_index, tuple_len, system_type, use_latex):
|
|
83
|
+
if system_type == 'complex':
|
|
84
|
+
variable_registry=get_variable_registry()
|
|
85
|
+
# Access the real and imaginary parts (assuming they are the 3rd and 4th elements in family_names)
|
|
86
|
+
family_houses = variable_registry['complex_variable_systems'][var_name]['family_houses']
|
|
87
|
+
family_names = variable_registry['complex_variable_systems'][var_name]['family_names']
|
|
88
|
+
|
|
89
|
+
if len(family_names[2]) > 1:
|
|
90
|
+
real_part = f"{family_houses[2]} = ({family_names[2][0]}, ..., {family_names[2][-1]})"
|
|
91
|
+
else:
|
|
92
|
+
real_part = f"{family_houses[2]} = ({family_names[2][0]})"
|
|
93
|
+
|
|
94
|
+
if len(family_names[3]) > 1:
|
|
95
|
+
imaginary_part = f"{family_houses[3]} = ({family_names[3][0]}, ..., {family_names[3][-1]})"
|
|
96
|
+
else:
|
|
97
|
+
imaginary_part = f"{family_houses[3]} = ({family_names[3][0]})"
|
|
98
|
+
|
|
99
|
+
vf_str = build_object_string_for_complex('D', family_houses, family_names, initial_index, use_latex)
|
|
100
|
+
df_str = build_object_string_for_complex('d', family_houses, family_names, initial_index, use_latex)
|
|
101
|
+
|
|
102
|
+
else: # Standard variables
|
|
103
|
+
real_part = '----' # Real part not applicable for standard variables
|
|
104
|
+
imaginary_part = '----' # Imaginary part not applicable for standard variables
|
|
105
|
+
vf_str = build_object_string('D', var_name, initial_index, tuple_len, system_type, use_latex)
|
|
106
|
+
df_str = build_object_string('d', var_name, initial_index, tuple_len, system_type, use_latex)
|
|
107
|
+
|
|
108
|
+
return real_part, imaginary_part, vf_str, df_str
|
|
109
|
+
|
|
110
|
+
def format_variable_name(var_name, system_type, use_latex=False):
|
|
111
|
+
variable_registry=get_variable_registry()
|
|
112
|
+
if system_type == 'standard':
|
|
113
|
+
family_type = variable_registry['standard_variable_systems'][var_name].get('family_type', 'single')
|
|
114
|
+
family_names = variable_registry['standard_variable_systems'][var_name]['family_names']
|
|
115
|
+
initial_index = variable_registry['standard_variable_systems'][var_name].get('initial_index', 1)
|
|
116
|
+
else: # system_type == 'complex'
|
|
117
|
+
family_type = variable_registry['complex_variable_systems'][var_name].get('family_type', 'single')
|
|
118
|
+
family_names = variable_registry['complex_variable_systems'][var_name]['family_names'][0] # First tuple entry
|
|
119
|
+
initial_index = variable_registry['complex_variable_systems'][var_name].get('initial_index', 1)
|
|
120
|
+
|
|
121
|
+
# Handle tuple or single variable cases
|
|
122
|
+
if family_type == 'tuple':
|
|
123
|
+
first_index = initial_index
|
|
124
|
+
last_index = initial_index + len(family_names) - 1
|
|
125
|
+
if use_latex:
|
|
126
|
+
content = f"{convert_to_greek(var_name)} = \\left( {convert_to_greek(var_name)}_{{{first_index}}}, \\ldots, {convert_to_greek(var_name)}_{{{last_index}}} \\right)"
|
|
127
|
+
else:
|
|
128
|
+
content = f"{var_name} = ({family_names[0]}, ..., {family_names[-1]})"
|
|
129
|
+
else:
|
|
130
|
+
content = convert_to_greek(var_name) if use_latex else var_name
|
|
131
|
+
|
|
132
|
+
return wrap_in_dollars(content) if use_latex else content
|
|
133
|
+
|
|
134
|
+
def format_algebra_name(var_name, algebra_family_names, use_latex=False):
|
|
135
|
+
if use_latex:
|
|
136
|
+
match = re.match(r'(.*?)(\d+)?$', var_name)
|
|
137
|
+
algebra_name = match.group(1) if match else var_name
|
|
138
|
+
algebra_number = match.group(2) if match else None
|
|
139
|
+
|
|
140
|
+
# Format the algebra name in LaTeX
|
|
141
|
+
algebra_label = f"\\mathfrak{{{convert_to_greek(algebra_name)}}}" if re.fullmatch(r'[a-z]+', algebra_name) else algebra_name
|
|
142
|
+
if algebra_number:
|
|
143
|
+
algebra_label += f"_{{{algebra_number}}}"
|
|
144
|
+
|
|
145
|
+
# Format the basis string
|
|
146
|
+
if len(algebra_family_names) > 1:
|
|
147
|
+
first_basis_label = process_basis_label(algebra_family_names[0])
|
|
148
|
+
last_basis_label = process_basis_label(algebra_family_names[-1])
|
|
149
|
+
basis_str = f"{first_basis_label}, \\ldots, {last_basis_label}"
|
|
150
|
+
else:
|
|
151
|
+
basis_str = process_basis_label(algebra_family_names[0]) if algebra_family_names else ""
|
|
152
|
+
return f"Algebra: {wrap_in_dollars(algebra_label)} \\\\ Basis: {wrap_in_dollars(basis_str)}"
|
|
153
|
+
else:
|
|
154
|
+
algebra_label = var_name
|
|
155
|
+
if len(algebra_family_names) > 1:
|
|
156
|
+
basis_str = f"{algebra_family_names[0]}, ..., {algebra_family_names[-1]}"
|
|
157
|
+
else:
|
|
158
|
+
basis_str = algebra_family_names[0] if algebra_family_names else ""
|
|
159
|
+
return f"Algebra: {algebra_label}<br>Basis: {basis_str}"
|
|
160
|
+
|
|
161
|
+
def build_object_string_for_complex(obj_type, part_names, family_names, start_index, use_latex=False):
|
|
162
|
+
parts = []
|
|
163
|
+
for part_name, part in zip(part_names, family_names):
|
|
164
|
+
if use_latex:
|
|
165
|
+
base_var = convert_to_greek(part_name.replace('BAR', '', 1)) if part_name.startswith('BAR') else convert_to_greek(part_name)
|
|
166
|
+
if len(part) > 1:
|
|
167
|
+
part_str = f"\\overline{{{base_var}_{{{start_index}}}}}, \\ldots, \\overline{{{base_var}_{{{start_index + len(part) - 1}}}}}"
|
|
168
|
+
else:
|
|
169
|
+
part_str = f"\\overline{{{base_var}}}" if part_name.startswith('BAR') else base_var
|
|
170
|
+
parts.append(f"d {part_str}" if obj_type == 'd' else f"\\frac{{\\partial}}{{\\partial {part_str}}}")
|
|
171
|
+
else:
|
|
172
|
+
part_str = f"{obj_type}_{convert_to_greek(part_name)}{start_index},...,{convert_to_greek(part_name)}{start_index + len(part) - 1}" if len(part) > 1 else f"{obj_type}_{convert_to_greek(part_name)}"
|
|
173
|
+
parts.append(part_str)
|
|
174
|
+
return ', '.join(parts)
|
|
175
|
+
|
|
176
|
+
def build_object_string(obj_type, var_name, start_index, tuple_len, system_type, use_latex=False):
|
|
177
|
+
if tuple_len == 1:
|
|
178
|
+
if use_latex:
|
|
179
|
+
content = f"d {convert_to_greek(var_name)}" if obj_type == 'd' else f"\\frac{{\\partial}}{{\\partial {convert_to_greek(var_name)}}}"
|
|
180
|
+
else:
|
|
181
|
+
content = f"{obj_type}_{var_name}"
|
|
182
|
+
else:
|
|
183
|
+
if use_latex:
|
|
184
|
+
content = f"d {convert_to_greek(var_name)}_{{{start_index}}}, \\ldots, d {convert_to_greek(var_name)}_{{{start_index + tuple_len - 1}}}" if obj_type == 'd' else f"\\frac{{\\partial}}{{\\partial {convert_to_greek(var_name)}_{{{start_index}}}}}, \\ldots, \\frac{{\\partial}}{{\\partial {convert_to_greek(var_name)}_{{{start_index + tuple_len - 1}}}}}"
|
|
185
|
+
else:
|
|
186
|
+
content = f"{obj_type}_{var_name}{start_index},...,{obj_type}_{var_name}{start_index + tuple_len - 1}"
|
|
187
|
+
return wrap_in_dollars(content) if use_latex else content
|
|
188
|
+
|
|
189
|
+
# Helper function to convert variable names to Greek letters (if applicable)
|
|
190
|
+
def convert_to_greek(var_name):
|
|
191
|
+
# Replace variable names with their corresponding Greek letters
|
|
192
|
+
for name, greek in greek_letters.items():
|
|
193
|
+
if var_name == name:
|
|
194
|
+
return greek
|
|
195
|
+
return var_name
|
|
196
|
+
|
|
197
|
+
# Helper function to wrap content in LaTeX dollar signs for rendering
|
|
198
|
+
def wrap_in_dollars(content):
|
|
199
|
+
return f"${content}$"
|
|
200
|
+
|
|
201
|
+
# Helper function to process basis labels (e.g., e1 -> e_{1})
|
|
202
|
+
def process_basis_label(label):
|
|
203
|
+
# Use regex to split the name and numeric suffix
|
|
204
|
+
match = re.match(r'(.*?)(\d+)?$', label)
|
|
205
|
+
basis_elem_name = match.group(1) # Alphabetic part
|
|
206
|
+
basis_elem_number = match.group(2) # Numeric part, if any
|
|
207
|
+
|
|
208
|
+
# Remove trailing underscores from the name
|
|
209
|
+
basis_elem_name = basis_elem_name.rstrip('_')
|
|
210
|
+
|
|
211
|
+
# Build the LaTeX string
|
|
212
|
+
if basis_elem_number:
|
|
213
|
+
return f"{convert_to_greek(basis_elem_name)}_{{{basis_elem_number}}}"
|
|
214
|
+
else:
|
|
215
|
+
return f"{convert_to_greek(basis_elem_name)}"
|
DGCV/DGCV_display.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
display.py
|
|
4
|
+
|
|
5
|
+
This module provides functions for customizing font display in Jupyter notebooks.
|
|
6
|
+
The `load_fonts()` function loads web fonts and applies them to the notebook
|
|
7
|
+
environment using HTML and CSS.
|
|
8
|
+
|
|
9
|
+
Functions
|
|
10
|
+
---------
|
|
11
|
+
- load_fonts: Injects HTML and CSS to load Google Fonts and apply custom fonts to the notebook.
|
|
12
|
+
"""
|
|
13
|
+
import sympy
|
|
14
|
+
from .classesAndVariables import DFClass,VFClass,STFClass,FAClass,DGCVPolyClass,symToHol,symToReal,TFClass,AlgebraElement
|
|
15
|
+
from .RiemannianGeometry import metricClass
|
|
16
|
+
|
|
17
|
+
from IPython.display import display, HTML, Latex
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
from sympy import latex, Basic
|
|
22
|
+
|
|
23
|
+
def LaTeX(obj,removeBARs=False):
|
|
24
|
+
"""
|
|
25
|
+
Custom LaTeX function for DGCV.
|
|
26
|
+
Applies sympy.latex() to the input object, with special handling for lists and tuples.
|
|
27
|
+
|
|
28
|
+
For lists, the elements are LaTeX-processed, stripped of surrounding $ or $$ symbols if present,
|
|
29
|
+
and wrapped in \left[ ... \right].
|
|
30
|
+
|
|
31
|
+
For tuples, the elements are LaTeX-processed similarly but wrapped in \left( ... \right).
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
obj : any
|
|
36
|
+
The object to convert to LaTeX. Can be a SymPy expression, DGCV object, or a list/tuple of such objects.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
str
|
|
41
|
+
The LaTeX-formatted string.
|
|
42
|
+
"""
|
|
43
|
+
def filter(term):
|
|
44
|
+
if removeBARs==True:
|
|
45
|
+
return latex(term)
|
|
46
|
+
if isinstance(term,(DFClass,VFClass,STFClass,DGCVPolyClass,TFClass)):
|
|
47
|
+
if term._varSpace_type == 'real':
|
|
48
|
+
return latex(symToReal(term))
|
|
49
|
+
elif term._varSpace_type == 'complex':
|
|
50
|
+
return latex(symToHol(term))
|
|
51
|
+
else:
|
|
52
|
+
return latex(term)
|
|
53
|
+
elif isinstance(term, FAClass):
|
|
54
|
+
return _alglabeldisplayclass(term.label)._repr_latex_()
|
|
55
|
+
elif isinstance(term, AlgebraElement):
|
|
56
|
+
return _alglabeldisplayclass(term.algebra.label,term)._repr_latex_()
|
|
57
|
+
else:
|
|
58
|
+
return latex(symToHol(term))
|
|
59
|
+
|
|
60
|
+
def strip_dollar_signs(latex_str):
|
|
61
|
+
"""Strip leading and trailing $ or $$ signs from a LaTeX string."""
|
|
62
|
+
# if latex_str == None:
|
|
63
|
+
# return ''
|
|
64
|
+
if latex_str.startswith("$$") and latex_str.endswith("$$"):
|
|
65
|
+
return latex_str[2:-2]
|
|
66
|
+
elif latex_str.startswith("$") and latex_str.endswith("$"):
|
|
67
|
+
return latex_str[1:-1]
|
|
68
|
+
return latex_str
|
|
69
|
+
|
|
70
|
+
if isinstance(obj, list):
|
|
71
|
+
# Handle lists by applying LaTeX and wrapping with \left[ ... \right]
|
|
72
|
+
latex_elements = [strip_dollar_signs(filter(elem)) for elem in obj]
|
|
73
|
+
return r"\left[ " + ", ".join(latex_elements) + r" \right]"
|
|
74
|
+
|
|
75
|
+
elif isinstance(obj, tuple):
|
|
76
|
+
# Handle tuples by applying LaTeX and wrapping with \left( ... \right)
|
|
77
|
+
latex_elements = [strip_dollar_signs(filter(elem)) for elem in obj]
|
|
78
|
+
return r"\left( " + ", ".join(latex_elements) + r" \right)"
|
|
79
|
+
|
|
80
|
+
else:
|
|
81
|
+
# Apply sympy.latex() for non-list/tuple objects
|
|
82
|
+
return strip_dollar_signs(filter(obj))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def display_DGCV(*args):
|
|
86
|
+
for j in args:
|
|
87
|
+
_display_DGCV_single(j)
|
|
88
|
+
|
|
89
|
+
def _display_DGCV_single(arg):
|
|
90
|
+
if isinstance(arg,str):
|
|
91
|
+
display(Latex(arg))
|
|
92
|
+
elif isinstance(arg,(sympy.Expr,metricClass,DFClass,VFClass,TFClass,STFClass,DGCVPolyClass)):
|
|
93
|
+
_complexDisplay(arg)
|
|
94
|
+
elif isinstance(arg,FAClass):
|
|
95
|
+
_complexDisplay(_alglabeldisplayclass(arg.label))
|
|
96
|
+
elif isinstance(arg,AlgebraElement):
|
|
97
|
+
_complexDisplay(_alglabeldisplayclass(arg.algebra.label,ae=arg))
|
|
98
|
+
else:
|
|
99
|
+
display(arg)
|
|
100
|
+
|
|
101
|
+
def _complexDisplay(*args):
|
|
102
|
+
"""
|
|
103
|
+
Taking DGCV expressions in *args* written in terms of symbolic conjugate variables, displays them with actual complex conjugates
|
|
104
|
+
"""
|
|
105
|
+
display(*[symToHol(j,simplify_everything=False) for j in args])
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class _alglabeldisplayclass(Basic):
|
|
109
|
+
|
|
110
|
+
def __new__(cls, label, ae = None):
|
|
111
|
+
obj = Basic.__new__(cls, label)
|
|
112
|
+
return obj
|
|
113
|
+
|
|
114
|
+
def __init__(self, label, ae = None):
|
|
115
|
+
self.label = str(label)
|
|
116
|
+
self.ae = ae
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def format_algebra_label(label):
|
|
120
|
+
"""Wrap the algebra label in \mathfrak{} if all characters are lowercase, and subscript any numeric suffix."""
|
|
121
|
+
if label[-1].isdigit():
|
|
122
|
+
# Split into text and number parts for subscript formatting
|
|
123
|
+
label_text = ''.join(filter(str.isalpha, label))
|
|
124
|
+
label_number = ''.join(filter(str.isdigit, label))
|
|
125
|
+
if label_text.islower():
|
|
126
|
+
return rf"\mathfrak{{{label_text}}}_{{{label_number}}}"
|
|
127
|
+
return rf"{label_text}_{{{label_number}}}"
|
|
128
|
+
elif label.islower():
|
|
129
|
+
return rf"\mathfrak{{{label}}}"
|
|
130
|
+
return label
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def format_ae(ae):
|
|
134
|
+
if ae != None:
|
|
135
|
+
terms = []
|
|
136
|
+
for coeff, basis_label in zip(ae.coeffs, ae.algebra.basis_labels):
|
|
137
|
+
if coeff == 0:
|
|
138
|
+
continue # Skip zero terms
|
|
139
|
+
elif coeff == 1:
|
|
140
|
+
terms.append(rf"{basis_label}") # Suppress 1 as coefficient
|
|
141
|
+
elif coeff == -1:
|
|
142
|
+
terms.append(rf"-{basis_label}") # Suppress 1 but keep the negative sign
|
|
143
|
+
else:
|
|
144
|
+
# Check if the coefficient has more than one term (e.g., 1 + I)
|
|
145
|
+
if isinstance(coeff, sympy.Expr) and len(coeff.args) > 1:
|
|
146
|
+
terms.append(rf"({sympy.latex(coeff)}) \cdot {basis_label}") # Wrap multi-term coefficient in parentheses
|
|
147
|
+
else:
|
|
148
|
+
terms.append(rf"{sympy.latex(coeff)} \cdot {basis_label}") # Single-term coefficient
|
|
149
|
+
|
|
150
|
+
# Handle special case: all zero coefficients
|
|
151
|
+
if not terms:
|
|
152
|
+
return rf"$0 \cdot {ae.algebra.basis_labels[0]}$"
|
|
153
|
+
|
|
154
|
+
# Join terms with proper LaTeX sign handling
|
|
155
|
+
result = " + ".join(terms).replace("+ -", "- ")
|
|
156
|
+
return rf"{result}"
|
|
157
|
+
|
|
158
|
+
def _repr_latex_(self):
|
|
159
|
+
if self.ae == None:
|
|
160
|
+
return _alglabeldisplayclass.format_algebra_label(self.label)
|
|
161
|
+
else:
|
|
162
|
+
return _alglabeldisplayclass.format_ae(self.ae)
|
|
163
|
+
|
|
164
|
+
def __str__(self):
|
|
165
|
+
return self.label
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def load_fonts():
|
|
169
|
+
"""
|
|
170
|
+
Load custom web fonts into the Jupyter notebook.
|
|
171
|
+
|
|
172
|
+
This function injects HTML and CSS to load fonts from Google Fonts and sets
|
|
173
|
+
the body font to 'Roboto'. It is intended for use in Jupyter notebooks to
|
|
174
|
+
customize the appearance of text.
|
|
175
|
+
|
|
176
|
+
Fonts Loaded
|
|
177
|
+
------------
|
|
178
|
+
- Orbitron
|
|
179
|
+
- Press Start 2P
|
|
180
|
+
- Roboto
|
|
181
|
+
|
|
182
|
+
Examples
|
|
183
|
+
--------
|
|
184
|
+
>>> load_fonts()
|
|
185
|
+
|
|
186
|
+
Notes
|
|
187
|
+
-----
|
|
188
|
+
The fonts are applied globally to the notebook interface via CSS.
|
|
189
|
+
"""
|
|
190
|
+
font_links = """
|
|
191
|
+
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Press+Start+2P&family=Roboto:wght@400;700&display=swap" rel="stylesheet">
|
|
192
|
+
<style>
|
|
193
|
+
body {
|
|
194
|
+
font-family: 'Roboto', sans-serif;
|
|
195
|
+
}
|
|
196
|
+
</style>
|
|
197
|
+
"""
|
|
198
|
+
display(HTML(font_links))
|