Skip to content

perf: comrade performance benchmark#2219

Merged
avik-pal merged 31 commits into
EnzymeAD:mainfrom
ptiede:ptiede-comradeinteg
Feb 13, 2026
Merged

perf: comrade performance benchmark#2219
avik-pal merged 31 commits into
EnzymeAD:mainfrom
ptiede:ptiede-comradeinteg

Conversation

@ptiede

@ptiede ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This is the start of adding Comrade integration tests to Reactant.

This does not currently work.

Integration checklist

@ptiede ptiede marked this pull request as draft January 26, 2026 04:45
@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Current failure

ERROR: MethodError: no method matching ancestor(::Type{ReactantNFFTPlan{…}})

Closest candidates are:
  ancestor(::Type{<:AbstractArray})
   @ Reactant ~/.julia/packages/Reactant/BbquM/src/Reactant.jl:61
  ancestor(::AbstractArray)
   @ Reactant ~/.julia/packages/Reactant/BbquM/src/Reactant.jl:55

Stacktrace:
  [1] ancestor(T::Type{Adjoint{ComplexF64, ReactantNFFTPlan{…}}})
    @ Reactant ~/.julia/packages/Reactant/BbquM/src/Reactant.jl:65
  [2] traced_type_inner(T::Type, seen::Dict{…}, mode::Reactant.TraceMode, track_numbers::Type, ndevices::Any, runtime::Any)
    @ Reactant ~/.julia/packages/Reactant/BbquM/src/Tracing.jl:691
  [3] traced_type_inner(T::Type, seen::Dict{…}, mode::Reactant.TraceMode, track_numbers::Type, ndevices::Any, runtime::Any) (repeats 5 times)
    @ Reactant ~/.julia/packages/Reactant/BbquM/src/Tracing.jl:679
  [4] traced_type(T::Type, ::Val{…}, track_numbers::Type, sharding::Reactant.Sharding.NoSharding, runtime::Val{…})
    @ Reactant ~/.julia/packages/Reactant/BbquM/src/Tracing.jl:981
  [5] make_tracer_unknown(seen::Reactant.OrderedIdDict{…}, prev::Any, path::Any, mode::Reactant.TraceMode; track_numbers::Type, sharding::Any, runtime::Any, kwargs::@Kwargs{})
    @ Reactant ~/.julia/packages/Reactant/BbquM/src/Tracing.jl:1143
  [6] make_tracer_unknown
    @ ~/.julia/packages/Reactant/BbquM/src/Tracing.jl:1120 [inlined]
  [7] #make_tracer#128
    @ ~/.julia/packages/Reactant/BbquM/src/Tracing.jl:1301 [inlined]
  [8] make_tracer
    @ ~/.julia/packages/Reactant/BbquM/src/Tracing.jl:1291 [inlined]
  [9] prepare_mlir_fn_args(args::Tuple{…}, name::String, concretein::Bool, toscalar::Bool, argprefix::Symbol, runtime::Val{…}, optimize_then_pad::Bool, do_transpose::Bool, input_shardings::Nothing, verify_arg_names::Nothing)
    @ Reactant.TracedUtils ~/.julia/packages/Reactant/BbquM/src/TracedUtils.jl:460
 [10] make_mlir_fn(f::typeof(logdensityof), args::Tuple{…}, kwargs::@NamedTuple{}, name::String, concretein::Bool; toscalar::Bool, return_dialect::Symbol, args_in_result::Symbol, construct_function_without_args::Bool, do_transpose::Bool, within_autodiff::Bool, input_shardings::Nothing, output_shardings::Nothing, runtime::Val{…}, verify_arg_names::Nothing, argprefix::Symbol, resprefix::Symbol, resargprefix::Symbol, num_replicas::Int64, optimize_then_pad::Bool)
    @ Reactant.TracedUtils ~/.julia/packages/Reactant/BbquM/src/TracedUtils.jl:331
 [11] make_mlir_fn
    @ ~/.julia/packages/Reactant/BbquM/src/TracedUtils.jl:284 [inlined]
 [12] compile_mlir!(mod::Reactant.MLIR.IR.Module, f::typeof(logdensityof), args::Tuple{…}, compile_options::CompileOptions, callcache::Dict{…}, sdycache::Dict{…}, sdygroupidcache::Tuple{…}; fn_kwargs::@NamedTuple{}, backend::String, runtime::Val{…}, legalize_stablehlo_to_mhlo::Bool, client::Reactant.XLA.PJRT.Client, kwargs::@Kwargs{})
    @ Reactant.Compiler ~/.julia/packages/Reactant/BbquM/src/Compiler.jl:1740
 [13] compile_mlir!
    @ ~/.julia/packages/Reactant/BbquM/src/Compiler.jl:1702 [inlined]
 [14] compile_xla(f::Function, args::Tuple{…}; before_xla_optimizations::Bool, client::Nothing, serializable::Bool, kwargs::@Kwargs{})
    @ Reactant.Compiler ~/.julia/packages/Reactant/BbquM/src/Compiler.jl:3708
 [15] compile_xla
    @ ~/.julia/packages/Reactant/BbquM/src/Compiler.jl:3680 [inlined]
 [16] compile(f::Function, args::Tuple{…}; kwargs::@Kwargs{})
    @ Reactant.Compiler ~/.julia/packages/Reactant/BbquM/src/Compiler.jl:3802
 [17] top-level scope
    @ ~/.julia/packages/Reactant/BbquM/src/Compiler.jl:2850
Some type information was truncated. Use `show(err)` to see complete types.

I am not sure why it is trying to trace the adjoint of the ReactantNFFTPlan

@avik-pal

Copy link
Copy Markdown
Collaborator

I am not sure why it is trying to trace the adjoint of the ReactantNFFTPlan

That's because Adjoint <: AbstractArray. We need to add the dispatches to

function Reactant.make_tracer(
seen,
@nospecialize(prev::AbstractFFTs.Plan{T}),
@nospecialize(path),
mode;
@nospecialize(track_numbers::Type = Union{}),
@nospecialize(sharding = Reactant.Sharding.NoSharding()),
@nospecialize(runtime),
kwargs...,
) where {T}
RT = Reactant.traced_type(typeof(prev), Val(mode), track_numbers, sharding, runtime)
return reactant_fftplan(RT, prev)
end
function Reactant.traced_type_inner(
@nospecialize(T::Type{<:AbstractFFTs.Plan}),
seen,
mode::Reactant.TraceMode,
@nospecialize(track_numbers::Type),
@nospecialize(ndevices),
@nospecialize(runtime)
)
RT = reactant_fftplan_type(T)
return RT
end
to avoid going down the AbstractArray path

Comment thread benchmark/Comrade/Project.toml Outdated
Comment thread test/runtests.jl
end

@safetestset "Comrade.jl Integration" include("integration/Comrade/comimager.jl")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to save some CI time, it might be worth commenting out the other tests and the non-integration builds in ci.yml

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Ok, it looks like I got through part of the NFFT. The next error is related to scalar indexing. It looks like it is because a Tuple is getting converted to a TracedRArray and then Base.tail is getting called on it. The code is https://github.com/tpapp/TransformVariables.jl/blob/1ccad119e40e87dfd5e20f8cefe63aff47449714/src/aggregation.jl#L386-L391

I guess Reactant is smart enough to make everything type stable if this is an array? The reason this was originally a tuple is that its elements can be scalars, arrays, or even other types, and with a tuple, I could make the code mostly type-stable.

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Ok, so I have managed to trace through a bunch of stuff. Now comes the bad part. Distributions.jl support. Distributions.jl is incredibly specific about types, and essentially if your arguments aren't <:Real it won't work out of the box.

So something as simple as

using Distributions
d = Normal()
x = rand()
xr = ConcreteRNumber(x)
@compile logpdf(d, x)
ERROR: MethodError: no method matching logpdf(::Normal{Float64}, ::Reactant.TracedRNumber{Float64})

Closest candidates are:
  logpdf(::Normal, ::Real)
   @ Distributions ~/.julia/packages/Distributions/xMnxM/src/univariates.jl:645
  logpdf(::UnivariateDistribution, ::AbstractArray{<:Real})
   @ Distributions deprecated.jl:103
  logpdf(::Distribution{ArrayLikeVariate{N}}, ::AbstractArray{<:AbstractArray{<:Real, N}}) where N
   @ Distributions ~/.julia/packages/Distributions/xMnxM/src/common.jl:329
  ...

@avik-pal @wsmoses is there any easy way to get around this that doesn't depend on #2170

@avik-pal

Copy link
Copy Markdown
Collaborator

Unfortunately no, the easiest would be to write out sampling on your own

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Ok I wrote some temporary dispatches. The next question is there a way to figure out what is taking so long to compile? The function has been compiling for > 10 minutes

@avik-pal

Copy link
Copy Markdown
Collaborator

Ok, it looks like I got through part of the NFFT. The next error is related to scalar indexing. It looks like it is because a Tuple is getting converted to a TracedRArray and then Base.tail is getting called on it. The code is tpapp/TransformVariables.jl@1ccad11/src/aggregation.jl#L386-L391

Do you have the stacktrace?

@avik-pal

Copy link
Copy Markdown
Collaborator

Ok I wrote some temporary dispatches. The next question is there a way to figure out what is taking so long to compile? The function has been compiling for > 10 minutes

Is allowscalar set to true/false?

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Ok, I figured out all the issues, and the function now compiles! Bad news is that I am seeing a 30x slowdown compared to my usual version. Here is the current MLIR I see

module @reactant_logdens... attributes {mhlo.num_partitions = 1 : i64, mhlo.num_replicas = 1 : i64} {
  func.func @main(%arg0: tensor<128x128xcomplex<f64>> {enzymexla.memory_effects = [], tf.aliasing_output = 1 : i32}, %arg1: tensor<64x64xcomplex<f64>> {enzymexla.memory_effects = []}, %arg2: tensor<4096xi64> {enzymexla.memory_effects = []}, %arg3: tensor<4096xcomplex<f64>> {enzymexla.memory_effects = []}, %arg4: tensor<216x16384xcomplex<f64>> {enzymexla.memory_effects = []}, %arg5: tensor<4368xf64> {enzymexla.memory_effects = []}) -> (tensor<f64>, tensor<128x128xcomplex<f64>>) attributes {enzymexla.memory_effects = []} {
    %cst = stablehlo.constant dense<"0xFA60D6535168FB4051606FE6DEB4A2401421C06514C7FD40608DAE263731AB40B25A9E4BD4F7A240F6AEB87FCE3AFE400699F673C7DDE440055FA319151DA3403E47D7975241FF40A9E80F1629C9E540057909148239A340032A23E8B0230041D4A989A4289CC8404EBCE906C720A3402D7BCA57E51C01417AE5C35FD9FCE640B6031BA2100DA340C7A64907F7AB07415C4601468E16024181C36D60FD3BDD404F806EE5C372E740C3B740C3992FDA408B4353460451A340132B5837D9C401412CAF9E057A711641FEA37F085BE206410D444A9041DEDC40C28F3CA2179CD44027306FD814F4BC4015CB9F1FE6B7E740FB71BF966192DA400624F9F020BAD140BE3A84CAB94CA34028B4BCEA03E5054100F225265897184192C427B986B0DD405764C0ED4377E14075969E1C6D0FC4400F72713C1AD1A3406287B32E576A05416EE02176AB131D414007C061D5230241A23B9CD5988ADC40A97908495393D7407AECC287C107C040B97063F45040E640C262F2419310D94069B400803908D340C00671DA89D50541AB10EA389827A440D64439240DF520418B004BE3C5E0DC4082556008B59EE740EA575B8196E0C740E24289E4EE1FA34020E173F42E5201418BD15C9412510541CEB97CDD0B811F411DCD18F64F3ADC40FE66FBC53AE1EB4087862C179B45C64038DB35257F76E440C77E869315A7E340825DA9D83F0ED7402DFEBFCA1A38A34016DF4F0E049F1F41FC2AFA4523030641E05AB15612FF00411EBF916CACBDDE40B4DA4AC0BEB1ED40CED78370479EC740E77F800E77B3E5405840CFFAD6CDD740B9B68903128FE3402DC420B417CD2041A12F4EBD801FA340004A95610E2B174149E10C83E340014109815F4E06DA0541511F552AC6FAD04035C71A24CE46BC40012B68B08BDCDC40C032EC4BDCCCCF4071EDFC957D0BEF40E9821379CE94C2408348B9D774FDC540ACF5EB76B43DE340DAA826C84C09E040893FE9863E4BD340C149D64934901F419306E19C5F8E184163F893695D90014132932DDD8314A3404CE85EDEF80405412DBA34B3CBD5D040A79DAD2F6C06BC40C98D5295454ADC40AA133174D10CD1408249C2CC1A23F040A3D1E879398FC240B9E072C2DF91C44080928136418FE240EEFE9494B71CD240C3523686EEDCDF40A84EBB949099164134DB9DE04C4AA3407545BC1223272241932D3F4AACA604412565E919C6ED014149CD1EAB9E632241255991263DCCCE40D67844015C28DF40439D4082BAEABB4076C1DCF97393DA405E47BAD7E620CE40C57FB169BE97D1406BC27ADBEA8EF0404F45F54AF59EC94037CD4C27F4B2E240430201E762E4C040D65CE3A71AEDDD40609A70F32CB3DF40277B322B81CDCD40B8447F660A9CD24064837D9D6487AE40F7CE4725023014413ECA22763011A340B9B9E2205F7F22417435C36C1F9E0441D2A43A8AFE7D244114F61BDF87480341FFCA32F29090D1406E2356910FB2E240AB5747E955DFBD40DE71C12D08EDDD405F34BB04CA3AD140DAC486201E98D340A1FD8ACD225DF340B5DE5D32B421CC4009389515A5A9E540765AA4414226C14062313EF89224E04017DB21B4268FCE40973921599C58E0403187C7B680B4D340FCED0FA8DF48AD40DFD20A0E2EE716418A5112C657A61D41838CF5684D37A2407FB491AD16D602419B094B9F03A12441C4231B85078BD040AFABDB96FC38E8408655BFA8A908BD4044F2CAA45ADBDB40A457CFC5C444D7407712B9C15E75D240EE9BCB525A4EF140E2F54754E6BEC64087E985ED8300EC409199DF3F2F29A44015BC194D03601B411101A76F75F3A1408812B337820E2841C1631AFA9A5638413C31EB4CB2000341A8E567EDB162D24093A0B8CC0230EC40E6BC840D48BFC0405B5381913BC1DB404FC795ECCAE3DB408C4A2276AC03D640803A21C6DDB5F340B80FC50C2F05F140CD051B2F866CD9400F7C32D88807A6406BA581C00F5919412B4BAB5897BDA140628D4844A3911541DEC578E5D744274149DDE0E2B3B90341F02261A78812D24029C6D53E45BCE9406A24372AEE78C1407E9DC9B57A91DA40B294A9DC533ADB40DB9ADEC28549D540D81AAFD82731F040663BA66B5212EE403A0CA0966389C64051ADC0D1B6E4A6408FCB5F666C69A1400B0BEF45CFED1341B5D2E21C039E0C41217B93893952054174B034ED54E12141305E20C1E4B9BD403D7F337EA1A8DA40475C2067A858C7405616EB5091B0C1401A94EE62157DE140CA2AEA2D5ED2DB406D35E3A9DDD5D440CE009A79FC0FC540A1AFCED609BDF04052DF589A0004A340A0D4D25D1D1807415D1B0D8244CA0241E5386712AC74114123A31E61010D1B418A3264A83E45AF4046B458BDB933D040BBE70ADBD4EDC24089754D3AE5C8C2407CEA29BC3218E240EADF5C8ACA54A040"> : tensor<216xf64>
    %cst_0 = stablehlo.constant dense<"0x49703506B427ED3F354477775E61DABF914B85FFFFFFEF3FE041E07B892706BFB2BB074EFA1DED3FC162EFE6328CDABFA0B7A50BFB20ED3F76EC875E027FDA3F7C0783FFFFFFEF3FA281C21BAA5B06BFF32814E34715ED3F0ED6919639B2DABF854749306D15ED3F6B542D0897B1DA3FAC007CFFFFFFEF3F466697A75FFA06BFDF88735AC502ED3F9E0BFCA05002DBBFD35D0623EC02ED3F2346D0FCA901DB3F0B9C79FFFFFFEF3FFB91D114752F07BFE09BFDE336FEEC3F85E6B4AEDB15DBBF17C500556BFFEC3F343D396CB210DB3F988D6CFFFFFFEF3FBC2ACD5B194908BF841954F07DF7EC3F367338C49132DBBF02340738A7F7EC3F696CF3E4E131DB3F9E8E67FFFFFFEF3FA31505C48CB108BF12ACC2F914AAEF3FBD1C94CB5E7DC2BF8EE2DC7782F7EC3F13B855787E32DBBFFB6C253E23AAEF3F15A76DCDD77BC23F1A155871ACF7EC3FDA78FBA2CB31DB3F065560E49AA0EE3F3AF52E941D8BD23F413F57FFFFFFEF3F5BCE40E921FB09BF76EF0264AEFDEC3F388823052418DBBF29ED395C11E7EF3F77C209CA28F5B3BF56F1149861BAEF3FAF0D20C6EEA6C0BFA760E21C6FBAEF3FFE8E2E9152A5C03F1DF2A57519E7EF3FC55D0BEDEBF1B33F4FDA0BBBBEF4EF3F23DF55A85AD4AABF65874062DAFDEC3F63D190B76717DB3F578ED90DC981EE3F0807261D2852D33FD190207A76F5ED3F02A4102CD97DD63F454550FFFFFFEF3F2B83BE6039830ABF97C03470BFBFEF3F26E850CD0100C0BF73E1D57EF7E8EF3FF2B63E6A052FB3BF558B28B1CCBFEF3F666848D9B9FCBF3F43E19B70FFE8EF3F94730163B72BB33FA67CCD4CA1F5EF3F4EC21BDEF4C0A9BF151939FFFFFFEF3FC04931D6DE340CBF75921F2558CDEF3F7CDB3BEFD16CBCBF675FB99A99EDEF3F888C285E0026B1BFB89BD059FC15ED3F7A3D19FA26AFDABFEC3B69AB64CDEF3F6873B8E95069BC3F99AEC028A1EDEF3F97F67AC77B22B13FA7B5A824FDF7EF3F8988B1783DA3A6BFC186E5642B16ED3F7C1A53DA59AEDA3F8C0157733163EE3FC2A7E4DB5F0FD43FFA6529BA0EEAED3FC5027CEF40BAD63FD59016144ED1EF3F67A96F9B654BBBBF084430FFFFFFEF3F8A67725473D30CBF3DBEDBC4E4EEEF3FC3B68D770989B0BF5F936B5E5AD1EF3F58FE4B70D047BB3F1827A736ECEEEF3F7CB86BF37085B03F05F9E025B6F8EF3F4250AC96CB97A5BF96E514FFFFFFEF3F61E866C888AA0EBF4C2A2F71723CED3F19EC5EE2E704DABF1EE46DCACEDAEF3F583714D0D05DB8BFC87C5F29DDF1EF3F90C7BADBBE10AEBF1A089676DADAEF3FA347C1E4FF59B83FDEAC695CE4F1EF3F2AD347A21709AE3FEC5DD8C985FAEF3F70B49F2D4DB8A2BFF918244FA43CED3F4A4A98BC0704DA3F84D4B8E319F3ED3F135240696A8AD63FEB9BC1F67657EE3F33EA7420E755D43F3CB109FFFFFFEF3FD448063A6D630FBF4A1A6B01C0F2EF3FA1F4EBB8CF1BADBF86F094E7CCDDEF3FE3B9A431245EB7BFF171E3854549ED3FE908B1BFF6CAD9BFC79B7C5CD8DDEF3FD70533F83B5AB73F2102CA23C7F2EF3F34A9C020FA13AD3F5834FF511EFBEF3FADD805BB3AACA1BF0DAAA01E7849ED3F5292AAEE10CAD93F168E72145557EE3F9DAC1456B156D43FD5B07202D8F8ED3F38FA7D5ACD6BD63F3323FE5D36F9EF3F7527869990D6A43F74F7E5FEFFFFEF3F9C5160B739CB10BF9D68115EBEF4EF3F1D950166C9D4AABFCC7BDCD15673ED3F990094E68008D9BF55172C1907E5EF3F76601678BFC1B4BF151402E530F9EF3F1F346B8AF4DEA43FB5277AA53AC3EF3F7EC7E771D81FBF3FE081B9FC11E5EF3F3DC4643790BDB43F0DB522397EDCEF3F6F20B8472ACFB73F4EF65C67C5F4EF3F99B2B5BC66CCAA3FC451B2D79DFCEF3FECF0E88A716D9DBF7FDDED4BAEEAEC3F1F2D7566E368DB3F2483B15E8B73ED3FB8B424968907D93FD78E47BAE510EE3FD2DB651E81E9D53FC7478423525EEE3F792BB1BDCD2CD43F5DA4555500F6EF3F5FCECC57F249A93F315693863DF5EF3F3396E3F7A03BAABFC42E44A2FE82ED3F73D1C94E53BED8BFD9D4D8FEFFFFEF3FFFDEB74C332E11BF44B0579F05E7EF3F010BB212D9F9B3BF6B765A8AF9F5EF3F4EE96BAB8652A93F55A2160D7BBDEF3F59E7E5D75A47C03F79D8C15710E7EF3FB8A83FE090F5B33F181A1C0486D6EF3F40D4651470BAB93F37D6319044F5EF3F591A61C20C33AA3F7EFAFDFE0BFDEF3FD0F9775F387E9BBFBC8BE20C57DDEC3FBA73323CE9A0DB3FFBA7D9C43383ED3FEC683BC955BDD83F2F913B9F1863EE3FFD00024BF60FD43F78BA4C51581BEE3F5AFF34D8D3AFD53F016FBF6EE2EAEF3FD3ADE333695EB23FA9B4B1FEFFFFEF3F78E593A9A14812BFC560F05735F6EF3F801332719906A9BF7F281C9D8BEBEF3F6F289A1A5514B2BF2312873DCCB1ED3F0FFD90CA3CDAD7BF13C0FD78E3EAEF3FBD98938AF55DB23F3F3872F0ECEAEF3F3CAF123BD859B23FB76A93FAEDEAEF3FEDCB7D816459B23F500F1F6FF8ACEF3F9E8E3035892DC23FF68993768FEBEF3FE2BC2E0DA212B23F4F07FA7DFAACEF3FE7A9C4D34F2DC23F76B8D22463C4EF3FAB05CC4DD5D3BE3FB969345C3BF6EF3F99245D1AE9FEA83F4A884E710EFEEF3FCD13F2F3FE4D96BF623BBEE364C4EF3F6C17362A62D3BE3FEB4B2F0422C3EC3F7940F33C670DDC3F4026CDD6AEB1ED3FBB7B5131CFDAD73F1E8CD783F13DEE3FBC97C272CFEBD43F63A5B6BD6F76EE3F5F421B674599D33F96CB9C5E28C3EC3F42CA8C2E4D0DDC3F6CB7FCFFFFFFEF3F5535D0E324FEDC3ECEBF9A3230E6EF3F3ADD14785B4EB43F28C8A1FEFFFFEF3F0852404DD0B612BFBA2DFB5431E6EF3FAE1FBB6CE94DB43FFA2D5ADEDFECEF3F3717A5DA9D7BB1BF8344011C6CF6EF3F54D8E59B44C0A8BFDF9A42682BC4ED3F3F3D279AF17DD7BF1930375124E6EF3F6DA6605F0553B43F9E15D07325E6EF3F5AAF34589352B43FA4E57D36BFA6EF3FF71A1926DED7C23F997A6216EAECEF3F6BFF77F3F276B13FB3147E51C1A6EF3F2CADD58FA5D7C23FE67ECE7B3ABDEF3F174FF434374FC03F026A6B5773F6EF3F96D6E8FDEBB6A83F23DBED365DFEEF3FA909EBFA957694BFC0F0624E3CBDEF3F2F41AB74FE4EC03F7C881808A5BDEC3FB6580C40DE23DC3F68843B5B62C4ED3F113E9412DB7CD73F45DC7490BB7FEE3FA6193D401A5FD33FE06DC7849F4CEE3F5381126F2A96D43FE2DA3E52ABBDEC3F5DC0E88DC423DC3F85CDFCFFFFFFEF3F054C9C24EF9BDC3EADD78E620AD0EF3FB68BC64718A9BB3F9F38ADFE7CF6EF3F79404BCF6CAAA8BFEF6755FEFFFFEF3F7C988D8476A714BFB6637F98E2F0EF3F214FC6CE8116AFBF7E7C9AD40BD0EF3FE56101E1ADA8BB3F9A598186F8CFEF3FC149C5633AAEBB3F189CC7F8F9CFEF3F77C81F00D0ADBB3F540F601A458BEF3FD546C353FE87C53F5BFD279FECF0EF3F7E2B8201330CAF3F3C5B895A478BEF3F28B6F291C987C53F313A805DF19BEF3FAAB2EE08CDF1C33F8176D1F284F6EF3FE49109221CA0A83FDB9AF4875AFFEF3F319D07CEF7B989BF45291473F39BEF3F51C55F2E98F1C33FF433FDFFFFFFEF3F38D7593C50C2DA3E644A32F6E9C0EF3F3050872AA0B5BF3FA7AC15FEFFFFEF3F52F7BA12AF2416BF7B96AA86EBC0EF3FF6432FE83BB5BF3FA5EA863992F5EF3FF437464DA3D3A9BFA3E2D1DB21F2EF3FFBEA195567C7ADBF4885EF02D4C0EF3FF75F9C731EBBBF3F4BE69B93D5C0EF3F2275DD35BABABF3FCB5AD9C62278EF3F6562A7B01D37C73F37A183272CF2EF3F78C123CA59BCAD3F910307112578EF3F4B5E0507EC36C73F8F8CF3856183EF3FE5AEE486D33DC63F6ABC2B279BF5EF3F17AA0C8F94C8A93F9F9486B76383EF3F4254DFCBA13DC63FB5B4D955C1FFEF3F693615BE06AA7FBFAF82FDFFFFFFEF3F69575FC2C23ED93EAE13ECA2D4B4EF3F0213770EDC4CC13F8EEBCAFDFFFFEF3FA5DA1E0A7BC517BFBE6E1D237EF3EF3F7611AB981D48ACBF64B63439D6B4EF3F91E29684AD4CC13F534E522FF6F1EF3F13800BA41CF6ADBF093A57ECBAB4EF3F92D0E6CCCD4FC13FDA1F6983BCB4EF3FD8BE0C349F4FC13FC863C2F42066EF3F2A3C6FF633B1C83F8B75FF4D01F2EF3FDE76C71F3FEAAD3FBB7F0B392366EF3F92A3DFD705B1C83F490E1331476BEF3F9F53C49D8447C83F5D3F14A288F3EF3F46DFEF823F3CAC3FE5BE806B496BEF3F82A2DA7A5647C83FB83B9CADF4FFEF3F08A7B06F16EB6ABFC8D7FDFFFFFFEF3F8B2BEFDBD27FD73E28EB87FDFFFFEF3F5E04479B272419BF1FBFBCB79BAFEF3F2C47A59663E3C13FEA80B40E6EF0EF3F3C1847355A8DAFBF7941300762F0EF3FADA8A9248599AFBF5C2D9A3E9DAFEF3FF42DD35038E3C13FD994D7D79EAFEF3F5288C7010BE3C13F44442E60A0AFEF3FADC05591DFE2C13FBA81B68C8FF0EF3F05AB6BAB606BAF3F8AEE37927C59EF3FD258454831ADC93FD53879C37E59EF3FAFD9F77306ADC93F0F50398CAFF0EF3FBFB5788DC84AAF3F5E8CBCB0A359EF3FDB8DA3E734AAC93F9F81ADFDFFFFEF3FD63B0189DA6118BF92CDD6E1A559EF3F95E91F110AAAC93F1622FEFFFFFFEF3F9273083779DCD53E318C237242AFEF3F15B27EE342EDC13F05FE98BF57EFEF3FD49E46762751B0BF330643B2D9EEEF3F754EFF26618EB0BFBE621DEE43AFEF3F9786ECE918EDC13FCAF70F78A355EF3F72F9BBF6EBF7C93FDC4CB89EA555EF3F47307C6FC2F7C93FBA4AE8431454EF3FDF7682F5F415CA3F87CFBE14FFFFEF3F3A2233D50FAD4E3F11DCFC6C1654EF3F2DF69371CB15CA3F613EFEFFFFFFEF3F39E0F9864834D53E"> : tensor<216xcomplex<f64>>
    %cst_1 = stablehlo.constant dense<1.562500e-02> : tensor<64x64xf64>
    %cst_2 = stablehlo.constant dense<-142.60790014549835> : tensor<f64>
    %cst_3 = stablehlo.constant dense<0.10132118364233778> : tensor<f64>
    %cst_4 = stablehlo.constant {enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} dense<"0xFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840"> : tensor<104xf64>
    %cst_5 = stablehlo.constant dense<0x7FF0000000000000> : tensor<216xf64>
    %cst_6 = stablehlo.constant dense<0xFFF0000000000000> : tensor<216xf64>
    %cst_7 = stablehlo.constant dense<0.000000e+00> : tensor<216xf64>
    %cst_8 = stablehlo.constant dense<1.000000e+00> : tensor<64x64xf64>
    %cst_9 = stablehlo.constant dense<3.000000e+00> : tensor<64x64xf64>
    %cst_10 = stablehlo.constant dense<1.000000e+00> : tensor<82xf64>
    %cst_11 = stablehlo.constant dense<0x7FF0000000000000> : tensor<104xf64>
    %cst_12 = stablehlo.constant dense<0xFFF0000000000000> : tensor<104xf64>
    %cst_13 = stablehlo.constant dense<-3776.4484124697938> : tensor<f64>
    %cst_14 = stablehlo.constant dense<6.399000e+01> : tensor<f64>
    %cst_15 = stablehlo.constant dense<4.1587268211513688> : tensor<f64>
    %cst_16 = stablehlo.constant dense<1.000000e-02> : tensor<f64>
    %cst_17 = stablehlo.constant {enzymexla.finite = [#enzymexla<guaranteed GUARANTEED>], enzymexla.no_nan = [#enzymexla<guaranteed GUARANTEED>]} dense<0.000000e+00> : tensor<f64>
    %cst_18 = stablehlo.constant {enzymexla.finite = [#enzymexla<guaranteed GUARANTEED>]} dense<0.000000e+00> : tensor<104xf64>
    %c = stablehlo.constant dense<104> : tensor<82x1xi64>
    %cst_19 = stablehlo.constant dense<0.000000e+00> : tensor<22xf64>
    %cst_20 = stablehlo.constant dense<0xFFF0000000000000> : tensor<f64>
    %cst_21 = stablehlo.constant dense<47.670366753349001> : tensor<f64>
    %cst_22 = stablehlo.constant dense<[[-1.5707963267948966, -1.521708941582556, -1.4726215563702154, -1.4235341711578751, -1.3744467859455345, -1.3253594007331939, -1.2762720155208536, -1.227184630308513, -1.1780972450961724, -1.1290098598838318, -1.0799224746714913, -1.0308350894591509, -0.98174770424681035, -0.93266031903446977, -0.88357293382212931, -0.83448554860978885, -0.78539816339744828, -0.73631077818510771, -0.68722339297276724, -0.63813600776042678, -0.58904862254808621, -0.53996123733574564, -0.49087385212340517, -0.44178646691106466, -0.39269908169872414, -0.34361169648638362, -0.2945243112740431, -0.24543692606170259, -0.19634954084936207, -0.14726215563702155, -0.098174770424681035, -0.049087385212340517, 0.000000e+00, 0.049087385212340517, 0.098174770424681035, 0.14726215563702155, 0.19634954084936207, 0.24543692606170259, 0.2945243112740431, 0.34361169648638362, 0.39269908169872414, 0.44178646691106466, 0.49087385212340517, 0.53996123733574564, 0.58904862254808621, 0.63813600776042678, 0.68722339297276724, 0.73631077818510771, 0.78539816339744828, 0.83448554860978885, 0.88357293382212931, 0.93266031903446977, 0.98174770424681035, 1.0308350894591509, 1.0799224746714913, 1.1290098598838318, 1.1780972450961724, 1.227184630308513, 1.2762720155208536, 1.3253594007331939, 1.3744467859455345, 1.4235341711578751, 1.4726215563702154, 1.521708941582556]]> : tensor<1x64xf64>
    %cst_23 = stablehlo.constant dense<3.8349519697141029E-4> : tensor<f64>
    %c_24 = stablehlo.constant dense<1> : tensor<4096x1xi64>
    %c_25 = stablehlo.constant dense<128> : tensor<4096x1xi64>
    %cst_26 = stablehlo.constant dense<1864.4723931804929> : tensor<f64>
    %cst_27 = stablehlo.constant dense<1.000000e+00> : tensor<f64>
    %cst_28 = stablehlo.constant dense<-2.000000e+00> : tensor<f64>
    %cst_29 = stablehlo.constant dense<5.000000e-01> : tensor<82xf64>
    %cst_30 = stablehlo.constant dense<-5.000000e-01> : tensor<82xf64>
    %cst_31 = stablehlo.constant dense<8.000000e+00> : tensor<82xf64>
    %c_32 = stablehlo.constant dense<[[1], [3], [4], [6], [7], [9], [10], [12], [13], [15], [16], [18], [19], [20], [22], [23], [24], [25], [27], [28], [29], [31], [32], [33], [34], [36], [37], [38], [40], [41], [42], [43], [45], [46], [47], [48], [50], [51], [52], [53], [54], [56], [57], [58], [59], [60], [62], [63], [64], [65], [66], [67], [69], [70], [71], [72], [73], [74], [76], [77], [78], [79], [80], [82], [83], [84], [85], [86], [88], [89], [90], [91], [92], [94], [95], [96], [97], [98], [100], [101], [102], [103]]> : tensor<82x1xi64>
    %c_33 = stablehlo.constant dense<[[0], [2], [5], [8], [11], [14], [17], [21], [26], [30], [35], [39], [44], [49], [55], [61], [68], [75], [81], [87], [93], [99]]> : tensor<22x1xi64>
    %cst_34 = stablehlo.constant dense<5.000000e-01> : tensor<f64>
    %cst_35 = stablehlo.constant dense<[-1.5707963267948966, -1.521708941582556, -1.4726215563702154, -1.4235341711578751, -1.3744467859455345, -1.3253594007331939, -1.2762720155208536, -1.227184630308513, -1.1780972450961724, -1.1290098598838318, -1.0799224746714913, -1.0308350894591509, -0.98174770424681035, -0.93266031903446977, -0.88357293382212931, -0.83448554860978885, -0.78539816339744828, -0.73631077818510771, -0.68722339297276724, -0.63813600776042678, -0.58904862254808621, -0.53996123733574564, -0.49087385212340529, -0.44178646691106471, -0.39269908169872414, -0.34361169648638357, -0.29452431127404299, -0.24543692606170264, -0.19634954084936207, -0.1472621556370215, -0.098174770424681145, -0.049087385212340573, 0.000000e+00, 0.049087385212340573, 0.098174770424681145, 0.1472621556370215, 0.19634954084936207, 0.24543692606170264, 0.29452431127404299, 0.34361169648638357, 0.39269908169872414, 0.44178646691106449, 0.49087385212340529, 0.53996123733574564, 0.58904862254808599, 0.63813600776042678, 0.68722339297276713, 0.73631077818510793, 0.78539816339744828, 0.83448554860978863, 0.88357293382212942, 0.93266031903446977, 0.98174770424681057, 1.0308350894591509, 1.0799224746714913, 1.1290098598838321, 1.1780972450961724, 1.2271846303085128, 1.2762720155208536, 1.3253594007331939, 1.3744467859455343, 1.4235341711578751, 1.4726215563702154, 1.5217089415825562]> : tensor<64xf64>
    %cst_36 = stablehlo.constant dense<(0.000000e+00,0.000000e+00)> : tensor<128x128xcomplex<f64>>
    %c_37 = stablehlo.constant dense<128> : tensor<4096x2xi64>
    %c_38 = stablehlo.constant dense<"0x01000000030000000400000003000000060000000700000006000000090000000A000000090000000C0000000D0000000C0000000F000000100000000F000000120000001300000014000000120000001200000013000000160000001900000018000000170000001600000016000000170000001600000017000000180000001B0000001C0000001D0000001B0000001B0000001C0000001F0000002000000021000000220000001F0000001F000000200000001F0000002000000021000000250000002400000026000000240000002400000025000000280000002B000000290000002A000000280000002800000029000000280000002A000000290000002D0000002F0000002E000000300000002D0000002D0000002E0000002D0000002E0000002F0000003400000032000000350000003600000033000000340000003400000032000000340000003200000033000000340000003200000035000000330000003A0000003B0000003C00000038000000390000003A0000003A000000380000003A00000038000000390000003A00000038000000390000003B000000400000003E000000410000003F00000042000000430000004000000043000000400000003E00000043000000400000003E0000003F00000043000000400000003E000000410000003F000000430000004000000047000000450000004A000000460000004800000049000000470000004A00000047000000450000004A0000004700000045000000460000004A000000470000004500000046000000480000004A000000470000004E0000004F0000004C0000004D000000500000004E000000500000004E0000004C000000500000004E0000004C0000004D000000500000004E0000005400000052000000560000005500000053000000540000005600000054000000520000005600000054000000520000005600000053000000540000005A000000580000005B0000005C000000590000005A0000005C0000005A000000580000005C0000005A000000580000005C000000590000005A0000005E00000060000000610000005F0000006200000060000000620000005E00000060000000620000005E000000600000005F000000620000006000000065000000640000006600000067000000650000006700000065000000640000006700000065000000"> : tensor<216x1xi32>
    %c_39 = stablehlo.constant dense<"0x0000000002000000020000000400000005000000050000000700000008000000080000000A0000000B0000000B0000000D0000000E0000000E00000010000000110000001100000011000000130000001400000014000000150000001500000015000000150000001700000018000000180000001900000019000000190000001A0000001A0000001A0000001C0000001D0000001D0000001E0000001E0000001E0000001E00000020000000210000002100000022000000220000002200000023000000230000002300000025000000260000002600000027000000270000002700000027000000290000002A0000002A0000002B0000002B0000002B0000002C0000002C0000002C0000002C0000002E0000002F0000002F00000030000000300000003000000031000000310000003100000031000000310000003200000033000000330000003500000035000000350000003600000036000000360000003600000037000000370000003700000037000000370000003800000039000000390000003B0000003B0000003B0000003C0000003C0000003C0000003C0000003D0000003D0000003D0000003D0000003D0000003D0000003E0000003E0000003F0000003F0000003F0000004100000041000000410000004100000042000000420000004200000042000000420000004300000044000000440000004400000044000000440000004400000045000000450000004600000046000000460000004800000048000000480000004800000049000000490000004900000049000000490000004A0000004B0000004B0000004B0000004B0000004B0000004C0000004C0000004D0000004D0000004D0000004F0000004F0000004F0000004F00000050000000510000005100000051000000510000005100000052000000520000005300000053000000530000005500000055000000550000005500000056000000570000005700000057000000570000005700000058000000580000005900000059000000590000005B0000005B0000005B0000005B0000005C0000005D0000005D0000005D0000005D0000005D0000005E0000005E0000005F0000005F0000005F000000610000006100000061000000610000006200000063000000630000006300000063000000640000006400000066000000660000006600000067000000"> : tensor<216x1xi32>
    %cst_40 = stablehlo.constant dense<"0x398EE3AC95A9C2BF711CC7ECC311753F5555555579A9E83FAAAAAA6A5E2DE5BF5555555BFCEFC1BFAAAA8A201E2F81BF555555A5DF4CC0BF000000F80161BA3F1CC77130096FEA3F1CC771CC34D7E2BF398EE33E68A8C1BFAAAAAAB83D1295BFE3388E1254ECBABF1CC771BE04C5B53FE3388E2F5ABFEB3F398EE30C1F9BE0BFAAAAAAE28A39C0BF711CC76132A6AABF8EE338046D0CB6BF398E83DFBA12B83F000000462371EB3F0000001EABDAE0BF0000003C773FBEBF8EE33858A788B0BF00000036D34CB3BF000000608AB9BB3FE3388EBF2D6CED3F711CC7B1A6C6DABF55555585DDBAB8BFC7711C670491B6BF0000C00A1544AABF8EE3385235D4BC3FAAAAAADA93C6ED3F000000AC8680D9BF388EE30E7C06993F1CC771609FC4BA3F398EE36C4F93B5BF711CC7A1995FB8BF5555D5F95E017BBFC7711CBF2AA4B9BFE3380EBB8620A6BFC7719CB69987BC3FE3380E247A17943FAAAA1A7D9507B83FAAAAAA62344EEE3FAAAAAA2E4B93D5BF555555A1E9E3ADBF55555561FE4FBDBF555555ADFE49B03F1CC77114A4CB9B3F1CC7CD80A5F966BF1CC771742618BC3FE338AE6B6101A6BFE3388E2C3C9AB9BF000020E65ABEAB3FAAAAD1402791A5BF8EE338FDB4A1CD3F000040B2CEE9C53F388E63FD64418DBF555555914B88BE3FAAAAEAED2D839E3F711CC7AF73B2B63F711C1F6F8DC2AF3FE3387E508A88B03F34488364247CEE3F976FF9063AA1D4BF2776E24DF6C384BF555555053AC6BC3F488334E0CE96B03F3BB1132B69CA9D3F133BF188104DA4BF76620730911ABDBFCBB7FC0B3C8DAB3F7DCB37AD7951A5BF6FF996431273CD3F900669DA9271CB3F1CC771541E85EE3F8EE338AA388ED1BFAAAAAA3899E7A5BF388EE396FBA8BA3FC7711C834393A93FE3388EF97A129A3F5555D5675C6C89BF555555438E19C0BF398EA30F8AB1B0BF1CC7710A3863B7BF1CC7B1240DC8AA3FC771DC31E78BA3BFAAAA0A1F6C45C43F5555555C9BD7CE3FC771CCD1165E923F0000007A94A2BF3F398EE3C953B7973FE3384E2F4D7BB83FE3384E3510B6B43F5555D5F61687A93FE3388E6BC2A7AABFAAAAAA429B22B93FE3388E3B375AEE3FE3388E510BC5D0BF711CC71DE943AA3F555555F9F6119D3F398E29FDE813B1BF5555D5C68250B5BF0000E074B077A73F398EA3AF7338A3BF00008093D4A3C43FC7711C0D691ED13F555555499A5CEF3FE3388E27D85DCFBFE3388EBDB7F6A23FAAAAAA82FBB9BFBF398EE31617DFB3BFAAAAAA16FF09B53F1CC771D8F9CFAA3FC7711CAF494EA23F1CC7E9B6434FB7BF398E231890FBB0BF555555CEDAA4A33FC7715CDACEFFA9BF711CC74F4B35C43F398EE37ED6EBD43F1CC7710F4511B03F1CC76121A954BD3FC7711C87584FBB3FAAAA2AB3071C8E3F5555F5A91F57AB3F8EE3F85AD350B83F83344813114AEF3F833448D3673DCFBF766227765667AA3FAAAAAA12ABA0A33F4FECC45E0D1FB6BF411AA4C9E142B23FA4411A64839DA83F4EECC46E4036BFBFA4419A5738EAB7BF1AA4C14EA85BA9BF277662344AD9A73F900649ABE115AABF5CBEE5CFC230C23F9DD889AD60E8D43F4FECC4E99AB2B13FCBB77C4B2CBEBA3F8A9DD82B6747AE3F5CBE65359734B93F8A9DD8A16400BF3FABAA6A61C4E6903FE3388E28E90B95BF711CC7EA3A95A23F711CC7F95555EF3FE3388E07DBDBCFBFC7711C879A3BAC3F1CC77180CA8BAB3F8EE3386EC573B43FE3388E2F1B1ABABF1CC7719C3004BBBF711CC751D86EA33FE3388E89CF738CBF5555D5E0C878973F1CC771CEEB7EA03FC7716C8771E2B2BFE33896E27607BBBFE338CE19CA1486BFAAAA000E016C9C3FE3388ECCF157883F398E23FE74F5A13F1CC7F12A434FAFBFE3384E5BC874BB3F000000F4DAC8DA3F1CC7719EEB458CBFAAAAAA89A80B8F3FE3388EC6BD3CB83F1CC731287EC0B43F00000046DDA9C43FE33862760A9391BFAAAACA424E1EB33FC7719CC681CABE3F398EE358E07A98BF711CC79DFE50A33F8EE338F625D1A93F00000030B33AAC3F8EE338D642ADB63F555555E1C09FB7BF000000F45656EF3F398EE3AC2930D0BF555555716754BCBFAAAAAA2427739D3F8EE338F9E30084BF398EE383709AA23FAAAAAA1C3AC59F3F711C0707AD0FB8BFAAAAAA7003E4BCBFAAAA2A119FA4733FAAAA1A6AED6D923F388EE34EA820993F5555F58E14A2A33F398EE327CEAAB0BF1CC751BB97C3BF3FE3388EA782E8DA3F555555D583BD5ABF398EE33BC7E5903F55555543EDADB83FE338FE7EFD22B23F5555ED0CA269B43FE3380EEA59C1BE3F555555C9569AC43F398EA361399DA0BFC7711C1F1EF5A4BF0000003DDA1EA83F0F0F0F8F54F3EE3F4B4B4BDB4EAED1BF8EE3382C9C54A03FE3388E4B8C09AA3F388EE38C948ABDBF1CC791FC5CE77ABF00000000EB1BBB3F555555AD975CB1BF8EE39806D3A084BF000000B83699AABF2D2D2DC70830A4BF0F0F0FB1485FAB3F96969645AF837C3F96961681B8C7AABF398ED3214452A13FE3388EB07AB8B9BFB5B4B40824BDBBBF3C3CFC8B6DACA23F398E03BAC493A13FE3384E6E1B48B53F8EE3381E89CA7E3FAAAAAAFB1C95973F878707434D2A973F969676FC7CF7ABBF398E6372D440B83F1CC771D2AD80D53F5555F5E27EE380BFE338A63495A980BFE3388ED3A194973F1CC7F16942B5913F969616E969E2BC3F0F0F0F668D55A63FE3388E49DD13C13F8EE3F8ADE12E9BBF8EE3B8EC312DB63F5555F549EA09C13F1CC771D4C7D579BF1CC771BFA3A382BF8EE338132E28E0BFE3380EC26160D2BF4883348820EAA8BF833448C31221AA3F7CCBB76C1AFFEE3F976FF94669B6D2BF699086B213E48ABF622776B2C003ABBF766227865A51BDBFCBB77CD3D88494BF1AA441FA050E9A3FF9966FC9F5D6A93FB1133B614A68BB3F8A9DD83930F1ACBF344883C89120AFBF0DD220C10F4AA23F622776EEAB3A6BBF2776E2DA4E6BABBFB1133B7F920EA13F210DD2C31A80BDBF976FF95E0C45B9BF2EDF1250F28FAD3F488334B88FDAAC3FD220AD402531A93F5CBEE55AD4DE97BF411AA415E33C913F7CCBB7354BDB8C3F5CBEE581717BACBF0DD22079E223B53F0DD22075CABCD43FA4411A1EE37783BF976FF9BF310587BFB1133B291D35703F976FF9E8990E983F6227768AD3CBBC3FB87C4B43E92F9B3FBEE59B5C38BCB53F900689F1B22BC03FD2200D2CF2ADC03FBEE55B0E1929A4BFAAAAAA107F4A8BBF2EDFF285929A693F622776F26287DABF411AA4B9B83DDFBFC7711C9F4DE5A9BF398EE3BC29E6A23FC7711C432DB49EBF388EE39855D7AE3F1CC7711861DCEE3FE3388EFB4911D8BFAAAAAAFA4D3DB7BFC7711C973889B4BF711CC785308BA7BFAAAAAA98154A99BFAAAAEAE2DF25A5BF711CC7E220968E3FC7711C0E38BBA3BF55551299D1A7A0BF8EE3B8A220C78ABF398E1B847C6AA7BF55555552F592ACBFC7719C8C96B9B83FC7717C84CA2FA53F711CC71AF68393BFE3388EB9391971BF5555D533F625A83F5555D54FA707A9BFAAAA2AE00A67A9BF8EE338621224D23F398EE3CA6FC9D03F5555D539633FA6BF711C6FAC83F1813F8EE3381E7D23DE3F1CC771ACD5C2E7BF388EE388B05BA9BFAAAAAA9A74669C3FAAAAAA2E7ED8ED3FAAAAAAEE34D9DDBF0000008CF108A9BF0000A0CA1A997B3F55555577AF7BA0BF8EE33819C49C573F0000004ABAF5A4BF8EE338265240BDBF711C475A734FABBF1CC7714CA4CC3F3F555595259505A5BF1CC77153C29085BF388EE36E02097EBF0000003BC82577BF8EE368E4E628813F55555DB47429BD3F1CC7717AE9F7603F711CAF9E7C7F94BFE3380E4F6AD28E3F8EE378872E83903F711CA76DDFC89FBFAAAAAA68C691873F555555783FBE8C3F711C076280199E3F0000008AE832C73F8EE3D88515D7913F00000058E879EA3F5555FDACDE36CEBF1CC7712C43B9ABBF398EE3289698973F711CC77D4D49EC3FAAAAAA1E9B11E2BF555555E1C7C5B1BF1CC7718C59DCA4BFC7711C1FC8DEA0BFC7711C86AFBAA23FAAAAAAAC54B5963F1CC771909BC0BDBF55555571E5D5AFBFE3388E1F4D4364BFAAAA6AF2953CA7BFAAAA49AC78C77D3FAAAAAA6A588F58BFAAAAAACC5F62933FE3383E1CE04AB43FE3382E2D10AEB63FAAAAAABF9CF86BBF555505D71B1D8E3F5555C546B08FB53F0000C0E50A13933F5555C58BE2DEA2BFE3380EED04E3B13F1CC7F1B94ABAB03FC7714C7FCA9983BFC7711CF323FED83F398E138C35EBA5BFE3388E93910FE93F00000059208ED33F222222C21485EA3F333333830A0DE5BF8EE338DE08ECB0BF5555555DAB2C953FAAAAAAA4A680B1BF711CC73BD7A3B2BFAAAAAAAA776FAD3F711CC7F152B8B8BFAAAAAAE06C9C97BFAAAAAA5E97F5AB3F444444042009A8BF9A9999D9A1DCA2BF333373FCBC79A8BF1111D12F0D5CA03F222222B8C1ADB93F55555532694FA53F00000020FB4F9F3FE338AEA5FA47903FC7716E0E89968D3F55555591A9AF673F33333369DDC971BF11111111A0EDB53F8EE33840073FB93FC7711CC11F357FBF1CC771307205DA3F8EE3B8A33DE0AABF711C87F63D9BAB3F8EE3784D0533B2BF00000070FC69E33F555555E54AAFE73F000000D46C93B2BF00000020AEC09B3F0000005DD86EB13F00000075B703B6BF00000058AB3BABBF0000805B627CB0BF0000001592848CBF000000341AE9AE3F0000005E5E31973F000000C07E30503F0000C060A17A943F0000388A4C7382BF0000000AA056B53F000080AC031193BF000080D8E664D53F0000C0248BA897BF000000A208EC9A3F0000602586DBAEBF000000964B98E03F000000407679EA3F"> : tensor<216xcomplex<f64>>
    %0 = stablehlo.reshape %arg2 : (tensor<4096xi64>) -> tensor<4096x1xi64>
    %1 = stablehlo.slice %arg5 [0:4096] : (tensor<4368xf64>) -> tensor<4096xf64>
    %2 = stablehlo.convert %1 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xf64>) -> tensor<4096xcomplex<f64>>
    %3 = stablehlo.reshape %2 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xcomplex<f64>>) -> tensor<64x64xcomplex<f64>>
    %4 = stablehlo.transpose %3, dims = [1, 0] : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xcomplex<f64>>
    %5 = stablehlo.slice %arg5 [4096:4097] : (tensor<4368xf64>) -> tensor<1xf64>
    %6 = stablehlo.reshape %5 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %7 = stablehlo.logistic %6 : tensor<f64>
    %8 = stablehlo.abs %6 : tensor<f64>
    %9 = stablehlo.negate %8 : tensor<f64>
    %10 = stablehlo.exponential %9 : tensor<f64>
    %11 = stablehlo.add %cst_27, %10 : tensor<f64>
    %12 = stablehlo.log %11 : tensor<f64>
    %13 = stablehlo.multiply %cst_28, %12 : tensor<f64>
    %14 = stablehlo.add %9, %13 : tensor<f64>
    %15 = stablehlo.multiply %cst_14, %7 : tensor<f64>
    %16 = stablehlo.add %15, %cst_16 : tensor<f64>
    %17 = stablehlo.add %14, %cst_15 : tensor<f64>
    %18 = stablehlo.slice %arg5 [4097:4098] : (tensor<4368xf64>) -> tensor<1xf64>
    %19 = stablehlo.reshape %18 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %20 = stablehlo.logistic %19 : tensor<f64>
    %21 = stablehlo.abs %19 : tensor<f64>
    %22 = stablehlo.negate %21 : tensor<f64>
    %23 = stablehlo.exponential %22 : tensor<f64>
    %24 = stablehlo.add %cst_27, %23 : tensor<f64>
    %25 = stablehlo.log %24 : tensor<f64>
    %26 = stablehlo.multiply %cst_28, %25 : tensor<f64>
    %27 = stablehlo.add %22, %26 : tensor<f64>
    %28 = stablehlo.multiply %cst_14, %20 : tensor<f64>
    %29 = stablehlo.add %28, %cst_16 : tensor<f64>
    %30 = stablehlo.add %27, %cst_15 : tensor<f64>
    %31 = stablehlo.slice %arg5 [4098:4099] : (tensor<4368xf64>) -> tensor<1xf64>
    %32 = stablehlo.reshape %31 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %33 = stablehlo.logistic %32 : tensor<f64>
    %34 = stablehlo.abs %32 : tensor<f64>
    %35 = stablehlo.negate %34 : tensor<f64>
    %36 = stablehlo.exponential %35 : tensor<f64>
    %37 = stablehlo.add %cst_27, %36 : tensor<f64>
    %38 = stablehlo.log %37 : tensor<f64>
    %39 = stablehlo.multiply %cst_28, %38 : tensor<f64>
    %40 = stablehlo.add %35, %39 : tensor<f64>
    %41 = stablehlo.multiply %cst_14, %33 : tensor<f64>
    %42 = stablehlo.add %41, %cst_16 : tensor<f64>
    %43 = stablehlo.add %40, %cst_15 : tensor<f64>
    %44 = stablehlo.add %30, %43 : tensor<f64>
    %45 = stablehlo.add %17, %44 : tensor<f64>
    %46 = stablehlo.slice %arg5 [4099:4100] : (tensor<4368xf64>) -> tensor<1xf64>
    %47 = stablehlo.reshape %46 {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.no_nan = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %48 = stablehlo.exponential %47 {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.no_nan = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} : tensor<f64>
    %49 = stablehlo.add %45, %47 : tensor<f64>
    %50 = stablehlo.slice %arg5 [4100:4204] {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4368xf64>) -> tensor<104xf64>
    %51 = stablehlo.slice %arg5 [4204:4367:2] : (tensor<4368xf64>) -> tensor<82xf64>
    %52 = stablehlo.slice %arg5 [4205:4368:2] : (tensor<4368xf64>) -> tensor<82xf64>
    %53 = stablehlo.atan2 %51, %52 : tensor<82xf64>
    %54 = stablehlo.multiply %52, %52 : tensor<82xf64>
    %55 = stablehlo.multiply %51, %51 : tensor<82xf64>
    %56 = stablehlo.add %55, %54 : tensor<82xf64>
    %57 = stablehlo.log %56 : tensor<82xf64>
    %58 = stablehlo.multiply %57, %cst_29 : tensor<82xf64>
    %59 = stablehlo.multiply %57, %cst_30 : tensor<82xf64>
    %60 = stablehlo.multiply %58, %58 : tensor<82xf64>
    %61 = stablehlo.negate %60 : tensor<82xf64>
    %62 = stablehlo.multiply %61, %cst_31 : tensor<82xf64>
    %63 = stablehlo.add %62, %59 : tensor<82xf64>
    %64 = stablehlo.reduce(%63 init: %cst_17) applies stablehlo.add across dimensions = [0] : (tensor<82xf64>, tensor<f64>) -> tensor<f64>
    %65 = stablehlo.remainder %c_32, %c : tensor<82x1xi64>
    %66 = "stablehlo.scatter"(%cst_18, %65, %53) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0], scatter_dims_to_operand_dims = [0], index_vector_dim = 1>}> ({
    ^bb0(%arg6: tensor<f64>, %arg7: tensor<f64>):
      stablehlo.return %arg7 : tensor<f64>
    }) : (tensor<104xf64>, tensor<82x1xi64>, tensor<82xf64>) -> tensor<104xf64>
    %67 = "stablehlo.scatter"(%66, %c_33, %cst_19) <{indices_are_sorted = false, scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0], scatter_dims_to_operand_dims = [0], index_vector_dim = 1>, unique_indices = true}> ({
    ^bb0(%arg6: tensor<f64>, %arg7: tensor<f64>):
      stablehlo.return %cst_17 : tensor<f64>
    }) : (tensor<104xf64>, tensor<22x1xi64>, tensor<22xf64>) -> tensor<104xf64>
    %68 = stablehlo.add %49, %64 : tensor<f64>
    %69 = stablehlo.dot_general %1, %1, contracting_dims = [0] x [0] : (tensor<4096xf64>, tensor<4096xf64>) -> tensor<f64>
    %70 = stablehlo.negate %69 : tensor<f64>
    %71 = stablehlo.multiply %70, %cst_34 : tensor<f64>
    %72 = stablehlo.negate %48 : tensor<f64>
    %73 = stablehlo.compare  LT, %48, %cst_17 : (tensor<f64>, tensor<f64>) -> tensor<i1>
    %74 = stablehlo.select %73, %cst_20, %72 : tensor<i1>, tensor<f64>
    %75 = stablehlo.add %71, %cst_13 : tensor<f64>
    %76 = stablehlo.add %75, %74 : tensor<f64>
    %77 = stablehlo.multiply %50, %50 {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} : tensor<104xf64>
    %78 = stablehlo.multiply %77, %cst_4 {enzymexla.no_nan = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} : tensor<104xf64>
    %79 = stablehlo.is_finite %78 : (tensor<104xf64>) -> tensor<104xi1>
    %80 = stablehlo.not %79 : tensor<104xi1>
    %81 = stablehlo.compare  NE, %78, %cst_11 : (tensor<104xf64>, tensor<104xf64>) -> tensor<104xi1>
    %82 = stablehlo.and %80, %81 : tensor<104xi1>
    %83 = stablehlo.compare  NE, %78, %cst_12 : (tensor<104xf64>, tensor<104xf64>) -> tensor<104xi1>
    %84 = stablehlo.and %82, %83 : tensor<104xi1>
    %85 = stablehlo.select %84, %cst_18, %78 : tensor<104xi1>, tensor<104xf64>
    %86 = stablehlo.reduce(%85 init: %cst_17) applies stablehlo.add across dimensions = [0] : (tensor<104xf64>, tensor<f64>) -> tensor<f64>
    %87 = stablehlo.negate %86 : tensor<f64>
    %88 = stablehlo.multiply %87, %cst_34 : tensor<f64>
    %89 = stablehlo.add %88, %cst_21 : tensor<f64>
    %90 = "stablehlo.gather"(%67, %65) <{dimension_numbers = #stablehlo.gather<offset_dims = [0], start_index_map = [0], index_vector_dim = 1>, indices_are_sorted = false, slice_sizes = array<i64: 1>}> : (tensor<104xf64>, tensor<82x1xi64>) -> tensor<1x82xf64>
    %91 = stablehlo.cosine %90 : tensor<1x82xf64>
    %92 = stablehlo.reshape %91 : (tensor<1x82xf64>) -> tensor<82xf64>
    %93 = stablehlo.subtract %92, %cst_10 : tensor<82xf64>
    %94 = stablehlo.reduce(%93 init: %cst_17) applies stablehlo.add across dimensions = [0] : (tensor<82xf64>, tensor<f64>) -> tensor<f64>
    %95 = stablehlo.multiply %94, %cst_3 : tensor<f64>
    %96 = stablehlo.add %95, %cst_2 : tensor<f64>
    %97 = stablehlo.add %89, %96 : tensor<f64>
    %98 = stablehlo.add %76, %97 : tensor<f64>
    %99 = stablehlo.broadcast_in_dim %cst_35, dims = [0] : (tensor<64xf64>) -> tensor<64x64xf64>
    %100 = stablehlo.broadcast_in_dim %cst_22, dims = [0, 1] : (tensor<1x64xf64>) -> tensor<64x64xf64>
    %101 = stablehlo.multiply %99, %99 : tensor<64x64xf64>
    %102 = stablehlo.multiply %100, %100 : tensor<64x64xf64>
    %103 = stablehlo.add %101, %102 : tensor<64x64xf64>
    %104 = stablehlo.multiply %16, %16 : tensor<f64>
    %105 = stablehlo.broadcast_in_dim %104, dims = [] : (tensor<f64>) -> tensor<64x64xf64>
    %106 = stablehlo.multiply %105, %103 : tensor<64x64xf64>
    %107 = stablehlo.multiply %29, %29 : tensor<f64>
    %108 = stablehlo.broadcast_in_dim %107, dims = [] : (tensor<f64>) -> tensor<64x64xf64>
    %109 = stablehlo.multiply %108, %103 : tensor<64x64xf64>
    %110 = stablehlo.multiply %109, %109 : tensor<64x64xf64>
    %111 = stablehlo.multiply %42, %42 : tensor<f64>
    %112 = stablehlo.broadcast_in_dim %111, dims = [] : (tensor<f64>) -> tensor<64x64xf64>
    %113 = stablehlo.multiply %112, %103 : tensor<64x64xf64>
    %114 = stablehlo.power %113, %cst_9 : tensor<64x64xf64>
    %115 = stablehlo.add %106, %110 : tensor<64x64xf64>
    %116 = stablehlo.add %115, %114 : tensor<64x64xf64>
    %117 = stablehlo.add %cst_8, %116 : tensor<64x64xf64>
    %118 = stablehlo.rsqrt %117 : tensor<64x64xf64>
    %119 = stablehlo.convert %118 : (tensor<64x64xf64>) -> tensor<64x64xcomplex<f64>>
    %120 = chlo.conj %119 : tensor<64x64xcomplex<f64>> -> tensor<64x64xcomplex<f64>>
    %121 = stablehlo.multiply %119, %120 : tensor<64x64xcomplex<f64>>
    %122 = stablehlo.real %121 : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xf64>
    %123 = stablehlo.reduce(%122 init: %cst_17) applies stablehlo.add across dimensions = [0, 1] : (tensor<64x64xf64>, tensor<f64>) -> tensor<f64>
    %124 = stablehlo.multiply %123, %cst_23 : tensor<f64>
    %125 = stablehlo.rsqrt %124 : tensor<f64>
    %126 = stablehlo.multiply %119, %4 : tensor<64x64xcomplex<f64>>
    %127 = stablehlo.convert %125 : (tensor<f64>) -> tensor<complex<f64>>
    %128 = stablehlo.broadcast_in_dim %127, dims = [] : (tensor<complex<f64>>) -> tensor<64x64xcomplex<f64>>
    %129 = stablehlo.multiply %126, %128 : tensor<64x64xcomplex<f64>>
    %130 = stablehlo.fft %129, type =  FFT, length = [64, 64] {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xcomplex<f64>>
    %131 = stablehlo.real %130 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xf64>
    %132 = stablehlo.imag %130 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xf64>
    %133 = stablehlo.add %131, %132 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %134 = stablehlo.multiply %133, %cst_1 : tensor<64x64xf64>
    %135 = stablehlo.broadcast_in_dim %48, dims = [] {enzymexla.symmetric_matrix = [#enzymexla<guaranteed GUARANTEED>]} : (tensor<f64>) -> tensor<64x64xf64>
    %136 = stablehlo.multiply %134, %135 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %137 = stablehlo.reduce(%136 init: %cst_20) applies stablehlo.maximum across dimensions = [0, 1] : (tensor<64x64xf64>, tensor<f64>) -> tensor<f64>
    %138 = stablehlo.broadcast_in_dim %137, dims = [] {enzymexla.symmetric_matrix = [#enzymexla<guaranteed GUARANTEED>]} : (tensor<f64>) -> tensor<64x64xf64>
    %139 = stablehlo.subtract %136, %138 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %140 = stablehlo.exponential %139 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %141 = stablehlo.transpose %140, dims = [1, 0] : (tensor<64x64xf64>) -> tensor<64x64xf64>
    %142 = stablehlo.reshape %141 : (tensor<64x64xf64>) -> tensor<4096xf64>
    %143 = stablehlo.reduce(%140 init: %cst_17) applies stablehlo.add across dimensions = [0, 1] : (tensor<64x64xf64>, tensor<f64>) -> tensor<f64>
    %144 = stablehlo.broadcast_in_dim %143, dims = [] : (tensor<f64>) -> tensor<4096xf64>
    %145 = stablehlo.divide %142, %144 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<4096xf64>
    %146 = stablehlo.convert %145 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xf64>) -> tensor<4096xcomplex<f64>>
    %147 = stablehlo.multiply %146, %arg3 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<4096xcomplex<f64>>
    %148 = stablehlo.subtract %0, %c_24 : tensor<4096x1xi64>
    %149 = stablehlo.divide %148, %c_25 : tensor<4096x1xi64>
    %150 = stablehlo.concatenate %148, %149, dim = 1 : (tensor<4096x1xi64>, tensor<4096x1xi64>) -> tensor<4096x2xi64>
    %151 = stablehlo.remainder %150, %c_37 : tensor<4096x2xi64>
    %152 = "stablehlo.scatter"(%cst_36, %151, %147) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0, 1], scatter_dims_to_operand_dims = [0, 1], index_vector_dim = 1>}> ({
    ^bb0(%arg6: tensor<complex<f64>>, %arg7: tensor<complex<f64>>):
      stablehlo.return %arg7 : tensor<complex<f64>>
    }) {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<128x128xcomplex<f64>>, tensor<4096x2xi64>, tensor<4096xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %153 = stablehlo.transpose %152, dims = [1, 0] : (tensor<128x128xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %154 = stablehlo.fft %153, type =  FFT, length = [128, 128] : (tensor<128x128xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %155 = stablehlo.reshape %154 : (tensor<128x128xcomplex<f64>>) -> tensor<16384x1xcomplex<f64>>
    %156 = stablehlo.dot_general %arg4, %155, contracting_dims = [1] x [0], precision = [DEFAULT, DEFAULT] : (tensor<216x16384xcomplex<f64>>, tensor<16384x1xcomplex<f64>>) -> tensor<216x1xcomplex<f64>>
    %157 = stablehlo.reshape %156 : (tensor<216x1xcomplex<f64>>) -> tensor<216xcomplex<f64>>
    %158 = stablehlo.multiply %157, %cst_0 : tensor<216xcomplex<f64>>
    %159 = "stablehlo.gather"(%50, %c_38) <{dimension_numbers = #stablehlo.gather<collapsed_slice_dims = [0], start_index_map = [0], index_vector_dim = 1>, indices_are_sorted = false, slice_sizes = array<i64: 1>}> : (tensor<104xf64>, tensor<216x1xi32>) -> tensor<216xf64>
    %160 = "stablehlo.gather"(%67, %c_38) <{dimension_numbers = #stablehlo.gather<collapsed_slice_dims = [0], start_index_map = [0], index_vector_dim = 1>, indices_are_sorted = false, slice_sizes = array<i64: 1>}> : (tensor<104xf64>, tensor<216x1xi32>) -> tensor<216xf64>
    %161 = "stablehlo.gather"(%50, %c_39) <{dimension_numbers = #stablehlo.gather<collapsed_slice_dims = [0], start_index_map = [0], index_vector_dim = 1>, indices_are_sorted = false, slice_sizes = array<i64: 1>}> : (tensor<104xf64>, tensor<216x1xi32>) -> tensor<216xf64>
    %162 = "stablehlo.gather"(%67, %c_39) <{dimension_numbers = #stablehlo.gather<collapsed_slice_dims = [0], start_index_map = [0], index_vector_dim = 1>, indices_are_sorted = false, slice_sizes = array<i64: 1>}> : (tensor<104xf64>, tensor<216x1xi32>) -> tensor<216xf64>
    %163 = stablehlo.complex %159, %160 : tensor<216xcomplex<f64>>
    %164 = stablehlo.complex %161, %162 : tensor<216xcomplex<f64>>
    %165 = stablehlo.exponential %163 : tensor<216xcomplex<f64>>
    %166 = stablehlo.exponential %164 : tensor<216xcomplex<f64>>
    %167 = chlo.conj %165 : tensor<216xcomplex<f64>> -> tensor<216xcomplex<f64>>
    %168 = stablehlo.multiply %166, %158 : tensor<216xcomplex<f64>>
    %169 = stablehlo.multiply %168, %167 : tensor<216xcomplex<f64>>
    %170 = stablehlo.subtract %cst_40, %169 : tensor<216xcomplex<f64>>
    %171 = chlo.conj %170 : tensor<216xcomplex<f64>> -> tensor<216xcomplex<f64>>
    %172 = stablehlo.multiply %170, %171 : tensor<216xcomplex<f64>>
    %173 = stablehlo.real %172 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<216xcomplex<f64>>) -> tensor<216xf64>
    %174 = stablehlo.multiply %173, %cst {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<216xf64>
    %175 = stablehlo.is_finite %174 : (tensor<216xf64>) -> tensor<216xi1>
    %176 = stablehlo.not %175 : tensor<216xi1>
    %177 = stablehlo.compare  NE, %174, %cst_5 : (tensor<216xf64>, tensor<216xf64>) -> tensor<216xi1>
    %178 = stablehlo.and %176, %177 : tensor<216xi1>
    %179 = stablehlo.compare  NE, %174, %cst_6 : (tensor<216xf64>, tensor<216xf64>) -> tensor<216xi1>
    %180 = stablehlo.and %178, %179 : tensor<216xi1>
    %181 = stablehlo.select %180, %cst_7, %174 : tensor<216xi1>, tensor<216xf64>
    %182 = stablehlo.reduce(%181 init: %cst_17) applies stablehlo.add across dimensions = [0] : (tensor<216xf64>, tensor<f64>) -> tensor<f64>
    %183 = stablehlo.negate %182 : tensor<f64>
    %184 = stablehlo.multiply %183, %cst_34 : tensor<f64>
    %185 = stablehlo.add %184, %cst_26 : tensor<f64>
    %186 = stablehlo.add %185, %98 : tensor<f64>
    %187 = stablehlo.add %186, %68 : tensor<f64>
    return %187, %154 : tensor<f64>, tensor<128x128xcomplex<f64>>
  }
}

@avik-pal

Copy link
Copy Markdown
Collaborator

Is this CPU/GPU slowdown?

@avik-pal

Copy link
Copy Markdown
Collaborator

Also just to rule out things, can you check if Reactant.Compiler.WHILE_UNROLL_THRESHOLD[] = 0 changes anything

@wsmoses

wsmoses commented Jan 26, 2026

Copy link
Copy Markdown
Member

I would start to look at the scatters/gather/giant constants

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

This is compared to my CPU code. Both the GPU and CPU code with Reactant seem to run at roughly the same speed.
Reactant.Compiler.WHILE_UNROLL_THRESHOLD[] = 0 didn't seem to make a big difference.

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Ok, it seems that a major slowdown is coming from the NFFT. I am not too surprised about that tbh. We aren't doing the optimal thing there. One way forward would be to use cufinufft.

@avik-pal

Copy link
Copy Markdown
Collaborator

Profiling script without any extra deps https://gist.github.com/avik-pal/3b2cc6ebbb8f9f6e68311a2825dd53da

@avik-pal

Copy link
Copy Markdown
Collaborator

I would also test F32 performance

@avik-pal

Copy link
Copy Markdown
Collaborator

I dont think it is the NFFT

╔================================================================================╗
║ KERNEL STATISTICS                                                              ║
╚================================================================================╝

┌───────────────────────────────────────────────────────┬─────────────┬────────────────┬──────────────┬──────────────┬──────────────┬──────────────┬───────────┬──────────┬────────────┬──────
│                                           Kernel Name │ Occurrences │ Total Duration │ Avg Duration │ Min Duration │ Max Duration │ Static Shmem │ Block Dim │ Grid Dim │ TensorCore │ Occ ⋯
├───────────────────────────────────────────────────────┼─────────────┼────────────────┼──────────────┼──────────────┼──────────────┼──────────────┼───────────┼──────────┼────────────┼──────
│                             loop_dynamic_slice_fusion │        4096 │    0.00477979s │  0.00000117s │  0.00000112s │  0.00001347s │      0 bytes │     1,1,1 │    1,1,1 │          ✗ │     ⋯
│                      loop_dynamic_update_slice_fusion │        4096 │    0.00439980s │  0.00000107s │  0.00000102s │  0.00001616s │      0 bytes │     1,1,1 │    1,1,1 │          ✗ │     ⋯
│                                   input_reduce_fusion │        4096 │    0.00431064s │  0.00000105s │  0.00000102s │  0.00001126s │      0 bytes │     2,1,1 │    1,1,1 │          ✗ │     ⋯
│                                       loop_add_fusion │        4096 │    0.00373408s │  0.00000091s │  0.00000090s │  0.00000378s │      0 bytes │     1,1,1 │    1,1,1 │          ✗ │     ⋯
│                                  loop_multiply_fusion │           1 │    0.00062912s │  0.00062912s │  0.00062912s │  0.00062912s │      0 bytes │   128,1,1 │ 6912,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_9 │           1 │    0.00037929s │  0.00037929s │  0.00037929s │  0.00037929s │   16.500 KiB │  1024,1,1 │  896,1,1 │          ✗ │     ⋯
│ void regular_fft<128u, EPT<8u>, 16u, 4u, (padding_... │           2 │    0.00003379s │  0.00001690s │  0.00001670s │  0.00001709s │   16.000 KiB │   16,16,1 │    8,1,1 │          ✗ │     ⋯
│ void vector_fft<128u, EPT<8u>, 2u, 24u, (padding_t... │           2 │    0.00001763s │  0.00000882s │  0.00000877s │  0.00000887s │    2.062 KiB │    16,2,1 │   64,1,1 │          ✗ │     ⋯
│ void regular_fft<64u, EPT<8u>, 32u, 4u, (padding_t... │           1 │    0.00001200s │  0.00001200s │  0.00001200s │  0.00001200s │   16.000 KiB │    32,8,1 │    2,1,1 │          ✗ │     ⋯
│                                loop_multiply_fusion_3 │           1 │    0.00000736s │  0.00000736s │  0.00000736s │  0.00000736s │      0 bytes │   128,1,1 │    2,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_8 │           1 │    0.00000666s │  0.00000666s │  0.00000666s │  0.00000666s │   16.500 KiB │  1024,1,1 │    7,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_2 │           1 │    0.00000528s │  0.00000528s │  0.00000528s │  0.00000528s │     64 bytes │   256,1,1 │    1,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_3 │           2 │    0.00000515s │  0.00000258s │  0.00000256s │  0.00000259s │     64 bytes │   256,1,1 │    1,1,1 │          ✗ │     ⋯
│ void vector_fft<64u, EPT<8u>, 8u, 18u, (padding_t)... │           1 │    0.00000429s │  0.00000429s │  0.00000429s │  0.00000429s │    8.000 KiB │     8,8,1 │    8,1,1 │          ✗ │     ⋯
│                                     loop_add_fusion_1 │           1 │    0.00000410s │  0.00000410s │  0.00000410s │  0.00000410s │      0 bytes │     1,1,1 │    1,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_6 │           1 │    0.00000371s │  0.00000371s │  0.00000371s │  0.00000371s │     64 bytes │   256,1,1 │    1,1,1 │          ✗ │     ⋯
│                                loop_multiply_fusion_1 │           1 │    0.00000317s │  0.00000317s │  0.00000317s │  0.00000317s │      0 bytes │   128,1,1 │   32,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_4 │           1 │    0.00000310s │  0.00000310s │  0.00000310s │  0.00000310s │      0 bytes │    32,1,1 │    1,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_7 │           1 │    0.00000301s │  0.00000301s │  0.00000301s │  0.00000301s │      0 bytes │    32,1,1 │    1,1,1 │          ✗ │     ⋯
│                              input_transpose_fusion_1 │           1 │    0.00000294s │  0.00000294s │  0.00000294s │  0.00000294s │    8.250 KiB │   128,1,1 │    4,1,1 │          ✗ │     ⋯
│                                  input_scatter_fusion │           1 │    0.00000272s │  0.00000272s │  0.00000272s │  0.00000272s │      0 bytes │    96,1,1 │    1,1,1 │          ✗ │     ⋯
│                                      loop_real_fusion │           1 │    0.00000237s │  0.00000237s │  0.00000237s │  0.00000237s │      0 bytes │   128,1,1 │   32,1,1 │          ✗ │     ⋯
│                                loop_multiply_fusion_2 │           1 │    0.00000227s │  0.00000227s │  0.00000227s │  0.00000227s │      0 bytes │   128,1,1 │   32,1,1 │          ✗ │     ⋯
│                               loop_exponential_fusion │           1 │    0.00000218s │  0.00000218s │  0.00000218s │  0.00000218s │      0 bytes │   128,1,1 │   32,1,1 │          ✗ │     ⋯
│                                     loop_add_fusion_2 │           1 │    0.00000198s │  0.00000198s │  0.00000198s │  0.00000198s │      0 bytes │     1,1,1 │    1,1,1 │          ✗ │     ⋯
│                                     loop_add_fusion_3 │           1 │    0.00000195s │  0.00000195s │  0.00000195s │  0.00000195s │      0 bytes │     1,1,1 │    1,1,1 │          ✗ │     ⋯
│                         input_broadcast_reduce_fusion │           1 │    0.00000176s │  0.00000176s │  0.00000176s │  0.00000176s │      0 bytes │    32,1,1 │    1,1,1 │          ✗ │     ⋯
│                                     wrapped_transpose │           1 │    0.00000173s │  0.00000173s │  0.00000173s │  0.00000173s │   16.500 KiB │   128,1,1 │   16,1,1 │          ✗ │     ⋯
│                                     loop_add_fusion_4 │           1 │    0.00000170s │  0.00000170s │  0.00000170s │  0.00000170s │      0 bytes │     1,1,1 │    1,1,1 │          ✗ │     ⋯
│                                    loop_divide_fusion │           1 │    0.00000141s │  0.00000141s │  0.00000141s │  0.00000141s │      0 bytes │   128,1,1 │   32,1,1 │          ✗ │     ⋯
│                                 input_reduce_fusion_5 │           1 │    0.00000134s │  0.00000134s │  0.00000134s │  0.00000134s │      0 bytes │    32,1,1 │    1,1,1 │          ✗ │     ⋯
│                               loop_concatenate_fusion │           1 │    0.00000125s │  0.00000125s │  0.00000125s │  0.00000125s │      0 bytes │   128,1,1 │   32,1,1 │          ✗ │     ⋯
│                                input_transpose_fusion │           1 │    0.00000115s │  0.00000115s │  0.00000115s │  0.00000115s │    8.250 KiB │   128,1,1 │    4,1,1 │          ✗ │     ⋯
│                                input_scatter_fusion_1 │           1 │    0.00000112s │  0.00000112s │  0.00000112s │  0.00000112s │      0 bytes │    32,1,1 │    1,1,1 │          ✗ │     ⋯
│                                 loop_broadcast_fusion │           1 │    0.00000109s │  0.00000109s │  0.00000109s │  0.00000109s │      0 bytes │   128,1,1 │  128,1,1 │          ✗ │     ⋯
└───────────────────────────────────────────────────────┴─────────────┴────────────────┴──────────────┴──────────────┴──────────────┴──────────────┴───────────┴──────────┴────────────┴──────
                                                                                                                                                                              1 column omitted

something is getting emitted as a while loop

%while_body (param.1: (s32[], c128[128,128], s64[4096,2], c128[4096])) -> (s32[], c128[128,128], s64[4096,2], c128[4096]) {
  %param.1 = (s32[], c128[128,128]{1,0}, s64[4096,2]{1,0}, c128[4096]{0}) parameter(0)
  %get-tuple-element.15 = s32[] get-tuple-element(%param.1), index=0
  %get-tuple-element.21 = s64[4096,2]{1,0} get-tuple-element(%param.1), index=2
  %get-tuple-element.16 = c128[128,128]{1,0} get-tuple-element(%param.1), index=1
  %loop_dynamic_slice_fusion = c128[1,1]{1,0} fusion(%get-tuple-element.16, %get-tuple-element.21, %get-tuple-element.15), kind=kLoop, calls=%fused_dynamic_slice
  %input_reduce_fusion = pred[] fusion(%get-tuple-element.21, %get-tuple-element.15), kind=kInput, calls=%fused_reduce, backend_config={"operation_queue_id":"0","wait_on_operation_queues":[],"force_earliest_schedule":false,"reification_cost":[],"device_type":"DEVICE_TYPE_INVALID","native_emitter_backend_config":{}}
  %get-tuple-element.22 = c128[4096]{0} get-tuple-element(%param.1), index=3
  %loop_dynamic_update_slice_fusion = c128[128,128]{1,0} fusion(%get-tuple-element.16, %loop_dynamic_slice_fusion, %input_reduce_fusion, %get-tuple-element.22, %get-tuple-element.15, /*index=5*/%get-tuple-element.21), kind=kLoop, calls=%fused_dynamic_update_slice, control-predecessors={%loop_dynamic_slice_fusion}
  %loop_add_fusion = s32[] fusion(%get-tuple-element.15), kind=kLoop, calls=%fused_add, control-predecessors={%loop_dynamic_update_slice_fusion, %loop_dynamic_slice_fusion, %input_reduce_fusion}
  ROOT %tuple.7 = (s32[], c128[128,128]{1,0}, s64[4096,2]{1,0}, c128[4096]{0}) tuple(%loop_add_fusion, %loop_dynamic_update_slice_fusion, %get-tuple-element.21, %get-tuple-element.22)
}

@avik-pal

avik-pal commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator
  %while = (s32[], c128[128,128]{1,0}, s64[4096,2]{1,0}, c128[4096]{0}) while(%tuple.5), condition=%while_cond, body=%while_body, backend_config={"known_trip_count":{"n":"4096"},"known_init_step":{"init":"0","step":"1"},"known_induction_variable":{"tuple_index":"0"},"dynamic_variable_tuple_indices":[]}

likely from

    %152 = "stablehlo.scatter"(%cst_36, %151, %147) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0, 1], scatter_dims_to_operand_dims = [0, 1], index_vector_dim = 1>}> ({
    ^bb0(%arg6: tensor<complex<f64>>, %arg7: tensor<complex<f64>>):
      stablehlo.return %arg7 : tensor<complex<f64>>
    }) {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<128x128xcomplex<f64>>, tensor<4096x2xi64>, tensor<4096xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
  %scatter.5 = c128[128,128]{1,0} scatter(%broadcast.42, %remainder.1, %multiply.71), update_window_dims={}, inserted_window_dims={0,1}, scatter_dims_to_operand_dims={0,1}, index_vector_dim=1, to_apply=%region_8.9

@avik-pal

Copy link
Copy Markdown
Collaborator

Ok I have a fix, we can decompose the setindex scatter for complex numbers into real parts

%152 = stablehlo.real %147 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xcomplex<f64>>) -> tensor<4096xf64>
    %153 = stablehlo.imag %147 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xcomplex<f64>>) -> tensor<4096xf64>
    %154 = "stablehlo.scatter"(%cst_41, %casted, %152) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0, 1], scatter_dims_to_operand_dims = [0, 1], index_vector_dim = 1>, unique_indices = true}> ({
    ^bb0(%arg6: tensor<f64>, %arg7: tensor<f64>):
      stablehlo.return %arg7 : tensor<f64>
    }) {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<128x128xf64>, tensor<4096x2xi32>, tensor<4096xf64>) -> tensor<128x128xf64>
    %155 = "stablehlo.scatter"(%cst_41, %casted, %153) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0, 1], scatter_dims_to_operand_dims = [0, 1], index_vector_dim = 1>, unique_indices = true}> ({
    ^bb0(%arg8: tensor<f64>, %arg9: tensor<f64>):
      stablehlo.return %arg9 : tensor<f64>
    }) {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<128x128xf64>, tensor<4096x2xi32>, tensor<4096xf64>) -> tensor<128x128xf64>
    %156 = stablehlo.complex %154, %155 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<128x128xcomplex<f64>> 
╔================================================================================╗
║ KERNEL STATISTICS                                                              ║
╚================================================================================╝

┌───────────────────────────────────────────────────────┬─────────────┬────────────────┬──────────────┬──────────────┬──────────────┬──────────────┬───────────┬──────────┬────────────┬─────────────┐
│                                           Kernel Name │ Occurrences │ Total Duration │ Avg Duration │ Min Duration │ Max Duration │ Static Shmem │ Block Dim │ Grid Dim │ TensorCore │ Occupancy % │
├───────────────────────────────────────────────────────┼─────────────┼────────────────┼──────────────┼──────────────┼──────────────┼──────────────┼───────────┼──────────┼────────────┼─────────────┤
│                                  loop_multiply_fusion │           1 │    0.00057494s │  0.00057494s │  0.00057494s │  0.00057494s │      0 bytes │   128,1,1 │ 6912,1,1 │          ✗ │      100.0% │
│                                 input_reduce_fusion_8 │           1 │    0.00037939s │  0.00037939s │  0.00037939s │  0.00037939s │   16.500 KiB │  1024,1,1 │  896,1,1 │          ✗ │       66.7% │
│ void regular_fft<128u, EPT<8u>, 16u, 4u, (padding_... │           2 │    0.00003245s │  0.00001622s │  0.00001616s │  0.00001629s │   16.000 KiB │   16,16,1 │    8,1,1 │          ✗ │       66.7% │
│ void vector_fft<128u, EPT<8u>, 2u, 24u, (padding_t... │           2 │    0.00001760s │  0.00000880s │  0.00000880s │  0.00000880s │    2.062 KiB │    16,2,1 │   64,1,1 │          ✗ │       50.0% │
│ void regular_fft<64u, EPT<8u>, 32u, 4u, (padding_t... │           1 │    0.00001203s │  0.00001203s │  0.00001203s │  0.00001203s │   16.000 KiB │    32,8,1 │    2,1,1 │          ✗ │       66.7% │
│                                loop_multiply_fusion_3 │           1 │    0.00000739s │  0.00000739s │  0.00000739s │  0.00000739s │      0 bytes │   128,1,1 │    2,1,1 │          ✗ │      100.0% │
│                                 input_reduce_fusion_7 │           1 │    0.00000666s │  0.00000666s │  0.00000666s │  0.00000666s │   16.500 KiB │  1024,1,1 │    7,1,1 │          ✗ │       66.7% │
│                                 input_reduce_fusion_1 │           1 │    0.00000525s │  0.00000525s │  0.00000525s │  0.00000525s │     64 bytes │   256,1,1 │    1,1,1 │          ✗ │      100.0% │
│                                 input_reduce_fusion_2 │           2 │    0.00000518s │  0.00000259s │  0.00000259s │  0.00000259s │     64 bytes │   256,1,1 │    1,1,1 │          ✗ │      100.0% │

@avik-pal

Copy link
Copy Markdown
Collaborator

That takes the runtime from 0.05150747s to 0.00118310s (@ptiede is this close to your CPU runtime for non-reactant version?)

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Ok so this is weird, on the Reactant#aem branch I am seeing a runtime of 3ms and on this branch before your change it was 30ms

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

The 3ms time matched the raw time I was seeing from the NFFT so I was tricked by that.

My regular Julia CPU time is 100 µs.

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

The 1ms you have is a great fix, though.

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

On the aem branch I was seeing the following mlir emitted

module @reactant_logdens... attributes {mhlo.num_partitions = 1 : i64, mhlo.num_replicas = 1 : i64} {
  func.func @main(%arg0: tensor<128x128xcomplex<f64>> {enzymexla.memory_effects = [], tf.aliasing_output = 1 : i32}, %arg1: tensor<64x64xcomplex<f64>> {enzymexla.memory_effects = []}, %arg2: tensor<4096xi64> {enzymexla.memory_effects = []}, %arg3: tensor<4096xcomplex<f64>> {enzymexla.memory_effects = []}, %arg4: tensor<274x16384xcomplex<f64>> {enzymexla.memory_effects = []}, %arg5: tensor<4428xf64> {enzymexla.memory_effects = []}) -> (tensor<f64>, tensor<128x128xcomplex<f64>>) attributes {enzymexla.memory_effects = []} {
    %cst = stablehlo.constant dense<"0xEAA6785FC7B800415ABF91665E099E408378D90DA6D2FE40C446EE1BA6E5104197CCB1C3F0D7D9402173A3460C3CDC404CA5256B5B56E0403F82EF1E6C0A9E4090ED221B56DC0941D67C3583C65B0141240BD80A47B4DC40B22B22D0649CDC4013481883D904E24068FE4B4476099E400DE9EC0615D102411E398AB7B9AF0C41EE1C4EAF6C69E040B600A0B005AFDC40BD37ED16AD24E540700BEAC913F69D40C43FDAA3F42603416CB8B952C2CE09417E346C43F0C7E3407CE1D0516CD4E040BA775682E57EE740844E7EF2D350EA4058EECAB08DD7EC40C26E901C6371E240C48E3CD7870E9E40EB2D6E45D80B234177BD1FC783C305410BA6D84E00B9EA401874A30F0C8DEB4084984014164BE1403A97704B930E9E40E035AB5224CE2841CFC6D9D65A1E06413494DF70A8EEEC40A07CA0EAD2E5E04017A3B9F32B14ED4067EBC794310F9E408C8CE80266E52A41B1BE9E9740E0054111AA6944E204F04012F4FF593F53ED4063B0B6B3B492E140078770BEC80E9E403A7A99ADF8EC07415748A86EA8180641256C46ED7AC332418FC188BC8CE5CA400F6EA1041BE0EE400C2EFA48F52DD240DC0404BF7E61DE40D5382A64AA25C94034412689C2B2EC4062220F9116FE9D40E6BB052A63E50841EC32319E407332411ADA49E2FBC30C41B06C78048EA0A440FDF375C3651FC740A835FF1DE4E1D240B828AE2C9373B74063C063C74357EC407A1BFF7E628BC940CE486E2D860F9E406DFA5FAAEAF10841C7F993C71D992941EAD6B264505D034101A32C46B0D6B14041339D065911BF405BF1CC3B313ED2408800A7AD3265C2408003AAAF4977C940101FA3F7F696EB408C7D01F7BEEB9D4018704AB721B90241E1BE534A2B6F0D41E90F586E7CE73241EFD7E958C6E004419FD71BBCF4337940CB22E12D9E189640FCE32E44616DA0405031BB00DC06BA40CBA24F397344C2409F31BBA62D92D440E4A24F301AF8A540937961E25D19B04082DF2D1CFC7CC8400F8D8CDAF073EA406062372D4E059E40CF60A6039ABE0441ED0F271E70B83241DCF264A843F80141A10D42FFA72209411542AC9505050B41291CF668EC1A984008AC06138D9EB0407973F73F54EEA4408460A9777F57B9407081F12A7514D24064CA53ED5B11C740ED3C1DF4E59EDC400962D71A0242D540D5928C775FAAB9404A950D5DE85CB040255C78A42C29C440FB7AF6CF8C5FC440849126C73C8BE640B53AF868162AAB40791BF68E086A90402C25CCC0EF0D9E400A1047E3F8160E41A8030B695FB80F4110F466A871333841E6EC2F31262412412F9B9C562075FF4003FB1D362CD1AF404FDA2CE5C9D5BF407253BE18A7FAAC4048C489FF9DADC140585F92A43144E14059D595738407D040CB10F8D35478D6406804BB239C57E4405CF0F692C40BC14040C7381848A3B040CC5695D77E25E1407DD5E23A09BFBF40702694503C96C540F3BFA2F2796BC24018B6AA317BCE9440B651937153CC9D40C493916046AE1341C0487832035E3D41DC5764ED7339134138540F525D751741F44C0642C18E1141BAC08803BECA78400A094E48C50C874041D0E45D0198B140D976580F73CBC5401BB01859F8B2AA40803D1F77181AD340D91EB4EDD0FFD740DE33D94FAD4EE940D75D531496A28F4075FFD10B49A6B6409E323680E172C34042EF61FD80E4CD4068EF05621FD3E540F2D38E1ABFCF944047A05162F5E796403FCC5585E0591041FDE2ABB7DFD31341538555CE05A80B41904504A125983541CBBA049164C9B24073E03F562786C9408C25D02377EBD44021A1F49321FDEC405C0BC1F5A559D840F8B65EE119039840CB9C3FDF46029E40FAAF52B4A9440841113059AEE8FF0F4160376E7459D9304131A0EC10C1F3A8400009520FF75DB340F2B59433514FB540F0544E0019B1D54051AD14A1C701D64078CCFA7B3FBBD84056648559F0F79D40C10CDC1F83EF124148CAB7965E7E1741CA2C8A74F9F83641B894EAC6ED9C0B415C8F5521F0389B408548283ABE3FA5407380E2C94AECB540E5D12B9B35C7CF407A3B1B841272C740191835C677F0D6408E3513908168F1404F0046F6310FDB404F02D1109D67B340A7A3A094FE50994056CEE0A2756A10411EFC3E99D16614416FF55FB95D0A3141AA117BF1B4500741C837F9E8F1B5B6404C1491B49B91D040A9C91B33F1FCD740EBA69E7F04E4D940E2FF83F2D727F24005FAD8DA86A399407B8D4AB2C2CC9D40754976DC963B134116F2678CB8CC064178C156876BA50E41D7B1AB0D057A33417C6D9DE8A2899240C3D0D050F5299740A0A459F3C12FB740FF79EABA1E0FD2404CB32B83BB6ABC40799A47D78CC9F24041967C187A30D840D89E4FBB5752DD40A00EFD4CBE1DA9405545542BC3ED994028000059E80A9E40FFE3D4656F8D1041ED69EB78A75D1441AC701F5BA9830A4141BBAAAD2DBB314141F4B8324F57C0401CDE87287E15C640920039BF685CB840F2006D533533D240B733F44FD26EE840393839030E1FDA405AE873253B46F34063CE39EB34B3DC40A35158625646D8400C035D5B04FC9940AB35C331140C9E40BAA0CB9D13351041F6E9FFFE3A5C0B4158EAC2135D3414416B956440B4B826414A623874A4F3C7404045B4F116CEB740318A28D32570D0405FB451E4476ED2405CCDCA518197F140104ED774E31CDA400D3491783246F3403BA0A3FCA3B4D9407A50FBCBE043E140822C5DB7BB2F9A4052240199A0099E405030500577A60E4177BC049291EB0E41E2E696A751242641AD5814EAEE6A1341B3A47B10D3A3C540404CD3CE8852B740D7F0E33EF34ACD40E215B4C1A270D240B2A47AB0B4FBEF402151B3578058D94093794ABA0622F440E2FCE4523056D9402868E5E78B37E040C108118E36219A40C973A196EB0A9E40908A6AD2FF650A41015E945111B80E4181FD25A5C27C1041CB3626E00DA12441CB4A23DC844EC340B5006A549A61CC401ABAED030A99B6409B5C3E566876D2404072B3BA95C0F240244EB2E8A48BED40C4DE75BAE112D840BE0A11B371DBDA402B138E8ADDCBDD40C092934669F29940"> : tensor<274xf64>
    %cst_0 = stablehlo.constant dense<"0x61D4D2585027ED3FF07E970B1763DABF2CF482FFFFFFEF3F93C80757645D06BFC9A6B0E3F814ED3F9A5D6ACA91B3DABF5F2DB5CF58C9EF3F4AFDCEDE8F85BDBFBB40492A63C9EF3F962ACB41C682BD3F549152031E15ED3F6720820CF0B2DA3F378C9E69706DEE3F801498B3DED0D33F0C2D7EFFFFFFEF3FA922F9FDBEC906BF8A378CBA9DD0EF3FBB96B8B7997EBBBFC330F3D1DE06ED3FF47569A1ACF0DABFDF93BC74A7D0EF3FF27E4533C97BBB3F516EB41A0507ED3F3D7D719F07F0DA3F6CC42C673D4EEE3F3BB67B5BA38CD43FEBC877FFFFFFEF3F182B53B09D5707BF90D2EA4C37FDEC3F764547A3211ADBBFCD2A64711AD7EF3FE66488435B8CB9BFEF26F9B823D7EF3FDA1F84F07689B93FDC4F6EF55EFDEC3F7F9E1EF37719DB3F8B86F0E75F32EE3F0764DA793D2ED53F6BB66FFFFFFFEF3FA316B5FF200608BFA62B8B8A27F8EC3F8EC6FB0BBF2FDBBF655EBE02D5DCEF3FC0C4E67C0FB2B7BF61E182E3DDDCEF3FB30DEE4413AFB73F73E02D5850F8EC3FBA27C31E112FDB3FBA1D2ABB6A1AEE3F26327D79FAB4D53F6053022262E2EF3FB4A2C210B1BFB53FD2B7266DFD04EE3FF485DA7D6E2AD63FF9AE6E2B2BF8EC3F6F79BF94AF2FDB3FE6CC58FFFFFFEF3FDDC9028573DC09BF9CD2D1E499E6EF3F8BAD16E0AD24B4BFFA5280B4CBFCEC3F8237BBE9ED1BDBBFBB50D606A2E6EF3F870FEF4B7521B43F443F301AD2F6ED3F621B85B19B76D63F98D8F28BF7FCEC3FFB162C62321BDB3F45FB4AFFFFFFEF3F0B746B669BE80ABF14D9AC5B39EAEF3F40D925FB49A7B2BF792FA58A2F06ED3F3837C4DA9FF3DABF2B341F2941EAEF3F5C72C24DF3A3B23F57FC6FC35C06ED3FD9D85D0BDDF2DA3F333D5D50CEEDED3F412098047BA6D63F5B233BFFFFFFEF3F8C9E5D3FBE0F0CBF2FE1204C45EDEF3F2ED259A5114DB1BF959E52C60814ED3F75496D7FA7B7DABF7EC9EEDF4CEDEF3F08456E609249B13FBC3DA25D22EAED3F19978C89D9B9D63F03986B9D3714ED3FD12A0691DBB6DA3FAC1127FFFFFFEF3F76A049FD07750DBF5B4E503FE9D4EF3FE516A883E838BABF551C5F1B6728ED3FC6238292465EDABFDCF6AA8B0BF0EF3F8835185376F0AFBFD94D6545F5D4EF3FD006B21F4235BA3F175FB6E212F0EF3F1A1E4C871EE9AF3FE435EE9F62F9EF3F388F7DFB3792A4BFB8D202889728ED3FE74CFB5D705DDA3F584D1FF5DB5AEE3F4B2340889941D43FD01D493569ECED3FB6FB3B17D9ADD63FF59515FFFFFFEF3FDFA4BFE7059F0EBF243A9F43EC3EED3F94575848C4F9D9BF3BF63C880CF2EF3F36ECA7653FDEADBF3383F7CD6CDBEF3F835C3B5EF429B8BF2EF53A09A9DAEF3F9FB6B289246AB83FCFFF1BBCD5F1EF3FCA503AEEA118AE3FB49477F8A4FAEF3F4D4BC2FFBB82A2BFCAA8E953DB3BED3F9B22DFE98E07DA3F28BE7F7122F4ED3FD6EAE69AEB84D63F14A97C195557EE3F575E0238B156D43F8808FCFEFFFFEF3F8B5502839C1F10BF494F360FE8E0EF3F4639F22B9048B6BFC0F2E6FBA2F3EF3F14B1B8085E1EACBFDDF3B93B1359ED3F2E616D8CB782D9BF83D3A576F7E0EF3FB20A491F0D43B63F5004BF33ABF3EF3F96A015D70515AC3FE7C1EA57C0FBEF3F56BCDEACD87CA0BF8CB60CDA5D59ED3F0AF5D2226081D93F3000336DCA58EE3FF8E94E6EFB4DD43FBD20B3751101EE3FE894B7BAA13FD63F262AE7FEFFFFEF3F8FA2F7A615C210BFF96138C598F8EF3FEDA0787A1FC3A53FC83A2BD173E5EF3F89EC8747D197B4BF8F1E141ADAF4EF3FDC0E81C7ACB3AABF3ABE97F37B76ED3F33771BE8AEF9D8BF3403D49976F9EF3F058F34BE1373A43FE6CE7D3DE0E4EF3F0DAF5772A7D0B43F5765857110C2EF3FFD17874A8F6BBF3FA4CD70CEB8F4EF3FB2CDA31F68DBAA3FB74D1FBB4CDBEF3FD4D6A3498434B83FDB847B23B5FCEF3FFE6FD3E776079DBFA6793B311B72ED3FDAA1EE654D0ED93FC4792D65CAE7EC3FF3EFC0681275DB3F0EC48649335FEE3F31C67D598127D43FB2941B41F112EE3F910BFD7E44DED53F18AAC8FEFFFFEF3F0022A5500BA511BF5601C6EAA2F0EF3F4334524EAA57AF3F362F3681CFF5EF3F7A3832AB5D87A9BF5C34A946789AED3FB4120FF0244DD8BF962301C3A3F0EF3FD9F3CDF0CD56AF3FA969C8EC85E9EF3FE7B981AF6DF3B2BFE1E2226599F1EF3FA02D19CE6958AE3FC50384FD27E9EF3F07883515D01AB33F9F1B483214B5EF3FD15581B29245C13F8693223F16B5EF3F7E50C2795645C13FB79FC83DC0F5EF3F4D2F2C57729AA93F90AFA42876CDEF3F98205D966B64BC3F28CA471078CDEF3FF41BAB07E363BC3FF085624599FDEF3F0200FBB3BACA98BFC3C1E6297696ED3FB9AC51C0A360D83F173E3F62D7CDEC3F03DEFC7651E1DB3F5912A4D1DDCDEC3F50CAFADE36E1DB3FC876EC80F16BEE3FBF1F0C310CDAD33F340391DF232CEE3F28BEE1E7A951D53FB6C6EDAD9AF1EF3F40F6EEA90F57AEBF169BFCFFFFFFEF3F3C1EA9D8327ADD3E311CADFEFFFFEF3F3458BDBBB16812BF3D36004FF6E8EF3F0AF203C2832FB33FA7A6E3511EECEF3FDF9815D21DD3B1BFB84FEB704EF6EF3FDD781F1477E6A8BF0CD5C164F7E8EF3F587B7542102FB33F3AD3A8525DB9ED3F0F9AB4EF6BB4D7BFEAF6921D8CE9EF3F8699CC54D2F0B23F8FF73322FAEBEF3FAC286D0C4AE3B13F0254CE9863AAEF3F82805A90F274C23F06D7B6CF65AAEF3F656C08C6B574C23F47ADEF064EF6EF3F994F041DFFE6A83F2A54312170C1EF3FCC0AA455F793BF3F5249FB3630FEEF3FBDA0B0DBD38895BFE0EE46FD71C1EF3F7E83F3A37F93BF3FB58637F818B7ED3F7B20B2AAC7BFD73FA44E50FF91C0EC3FB5DADE48E717DC3FBE9EEF5CEC43EE3FFB94EFBF1BC9D43FDEE1D16C297AEE3FCF7A98EA0C82D33FF89F135D98C0EC3F388FDF38CD17DC3F7AF3F14D8DE9EF3F653F9A1E52F0B2BF8BC0FCFFFFFFEF3FABD04A5EC2D5DC3E9C3A94FEFFFFEF3FC8FDB3E7A11213BFCAA9372D95E0EF3F683702FC2066B63FAE50BAA893F6EF3F0E2338ABFC8CA8BF431C3ADC30EEEF3F9299353D05DFB0BFFE16758B96E0EF3F2966015EA465B63F7058AC84C4D9ED3F330DDEF74D0FD7BF131F355A0BE2EF3F50C2D90268DFB53F31E0ADE2E6EDEF3FC3BB8161E101B13F51D80EDB9A9FEF3F1C35F3CC0E94C33FEFEE94F99C9FEF3F7F8EDE07D893C33FD5A2D22593F6EF3F9DF89116A78DA83F8E43B572D3B4EF3F621DECE6FE4CC13FF236FEF3ACFEEF3FC29C806C986992BF0175B863D5B4EF3FBC13E7F8C54CC13F93CD0ECE23D4ED3F39FB28DE5C2CD73FDEE84F0F34BAEC3F6D4BB303E931DC3FBFC5C83DAD8BEE3F8559E3AA3E13D33F11A560423ABAEC3F6E1A83BFCF31DC3F8C31EACF825EEE3FAB6466A4A82BD43F805CBD470CE2EF3F3757B47211DFB5BF4CE7FCFFFFFFEF3FB0B24047AE27DC3EBC7989D6E8D7EF3FC17F7342BA4BB93F25F38A37EAD7EF3F5C9F4B294B4BB93F773BDBE2CAEFEF3F125FBC8D6E18B0BF4FF7D928A1F6EF3FD077D6BB627BA8BFA368F074E394EF3F8A734D1194A1C43F52332991E594EF3F10E0BE6160A1C43F2872FD34E1A7EF3FA8F7791B53B9C23F824F991AE3A7EF3FCF6735CB1FB9C23FA69B309011FFEF3F2D15AF54C5E18EBF030FFDFFFFFFEF3F57BCDE46CD70DB3EE8474FFEFFFFEF3F45FE8A6B49CD14BFF598292833F1EF3F7F408F794CC3AEBF237BBC0340CDEF3F54457CF29073BC3F1CF04F2464F6EF3F1C83DF738CCAA8BFCEEDD54657CEEF3FB402A6021A25BC3F3CD023191DF1EF3F4E84C5712BDAAE3F8CCA60BAD687EF3FF752E891D3D7C53F3A2F90B877F6EF3FA3B4C16441B1A83F0FEBBAD29D97EF3FD58377EF525EC43F35F6FCEF70FFEF3F42E40C28DDEB87BF86432FFEFFFFEF3FB792D22DC88E15BF88D9A4B94EC5EF3F7C67F86EE796BE3F5E4A4E4450C5EF3F073689F48096BE3F82B1A646F3F5EF3FCD65578F6D5AA9BF5A06A521E4F1EF3F569512235609AEBF8B6041346AC6EF3F9CEBD279F14CBE3FEBA7504BD9F1EF3F9429C185DA14AE3F557FC1AEDF7DEF3FD5991FC84AB9C63F31D4BD14E27DEF3FA36AA29915B9C63FC04B4CA811F6EF3F7E8C26BF0334A93FFF66DDA3DB8AEF3FB7F3F736A491C53F0175B8ABDD8AEF3F61E0F3B27491C53FFE968002A8FFEF3F125CD329ABC282BFBD1239CE6BC6EF3FE40958FE854CBEBF296AFDFFFFFFEF3F859EDEA9EBB9D93EB7C877A83BBEEF3F31ACB2D8D02FC03F27F1B62A3DBEEF3FAC963B81A12FC03FFD48611E46F5EF3F8DDCC0FB2631AABF94FB346E38F2EF3FD834FF8F26AFADBFC8D772A08074EF3F3D596EE56285C73F25438EB78274EF3F0C9A882B3685C73F79B01FC8987EEF3F27B57C9F3CA9C63F35FEDD12CFFFEF3F52AFC0C990FA7BBF12DDFFF79A7EEF3F63E95FFD0BA9C63FBB92FDFFFFFFEF3F93092CE7DEECD83E1025EBFDFFFFEF3F0AB18A8A6A1517BF23EEB1C14EB8EF3F5F2FA666ADE5C03F60CC87D932F2EF3F1211697F27B5ADBFEE76B5334DB8EF3F46E53318DCE5C03FEC29D9FD57F4EF3F46C0CF79A64DABBFCDE9186921B9EF3F0AF6ACC0E3CCC03F72AFC96E45F2EF3F0AA3A20525A1AD3F3A48EB20DF6BEF3F2B3EEB86373BC83F10D6E663E16BEF3F91203A9A083BC83FB161822190F4EF3F9954588EA20BAB3F2B810EEA1573EF3F511E1CC39FA3C73F2615F3801373EF3F6EB1E112D3A3C73F0A2B21CEE8FFEF3F2B5FF4E0AB4373BF4E48C5F922B9EF3F1F234E77B4CCC0BFE9BAFDFFFFFFEF3F8388D3BE151BD83EE116BAFDFFFFEF3FAB2EF55F711F18BFB0D03427D5B2EF3F51A8F0C10E87C13FB2F47BBCD6B2EF3F41C298F2E086C13F11BAEDEAACF1EF3FF78509C3D543AEBF78F0C0ADC9F2EF3F8F3FDDDE2F11ADBFBF6EE46DECB2EF3F2D08180A6D84C13FCDC77DDFC1F1EF3FBD393A72AF2DAE3F3A77A5865562EF3F3CF72FA6ECFDC83FB2668CB95762EF3FC38D0078C0FDC83FD638FD9FE9F2EF3FCAE4EF98FDEDAC3F8EB437630F66EF3F60A41D5E99B2C83F64F9FD8C1166EF3F496C8B5D6DB2C83FDBA3FF3DFAFFEF3F6F9D01FB433263BF994AC2F8EDB2EF3F9A4230614084C1BF2AECFDFFFFFFEF3F32422AE0C00FD73E154793FDFFFFEF3FB7E2A78F0FEA18BF03B9F81436B0EF3F2F62655A44D2C13FE9BBC7F2D7F0EF3FCCCB70637021AFBF4EC70FA837B0EF3FC7AC5B8E17D2C13F4C9C0F7E31F1EF3F4358C1DC06C5AEBF90F219561AB0EF3F9408BA6F59D5C13FA0E8A8A3DA5BEF3FA21019FEC57EC93F57E0D711E4F0EF3FDC892112FE14AF3F061633D4DC5BEF3FC12EA2E69A7EC93F6D974F7D3DF1EF3FA636410B90B8AE3F1F36893C015DEF3FC55A92DD1568C93F8374275B035DEF3FB3EF0500EC67C93F64B4117AFFFFEF3FC00714694C2547BF6C52C1E01BB0EF3F4C3B709B2DD5C1BF7C12FEFFFFFFEF3F5C6F8E1B1A37D63E812D6EFDFFFFEF3FC7E77351E6A519BF160BCCF19DEFEF3F02D2523EAA2EB0BF341636D541AFEF3FDB3C3B3954EDC13FC45755CE40EFEF3FB05EAD515D5CB0BFAB528D5443AFEF3FE862AAE029EDC13FDFB9E41525AFEF3FCE578DDF80F0C13F961314958256EF3F964927CA12E7C93F5E0BC1E6AAEFEF3F0264E0744428B03F61CA37DC8456EF3FB99CF3B1E6E6C93F04A864E34DEFEF3FE1BBEECFF955B03F21BA25A65955EF3F58B4C8867CFDC93F3D2C0CB55B55EF3FE8AC15D354FDC93F90F1F37CFFFFEF3FA2E62C2829E5463FA170A09526AFEF3F27BB898356F0C1BF9837FEFFFFFFEF3F208FF1421A5DD53E7BF448FDFFFFEF3F26D86BD71B5D1ABF66C2934201B0EF3F8C03242322D8C13FDFC41287F5EDEF3F2141E8B000FBB0BFFD15C6B402B0EF3F2814BE0CF9D7C13FE1E1BB7CEEECEF3FAE378517F074B1BF1E385FD9E3AFEF3FF824C77865DBC13F6D05318A03EEEF3FC965A72169F4B03F7E3D12AC6352EF3FCD7E51885836CA3FCAC9F9C76552EF3FE407D4353036CA3F4659494C414FEF3F8B9D3B28FE71CA3FE3C322DFFCECEF3F66D20B395B6EB13F4B531B353F4FEF3F38EB07C22572CA3FD4776A5AFCFFEF3F795E11F6F98D5E3F94AA6D42E5AFEF3FF8308D6D3DDBC1BF4C5BFEFFFFFFEF3F042CF3A8D582D43E"> : tensor<274xcomplex<f64>>
    %cst_1 = stablehlo.constant dense<1.562500e-02> : tensor<64x64xf64>
    %cst_2 = stablehlo.constant dense<-175.65119408165049> : tensor<f64>
    %cst_3 = stablehlo.constant dense<0.10132118364233778> : tensor<f64>
    %cst_4 = stablehlo.constant {enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} dense<"0xFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840FFFFFFFFFFFF3840000000000000F03FFFFFFFFFFFFF3840"> : tensor<126xf64>
    %cst_5 = stablehlo.constant dense<0x7FF0000000000000> : tensor<274xf64>
    %cst_6 = stablehlo.constant dense<0xFFF0000000000000> : tensor<274xf64>
    %cst_7 = stablehlo.constant dense<0.000000e+00> : tensor<274xf64>
    %cst_8 = stablehlo.constant dense<1.000000e+00> : tensor<64x64xf64>
    %cst_9 = stablehlo.constant dense<3.000000e+00> : tensor<64x64xf64>
    %cst_10 = stablehlo.constant dense<1.000000e+00> : tensor<101xf64>
    %cst_11 = stablehlo.constant dense<0x7FF0000000000000> : tensor<126xf64>
    %cst_12 = stablehlo.constant dense<0xFFF0000000000000> : tensor<126xf64>
    %cst_13 = stablehlo.constant dense<-3776.4484124697938> : tensor<f64>
    %c = stablehlo.constant dense<1> : tensor<i64>
    %c_14 = stablehlo.constant dense<1> : tensor<i32>
    %cst_15 = stablehlo.constant dense<6.399000e+01> : tensor<f64>
    %cst_16 = stablehlo.constant dense<4.1587268211513688> : tensor<f64>
    %cst_17 = stablehlo.constant dense<1.000000e-02> : tensor<f64>
    %cst_18 = stablehlo.constant {enzymexla.finite = [#enzymexla<guaranteed GUARANTEED>], enzymexla.no_nan = [#enzymexla<guaranteed GUARANTEED>]} dense<0.000000e+00> : tensor<f64>
    %c_19 = stablehlo.constant dense<0> : tensor<i64>
    %cst_20 = stablehlo.constant {enzymexla.finite = [#enzymexla<guaranteed GUARANTEED>]} dense<0.000000e+00> : tensor<126xf64>
    %c_21 = stablehlo.constant dense<126> : tensor<101x1xi64>
    %cst_22 = stablehlo.constant dense<0.000000e+00> : tensor<25xf64>
    %cst_23 = stablehlo.constant dense<0xFFF0000000000000> : tensor<f64>
    %cst_24 = stablehlo.constant dense<48.376411884489357> : tensor<f64>
    %cst_25 = stablehlo.constant dense<[[-1.5707963267948966, -1.521708941582556, -1.4726215563702154, -1.4235341711578751, -1.3744467859455345, -1.3253594007331939, -1.2762720155208536, -1.227184630308513, -1.1780972450961724, -1.1290098598838318, -1.0799224746714913, -1.0308350894591509, -0.98174770424681035, -0.93266031903446977, -0.88357293382212931, -0.83448554860978885, -0.78539816339744828, -0.73631077818510771, -0.68722339297276724, -0.63813600776042678, -0.58904862254808621, -0.53996123733574564, -0.49087385212340517, -0.44178646691106466, -0.39269908169872414, -0.34361169648638362, -0.2945243112740431, -0.24543692606170259, -0.19634954084936207, -0.14726215563702155, -0.098174770424681035, -0.049087385212340517, 0.000000e+00, 0.049087385212340517, 0.098174770424681035, 0.14726215563702155, 0.19634954084936207, 0.24543692606170259, 0.2945243112740431, 0.34361169648638362, 0.39269908169872414, 0.44178646691106466, 0.49087385212340517, 0.53996123733574564, 0.58904862254808621, 0.63813600776042678, 0.68722339297276724, 0.73631077818510771, 0.78539816339744828, 0.83448554860978885, 0.88357293382212931, 0.93266031903446977, 0.98174770424681035, 1.0308350894591509, 1.0799224746714913, 1.1290098598838318, 1.1780972450961724, 1.227184630308513, 1.2762720155208536, 1.3253594007331939, 1.3744467859455345, 1.4235341711578751, 1.4726215563702154, 1.521708941582556]]> : tensor<1x64xf64>
    %cst_26 = stablehlo.constant dense<3.8349519697141029E-4> : tensor<f64>
    %cst_27 = stablehlo.constant dense<(0.000000e+00,0.000000e+00)> : tensor<274xcomplex<f64>>
    %c_28 = stablehlo.constant dense<1> : tensor<4096x1xi64>
    %c_29 = stablehlo.constant dense<128> : tensor<4096x1xi64>
    %cst_30 = stablehlo.constant dense<2301.0868138410601> : tensor<f64>
    %cst_31 = stablehlo.constant dense<1.000000e+00> : tensor<f64>
    %cst_32 = stablehlo.constant dense<-2.000000e+00> : tensor<f64>
    %cst_33 = stablehlo.constant dense<5.000000e-01> : tensor<101xf64>
    %cst_34 = stablehlo.constant dense<-5.000000e-01> : tensor<101xf64>
    %cst_35 = stablehlo.constant dense<8.000000e+00> : tensor<101xf64>
    %c_36 = stablehlo.constant dense<"0x01000000000000000300000000000000040000000000000005000000000000000700000000000000080000000000000009000000000000000B000000000000000C000000000000000D000000000000000F0000000000000010000000000000001100000000000000130000000000000014000000000000001600000000000000170000000000000018000000000000001A000000000000001B000000000000001C000000000000001E000000000000001F00000000000000200000000000000022000000000000002300000000000000240000000000000025000000000000002700000000000000280000000000000029000000000000002A000000000000002C000000000000002D000000000000002E000000000000002F00000000000000310000000000000032000000000000003300000000000000340000000000000035000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003E000000000000003F000000000000004000000000000000410000000000000042000000000000004300000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004C000000000000004D000000000000004E000000000000004F00000000000000510000000000000052000000000000005300000000000000540000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005C000000000000005D000000000000005E000000000000005F00000000000000610000000000000062000000000000006300000000000000640000000000000065000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006D000000000000006E000000000000006F00000000000000700000000000000071000000000000007300000000000000740000000000000075000000000000007600000000000000770000000000000079000000000000007A000000000000007B000000000000007C000000000000007D00000000000000"> : tensor<101x1xi64>
    %c_37 = stablehlo.constant dense<[[0], [2], [6], [10], [14], [18], [21], [25], [29], [33], [38], [43], [48], [54], [61], [68], [75], [80], [85], [91], [96], [102], [108], [114], [120]]> : tensor<25x1xi64>
    %cst_38 = stablehlo.constant dense<5.000000e-01> : tensor<f64>
    %cst_39 = stablehlo.constant dense<[-1.5707963267948966, -1.521708941582556, -1.4726215563702154, -1.4235341711578751, -1.3744467859455345, -1.3253594007331939, -1.2762720155208536, -1.227184630308513, -1.1780972450961724, -1.1290098598838318, -1.0799224746714913, -1.0308350894591509, -0.98174770424681035, -0.93266031903446977, -0.88357293382212931, -0.83448554860978885, -0.78539816339744828, -0.73631077818510771, -0.68722339297276724, -0.63813600776042678, -0.58904862254808621, -0.53996123733574564, -0.49087385212340529, -0.44178646691106471, -0.39269908169872414, -0.34361169648638357, -0.29452431127404299, -0.24543692606170264, -0.19634954084936207, -0.1472621556370215, -0.098174770424681145, -0.049087385212340573, 0.000000e+00, 0.049087385212340573, 0.098174770424681145, 0.1472621556370215, 0.19634954084936207, 0.24543692606170264, 0.29452431127404299, 0.34361169648638357, 0.39269908169872414, 0.44178646691106449, 0.49087385212340529, 0.53996123733574564, 0.58904862254808599, 0.63813600776042678, 0.68722339297276713, 0.73631077818510793, 0.78539816339744828, 0.83448554860978863, 0.88357293382212942, 0.93266031903446977, 0.98174770424681057, 1.0308350894591509, 1.0799224746714913, 1.1290098598838321, 1.1780972450961724, 1.2271846303085128, 1.2762720155208536, 1.3253594007331939, 1.3744467859455343, 1.4235341711578751, 1.4726215563702154, 1.5217089415825562]> : tensor<64xf64>
    %cst_40 = stablehlo.constant dense<(0.000000e+00,0.000000e+00)> : tensor<128x128xcomplex<f64>>
    %c_41 = stablehlo.constant dense<128> : tensor<4096x2xi64>
    %c_42 = stablehlo.constant dense<274> : tensor<i64>
    %c_43 = stablehlo.constant dense<"0x000000000200000002000000020000000400000005000000050000000600000006000000060000000800000009000000090000000A0000000A0000000A0000000C0000000D0000000D0000000E0000000E0000000E0000001000000011000000110000001300000014000000140000001500000015000000150000001700000018000000180000001900000019000000190000001B0000001C0000001C0000001D0000001D0000001D0000001F000000200000002000000021000000210000002100000021000000230000002400000024000000250000002500000025000000260000002600000026000000260000002800000029000000290000002A0000002A0000002A0000002B0000002B0000002B0000002B0000002D0000002E0000002E0000002F0000002F0000002F000000300000003000000030000000300000003000000031000000320000003200000034000000340000003400000035000000350000003500000035000000360000003600000036000000360000003600000036000000370000003800000038000000380000003A0000003A0000003A0000003A0000003B0000003B0000003B0000003B0000003B0000003C0000003C0000003D0000003D0000003D0000003D0000003D0000003D0000003E0000003F0000003F0000003F0000004100000041000000410000004100000042000000420000004200000042000000420000004300000043000000440000004400000044000000440000004400000044000000450000004600000046000000460000004800000048000000480000004800000049000000490000004900000049000000490000004A0000004A0000004B0000004B0000004B0000004B0000004C0000004C0000004E0000004E0000004E0000004F00000050000000500000005000000050000000510000005200000052000000540000005400000054000000550000005500000055000000550000005500000056000000570000005700000057000000590000005900000059000000590000005A0000005A0000005B0000005B0000005B0000005B0000005C0000005C0000005E0000005E0000005E0000005F0000006000000060000000600000006000000060000000610000006200000062000000620000006400000064000000640000006400000065000000650000006600000066000000660000006600000066000000670000006800000068000000680000006A0000006A0000006A0000006A0000006B0000006B0000006C0000006C0000006C0000006C0000006C0000006D0000006E0000006E0000006E0000007000000070000000700000007000000071000000710000007200000072000000720000007200000072000000730000007400000074000000740000007600000076000000760000007600000077000000770000007800000078000000780000007800000078000000790000007A0000007A0000007A0000007C0000007C0000007C0000007C0000007D0000007D000000"> : tensor<274xi32>
    %c_44 = stablehlo.constant dense<"0x010000000300000005000000040000000300000003000000040000000700000008000000090000000700000007000000080000000B0000000D0000000C0000000B0000000B0000000C0000000F00000011000000100000000F0000000F000000100000001200000013000000120000001600000017000000180000001600000017000000160000001A0000001B0000001C0000001A0000001A0000001B0000001E0000001F000000200000001E0000001F0000001E00000022000000230000002500000024000000220000002200000023000000220000002300000024000000270000002A00000029000000280000002700000027000000280000002700000029000000280000002C0000002D0000002E0000002F0000002C0000002C0000002D0000002C0000002D0000002E00000031000000330000003200000034000000350000003300000031000000330000003100000033000000320000003100000033000000320000003400000037000000390000003A0000003B0000003C000000380000003900000037000000390000003C00000037000000390000003C0000003800000037000000390000003C000000380000003A00000037000000390000003E000000400000003F000000410000004300000042000000400000003E00000040000000430000003E000000400000003F000000430000003E00000040000000410000003F000000430000003E00000040000000450000004700000048000000460000004A000000490000004700000045000000470000004A0000004500000047000000460000004A0000004500000047000000460000004A0000004800000045000000470000004D0000004F0000004C0000004E0000004D0000004F0000004D0000004F0000004C0000004D0000005100000052000000530000005400000053000000510000005300000051000000530000005200000056000000580000005A00000059000000570000005800000056000000580000005A00000056000000580000005A0000005700000056000000580000005D0000005F0000005E0000005C0000005D0000005F0000005D0000005C0000005F0000005D00000061000000650000006200000063000000640000006300000061000000630000006500000061000000650000006300000062000000610000006300000067000000690000006B000000680000006A0000006900000067000000690000006B00000067000000690000006B0000006800000067000000690000006D0000006F0000006E00000071000000700000006F0000006F0000006D000000710000006D0000006F000000710000006E0000006D0000006F000000730000007400000075000000760000007700000075000000750000007300000077000000730000007500000077000000740000007300000075000000790000007B0000007A0000007D0000007C0000007B000000790000007B0000007D0000007D000000790000007B0000007A000000790000007B000000"> : tensor<274xi32>
    %cst_45 = stablehlo.constant dense<"0xAAAAAAF3CC6FC0BF711CC745A627563F398EE338C361E4BF000000A80C40EE3F000000940D55C1BFAAAAAAF2CB3698BF8EE338DAB6D0B43F711CC7E97B70A23F0000002258399CBF8EE3385227C0B43FE3388E672C4CB33F1CC77144368EBFBF1CC7712EC0BF88BFC7711CF37064BC3F1CC77104F82BE6BF388EE3106DF6EC3FAAAAAAA2DECBB83FAAAAAA06E350A43FE3388E43F101BFBF1CC771C421ACA7BF398EE38F2B6AA5BF8EE338F65BD8B93FC7711CFD4BBEA53F0000002073C6BFBF000000A2D2E8933F55555515103FBF3FAAAAAA92E175E7BF1CC7718CC5EEEB3FC7711C27AB67BBBF5555559DF436B0BF398EE3B82FA6B73F398EE34CDE1FA33FE3388EDD31AFA4BFE3388E8B3D23B53F721CC770E15C903F1CC771BCA304C1BF000000D9115BA33FC7711C1B0D02B93FC7711CDF0CAEE8BFE3388E83F2DAEA3F55555565E2A0B5BF55555519CF6AB3BFC7711C5712DAB63F555555753F46A13F8EE338887E1DA7BFE3388EE76003B63F555555F57325763FE3388E1373A9BEBFC7711CE4CFAEAD3F1CC7716ACB1FB43F000000E7BA91B13F1CC7713C6B1F813F388EE322EE73ABBF711CC73A2CAA9D3F711CC73B997A85BFE3388EC39952BBBF000000A832D7EABF0000003047B1E83FE3388E3BAD0DAC3FAAAAAA2AB937973F388EE320A57CAABFE3388E13BF79BABFC7711C3C35BA97BF1CC771FE2926AB3F711CC7476928A83F1CC771815C49A03F555555094C7B9CBFAAAAAA2A28BCBDBFE3388E5B3794EBBFAAAAAABA41DDE73F1CC77144D903A83FAAAAAADA5404953F721CC70D4211A0BFC7711CAF2936BCBFE3388EC8FAFC95BFC7711C7327A0A33F8EE3388508EEA7BFAAAAAA3A12E4BBBF711CC7C5AE72AC3FC7711C9751139C3FC7711C2FC711ECBF000000C0CF48E73F00000018C260A63F555555F5B98B963FE3388E333C2384BF000000706461BDBF388EE3CEAB1B9CBFE3380E82E681A43FC7711C0632FCAA3FAAAAAAFE1214893F8EE338A2A8B9AFBF711CC77943BBB9BF711CC7996467ECBFAAAAAABA3EE0E63F000000D080D5843FC7711C6F45B8BA3F8EE3380EB2238D3F388EE3888722BDBFAAAA6AC6F514A23F555515B3BBBB943F0000004C424AAE3F711CC7E93F21B83FAAAAAAA4839284BF8EE338C63AC0A23FAAAAAA1E642DC63F000080B443CBB13FC7711CB6C644B4BF5555558DC812B6BF00000014A1EBBC3F711C4797B47AA63F5555551EF907AD3F1CC7714C490755BF24499224C9B9EBBF00000060B8B0E73F721CC7F10980A13FAAAAAA826D31BABF1CC771BC70B2A13FC7711CD7BC2C983F398EE3CC6CE084BF55555595B966B83FB76DDBEA7A1EB03F244992C4EC28BB3F92244932715290BFB76DDB86E6ACA53F8EE33876993DC63F5555D579F266B43F922449F28BFCB7BF922449CA0BBBAABFE3388E85E021AF3F8EE3387E362769BFC7711CD92EF1BC3F000000CF73AA9E3FF8E0836F2E49ECBFABAAAA4A4E04E73F1CC771C09D95A0BF555555B5F5E6B83FAAAAAA623BD5A33FE3388EE35023A13F1CC771C4D530AF3F5555550D2229BBBFC4C3C38312F2B83FE2E1E1378819B03FA6A5A54DF13973BF1E1E1EC42573B03FE3388EFB9C92CA3F1CC77178BA78BB3FC4C3C3B3340DBEBFD3D2D2C63918A6BF711CC7C5F3BDBB3F5555552C4C23A03F1CC77160717AB43F711CC719A6FF75BF000000F87A2BEABF000000309B65E93FC7711C1F4E42ABBF8EE338BEC5CAB7BF1CC771E406D2A9BF8EE338AEEA7BB43F8EE338B6C4749D3FC7711C27B0719E3FC7711C3F6182B33F398EE3A8AF08B7BF00000068A3C6AF3F000000C4D895AB3F000000488964BA3F000000801095923F55555520E184AFBFAAAAAA02BFDBC33F00000000CB944A3F000000E48A38B03F8EE358B5558EA2BF0000001206C2713FC7711C773FF1C53F555555A956FFBB3F000000D8F718BEBF000000F4836A88BF1CC771ACFBE49FBF8EE33852A68C843F721CC7D3E8B3C13FAAAAAA82478E8F3F555555D54D5CB33F1CC771B2EAD597BFC7711C47113CEBBF000000A0A93FE83FAAAAAADADB21AFBF5555550D28FCB4BFE3388E232E6B993F8EE338AA81C1A03FAAAAAA42EDC9B93F555555557F8BB3BF711CC771B4C7AD3FC7711CCF9183B5BFC7711CAB2B75B2BF555555A1DE51B13F398EE3B8CA8286BF1CC77190699DBA3F711CC791F463BD3FC7711CC759A6503F8EE3388E1FF34ABFE3388E696764C43F711CC7AD5C86BDBF8EE338D2FDA0A43FE3388EE369AC5EBF398EE3A443C4A03F398EE3E6616B90BF1CC77138A5E2763FC7711CFFF2D891BF8EE3384DFB109EBF711CC78964BCC43FAAAAAA6E0164BD3F711CC731EAC7BEBF55555559D7A594BF711CC7FFCEE48E3FE3380EF71022A33FE3388E333C0F92BF8EE33846D8279DBF1CC771A0700DC23FAAAAAA0A6D19833F398EE3A0D482B33F388EE35E7EE09ABFE3388E03E7F9B5BFC7711C1723F19FBFE3388EA397F0D63F555555258B37F1BF555555750D4BEABFE7799EC77643E93F388EE398D670ADBF000000A86264B0BF5555558153EAB3BFC7711C27F031A83F398EE3DCFD5F913FAAAAAA0A8414A03FE3388EEB44FEB03F388EE328B2D6ABBFC7711CA77C10BE3F8EE338FA241DB1BFAAAAAAB2A10D863FF33CCF934D8AB73F611886E51AEBB63F866118DAF50A96BF0000009838959C3FC7719C4225D6BB3FAAAAAAA6FACBC1BFAAAAAAE7610EA33F4992248BF4FE8F3F611886A11403A53F388EE3EB78BC8ABF0000003CFC68763F000000147FCEC33FC7711C7FEAE9B93FAAAAAAFA52EB6FBFC7711C6B55A59BBF6DDBB66D120CC1BF9EE7796E89C29A3F8EE3388CA7AF96BF8EE338F9D285973F398EA3CA1477B03FE3388E1B13F89ABF398EE3229D34C33F55555543783E953F721CC783FE64A1BF8EE3B8F36360A0BF922449762DA5B6BFC3300CA39EC58BBF398EE378F85A40BF398EE3D80035F2BF00000030D651E8BF000000E0032DEB3F8EE3385E9E39ACBFAAAAAAB2BCDFAABF711CC7C5753C853F711CC7B9A1909F3FC7711C9F50C7B3BF1CC771140F749E3F1CC7713CA4C1B13F1CC7712C8AA69FBF711CC76D5A15B53FC7711C4BB3D3A0BF0000004037F292BF0000002009E6BF3F000000307C00B23F000000E8A77CA6BF388EE3E9C918A93F711C07701914B63FE3388E2B3C2BBFBFC7711CFF4CF78E3F0000000072E3493F00000020558FA93F000080A1FE65A3BFAAAA6AF5F5A48A3FE3388E677F7AC33F1CC771948C73B63F398EE3B8E6F5363FC7711C162B0CA1BF000000A04792BBBF00000000A3D0AC3F5555D5158B5A7FBFAAAAAA1AA2FE8E3F0000008C75B0BC3F388EE3B82791793FE3388E278D619CBFC7711C0373148FBF1CC771CBD805AE3FE3388E4FE2FE85BF0000005018D2B2BF00000080C2A47DBF711CC78D7DA0DBBFE3388E9F64D6F0BFC7711CC3B578B0BF000000B8BF8EAABF000000C09CD9B43F555555A90E3E8ABF5555555DC9C4B8BFC7711C7FB2078A3F398EE378B35F403F711CC7C1A070A33F1CC7A10C2630A43F555555B222DAA93F1CC77159F709B7BF1CC771CC040C753F5555751702B799BFE3388E21F10F933F711CC719496C833FE3388ED12E599DBF555555154BB2C43FAAAAAA72BBB3B13F8EE338A64DA8E7BF388EE3E8A797EBBF00000080064CE6BFAAAAAA0A5ADCEC3F388EE3F04051BABF398EE3E86EB890BFC7711CF3FC7CB1BF8EE338A67016A8BFAAAAAADAD5D39BBFAAAAAA5EA236A13F55555565777383BF711CC7518433B23FC7711C77BFBFAB3F000000407263BABF5555D59A0E07AC3F000000362D03A63FC7711C979A05A93FAAAAAAAAEA2080BF8EE3780757CE90BF5555958A616CA63F8EE338F2401DC63F388EE3A0A67D7BBF555555753F5EE4BFAAAAAA2A1541EE3FAAAAAAA6D3B6B0BF000000E846FAA3BFAAAAAA42AB2CB33FAAAAAA9ADF00883F555555A948C7A1BF000000B4C60E853F8EE3388E1C5CB7BF8EE338029516A2BFAAAAAAEACB719D3F000000902547B03F000000201703873FAAAAAACA064CB5BF711CC7C29A72A73F8EE3382B12E4923F8EE338384473ACBFC7711CF33A9085BF00000020D45E963FAAAAAA120D43A1BFC7711C4736707C3F8EE3546861FD983F1CC77170EF548CBF398EE330B45490BF1CC771C48EEEBF3FE3388EB3032FB4BFAAAAAA1AEAA9A7BF555555351F83B43F00000004EA63F0BFC7711C5FB08DDFBF000000303F6AB2BFC7711CA71E8AA3BF1CC771941F0DB43F55555585EA6E963F8EE3383E64B9A5BF711CC7DD93C673BF000000C0A784B6BF711CC7B98283AEBF398EE3D29120A53F8EE338C6EE8D88BFAAAAAA240085A9BF8EE338DE0D7F683F711CC748F1F3973F55555510E5E7973F1CC771CA7206C03F711CC71D6CF7B8BFE3388EF9B03597BFAAAAAA4F9DB791BF1CC771E48490F1BF711CC7A957F0D2BFAAAAAA0A66ACE2BF555555F59054EF3FE3388E1B27F0B33F000000E801DE9F3FE3388E5BA1A1B1BF00000088E9E2B4BF1CC771F4107CB3BF1CC7717832E5A1BFAAAAAA8E847CA2BFAAAAAA82EBB48DBF55555505BF73B0BF55555535E1D2B63F55555505002190BF000000A0D60DBCBF1CC7B1025D36A23F711CC709C5BE773F8EE3380821469ABF555555910F50793F555555D50F0F53BF00000000C843A7BF711CC7CFF9A396BF000000621D1991BFAAAA6CCECD6F933F8EE368C0B1348C3F711CC7BD15F7B83FC7711C03E591B5BFAAAAAABA3915A1BFAAAAAA8AB79AA43FE3388E1BBF14F2BF711CC7F86F5FBDBF85EB51D8019ADEBF5C8FC275C28DF03F1CC771F89277B3BF711CC70185FD9DBF55555575404DB33F388EE330B29D9F3F555555BDF705A8BF8EE338EEF233B6BF398EE3A41E5DA1BF000000D0762099BF90C2F5A0D6F68F3F6766665EBBF0B43F3E0AD7439CDBADBFA4703D625A59B5BF1CC771BF622E9E3FC7711C6FCFBA79BFE3388EB38F038FBF388EE3607E2C5A3F7B14AE07326960BF1F85EB7125E5A2BF00008093C1089D3F00000004C27768BF8EE338AB03D69EBF00000038F8F68ABFAAAAAA5AC4B2B93F000000961BD4BABF713D0A57D71860BF5C8FC27565CFB43F000000208423F2BF555555C1109CAFBF388EE318E069DBBF5555553D64E6F03F000000C83A07B4BF388EE3C880B29ABF55555525C4A79DBFC7711C7FD59EB7BFE3388EDBC577B33FAAAAAA422FE69F3F1CC7712479C5A3BF8EE3386E90A9A3BFE3388E8682DB7D3F8EE338585F45B53F388EE3A90F869D3F711C4766D10D9ABF000000310E59B1BF721CC7BE87CCB0BF1CC771A47BCC98BF711CC7B1B8C347BFE3388EB2E20C95BFAAAAAAD6A79DADBF398E639FBA0CA53F555555D350AD72BFC7711C83030BA6BF1CC7719402F489BFAAAAAA349C5FC03F8EE338EE8B62BEBF711CC719C7207ABFC7711C0F56ADB53F8EE33866442DF2BF555555B8D7B484BF5555559558D0D6BF1CC771048E52F13F398EE3C80F1A88BF398EE340E8D6B6BFE3388E8F2FC7B4BF8EE338AE6DA297BFC7711C7F8851A1BFC7711C0FC645A6BF5555550D0774B43F1CC771BC2D499A3F711CFFBE10858EBF721C27A554F4B03F5555DD6396868B3F555555736C14733F5555556A081DB8BF555555C5D4C0A6BF711CC74137B485BF1CC7711E1829833F711CC79BFFA29FBFC7711C3D5A09A9BF398EE3DE4EC8A23F1CC7719068666E3FAAAAAAE979C1A1BFE3388E73182070BF5555557123BFC03F8EE338068982BFBFAAAAAA8A67BC81BF000000E4012BB63FC7711C1F622FF2BF711CC7D69CEDA5BFAAAAAA123965D2BF721CC721A2A5F13FC7711C6F57C3B6BF5555553DE75994BF8EE338325BD880BF1CC771741F86B6BF0000006879B1B63FE3388EDBAF7E953F8EE338EEF3B99EBF711CC701F9B3A8BF711CC77CB538923FE3388E96EB62B73FC7711C53B4D1B4BFC7711CF3EE22A7BF398EE302DD28613FE3388EFB2B2B8B3FE3388E0BE00C77BF1CC77134319A72BFAAAAAAC44289A2BF721CC7190D93503F711CC7732294A6BF8EE338DE577DA6BF1CC771DF06BBA83FC771FC31C4E076BF711CC7BDEEA7BC3FE3388E0BE845BBBF000000005A67553F711CC7AD49C5B63FC7711CD7C325F2BFC7711CADB87FA6BF"> : tensor<274xcomplex<f64>>
    %0 = stablehlo.reshape %arg2 : (tensor<4096xi64>) -> tensor<4096x1xi64>
    %1 = stablehlo.slice %arg5 [0:4096] : (tensor<4428xf64>) -> tensor<4096xf64>
    %2 = stablehlo.convert %1 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xf64>) -> tensor<4096xcomplex<f64>>
    %3 = stablehlo.reshape %2 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xcomplex<f64>>) -> tensor<64x64xcomplex<f64>>
    %4 = stablehlo.transpose %3, dims = [1, 0] : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xcomplex<f64>>
    %5 = stablehlo.slice %arg5 [4096:4097] : (tensor<4428xf64>) -> tensor<1xf64>
    %6 = stablehlo.reshape %5 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %7 = stablehlo.logistic %6 : tensor<f64>
    %8 = stablehlo.abs %6 : tensor<f64>
    %9 = stablehlo.negate %8 : tensor<f64>
    %10 = stablehlo.exponential %9 : tensor<f64>
    %11 = stablehlo.add %cst_31, %10 : tensor<f64>
    %12 = stablehlo.log %11 : tensor<f64>
    %13 = stablehlo.multiply %cst_32, %12 : tensor<f64>
    %14 = stablehlo.add %9, %13 : tensor<f64>
    %15 = stablehlo.multiply %cst_15, %7 : tensor<f64>
    %16 = stablehlo.add %15, %cst_17 : tensor<f64>
    %17 = stablehlo.add %14, %cst_16 : tensor<f64>
    %18 = stablehlo.slice %arg5 [4097:4098] : (tensor<4428xf64>) -> tensor<1xf64>
    %19 = stablehlo.reshape %18 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %20 = stablehlo.logistic %19 : tensor<f64>
    %21 = stablehlo.abs %19 : tensor<f64>
    %22 = stablehlo.negate %21 : tensor<f64>
    %23 = stablehlo.exponential %22 : tensor<f64>
    %24 = stablehlo.add %cst_31, %23 : tensor<f64>
    %25 = stablehlo.log %24 : tensor<f64>
    %26 = stablehlo.multiply %cst_32, %25 : tensor<f64>
    %27 = stablehlo.add %22, %26 : tensor<f64>
    %28 = stablehlo.multiply %cst_15, %20 : tensor<f64>
    %29 = stablehlo.add %28, %cst_17 : tensor<f64>
    %30 = stablehlo.add %27, %cst_16 : tensor<f64>
    %31 = stablehlo.slice %arg5 [4098:4099] : (tensor<4428xf64>) -> tensor<1xf64>
    %32 = stablehlo.reshape %31 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %33 = stablehlo.logistic %32 : tensor<f64>
    %34 = stablehlo.abs %32 : tensor<f64>
    %35 = stablehlo.negate %34 : tensor<f64>
    %36 = stablehlo.exponential %35 : tensor<f64>
    %37 = stablehlo.add %cst_31, %36 : tensor<f64>
    %38 = stablehlo.log %37 : tensor<f64>
    %39 = stablehlo.multiply %cst_32, %38 : tensor<f64>
    %40 = stablehlo.add %35, %39 : tensor<f64>
    %41 = stablehlo.multiply %cst_15, %33 : tensor<f64>
    %42 = stablehlo.add %41, %cst_17 : tensor<f64>
    %43 = stablehlo.add %40, %cst_16 : tensor<f64>
    %44 = stablehlo.add %30, %43 : tensor<f64>
    %45 = stablehlo.add %17, %44 : tensor<f64>
    %46 = stablehlo.slice %arg5 [4099:4100] : (tensor<4428xf64>) -> tensor<1xf64>
    %47 = stablehlo.reshape %46 {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.no_nan = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<1xf64>) -> tensor<f64>
    %48 = stablehlo.exponential %47 {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.no_nan = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} : tensor<f64>
    %49 = stablehlo.add %45, %47 : tensor<f64>
    %50 = stablehlo.slice %arg5 [4100:4226] {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4428xf64>) -> tensor<126xf64>
    %51 = stablehlo.slice %arg5 [4226:4427:2] : (tensor<4428xf64>) -> tensor<101xf64>
    %52 = stablehlo.slice %arg5 [4227:4428:2] : (tensor<4428xf64>) -> tensor<101xf64>
    %53 = stablehlo.atan2 %51, %52 : tensor<101xf64>
    %54 = stablehlo.multiply %52, %52 : tensor<101xf64>
    %55 = stablehlo.multiply %51, %51 : tensor<101xf64>
    %56 = stablehlo.add %55, %54 : tensor<101xf64>
    %57 = stablehlo.log %56 : tensor<101xf64>
    %58 = stablehlo.multiply %57, %cst_33 : tensor<101xf64>
    %59 = stablehlo.multiply %57, %cst_34 : tensor<101xf64>
    %60 = stablehlo.multiply %58, %58 : tensor<101xf64>
    %61 = stablehlo.negate %60 : tensor<101xf64>
    %62 = stablehlo.multiply %61, %cst_35 : tensor<101xf64>
    %63 = stablehlo.add %62, %59 : tensor<101xf64>
    %64 = stablehlo.reduce(%63 init: %cst_18) applies stablehlo.add across dimensions = [0] : (tensor<101xf64>, tensor<f64>) -> tensor<f64>
    %65 = stablehlo.remainder %c_36, %c_21 : tensor<101x1xi64>
    %66 = "stablehlo.scatter"(%cst_20, %65, %53) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0], scatter_dims_to_operand_dims = [0], index_vector_dim = 1>}> ({
    ^bb0(%arg6: tensor<f64>, %arg7: tensor<f64>):
      stablehlo.return %arg7 : tensor<f64>
    }) : (tensor<126xf64>, tensor<101x1xi64>, tensor<101xf64>) -> tensor<126xf64>
    %67 = "stablehlo.scatter"(%66, %c_37, %cst_22) <{indices_are_sorted = false, scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0], scatter_dims_to_operand_dims = [0], index_vector_dim = 1>, unique_indices = true}> ({
    ^bb0(%arg6: tensor<f64>, %arg7: tensor<f64>):
      stablehlo.return %cst_18 : tensor<f64>
    }) : (tensor<126xf64>, tensor<25x1xi64>, tensor<25xf64>) -> tensor<126xf64>
    %68 = stablehlo.add %49, %64 : tensor<f64>
    %69 = stablehlo.dot_general %1, %1, contracting_dims = [0] x [0] : (tensor<4096xf64>, tensor<4096xf64>) -> tensor<f64>
    %70 = stablehlo.negate %69 : tensor<f64>
    %71 = stablehlo.multiply %70, %cst_38 : tensor<f64>
    %72 = stablehlo.negate %48 : tensor<f64>
    %73 = stablehlo.compare  LT, %48, %cst_18 : (tensor<f64>, tensor<f64>) -> tensor<i1>
    %74 = stablehlo.select %73, %cst_23, %72 : tensor<i1>, tensor<f64>
    %75 = stablehlo.add %71, %cst_13 : tensor<f64>
    %76 = stablehlo.add %75, %74 : tensor<f64>
    %77 = stablehlo.multiply %50, %50 {enzymexla.finite = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} : tensor<126xf64>
    %78 = stablehlo.multiply %77, %cst_4 {enzymexla.no_nan = [#enzymexla<guaranteed NOTGUARANTEED>], enzymexla.non_negative = [#enzymexla<guaranteed GUARANTEED>]} : tensor<126xf64>
    %79 = stablehlo.is_finite %78 : (tensor<126xf64>) -> tensor<126xi1>
    %80 = stablehlo.not %79 : tensor<126xi1>
    %81 = stablehlo.compare  NE, %78, %cst_11 : (tensor<126xf64>, tensor<126xf64>) -> tensor<126xi1>
    %82 = stablehlo.and %80, %81 : tensor<126xi1>
    %83 = stablehlo.compare  NE, %78, %cst_12 : (tensor<126xf64>, tensor<126xf64>) -> tensor<126xi1>
    %84 = stablehlo.and %82, %83 : tensor<126xi1>
    %85 = stablehlo.select %84, %cst_20, %78 : tensor<126xi1>, tensor<126xf64>
    %86 = stablehlo.reduce(%85 init: %cst_18) applies stablehlo.add across dimensions = [0] : (tensor<126xf64>, tensor<f64>) -> tensor<f64>
    %87 = stablehlo.negate %86 : tensor<f64>
    %88 = stablehlo.multiply %87, %cst_38 : tensor<f64>
    %89 = stablehlo.add %88, %cst_24 : tensor<f64>
    %90 = "stablehlo.gather"(%67, %65) <{dimension_numbers = #stablehlo.gather<offset_dims = [0], start_index_map = [0], index_vector_dim = 1>, indices_are_sorted = false, slice_sizes = array<i64: 1>}> : (tensor<126xf64>, tensor<101x1xi64>) -> tensor<1x101xf64>
    %91 = stablehlo.cosine %90 : tensor<1x101xf64>
    %92 = stablehlo.reshape %91 : (tensor<1x101xf64>) -> tensor<101xf64>
    %93 = stablehlo.subtract %92, %cst_10 : tensor<101xf64>
    %94 = stablehlo.reduce(%93 init: %cst_18) applies stablehlo.add across dimensions = [0] : (tensor<101xf64>, tensor<f64>) -> tensor<f64>
    %95 = stablehlo.multiply %94, %cst_3 : tensor<f64>
    %96 = stablehlo.add %95, %cst_2 : tensor<f64>
    %97 = stablehlo.add %89, %96 : tensor<f64>
    %98 = stablehlo.add %76, %97 : tensor<f64>
    %99 = stablehlo.broadcast_in_dim %cst_39, dims = [0] : (tensor<64xf64>) -> tensor<64x64xf64>
    %100 = stablehlo.broadcast_in_dim %cst_25, dims = [0, 1] : (tensor<1x64xf64>) -> tensor<64x64xf64>
    %101 = stablehlo.multiply %99, %99 : tensor<64x64xf64>
    %102 = stablehlo.multiply %100, %100 : tensor<64x64xf64>
    %103 = stablehlo.add %101, %102 : tensor<64x64xf64>
    %104 = stablehlo.multiply %16, %16 : tensor<f64>
    %105 = stablehlo.broadcast_in_dim %104, dims = [] : (tensor<f64>) -> tensor<64x64xf64>
    %106 = stablehlo.multiply %105, %103 : tensor<64x64xf64>
    %107 = stablehlo.multiply %29, %29 : tensor<f64>
    %108 = stablehlo.broadcast_in_dim %107, dims = [] : (tensor<f64>) -> tensor<64x64xf64>
    %109 = stablehlo.multiply %108, %103 : tensor<64x64xf64>
    %110 = stablehlo.multiply %109, %109 : tensor<64x64xf64>
    %111 = stablehlo.multiply %42, %42 : tensor<f64>
    %112 = stablehlo.broadcast_in_dim %111, dims = [] : (tensor<f64>) -> tensor<64x64xf64>
    %113 = stablehlo.multiply %112, %103 : tensor<64x64xf64>
    %114 = stablehlo.power %113, %cst_9 : tensor<64x64xf64>
    %115 = stablehlo.add %106, %110 : tensor<64x64xf64>
    %116 = stablehlo.add %115, %114 : tensor<64x64xf64>
    %117 = stablehlo.add %cst_8, %116 : tensor<64x64xf64>
    %118 = stablehlo.rsqrt %117 : tensor<64x64xf64>
    %119 = stablehlo.convert %118 : (tensor<64x64xf64>) -> tensor<64x64xcomplex<f64>>
    %120 = chlo.conj %119 : tensor<64x64xcomplex<f64>> -> tensor<64x64xcomplex<f64>>
    %121 = stablehlo.multiply %119, %120 : tensor<64x64xcomplex<f64>>
    %122 = stablehlo.real %121 : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xf64>
    %123 = stablehlo.reduce(%122 init: %cst_18) applies stablehlo.add across dimensions = [0, 1] : (tensor<64x64xf64>, tensor<f64>) -> tensor<f64>
    %124 = stablehlo.multiply %123, %cst_26 : tensor<f64>
    %125 = stablehlo.rsqrt %124 : tensor<f64>
    %126 = stablehlo.multiply %119, %4 : tensor<64x64xcomplex<f64>>
    %127 = stablehlo.convert %125 : (tensor<f64>) -> tensor<complex<f64>>
    %128 = stablehlo.broadcast_in_dim %127, dims = [] : (tensor<complex<f64>>) -> tensor<64x64xcomplex<f64>>
    %129 = stablehlo.multiply %126, %128 : tensor<64x64xcomplex<f64>>
    %130 = stablehlo.fft %129, type =  FFT, length = [64, 64] {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xcomplex<f64>>
    %131 = stablehlo.real %130 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xf64>
    %132 = stablehlo.imag %130 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<64x64xcomplex<f64>>) -> tensor<64x64xf64>
    %133 = stablehlo.add %131, %132 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %134 = stablehlo.multiply %133, %cst_1 : tensor<64x64xf64>
    %135 = stablehlo.broadcast_in_dim %48, dims = [] {enzymexla.symmetric_matrix = [#enzymexla<guaranteed GUARANTEED>]} : (tensor<f64>) -> tensor<64x64xf64>
    %136 = stablehlo.multiply %134, %135 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %137 = stablehlo.reduce(%136 init: %cst_23) applies stablehlo.maximum across dimensions = [0, 1] : (tensor<64x64xf64>, tensor<f64>) -> tensor<f64>
    %138 = stablehlo.broadcast_in_dim %137, dims = [] {enzymexla.symmetric_matrix = [#enzymexla<guaranteed GUARANTEED>]} : (tensor<f64>) -> tensor<64x64xf64>
    %139 = stablehlo.subtract %136, %138 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %140 = stablehlo.exponential %139 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<64x64xf64>
    %141 = stablehlo.transpose %140, dims = [1, 0] : (tensor<64x64xf64>) -> tensor<64x64xf64>
    %142 = stablehlo.reshape %141 : (tensor<64x64xf64>) -> tensor<4096xf64>
    %143 = stablehlo.reduce(%140 init: %cst_18) applies stablehlo.add across dimensions = [0, 1] : (tensor<64x64xf64>, tensor<f64>) -> tensor<f64>
    %144 = stablehlo.broadcast_in_dim %143, dims = [] : (tensor<f64>) -> tensor<4096xf64>
    %145 = stablehlo.divide %142, %144 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<4096xf64>
    %146 = stablehlo.convert %145 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<4096xf64>) -> tensor<4096xcomplex<f64>>
    %147 = stablehlo.multiply %146, %arg3 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<4096xcomplex<f64>>
    %148 = stablehlo.subtract %0, %c_28 : tensor<4096x1xi64>
    %149 = stablehlo.divide %148, %c_29 : tensor<4096x1xi64>
    %150 = stablehlo.concatenate %148, %149, dim = 1 : (tensor<4096x1xi64>, tensor<4096x1xi64>) -> tensor<4096x2xi64>
    %151 = stablehlo.remainder %150, %c_41 : tensor<4096x2xi64>
    %152 = "stablehlo.scatter"(%cst_40, %151, %147) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0, 1], scatter_dims_to_operand_dims = [0, 1], index_vector_dim = 1>}> ({
    ^bb0(%arg6: tensor<complex<f64>>, %arg7: tensor<complex<f64>>):
      stablehlo.return %arg7 : tensor<complex<f64>>
    }) {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<128x128xcomplex<f64>>, tensor<4096x2xi64>, tensor<4096xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %153 = stablehlo.transpose %152, dims = [1, 0] : (tensor<128x128xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %154 = stablehlo.fft %153, type =  FFT, length = [128, 128] : (tensor<128x128xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %155 = stablehlo.reshape %154 : (tensor<128x128xcomplex<f64>>) -> tensor<16384x1xcomplex<f64>>
    %156 = stablehlo.dot_general %arg4, %155, contracting_dims = [1] x [0], precision = [DEFAULT, DEFAULT] : (tensor<274x16384xcomplex<f64>>, tensor<16384x1xcomplex<f64>>) -> tensor<274x1xcomplex<f64>>
    %157 = stablehlo.reshape %156 : (tensor<274x1xcomplex<f64>>) -> tensor<274xcomplex<f64>>
    %158 = stablehlo.multiply %157, %cst_0 : tensor<274xcomplex<f64>>
    %159:2 = stablehlo.while(%iterArg = %c_19, %iterArg_46 = %cst_27) : tensor<i64>, tensor<274xcomplex<f64>> attributes {enzyme.disable_mincut}
    cond {
      %178 = stablehlo.compare  LT, %iterArg, %c_42 : (tensor<i64>, tensor<i64>) -> tensor<i1>
      stablehlo.return %178 : tensor<i1>
    } do {
      %178 = stablehlo.add %c, %iterArg {enzymexla.bounds = [[1, 274]]} : tensor<i64>
      %179 = stablehlo.convert %178 {enzymexla.bounds = [[1, 274]]} : (tensor<i64>) -> tensor<i32>
      %180 = stablehlo.subtract %179, %c_14 {enzymexla.bounds = [[0, 273]]} : tensor<i32>
      %181 = stablehlo.dynamic_slice %158, %180, sizes = [1] : (tensor<274xcomplex<f64>>, tensor<i32>) -> tensor<1xcomplex<f64>>
      %182 = stablehlo.dynamic_slice %c_43, %iterArg, sizes = [1] : (tensor<274xi32>, tensor<i64>) -> tensor<1xi32>
      %183 = stablehlo.reshape %182 : (tensor<1xi32>) -> tensor<i32>
      %184 = stablehlo.dynamic_slice %50, %183, sizes = [1] : (tensor<126xf64>, tensor<i32>) -> tensor<1xf64>
      %185 = stablehlo.dynamic_slice %67, %183, sizes = [1] : (tensor<126xf64>, tensor<i32>) -> tensor<1xf64>
      %186 = stablehlo.complex %184, %185 : tensor<1xcomplex<f64>>
      %187 = stablehlo.exponential %186 : tensor<1xcomplex<f64>>
      %188 = stablehlo.dynamic_slice %c_44, %iterArg, sizes = [1] : (tensor<274xi32>, tensor<i64>) -> tensor<1xi32>
      %189 = stablehlo.reshape %188 : (tensor<1xi32>) -> tensor<i32>
      %190 = stablehlo.dynamic_slice %50, %189, sizes = [1] : (tensor<126xf64>, tensor<i32>) -> tensor<1xf64>
      %191 = stablehlo.dynamic_slice %67, %189, sizes = [1] : (tensor<126xf64>, tensor<i32>) -> tensor<1xf64>
      %192 = stablehlo.complex %190, %191 : tensor<1xcomplex<f64>>
      %193 = stablehlo.exponential %192 : tensor<1xcomplex<f64>>
      %194 = chlo.conj %193 : tensor<1xcomplex<f64>> -> tensor<1xcomplex<f64>>
      %195 = stablehlo.multiply %187, %181 : tensor<1xcomplex<f64>>
      %196 = stablehlo.multiply %195, %194 : tensor<1xcomplex<f64>>
      %197 = stablehlo.dynamic_update_slice %iterArg_46, %196, %180 : (tensor<274xcomplex<f64>>, tensor<1xcomplex<f64>>, tensor<i32>) -> tensor<274xcomplex<f64>>
      stablehlo.return %178, %197 : tensor<i64>, tensor<274xcomplex<f64>>
    }
    %160 = stablehlo.subtract %cst_45, %159#1 : tensor<274xcomplex<f64>>
    %161 = chlo.conj %160 : tensor<274xcomplex<f64>> -> tensor<274xcomplex<f64>>
    %162 = stablehlo.multiply %160, %161 : tensor<274xcomplex<f64>>
    %163 = stablehlo.real %162 {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<274xcomplex<f64>>) -> tensor<274xf64>
    %164 = stablehlo.multiply %163, %cst {enzymexla.non_negative = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<274xf64>
    %165 = stablehlo.is_finite %164 : (tensor<274xf64>) -> tensor<274xi1>
    %166 = stablehlo.not %165 : tensor<274xi1>
    %167 = stablehlo.compare  NE, %164, %cst_5 : (tensor<274xf64>, tensor<274xf64>) -> tensor<274xi1>
    %168 = stablehlo.and %166, %167 : tensor<274xi1>
    %169 = stablehlo.compare  NE, %164, %cst_6 : (tensor<274xf64>, tensor<274xf64>) -> tensor<274xi1>
    %170 = stablehlo.and %168, %169 : tensor<274xi1>
    %171 = stablehlo.select %170, %cst_7, %164 : tensor<274xi1>, tensor<274xf64>
    %172 = stablehlo.reduce(%171 init: %cst_18) applies stablehlo.add across dimensions = [0] : (tensor<274xf64>, tensor<f64>) -> tensor<f64>
    %173 = stablehlo.negate %172 : tensor<f64>
    %174 = stablehlo.multiply %173, %cst_38 : tensor<f64>
    %175 = stablehlo.add %174, %cst_30 : tensor<f64>
    %176 = stablehlo.add %175, %98 : tensor<f64>
    %177 = stablehlo.add %176, %68 : tensor<f64>
    return %177, %154 : tensor<f64>, tensor<128x128xcomplex<f64>>
  }
}

@ptiede

ptiede commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator Author

Just to put some numbers down for the NFFT. On my machine I see the following

# Regular julia nfft on CPU
@benchmark VLBISkyModels._jlnuft!(out, post.skymodel.grid.plan_forward.plan, img)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min  max):  51.600 μs  97.009 μs  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     52.540 μs              ┊ GC (median):    0.00%
 Time  (mean ± σ):   52.858 μs ±  1.262 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

     ▂▄▅▆▇███▇▆▅▄▃▃▂▂                               ▁▁▁       ▃
  ▃▄███████████████████▇▇▇▇▆▆▆▆▇▇▆█▆▇▇█▇▇██▇█▇▇▇█▇███████▇▆▇▇ █
  51.6 μs      Histogram: log(frequency) by time      57.2 μs <

 Memory estimate: 2.98 KiB, allocs estimate: 14.

# Reactant compiled nfft (can't use the same code as CPU version so this is slightly different)
BenchmarkTools.Trial: 1068 samples with 1 evaluation per sample.
 Range (min  max):  4.078 ms    7.306 ms  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     4.546 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   4.671 ms ± 504.530 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

        ▅▅██▇▄▅▂▃                                              
  ▃▄▄▆▇████████████▄▅▃▃▃▃▂▂▂▁▂▁▂▁▁▁▁▂▂▂▂▂▂▂▃▃▂▂▃▂▃▂▂▃▃▂▁▂▁▃▁▂ ▃
  4.08 ms         Histogram: frequency by time        6.67 ms <

 Memory estimate: 1.67 KiB, allocs estimate: 30.

and the stable HLO code emitted is

module @"reactant__jlnuft!" attributes {mhlo.num_partitions = 1 : i64, mhlo.num_replicas = 1 : i64} {
  func.func @main(%arg0: tensor<274xcomplex<f64>> {enzymexla.memory_effects = [], tf.aliasing_output = 0 : i32}, %arg1: tensor<128x128xcomplex<f64>> {enzymexla.memory_effects = [], tf.aliasing_output = 1 : i32}, %arg2: tensor<64x64xcomplex<f64>> {enzymexla.memory_effects = []}, %arg3: tensor<4096xi64> {enzymexla.memory_effects = []}, %arg4: tensor<4096xcomplex<f64>> {enzymexla.memory_effects = []}, %arg5: tensor<274x16384xcomplex<f64>> {enzymexla.memory_effects = []}, %arg6: tensor<64x64xf64> {enzymexla.memory_effects = []}) -> (tensor<274xcomplex<f64>>, tensor<128x128xcomplex<f64>>) attributes {enzymexla.memory_effects = []} {
    %c = stablehlo.constant dense<1> : tensor<4096x1xi64>
    %c_0 = stablehlo.constant dense<128> : tensor<4096x1xi64>
    %cst = stablehlo.constant dense<(0.000000e+00,0.000000e+00)> : tensor<128x128xcomplex<f64>>
    %c_1 = stablehlo.constant dense<128> : tensor<4096x2xi64>
    %0 = stablehlo.reshape %arg3 : (tensor<4096xi64>) -> tensor<4096x1xi64>
    %1 = stablehlo.convert %arg6 : (tensor<64x64xf64>) -> tensor<64x64xcomplex<f64>>
    %2 = stablehlo.reshape %1 : (tensor<64x64xcomplex<f64>>) -> tensor<4096xcomplex<f64>>
    %3 = stablehlo.multiply %2, %arg4 {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : tensor<4096xcomplex<f64>>
    %4 = stablehlo.subtract %0, %c : tensor<4096x1xi64>
    %5 = stablehlo.divide %4, %c_0 : tensor<4096x1xi64>
    %6 = stablehlo.concatenate %4, %5, dim = 1 : (tensor<4096x1xi64>, tensor<4096x1xi64>) -> tensor<4096x2xi64>
    %7 = stablehlo.remainder %6, %c_1 : tensor<4096x2xi64>
    %8 = "stablehlo.scatter"(%cst, %7, %3) <{scatter_dimension_numbers = #stablehlo.scatter<inserted_window_dims = [0, 1], scatter_dims_to_operand_dims = [0, 1], index_vector_dim = 1>}> ({
    ^bb0(%arg7: tensor<complex<f64>>, %arg8: tensor<complex<f64>>):
      stablehlo.return %arg8 : tensor<complex<f64>>
    }) {enzymexla.symmetric_matrix = [#enzymexla<guaranteed NOTGUARANTEED>]} : (tensor<128x128xcomplex<f64>>, tensor<4096x2xi64>, tensor<4096xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %9 = stablehlo.transpose %8, dims = [1, 0] : (tensor<128x128xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %10 = stablehlo.fft %9, type =  FFT, length = [128, 128] : (tensor<128x128xcomplex<f64>>) -> tensor<128x128xcomplex<f64>>
    %11 = stablehlo.reshape %10 : (tensor<128x128xcomplex<f64>>) -> tensor<16384x1xcomplex<f64>>
    %12 = stablehlo.dot_general %arg5, %11, contracting_dims = [1] x [0], precision = [DEFAULT, DEFAULT] : (tensor<274x16384xcomplex<f64>>, tensor<16384x1xcomplex<f64>>) -> tensor<274x1xcomplex<f64>>
    %13 = stablehlo.reshape %12 : (tensor<274x1xcomplex<f64>>) -> tensor<274xcomplex<f64>>
    return %13, %10 : tensor<274xcomplex<f64>>, tensor<128x128xcomplex<f64>>
  }
}

@avik-pal

Copy link
Copy Markdown
Collaborator

I cant find any branch Reactant#aem. What is the main difference in that branch?

@avik-pal

Copy link
Copy Markdown
Collaborator

Also F64 performance on most consumer chips is typically abysmal

@avik-pal avik-pal force-pushed the ptiede-comradeinteg branch from f583bf8 to 91ce070 Compare February 12, 2026 20:42
@avik-pal avik-pal force-pushed the ptiede-comradeinteg branch 2 times, most recently from 8f13168 to 8770257 Compare February 13, 2026 13:48
@avik-pal avik-pal force-pushed the ptiede-comradeinteg branch from 8770257 to 22106b3 Compare February 13, 2026 13:54
Comment thread benchmark/comrade/comimager.jl Outdated
@avik-pal avik-pal changed the title Start adding Comrade integration tests perf: comrade performance benchmark Feb 13, 2026
@avik-pal avik-pal merged commit 781e746 into EnzymeAD:main Feb 13, 2026
9 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants