1- export Variable, @polyvar , @ncpolyvar
1+ export Variable, @polyvar , @ncpolyvar , @complex_polyvar
22
3- function polyarrayvar (variable_order, monomial_order, prefix, indices... )
3+ function polyarrayvar (
4+ variable_order,
5+ monomial_order,
6+ complex_kind,
7+ prefix,
8+ indices... ,
9+ )
410 return map (
511 i -> Variable (
612 " $(prefix) [$(join (i, " ," )) ]" ,
713 variable_order,
814 monomial_order,
15+ complex_kind,
916 ),
1017 Iterators. product (indices... ),
1118 )
1219end
1320
14- function buildpolyvar (var, variable_order, monomial_order)
21+ function buildpolyvar (var, variable_order, monomial_order, complex_kind )
1522 if isa (var, Symbol)
1623 var,
17- :($ (esc (var)) = $ Variable ($ " $var " , $ variable_order, $ monomial_order))
24+ :(
25+ $ (esc (var)) = $ Variable (
26+ $ " $var " ,
27+ $ variable_order,
28+ $ monomial_order,
29+ $ complex_kind,
30+ )
31+ )
1832 else
1933 isa (var, Expr) || error (" Expected $var to be a variable name" )
2034 Base. Meta. isexpr (var, :ref ) ||
@@ -28,26 +42,28 @@ function buildpolyvar(var, variable_order, monomial_order)
2842 $ (esc (varname)) = polyarrayvar (
2943 $ (variable_order),
3044 $ (monomial_order),
45+ $ (complex_kind),
3146 $ prefix,
3247 $ (esc .(var. args[2 : end ])... ),
3348 )
3449 )
3550 end
3651end
3752
38- function buildpolyvars (args, variable_order, monomial_order)
53+ function buildpolyvars (args, variable_order, monomial_order, complex_kind )
3954 vars = Symbol[]
4055 exprs = []
4156 for arg in args
42- var, expr = buildpolyvar (arg, variable_order, monomial_order)
57+ var, expr =
58+ buildpolyvar (arg, variable_order, monomial_order, complex_kind)
4359 push! (vars, var)
4460 push! (exprs, expr)
4561 end
4662 return vars, exprs
4763end
4864
4965# Inspired from `JuMP.Containers._extract_kw_args`
50- function _extract_kw_args (args, variable_order)
66+ function _extract_kw_args (args, variable_order, complex_kind )
5167 positional_args = Any[]
5268 monomial_order = :($ (MP. Graded{MP. LexOrder}))
5369 for arg in args
@@ -56,29 +72,42 @@ function _extract_kw_args(args, variable_order)
5672 variable_order = esc (arg. args[2 ])
5773 elseif arg. args[1 ] == :monomial_order
5874 monomial_order = esc (arg. args[2 ])
75+ elseif arg. args[1 ] == :complex
76+ complex_kind = arg. args[2 ] == :true ? COMPLEX : REAL
5977 else
6078 error (" Unrecognized keyword argument `$(arg. args[1 ]) `" )
6179 end
6280 else
6381 push! (positional_args, arg)
6482 end
6583 end
66- return positional_args, variable_order, monomial_order
84+ return positional_args, variable_order, monomial_order, complex_kind
6785end
6886
6987# Variable vector x returned garanteed to be sorted so that if p is built with x then vars(p) == x
7088macro polyvar (args... )
71- pos_args, variable_order, monomial_order =
72- _extract_kw_args (args, :($ (Commutative{CreationOrder})))
73- vars, exprs = buildpolyvars (pos_args, variable_order, monomial_order)
89+ pos_args, variable_order, monomial_order, complex_kind =
90+ _extract_kw_args (args, :($ (Commutative{CreationOrder})), REAL)
91+ vars, exprs =
92+ buildpolyvars (pos_args, variable_order, monomial_order, complex_kind)
7493 return :($ (foldl ((x, y) -> :($ x; $ y), exprs, init = :()));
7594 $ (Expr (:tuple , esc .(vars)... )))
7695end
7796
7897macro ncpolyvar (args... )
79- pos_args, variable_order, monomial_order =
80- _extract_kw_args (args, :($ (NonCommutative{CreationOrder})))
81- vars, exprs = buildpolyvars (pos_args, variable_order, monomial_order)
98+ pos_args, variable_order, monomial_order, complex_kind =
99+ _extract_kw_args (args, :($ (NonCommutative{CreationOrder})), REAL)
100+ vars, exprs =
101+ buildpolyvars (pos_args, variable_order, monomial_order, complex_kind)
102+ return :($ (foldl ((x, y) -> :($ x; $ y), exprs, init = :()));
103+ $ (Expr (:tuple , esc .(vars)... )))
104+ end
105+
106+ macro complex_polyvar (args... )
107+ pos_args, variable_order, monomial_order, complex_kind =
108+ _extract_kw_args (args, :($ (Commutative{CreationOrder})), COMPLEX)
109+ vars, exprs =
110+ buildpolyvars (pos_args, variable_order, monomial_order, complex_kind)
82111 return :($ (foldl ((x, y) -> :($ x; $ y), exprs, init = :()));
83112 $ (Expr (:tuple , esc .(vars)... )))
84113end
@@ -114,19 +143,54 @@ function instantiate(::Type{NonCommutative{O}}) where {O}
114143 return NonCommutative (instantiate (O))
115144end
116145
146+ """
147+ ComplexKind
148+
149+ The type used to identify whether a variable is complex-valued. It has the following instances:
150+ - `REAL`: the variable is real-valued, [`conj`](@ref) and [`real`](@ref) are identities, [`imag`](@ref) is zero.
151+ - `COMPLEX`: the variable is a declared complex-valued variable with distinct conjugate, real, and imaginary part.
152+ [`ordinary_variable`](@ref) is an identity.
153+ - `CONJ`: the variable is the conjugate of a declared complex-valued variable. [`ordinary_variable`](@ref) is equal to
154+ [`conj`](@ref). It will print with an over-bar.
155+ - `REAL_PART`: the variable is the real part of a complex-valued variable. It is real-valued itself: [`conj`](@ref) and
156+ [`real`](@ref) are identities, [`imag`](@ref) is zero. [`ordinary_variable`](@ref) will give back the original complex-valued
157+ _declared_ variable from which the real part was extracted. It will print with an `ᵣ` subscript.
158+ - `IMAG_PART`: the variable is the imaginary part of a declared complex-valued variable (or the negative imaginary part of the
159+ conjugate of a declared complex-valued variable). It is real-valued itself: [`conj`](@ref) and [`real`](@ref) are identities,
160+ [`imag`](@ref) is zero. [`ordinary_variable`](@ref) will give back the original complex-valued _declared_ variable from which
161+ the imaginary part was extracted. It will print with an `ᵢ` subscript.
162+ """
163+ @enum ComplexKind REAL COMPLEX CONJ REAL_PART IMAG_PART
164+
117165struct Variable{V,M} <: AbstractVariable
118166 name:: String
167+ kind:: ComplexKind
119168 variable_order:: V
120169
121- function Variable {V,M} (name:: AbstractString ) where {V<: AbstractVariableOrdering ,M<: MP.AbstractMonomialOrdering }
122- return new {V,M} (convert (String, name), instantiate (V))
170+ function Variable {V,M} (
171+ name:: AbstractString ,
172+ kind:: ComplexKind = REAL,
173+ ) where {V<: AbstractVariableOrdering ,M<: MP.AbstractMonomialOrdering }
174+ return new {V,M} (convert (String, name), kind, instantiate (V))
123175 end
176+
124177 function Variable (
125178 name:: AbstractString ,
126179 :: Type{V} ,
127180 :: Type{M} ,
181+ kind:: ComplexKind = REAL,
128182 ) where {V<: AbstractVariableOrdering ,M<: MP.AbstractMonomialOrdering }
129- return new {V,M} (convert (String, name), instantiate (V))
183+ return new {V,M} (convert (String, name), kind, instantiate (V))
184+ end
185+
186+ function Variable (
187+ from:: Variable{V,M} ,
188+ kind:: ComplexKind ,
189+ ) where {V<: AbstractVariableOrdering ,M<: MP.AbstractMonomialOrdering }
190+ (from. kind == REAL && kind == REAL) ||
191+ (from. kind != REAL && kind != REAL) ||
192+ error (" Cannot change the complex type of an existing variable" )
193+ return new {V,M} (from. name, kind, from. variable_order)
130194 end
131195end
132196
@@ -150,6 +214,41 @@ MP.ordering(::Type{Variable{V,M}}) where {V,M} = M
150214
151215iscomm (:: Type{Variable{C}} ) where {C} = C
152216
217+ Base. isreal (x:: Variable{C} ) where {C} = x. kind != COMPLEX && x. kind != CONJ
218+ MP. isrealpart (x:: Variable{C} ) where {C} = x. kind == REAL_PART
219+ MP. isimagpart (x:: Variable{C} ) where {C} = x. kind == IMAG_PART
220+ MP. isconj (x:: Variable{C} ) where {C} = x. kind == CONJ
221+ function MP. ordinary_variable (x:: Variable )
222+ return x. kind == REAL || x. kind == COMPLEX ? x : Variable (x, COMPLEX)
223+ end
224+
225+ function Base. conj (x:: Variable )
226+ if x. kind == COMPLEX
227+ return Variable (x, CONJ)
228+ elseif x. kind == CONJ
229+ return Variable (x, COMPLEX)
230+ else
231+ return x
232+ end
233+ end
234+
235+ function Base. real (x:: Variable )
236+ if x. kind == COMPLEX || x. kind == CONJ
237+ return Variable (x, REAL_PART)
238+ else
239+ return x
240+ end
241+ end
242+ function Base. imag (x:: Variable{V,M} ) where {V,M}
243+ if x. kind == COMPLEX
244+ return Variable (x, IMAG_PART)
245+ elseif x. kind == CONJ
246+ return _Term {V,M,Int} (- 1 , Monomial (Variable (x, IMAG_PART)))
247+ else
248+ return MA. Zero ()
249+ end
250+ end
251+
153252function mergevars_to! (
154253 vars:: Vector{PV} ,
155254 varsvec:: Vector{Vector{PV}} ,
0 commit comments