Adapters
GhostNetworkUser commited on
Commit
28365d2
·
verified ·
1 Parent(s): 6cd92d9

Upload 64 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
.gitattributes CHANGED
@@ -33,3 +33,29 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ datasets-cli.exe filter=lfs diff=lfs merge=lfs -text
37
+ f2py.exe filter=lfs diff=lfs merge=lfs -text
38
+ huggingface-cli.exe filter=lfs diff=lfs merge=lfs -text
39
+ import_pb_to_tensorboard.exe filter=lfs diff=lfs merge=lfs -text
40
+ isympy.exe filter=lfs diff=lfs merge=lfs -text
41
+ markdown_py.exe filter=lfs diff=lfs merge=lfs -text
42
+ markdown-it.exe filter=lfs diff=lfs merge=lfs -text
43
+ normalizer.exe filter=lfs diff=lfs merge=lfs -text
44
+ numpy-config.exe filter=lfs diff=lfs merge=lfs -text
45
+ pip.exe filter=lfs diff=lfs merge=lfs -text
46
+ pip3.12.exe filter=lfs diff=lfs merge=lfs -text
47
+ pip3.exe filter=lfs diff=lfs merge=lfs -text
48
+ pygmentize.exe filter=lfs diff=lfs merge=lfs -text
49
+ python.exe filter=lfs diff=lfs merge=lfs -text
50
+ pythonw.exe filter=lfs diff=lfs merge=lfs -text
51
+ saved_model_cli.exe filter=lfs diff=lfs merge=lfs -text
52
+ tensorboard.exe filter=lfs diff=lfs merge=lfs -text
53
+ tf_upgrade_v2.exe filter=lfs diff=lfs merge=lfs -text
54
+ tflite_convert.exe filter=lfs diff=lfs merge=lfs -text
55
+ toco_from_protos.exe filter=lfs diff=lfs merge=lfs -text
56
+ toco.exe filter=lfs diff=lfs merge=lfs -text
57
+ torchfrtrace.exe filter=lfs diff=lfs merge=lfs -text
58
+ torchrun.exe filter=lfs diff=lfs merge=lfs -text
59
+ tqdm.exe filter=lfs diff=lfs merge=lfs -text
60
+ transformers-cli.exe filter=lfs diff=lfs merge=lfs -text
61
+ wheel.exe filter=lfs diff=lfs merge=lfs -text
Activate.ps1 ADDED
@@ -0,0 +1,502 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <#
2
+ .Synopsis
3
+ Activate a Python virtual environment for the current PowerShell session.
4
+
5
+ .Description
6
+ Pushes the python executable for a virtual environment to the front of the
7
+ $Env:PATH environment variable and sets the prompt to signify that you are
8
+ in a Python virtual environment. Makes use of the command line switches as
9
+ well as the `pyvenv.cfg` file values present in the virtual environment.
10
+
11
+ .Parameter VenvDir
12
+ Path to the directory that contains the virtual environment to activate. The
13
+ default value for this is the parent of the directory that the Activate.ps1
14
+ script is located within.
15
+
16
+ .Parameter Prompt
17
+ The prompt prefix to display when this virtual environment is activated. By
18
+ default, this prompt is the name of the virtual environment folder (VenvDir)
19
+ surrounded by parentheses and followed by a single space (ie. '(.venv) ').
20
+
21
+ .Example
22
+ Activate.ps1
23
+ Activates the Python virtual environment that contains the Activate.ps1 script.
24
+
25
+ .Example
26
+ Activate.ps1 -Verbose
27
+ Activates the Python virtual environment that contains the Activate.ps1 script,
28
+ and shows extra information about the activation as it executes.
29
+
30
+ .Example
31
+ Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
32
+ Activates the Python virtual environment located in the specified location.
33
+
34
+ .Example
35
+ Activate.ps1 -Prompt "MyPython"
36
+ Activates the Python virtual environment that contains the Activate.ps1 script,
37
+ and prefixes the current prompt with the specified string (surrounded in
38
+ parentheses) while the virtual environment is active.
39
+
40
+ .Notes
41
+ On Windows, it may be required to enable this Activate.ps1 script by setting the
42
+ execution policy for the user. You can do this by issuing the following PowerShell
43
+ command:
44
+
45
+ PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
46
+
47
+ For more information on Execution Policies:
48
+ https://go.microsoft.com/fwlink/?LinkID=135170
49
+
50
+ #>
51
+ Param(
52
+ [Parameter(Mandatory = $false)]
53
+ [String]
54
+ $VenvDir,
55
+ [Parameter(Mandatory = $false)]
56
+ [String]
57
+ $Prompt
58
+ )
59
+
60
+ <# Function declarations --------------------------------------------------- #>
61
+
62
+ <#
63
+ .Synopsis
64
+ Remove all shell session elements added by the Activate script, including the
65
+ addition of the virtual environment's Python executable from the beginning of
66
+ the PATH variable.
67
+
68
+ .Parameter NonDestructive
69
+ If present, do not remove this function from the global namespace for the
70
+ session.
71
+
72
+ #>
73
+ function global:deactivate ([switch]$NonDestructive) {
74
+ # Revert to original values
75
+
76
+ # The prior prompt:
77
+ if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
78
+ Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
79
+ Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
80
+ }
81
+
82
+ # The prior PYTHONHOME:
83
+ if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
84
+ Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
85
+ Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
86
+ }
87
+
88
+ # The prior PATH:
89
+ if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
90
+ Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
91
+ Remove-Item -Path Env:_OLD_VIRTUAL_PATH
92
+ }
93
+
94
+ # Just remove the VIRTUAL_ENV altogether:
95
+ if (Test-Path -Path Env:VIRTUAL_ENV) {
96
+ Remove-Item -Path env:VIRTUAL_ENV
97
+ }
98
+
99
+ # Just remove VIRTUAL_ENV_PROMPT altogether.
100
+ if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
101
+ Remove-Item -Path env:VIRTUAL_ENV_PROMPT
102
+ }
103
+
104
+ # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
105
+ if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
106
+ Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
107
+ }
108
+
109
+ # Leave deactivate function in the global namespace if requested:
110
+ if (-not $NonDestructive) {
111
+ Remove-Item -Path function:deactivate
112
+ }
113
+ }
114
+
115
+ <#
116
+ .Description
117
+ Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
118
+ given folder, and returns them in a map.
119
+
120
+ For each line in the pyvenv.cfg file, if that line can be parsed into exactly
121
+ two strings separated by `=` (with any amount of whitespace surrounding the =)
122
+ then it is considered a `key = value` line. The left hand string is the key,
123
+ the right hand is the value.
124
+
125
+ If the value starts with a `'` or a `"` then the first and last character is
126
+ stripped from the value before being captured.
127
+
128
+ .Parameter ConfigDir
129
+ Path to the directory that contains the `pyvenv.cfg` file.
130
+ #>
131
+ function Get-PyVenvConfig(
132
+ [String]
133
+ $ConfigDir
134
+ ) {
135
+ Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
136
+
137
+ # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
138
+ $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
139
+
140
+ # An empty map will be returned if no config file is found.
141
+ $pyvenvConfig = @{ }
142
+
143
+ if ($pyvenvConfigPath) {
144
+
145
+ Write-Verbose "File exists, parse `key = value` lines"
146
+ $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
147
+
148
+ $pyvenvConfigContent | ForEach-Object {
149
+ $keyval = $PSItem -split "\s*=\s*", 2
150
+ if ($keyval[0] -and $keyval[1]) {
151
+ $val = $keyval[1]
152
+
153
+ # Remove extraneous quotations around a string value.
154
+ if ("'""".Contains($val.Substring(0, 1))) {
155
+ $val = $val.Substring(1, $val.Length - 2)
156
+ }
157
+
158
+ $pyvenvConfig[$keyval[0]] = $val
159
+ Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
160
+ }
161
+ }
162
+ }
163
+ return $pyvenvConfig
164
+ }
165
+
166
+
167
+ <# Begin Activate script --------------------------------------------------- #>
168
+
169
+ # Determine the containing directory of this script
170
+ $VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
171
+ $VenvExecDir = Get-Item -Path $VenvExecPath
172
+
173
+ Write-Verbose "Activation script is located in path: '$VenvExecPath'"
174
+ Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
175
+ Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
176
+
177
+ # Set values required in priority: CmdLine, ConfigFile, Default
178
+ # First, get the location of the virtual environment, it might not be
179
+ # VenvExecDir if specified on the command line.
180
+ if ($VenvDir) {
181
+ Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
182
+ }
183
+ else {
184
+ Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
185
+ $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
186
+ Write-Verbose "VenvDir=$VenvDir"
187
+ }
188
+
189
+ # Next, read the `pyvenv.cfg` file to determine any required value such
190
+ # as `prompt`.
191
+ $pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
192
+
193
+ # Next, set the prompt from the command line, or the config file, or
194
+ # just use the name of the virtual environment folder.
195
+ if ($Prompt) {
196
+ Write-Verbose "Prompt specified as argument, using '$Prompt'"
197
+ }
198
+ else {
199
+ Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
200
+ if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
201
+ Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
202
+ $Prompt = $pyvenvCfg['prompt'];
203
+ }
204
+ else {
205
+ Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
206
+ Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
207
+ $Prompt = Split-Path -Path $venvDir -Leaf
208
+ }
209
+ }
210
+
211
+ Write-Verbose "Prompt = '$Prompt'"
212
+ Write-Verbose "VenvDir='$VenvDir'"
213
+
214
+ # Deactivate any currently active virtual environment, but leave the
215
+ # deactivate function in place.
216
+ deactivate -nondestructive
217
+
218
+ # Now set the environment variable VIRTUAL_ENV, used by many tools to determine
219
+ # that there is an activated venv.
220
+ $env:VIRTUAL_ENV = $VenvDir
221
+
222
+ if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
223
+
224
+ Write-Verbose "Setting prompt to '$Prompt'"
225
+
226
+ # Set the prompt to include the env name
227
+ # Make sure _OLD_VIRTUAL_PROMPT is global
228
+ function global:_OLD_VIRTUAL_PROMPT { "" }
229
+ Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
230
+ New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
231
+
232
+ function global:prompt {
233
+ Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
234
+ _OLD_VIRTUAL_PROMPT
235
+ }
236
+ $env:VIRTUAL_ENV_PROMPT = $Prompt
237
+ }
238
+
239
+ # Clear PYTHONHOME
240
+ if (Test-Path -Path Env:PYTHONHOME) {
241
+ Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
242
+ Remove-Item -Path Env:PYTHONHOME
243
+ }
244
+
245
+ # Add the venv to the PATH
246
+ Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
247
+ $Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
248
+
249
+ # SIG # Begin signature block
250
+ # MIIvIwYJKoZIhvcNAQcCoIIvFDCCLxACAQExDzANBglghkgBZQMEAgEFADB5Bgor
251
+ # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
252
+ # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnL745ElCYk8vk
253
+ # dBtMuQhLeWJ3ZGfzKW4DHCYzAn+QB6CCE8MwggWQMIIDeKADAgECAhAFmxtXno4h
254
+ # MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
255
+ # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
256
+ # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z
257
+ # ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
258
+ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
259
+ # IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
260
+ # AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z
261
+ # G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ
262
+ # anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s
263
+ # Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL
264
+ # 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb
265
+ # BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3
266
+ # JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c
267
+ # AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx
268
+ # YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0
269
+ # viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL
270
+ # T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud
271
+ # EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf
272
+ # Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk
273
+ # aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS
274
+ # PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK
275
+ # 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB
276
+ # cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp
277
+ # 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg
278
+ # dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri
279
+ # RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7
280
+ # 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5
281
+ # nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3
282
+ # i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H
283
+ # EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G
284
+ # CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
285
+ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
286
+ # IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla
287
+ # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
288
+ # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
289
+ # ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C
290
+ # 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce
291
+ # 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da
292
+ # E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T
293
+ # SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA
294
+ # FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh
295
+ # D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM
296
+ # 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z
297
+ # 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05
298
+ # huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY
299
+ # mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP
300
+ # /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T
301
+ # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD
302
+ # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
303
+ # A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
304
+ # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
305
+ # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
306
+ # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
307
+ # cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN
308
+ # BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry
309
+ # sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL
310
+ # IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf
311
+ # Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh
312
+ # OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh
313
+ # dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV
314
+ # 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j
315
+ # wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH
316
+ # Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC
317
+ # XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l
318
+ # /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW
319
+ # eE4wggd3MIIFX6ADAgECAhAHHxQbizANJfMU6yMM0NHdMA0GCSqGSIb3DQEBCwUA
320
+ # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
321
+ # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
322
+ # ODQgMjAyMSBDQTEwHhcNMjIwMTE3MDAwMDAwWhcNMjUwMTE1MjM1OTU5WjB8MQsw
323
+ # CQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQHEwlCZWF2ZXJ0b24x
324
+ # IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQDExpQ
325
+ # eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
326
+ # ADCCAgoCggIBAKgc0BTT+iKbtK6f2mr9pNMUTcAJxKdsuOiSYgDFfwhjQy89koM7
327
+ # uP+QV/gwx8MzEt3c9tLJvDccVWQ8H7mVsk/K+X+IufBLCgUi0GGAZUegEAeRlSXx
328
+ # xhYScr818ma8EvGIZdiSOhqjYc4KnfgfIS4RLtZSrDFG2tN16yS8skFa3IHyvWdb
329
+ # D9PvZ4iYNAS4pjYDRjT/9uzPZ4Pan+53xZIcDgjiTwOh8VGuppxcia6a7xCyKoOA
330
+ # GjvCyQsj5223v1/Ig7Dp9mGI+nh1E3IwmyTIIuVHyK6Lqu352diDY+iCMpk9Zanm
331
+ # SjmB+GMVs+H/gOiofjjtf6oz0ki3rb7sQ8fTnonIL9dyGTJ0ZFYKeb6BLA66d2GA
332
+ # LwxZhLe5WH4Np9HcyXHACkppsE6ynYjTOd7+jN1PRJahN1oERzTzEiV6nCO1M3U1
333
+ # HbPTGyq52IMFSBM2/07WTJSbOeXjvYR7aUxK9/ZkJiacl2iZI7IWe7JKhHohqKuc
334
+ # eQNyOzxTakLcRkzynvIrk33R9YVqtB4L6wtFxhUjvDnQg16xot2KVPdfyPAWd81w
335
+ # tZADmrUtsZ9qG79x1hBdyOl4vUtVPECuyhCxaw+faVjumapPUnwo8ygflJJ74J+B
336
+ # Yxf6UuD7m8yzsfXWkdv52DjL74TxzuFTLHPyARWCSCAbzn3ZIly+qIqDAgMBAAGj
337
+ # ggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfROQjAdBgNVHQ4E
338
+ # FgQUt/1Teh2XDuUj2WW3siYWJgkZHA8wDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM
339
+ # MAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0dHA6Ly9jcmwzLmRp
340
+ # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI
341
+ # QTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5kaWdpY2VydC5jb20v
342
+ # RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex
343
+ # LmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRwOi8v
344
+ # d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUF
345
+ # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6
346
+ # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu
347
+ # aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZI
348
+ # hvcNAQELBQADggIBABxv4AeV/5ltkELHSC63fXAFYS5tadcWTiNc2rskrNLrfH1N
349
+ # s0vgSZFoQxYBFKI159E8oQQ1SKbTEubZ/B9kmHPhprHya08+VVzxC88pOEvz68nA
350
+ # 82oEM09584aILqYmj8Pj7h/kmZNzuEL7WiwFa/U1hX+XiWfLIJQsAHBla0i7QRF2
351
+ # de8/VSF0XXFa2kBQ6aiTsiLyKPNbaNtbcucaUdn6vVUS5izWOXM95BSkFSKdE45O
352
+ # q3FForNJXjBvSCpwcP36WklaHL+aHu1upIhCTUkzTHMh8b86WmjRUqbrnvdyR2yd
353
+ # I5l1OqcMBjkpPpIV6wcc+KY/RH2xvVuuoHjlUjwq2bHiNoX+W1scCpnA8YTs2d50
354
+ # jDHUgwUo+ciwpffH0Riq132NFmrH3r67VaN3TuBxjI8SIZM58WEDkbeoriDk3hxU
355
+ # 8ZWV7b8AW6oyVBGfM06UgkfMb58h+tJPrFx8VI/WLq1dTqMfZOm5cuclMnUHs2uq
356
+ # rRNtnV8UfidPBL4ZHkTcClQbCoz0UbLhkiDvIS00Dn+BBcxw/TKqVL4Oaz3bkMSs
357
+ # M46LciTeucHY9ExRVt3zy7i149sd+F4QozPqn7FrSVHXmem3r7bjyHTxOgqxRCVa
358
+ # 18Vtx7P/8bYSBeS+WHCKcliFCecspusCDSlnRUjZwyPdP0VHxaZg2unjHY3rMYIa
359
+ # tjCCGrICAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu
360
+ # Yy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJT
361
+ # QTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAHHxQbizANJfMU6yMM0NHdMA0GCWCGSAFl
362
+ # AwQCAQUAoIHIMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC
363
+ # AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBnAZ6P7YvTwq0fbF62
364
+ # o7E75R0LxsW5OtyYiFESQckLhjBcBgorBgEEAYI3AgEMMU4wTKBGgEQAQgB1AGkA
365
+ # bAB0ADoAIABSAGUAbABlAGEAcwBlAF8AdgAzAC4AMQAyAC4ANgBfADIAMAAyADQA
366
+ # MAA5ADAANgAuADAAMqECgAAwDQYJKoZIhvcNAQEBBQAEggIAhen5GN03SF9I96DT
367
+ # rrWEsN7FAyx8BHoRf9WFBqoBXpFkBwlE6OWj/rxohuwB/b+3vcBGWaP497ACku4l
368
+ # lgrWCrmYOVMKTjeHtDDkvgmygvGAtWB5drf56553na9RYjTxRqxto5LBMsHtPZy6
369
+ # 1D+touyLSHx+QXzqXO4ssUq7oHtsmjDCKMLdcTuoqNGtpxaIwwlOAK+0DaLLUpkX
370
+ # VRUUzMWBb+2FlmJ2wWtXXs6OtlACm4By2hHmKhd6OYwnHPe6fDVdrhGa0BcDAIIO
371
+ # +elm895ddmfX2KqHWrKpgZ/0DM46pbEiYX4GVwY+kmrK9p8XF7c50c331vPPuImL
372
+ # URRShtCM9F/5e522nQm0NxQ0Pz+thMD+qGBA8WuSoD+RRG+JKOXgM8sMX46goR8P
373
+ # 1IJLeUnEKSOgMNcP0EUeWthrqXRjVgNcazIDgPFpPGMyo4Pp0D8SPvp/RzP3CPVo
374
+ # uVj6r0OnhyoDuDEX4KCyo/+TCSm+2T+hv+cPWQaukovXF1TmahWb/8j1+K1RkCVd
375
+ # UQ5v07AHYoHmJ2gxEgtM9qaVDx4woVVCpUrOhiAP/K1WSRw710oTqECG+4y+g67D
376
+ # P2UuOxxaxhPk0pITFj9pZQcVsrCk5QbW3Yj/I3fISZgjVfYK1IDKzaWQQuBhOuim
377
+ # j2/Tfcg+cLDbY4XEs5vpbKSYsCWhghc/MIIXOwYKKwYBBAGCNwMDATGCFyswghcn
378
+ # BgkqhkiG9w0BBwKgghcYMIIXFAIBAzEPMA0GCWCGSAFlAwQCAQUAMHcGCyqGSIb3
379
+ # DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQgS2eq
380
+ # 9RcYET/J2twNl3zStqvYDUBOrSdHvMcFbSu+C2sCEGHEWhqgAhMA1D+QZOB9TC4Y
381
+ # DzIwMjQwOTA2MjAyNzExWqCCEwkwggbCMIIEqqADAgECAhAFRK/zlJ0IOaa/2z9f
382
+ # 5WEWMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
383
+ # Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2
384
+ # IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAwMDAwWhcNMzQxMDEz
385
+ # MjM1OTU5WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x
386
+ # IDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIICIjANBgkqhkiG9w0B
387
+ # AQEFAAOCAg8AMIICCgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl0uddoQ4J3C9Io5d6
388
+ # OyqcZ9xiFVjBqZMRp82qsmrdECmKHmJjadNYnDVxvzqX65RQjxwg6seaOy+WZuNp
389
+ # 52n+W8PWKyAcwZeUtKVQgfLPywemMGjKg0La/H8JJJSkghraarrYO8pd3hkYhftF
390
+ # 6g1hbJ3+cV7EBpo88MUueQ8bZlLjyNY+X9pD04T10Mf2SC1eRXWWdf7dEKEbg8G4
391
+ # 5lKVtUfXeCk5a+B4WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSkIWRw69XloNpjsy7p
392
+ # Be6q9iT1HbybHLK3X9/w7nZ9MZllR1WdSiQvrCuXvp/k/XtzPjLuUjT71Lvr1KAs
393
+ # NJvj3m5kGQc3AZEPHLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB+9ixLOFRr7StFQYU
394
+ # 6mIIE9NpHnxkTZ0P387RXoyqq1AVybPKvNfEO2hEo6U7Qv1zfe7dCv95NBB+plwK
395
+ # WEwAPoVpdceDZNZ1zY8SdlalJPrXxGshuugfNJgvOuprAbD3+yqG7HtSOKmYCaFx
396
+ # smxxrz64b5bV4RAT/mFHCoz+8LbH1cfebCTwv0KCyqBxPZySkwS0aXAnDU+3tTbR
397
+ # yV8IpHCj7ArxES5k4MsiK8rxKBMhSVF+BmbTO77665E42FEHypS34lCh8zrTioPL
398
+ # QHsCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYG
399
+ # A1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCG
400
+ # SAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4E
401
+ # FgQUpbbvE+fvzdBkodVWqWUxo97V40kwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDov
402
+ # L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1
403
+ # NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUH
404
+ # MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDov
405
+ # L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNI
406
+ # QTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAgRrW3qCp
407
+ # tZgXvHCNT4o8aJzYJf/LLOTN6l0ikuyMIgKpuM+AqNnn48XtJoKKcS8Y3U623mzX
408
+ # 4WCcK+3tPUiOuGu6fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJAOJ9dyKAuJXglnSoF
409
+ # eoQpmLZXeY/bJlYrsPOnvTcM2Jh2T1a5UsK2nTipgedtQVyMadG5K8TGe8+c+nji
410
+ # kxp2oml101DkRBK+IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzBaRm6zxbygzc0brBB
411
+ # Jt3eWpdPM43UjXd9dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo063nQwBw3syYnhmJ
412
+ # A+rUkTfvTVLzyWAhxFZH7doRS4wyw4jmWOK22z75X7BC1o/jF5HRqsBV44a/rCcs
413
+ # QdCaM0qoNtS5cpZ+l3k4SF/Kwtw9Mt911jZnWon49qfH5U81PAC9vpwqbHkB3NpE
414
+ # 5jreODsHXjlY9HxzMVWggBHLFAx+rrz+pOt5Zapo1iLKO+uagjVXKBbLafIymrLS
415
+ # 2Dq4sUaGa7oX/cR3bBVsrquvczroSUa31X/MtjjA2Owc9bahuEMs305MfR5ocMB3
416
+ # CtQC4Fxguyj/OOVSWtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4RtNsMnxYL2dHZeUb
417
+ # c7aZ+WssBkbvQR7w8F/g29mtkIBEr4AQQYowggauMIIElqADAgECAhAHNje3JFR8
418
+ # 2Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
419
+ # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
420
+ # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0z
421
+ # NzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
422
+ # SW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1
423
+ # NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
424
+ # AQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI
425
+ # 82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9
426
+ # xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ
427
+ # 3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5Emfv
428
+ # DqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDET
429
+ # qVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHe
430
+ # IhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jo
431
+ # n7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ
432
+ # 9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/T
433
+ # Xkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJg
434
+ # o1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkw
435
+ # EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+e
436
+ # yG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQD
437
+ # AgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEF
438
+ # BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRw
439
+ # Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNy
440
+ # dDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln
441
+ # aUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg
442
+ # hkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGw
443
+ # GC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0
444
+ # MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1D
445
+ # X+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw
446
+ # 1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY
447
+ # +/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0I
448
+ # SQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr
449
+ # 5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7y
450
+ # Rp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDop
451
+ # hrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/
452
+ # AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMO
453
+ # Hds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkq
454
+ # hkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
455
+ # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB
456
+ # c3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5
457
+ # WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
458
+ # ExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJv
459
+ # b3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1K
460
+ # PDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2r
461
+ # snnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C
462
+ # 8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBf
463
+ # sXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
464
+ # QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8
465
+ # rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaY
466
+ # dj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+
467
+ # wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw
468
+ # ++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+N
469
+ # P8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7F
470
+ # wI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUw
471
+ # AwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAU
472
+ # Reuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEB
473
+ # BG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsG
474
+ # AQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1
475
+ # cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRp
476
+ # Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAow
477
+ # CDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/
478
+ # Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLe
479
+ # JLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE
480
+ # 1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9Hda
481
+ # XFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbO
482
+ # byMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYID
483
+ # djCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu
484
+ # Yy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYg
485
+ # VGltZVN0YW1waW5nIENBAhAFRK/zlJ0IOaa/2z9f5WEWMA0GCWCGSAFlAwQCAQUA
486
+ # oIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcN
487
+ # MjQwOTA2MjAyNzExWjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRm8CsywsLJD4Jd
488
+ # zqqKycZPGZzPQDAvBgkqhkiG9w0BCQQxIgQgXSdFKsIxhS4gvdZFC5i8csELx4EN
489
+ # gje4K7DDRX8dz3AwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQg0vbkbe10IszR1EBX
490
+ # aEE2b4KK2lWarjMWr00amtQMeCgwDQYJKoZIhvcNAQEBBQAEggIAYX9aC647tWiS
491
+ # rGwjsC+5s2CosHEwRzUG9YNI58OJgUfCwsfgMkgKWkSi/K7mumf5RHkU+P+HCwoy
492
+ # kvIOZ7viK9fcAkK9zS3eKPUA6mGQS11yEnEhRUZbrrsG1uHQO+gSO2SgyLs8+3vX
493
+ # /8+YEl1IkGbw4/oeLavq79jULQqZ6/00n0E0nFDmbprjFK4wUX4CoIqt8AAWCt4F
494
+ # Az8XwvYxa63A2JQmeDzDAWR4lfNbREQaC3MdnqbnvQIBQUspJsn3t7zxU+ubzCez
495
+ # kCkk+7Tt5FFCP9OJvc/BEv3HcXrTAoZ4VFfAwL9K1DQ4A3hbsvKlwV0OxZlhouMd
496
+ # fGq+R8IGMsy7mGxeHx67nzKIr6Rjd426YsGskp5D3gE9shvH8i3GOTBi2Y9JUnaU
497
+ # /KX+IMzKbvR0Y9echgTb17v3D/+fYzDD/kSGJcuQEIbJEyYsCDBF53xoKd6K0Pgz
498
+ # 2drucT9otwOLUgGfR1N6lRwDtkMHYB25OMIKLYtcfHjQZn+Howq/TVUbp9ohhW1N
499
+ # jim3nJfNvmRe2zN5476SOn86GzzrqxfAMCTtbZeim2ltOHxlnPUE8EJLdRFesKMK
500
+ # 6izgaxptlT+MO0R8jx1VoOn+qbQPbNn2GCOUvh/yFkjwDLtFb/rNdoWMNrSMZDhV
501
+ # mRCM17SwjW6qRmsrC7VSaSAgPsokYM0=
502
+ # SIG # End signature block
INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
LICENSE ADDED
The diff for this file is too large to render. See raw diff
 
METADATA ADDED
@@ -0,0 +1,549 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: torch
3
+ Version: 2.6.0
4
+ Summary: Tensors and Dynamic neural networks in Python with strong GPU acceleration
5
+ Home-page: https://pytorch.org/
6
+ Download-URL: https://github.com/pytorch/pytorch/tags
7
+ Author: PyTorch Team
8
+ Author-email: [email protected]
9
+ License: BSD-3-Clause
10
+ Keywords: pytorch,machine learning
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Education
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: BSD License
16
+ Classifier: Topic :: Scientific/Engineering
17
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Topic :: Software Development
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Programming Language :: C++
23
+ Classifier: Programming Language :: Python :: 3
24
+ Classifier: Programming Language :: Python :: 3.9
25
+ Classifier: Programming Language :: Python :: 3.10
26
+ Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
28
+ Classifier: Programming Language :: Python :: 3.13
29
+ Requires-Python: >=3.9.0
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENSE
32
+ License-File: NOTICE
33
+ Requires-Dist: filelock
34
+ Requires-Dist: typing-extensions>=4.10.0
35
+ Requires-Dist: networkx
36
+ Requires-Dist: jinja2
37
+ Requires-Dist: fsspec
38
+ Requires-Dist: nvidia-cuda-nvrtc-cu12==12.4.127; platform_system == "Linux" and platform_machine == "x86_64"
39
+ Requires-Dist: nvidia-cuda-runtime-cu12==12.4.127; platform_system == "Linux" and platform_machine == "x86_64"
40
+ Requires-Dist: nvidia-cuda-cupti-cu12==12.4.127; platform_system == "Linux" and platform_machine == "x86_64"
41
+ Requires-Dist: nvidia-cudnn-cu12==9.1.0.70; platform_system == "Linux" and platform_machine == "x86_64"
42
+ Requires-Dist: nvidia-cublas-cu12==12.4.5.8; platform_system == "Linux" and platform_machine == "x86_64"
43
+ Requires-Dist: nvidia-cufft-cu12==11.2.1.3; platform_system == "Linux" and platform_machine == "x86_64"
44
+ Requires-Dist: nvidia-curand-cu12==10.3.5.147; platform_system == "Linux" and platform_machine == "x86_64"
45
+ Requires-Dist: nvidia-cusolver-cu12==11.6.1.9; platform_system == "Linux" and platform_machine == "x86_64"
46
+ Requires-Dist: nvidia-cusparse-cu12==12.3.1.170; platform_system == "Linux" and platform_machine == "x86_64"
47
+ Requires-Dist: nvidia-cusparselt-cu12==0.6.2; platform_system == "Linux" and platform_machine == "x86_64"
48
+ Requires-Dist: nvidia-nccl-cu12==2.21.5; platform_system == "Linux" and platform_machine == "x86_64"
49
+ Requires-Dist: nvidia-nvtx-cu12==12.4.127; platform_system == "Linux" and platform_machine == "x86_64"
50
+ Requires-Dist: nvidia-nvjitlink-cu12==12.4.127; platform_system == "Linux" and platform_machine == "x86_64"
51
+ Requires-Dist: triton==3.2.0; platform_system == "Linux" and platform_machine == "x86_64"
52
+ Requires-Dist: setuptools; python_version >= "3.12"
53
+ Requires-Dist: sympy==1.13.1; python_version >= "3.9"
54
+ Provides-Extra: opt-einsum
55
+ Requires-Dist: opt-einsum>=3.3; extra == "opt-einsum"
56
+ Provides-Extra: optree
57
+ Requires-Dist: optree>=0.13.0; extra == "optree"
58
+
59
+ ![PyTorch Logo](https://github.com/pytorch/pytorch/raw/main/docs/source/_static/img/pytorch-logo-dark.png)
60
+
61
+ --------------------------------------------------------------------------------
62
+
63
+ PyTorch is a Python package that provides two high-level features:
64
+ - Tensor computation (like NumPy) with strong GPU acceleration
65
+ - Deep neural networks built on a tape-based autograd system
66
+
67
+ You can reuse your favorite Python packages such as NumPy, SciPy, and Cython to extend PyTorch when needed.
68
+
69
+ Our trunk health (Continuous Integration signals) can be found at [hud.pytorch.org](https://hud.pytorch.org/ci/pytorch/pytorch/main).
70
+
71
+ <!-- toc -->
72
+
73
+ - [More About PyTorch](#more-about-pytorch)
74
+ - [A GPU-Ready Tensor Library](#a-gpu-ready-tensor-library)
75
+ - [Dynamic Neural Networks: Tape-Based Autograd](#dynamic-neural-networks-tape-based-autograd)
76
+ - [Python First](#python-first)
77
+ - [Imperative Experiences](#imperative-experiences)
78
+ - [Fast and Lean](#fast-and-lean)
79
+ - [Extensions Without Pain](#extensions-without-pain)
80
+ - [Installation](#installation)
81
+ - [Binaries](#binaries)
82
+ - [NVIDIA Jetson Platforms](#nvidia-jetson-platforms)
83
+ - [From Source](#from-source)
84
+ - [Prerequisites](#prerequisites)
85
+ - [NVIDIA CUDA Support](#nvidia-cuda-support)
86
+ - [AMD ROCm Support](#amd-rocm-support)
87
+ - [Intel GPU Support](#intel-gpu-support)
88
+ - [Get the PyTorch Source](#get-the-pytorch-source)
89
+ - [Install Dependencies](#install-dependencies)
90
+ - [Install PyTorch](#install-pytorch)
91
+ - [Adjust Build Options (Optional)](#adjust-build-options-optional)
92
+ - [Docker Image](#docker-image)
93
+ - [Using pre-built images](#using-pre-built-images)
94
+ - [Building the image yourself](#building-the-image-yourself)
95
+ - [Building the Documentation](#building-the-documentation)
96
+ - [Previous Versions](#previous-versions)
97
+ - [Getting Started](#getting-started)
98
+ - [Resources](#resources)
99
+ - [Communication](#communication)
100
+ - [Releases and Contributing](#releases-and-contributing)
101
+ - [The Team](#the-team)
102
+ - [License](#license)
103
+
104
+ <!-- tocstop -->
105
+
106
+ ## More About PyTorch
107
+
108
+ [Learn the basics of PyTorch](https://pytorch.org/tutorials/beginner/basics/intro.html)
109
+
110
+ At a granular level, PyTorch is a library that consists of the following components:
111
+
112
+ | Component | Description |
113
+ | ---- | --- |
114
+ | [**torch**](https://pytorch.org/docs/stable/torch.html) | A Tensor library like NumPy, with strong GPU support |
115
+ | [**torch.autograd**](https://pytorch.org/docs/stable/autograd.html) | A tape-based automatic differentiation library that supports all differentiable Tensor operations in torch |
116
+ | [**torch.jit**](https://pytorch.org/docs/stable/jit.html) | A compilation stack (TorchScript) to create serializable and optimizable models from PyTorch code |
117
+ | [**torch.nn**](https://pytorch.org/docs/stable/nn.html) | A neural networks library deeply integrated with autograd designed for maximum flexibility |
118
+ | [**torch.multiprocessing**](https://pytorch.org/docs/stable/multiprocessing.html) | Python multiprocessing, but with magical memory sharing of torch Tensors across processes. Useful for data loading and Hogwild training |
119
+ | [**torch.utils**](https://pytorch.org/docs/stable/data.html) | DataLoader and other utility functions for convenience |
120
+
121
+ Usually, PyTorch is used either as:
122
+
123
+ - A replacement for NumPy to use the power of GPUs.
124
+ - A deep learning research platform that provides maximum flexibility and speed.
125
+
126
+ Elaborating Further:
127
+
128
+ ### A GPU-Ready Tensor Library
129
+
130
+ If you use NumPy, then you have used Tensors (a.k.a. ndarray).
131
+
132
+ ![Tensor illustration](./docs/source/_static/img/tensor_illustration.png)
133
+
134
+ PyTorch provides Tensors that can live either on the CPU or the GPU and accelerates the
135
+ computation by a huge amount.
136
+
137
+ We provide a wide variety of tensor routines to accelerate and fit your scientific computation needs
138
+ such as slicing, indexing, mathematical operations, linear algebra, reductions.
139
+ And they are fast!
140
+
141
+ ### Dynamic Neural Networks: Tape-Based Autograd
142
+
143
+ PyTorch has a unique way of building neural networks: using and replaying a tape recorder.
144
+
145
+ Most frameworks such as TensorFlow, Theano, Caffe, and CNTK have a static view of the world.
146
+ One has to build a neural network and reuse the same structure again and again.
147
+ Changing the way the network behaves means that one has to start from scratch.
148
+
149
+ With PyTorch, we use a technique called reverse-mode auto-differentiation, which allows you to
150
+ change the way your network behaves arbitrarily with zero lag or overhead. Our inspiration comes
151
+ from several research papers on this topic, as well as current and past work such as
152
+ [torch-autograd](https://github.com/twitter/torch-autograd),
153
+ [autograd](https://github.com/HIPS/autograd),
154
+ [Chainer](https://chainer.org), etc.
155
+
156
+ While this technique is not unique to PyTorch, it's one of the fastest implementations of it to date.
157
+ You get the best of speed and flexibility for your crazy research.
158
+
159
+ ![Dynamic graph](https://github.com/pytorch/pytorch/raw/main/docs/source/_static/img/dynamic_graph.gif)
160
+
161
+ ### Python First
162
+
163
+ PyTorch is not a Python binding into a monolithic C++ framework.
164
+ It is built to be deeply integrated into Python.
165
+ You can use it naturally like you would use [NumPy](https://www.numpy.org/) / [SciPy](https://www.scipy.org/) / [scikit-learn](https://scikit-learn.org) etc.
166
+ You can write your new neural network layers in Python itself, using your favorite libraries
167
+ and use packages such as [Cython](https://cython.org/) and [Numba](http://numba.pydata.org/).
168
+ Our goal is to not reinvent the wheel where appropriate.
169
+
170
+ ### Imperative Experiences
171
+
172
+ PyTorch is designed to be intuitive, linear in thought, and easy to use.
173
+ When you execute a line of code, it gets executed. There isn't an asynchronous view of the world.
174
+ When you drop into a debugger or receive error messages and stack traces, understanding them is straightforward.
175
+ The stack trace points to exactly where your code was defined.
176
+ We hope you never spend hours debugging your code because of bad stack traces or asynchronous and opaque execution engines.
177
+
178
+ ### Fast and Lean
179
+
180
+ PyTorch has minimal framework overhead. We integrate acceleration libraries
181
+ such as [Intel MKL](https://software.intel.com/mkl) and NVIDIA ([cuDNN](https://developer.nvidia.com/cudnn), [NCCL](https://developer.nvidia.com/nccl)) to maximize speed.
182
+ At the core, its CPU and GPU Tensor and neural network backends
183
+ are mature and have been tested for years.
184
+
185
+ Hence, PyTorch is quite fast — whether you run small or large neural networks.
186
+
187
+ The memory usage in PyTorch is extremely efficient compared to Torch or some of the alternatives.
188
+ We've written custom memory allocators for the GPU to make sure that
189
+ your deep learning models are maximally memory efficient.
190
+ This enables you to train bigger deep learning models than before.
191
+
192
+ ### Extensions Without Pain
193
+
194
+ Writing new neural network modules, or interfacing with PyTorch's Tensor API was designed to be straightforward
195
+ and with minimal abstractions.
196
+
197
+ You can write new neural network layers in Python using the torch API
198
+ [or your favorite NumPy-based libraries such as SciPy](https://pytorch.org/tutorials/advanced/numpy_extensions_tutorial.html).
199
+
200
+ If you want to write your layers in C/C++, we provide a convenient extension API that is efficient and with minimal boilerplate.
201
+ No wrapper code needs to be written. You can see [a tutorial here](https://pytorch.org/tutorials/advanced/cpp_extension.html) and [an example here](https://github.com/pytorch/extension-cpp).
202
+
203
+
204
+ ## Installation
205
+
206
+ ### Binaries
207
+ Commands to install binaries via Conda or pip wheels are on our website: [https://pytorch.org/get-started/locally/](https://pytorch.org/get-started/locally/)
208
+
209
+
210
+ #### NVIDIA Jetson Platforms
211
+
212
+ Python wheels for NVIDIA's Jetson Nano, Jetson TX1/TX2, Jetson Xavier NX/AGX, and Jetson AGX Orin are provided [here](https://forums.developer.nvidia.com/t/pytorch-for-jetson-version-1-10-now-available/72048) and the L4T container is published [here](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/l4t-pytorch)
213
+
214
+ They require JetPack 4.2 and above, and [@dusty-nv](https://github.com/dusty-nv) and [@ptrblck](https://github.com/ptrblck) are maintaining them.
215
+
216
+
217
+ ### From Source
218
+
219
+ #### Prerequisites
220
+ If you are installing from source, you will need:
221
+ - Python 3.9 or later
222
+ - A compiler that fully supports C++17, such as clang or gcc (gcc 9.4.0 or newer is required, on Linux)
223
+ - Visual Studio or Visual Studio Build Tool (Windows only)
224
+
225
+ \* PyTorch CI uses Visual C++ BuildTools, which come with Visual Studio Enterprise,
226
+ Professional, or Community Editions. You can also install the build tools from
227
+ https://visualstudio.microsoft.com/visual-cpp-build-tools/. The build tools *do not*
228
+ come with Visual Studio Code by default.
229
+
230
+ \* We highly recommend installing an [Anaconda](https://www.anaconda.com/download) environment. You will get a high-quality BLAS library (MKL) and you get controlled dependency versions regardless of your Linux distro.
231
+
232
+ An example of environment setup is shown below:
233
+
234
+ * Linux:
235
+
236
+ ```bash
237
+ $ source <CONDA_INSTALL_DIR>/bin/activate
238
+ $ conda create -y -n <CONDA_NAME>
239
+ $ conda activate <CONDA_NAME>
240
+ ```
241
+
242
+ * Windows:
243
+
244
+ ```bash
245
+ $ source <CONDA_INSTALL_DIR>\Scripts\activate.bat
246
+ $ conda create -y -n <CONDA_NAME>
247
+ $ conda activate <CONDA_NAME>
248
+ $ call "C:\Program Files\Microsoft Visual Studio\<VERSION>\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
249
+ ```
250
+
251
+ ##### NVIDIA CUDA Support
252
+ If you want to compile with CUDA support, [select a supported version of CUDA from our support matrix](https://pytorch.org/get-started/locally/), then install the following:
253
+ - [NVIDIA CUDA](https://developer.nvidia.com/cuda-downloads)
254
+ - [NVIDIA cuDNN](https://developer.nvidia.com/cudnn) v8.5 or above
255
+ - [Compiler](https://gist.github.com/ax3l/9489132) compatible with CUDA
256
+
257
+ Note: You could refer to the [cuDNN Support Matrix](https://docs.nvidia.com/deeplearning/cudnn/reference/support-matrix.html) for cuDNN versions with the various supported CUDA, CUDA driver and NVIDIA hardware
258
+
259
+ If you want to disable CUDA support, export the environment variable `USE_CUDA=0`.
260
+ Other potentially useful environment variables may be found in `setup.py`.
261
+
262
+ If you are building for NVIDIA's Jetson platforms (Jetson Nano, TX1, TX2, AGX Xavier), Instructions to install PyTorch for Jetson Nano are [available here](https://devtalk.nvidia.com/default/topic/1049071/jetson-nano/pytorch-for-jetson-nano/)
263
+
264
+ ##### AMD ROCm Support
265
+ If you want to compile with ROCm support, install
266
+ - [AMD ROCm](https://rocm.docs.amd.com/en/latest/deploy/linux/quick_start.html) 4.0 and above installation
267
+ - ROCm is currently supported only for Linux systems.
268
+
269
+ By default the build system expects ROCm to be installed in `/opt/rocm`. If ROCm is installed in a different directory, the `ROCM_PATH` environment variable must be set to the ROCm installation directory. The build system automatically detects the AMD GPU architecture. Optionally, the AMD GPU architecture can be explicitly set with the `PYTORCH_ROCM_ARCH` environment variable [AMD GPU architecture](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html#supported-gpus)
270
+
271
+ If you want to disable ROCm support, export the environment variable `USE_ROCM=0`.
272
+ Other potentially useful environment variables may be found in `setup.py`.
273
+
274
+ ##### Intel GPU Support
275
+ If you want to compile with Intel GPU support, follow these
276
+ - [PyTorch Prerequisites for Intel GPUs](https://www.intel.com/content/www/us/en/developer/articles/tool/pytorch-prerequisites-for-intel-gpus.html) instructions.
277
+ - Intel GPU is supported for Linux and Windows.
278
+
279
+ If you want to disable Intel GPU support, export the environment variable `USE_XPU=0`.
280
+ Other potentially useful environment variables may be found in `setup.py`.
281
+
282
+ #### Get the PyTorch Source
283
+ ```bash
284
+ git clone --recursive https://github.com/pytorch/pytorch
285
+ cd pytorch
286
+ # if you are updating an existing checkout
287
+ git submodule sync
288
+ git submodule update --init --recursive
289
+ ```
290
+
291
+ #### Install Dependencies
292
+
293
+ **Common**
294
+
295
+ ```bash
296
+ conda install cmake ninja
297
+ # Run this command from the PyTorch directory after cloning the source code using the “Get the PyTorch Source“ section below
298
+ pip install -r requirements.txt
299
+ ```
300
+
301
+ **On Linux**
302
+
303
+ ```bash
304
+ pip install mkl-static mkl-include
305
+ # CUDA only: Add LAPACK support for the GPU if needed
306
+ conda install -c pytorch magma-cuda121 # or the magma-cuda* that matches your CUDA version from https://anaconda.org/pytorch/repo
307
+
308
+ # (optional) If using torch.compile with inductor/triton, install the matching version of triton
309
+ # Run from the pytorch directory after cloning
310
+ # For Intel GPU support, please explicitly `export USE_XPU=1` before running command.
311
+ make triton
312
+ ```
313
+
314
+ **On MacOS**
315
+
316
+ ```bash
317
+ # Add this package on intel x86 processor machines only
318
+ pip install mkl-static mkl-include
319
+ # Add these packages if torch.distributed is needed
320
+ conda install pkg-config libuv
321
+ ```
322
+
323
+ **On Windows**
324
+
325
+ ```bash
326
+ pip install mkl-static mkl-include
327
+ # Add these packages if torch.distributed is needed.
328
+ # Distributed package support on Windows is a prototype feature and is subject to changes.
329
+ conda install -c conda-forge libuv=1.39
330
+ ```
331
+
332
+ #### Install PyTorch
333
+ **On Linux**
334
+
335
+ If you would like to compile PyTorch with [new C++ ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html) enabled, then first run this command:
336
+ ```bash
337
+ export _GLIBCXX_USE_CXX11_ABI=1
338
+ ```
339
+
340
+ Please **note** that starting from PyTorch 2.5, the PyTorch build with XPU supports both new and old C++ ABIs. Previously, XPU only supported the new C++ ABI. If you want to compile with Intel GPU support, please follow [Intel GPU Support](#intel-gpu-support).
341
+
342
+ If you're compiling for AMD ROCm then first run this command:
343
+ ```bash
344
+ # Only run this if you're compiling for ROCm
345
+ python tools/amd_build/build_amd.py
346
+ ```
347
+
348
+ Install PyTorch
349
+ ```bash
350
+ export CMAKE_PREFIX_PATH="${CONDA_PREFIX:-'$(dirname $(which conda))/../'}:${CMAKE_PREFIX_PATH}"
351
+ python setup.py develop
352
+ ```
353
+
354
+ **On macOS**
355
+
356
+ ```bash
357
+ python3 setup.py develop
358
+ ```
359
+
360
+ **On Windows**
361
+
362
+ If you want to build legacy python code, please refer to [Building on legacy code and CUDA](https://github.com/pytorch/pytorch/blob/main/CONTRIBUTING.md#building-on-legacy-code-and-cuda)
363
+
364
+ **CPU-only builds**
365
+
366
+ In this mode PyTorch computations will run on your CPU, not your GPU
367
+
368
+ ```cmd
369
+ python setup.py develop
370
+ ```
371
+
372
+ Note on OpenMP: The desired OpenMP implementation is Intel OpenMP (iomp). In order to link against iomp, you'll need to manually download the library and set up the building environment by tweaking `CMAKE_INCLUDE_PATH` and `LIB`. The instruction [here](https://github.com/pytorch/pytorch/blob/main/docs/source/notes/windows.rst#building-from-source) is an example for setting up both MKL and Intel OpenMP. Without these configurations for CMake, Microsoft Visual C OpenMP runtime (vcomp) will be used.
373
+
374
+ **CUDA based build**
375
+
376
+ In this mode PyTorch computations will leverage your GPU via CUDA for faster number crunching
377
+
378
+ [NVTX](https://docs.nvidia.com/gameworks/content/gameworkslibrary/nvtx/nvidia_tools_extension_library_nvtx.htm) is needed to build Pytorch with CUDA.
379
+ NVTX is a part of CUDA distributive, where it is called "Nsight Compute". To install it onto an already installed CUDA run CUDA installation once again and check the corresponding checkbox.
380
+ Make sure that CUDA with Nsight Compute is installed after Visual Studio.
381
+
382
+ Currently, VS 2017 / 2019, and Ninja are supported as the generator of CMake. If `ninja.exe` is detected in `PATH`, then Ninja will be used as the default generator, otherwise, it will use VS 2017 / 2019.
383
+ <br/> If Ninja is selected as the generator, the latest MSVC will get selected as the underlying toolchain.
384
+
385
+ Additional libraries such as
386
+ [Magma](https://developer.nvidia.com/magma), [oneDNN, a.k.a. MKLDNN or DNNL](https://github.com/oneapi-src/oneDNN), and [Sccache](https://github.com/mozilla/sccache) are often needed. Please refer to the [installation-helper](https://github.com/pytorch/pytorch/tree/main/.ci/pytorch/win-test-helpers/installation-helpers) to install them.
387
+
388
+ You can refer to the [build_pytorch.bat](https://github.com/pytorch/pytorch/blob/main/.ci/pytorch/win-test-helpers/build_pytorch.bat) script for some other environment variables configurations
389
+
390
+
391
+ ```cmd
392
+ cmd
393
+
394
+ :: Set the environment variables after you have downloaded and unzipped the mkl package,
395
+ :: else CMake would throw an error as `Could NOT find OpenMP`.
396
+ set CMAKE_INCLUDE_PATH={Your directory}\mkl\include
397
+ set LIB={Your directory}\mkl\lib;%LIB%
398
+
399
+ :: Read the content in the previous section carefully before you proceed.
400
+ :: [Optional] If you want to override the underlying toolset used by Ninja and Visual Studio with CUDA, please run the following script block.
401
+ :: "Visual Studio 2019 Developer Command Prompt" will be run automatically.
402
+ :: Make sure you have CMake >= 3.12 before you do this when you use the Visual Studio generator.
403
+ set CMAKE_GENERATOR_TOOLSET_VERSION=14.27
404
+ set DISTUTILS_USE_SDK=1
405
+ for /f "usebackq tokens=*" %i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version [15^,17^) -products * -latest -property installationPath`) do call "%i\VC\Auxiliary\Build\vcvarsall.bat" x64 -vcvars_ver=%CMAKE_GENERATOR_TOOLSET_VERSION%
406
+
407
+ :: [Optional] If you want to override the CUDA host compiler
408
+ set CUDAHOSTCXX=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\bin\HostX64\x64\cl.exe
409
+
410
+ python setup.py develop
411
+
412
+ ```
413
+
414
+ ##### Adjust Build Options (Optional)
415
+
416
+ You can adjust the configuration of cmake variables optionally (without building first), by doing
417
+ the following. For example, adjusting the pre-detected directories for CuDNN or BLAS can be done
418
+ with such a step.
419
+
420
+ On Linux
421
+ ```bash
422
+ export CMAKE_PREFIX_PATH="${CONDA_PREFIX:-'$(dirname $(which conda))/../'}:${CMAKE_PREFIX_PATH}"
423
+ python setup.py build --cmake-only
424
+ ccmake build # or cmake-gui build
425
+ ```
426
+
427
+ On macOS
428
+ ```bash
429
+ export CMAKE_PREFIX_PATH="${CONDA_PREFIX:-'$(dirname $(which conda))/../'}:${CMAKE_PREFIX_PATH}"
430
+ MACOSX_DEPLOYMENT_TARGET=10.9 CC=clang CXX=clang++ python setup.py build --cmake-only
431
+ ccmake build # or cmake-gui build
432
+ ```
433
+
434
+ ### Docker Image
435
+
436
+ #### Using pre-built images
437
+
438
+ You can also pull a pre-built docker image from Docker Hub and run with docker v19.03+
439
+
440
+ ```bash
441
+ docker run --gpus all --rm -ti --ipc=host pytorch/pytorch:latest
442
+ ```
443
+
444
+ Please note that PyTorch uses shared memory to share data between processes, so if torch multiprocessing is used (e.g.
445
+ for multithreaded data loaders) the default shared memory segment size that container runs with is not enough, and you
446
+ should increase shared memory size either with `--ipc=host` or `--shm-size` command line options to `nvidia-docker run`.
447
+
448
+ #### Building the image yourself
449
+
450
+ **NOTE:** Must be built with a docker version > 18.06
451
+
452
+ The `Dockerfile` is supplied to build images with CUDA 11.1 support and cuDNN v8.
453
+ You can pass `PYTHON_VERSION=x.y` make variable to specify which Python version is to be used by Miniconda, or leave it
454
+ unset to use the default.
455
+
456
+ ```bash
457
+ make -f docker.Makefile
458
+ # images are tagged as docker.io/${your_docker_username}/pytorch
459
+ ```
460
+
461
+ You can also pass the `CMAKE_VARS="..."` environment variable to specify additional CMake variables to be passed to CMake during the build.
462
+ See [setup.py](./setup.py) for the list of available variables.
463
+
464
+ ```bash
465
+ make -f docker.Makefile
466
+ ```
467
+
468
+ ### Building the Documentation
469
+
470
+ To build documentation in various formats, you will need [Sphinx](http://www.sphinx-doc.org) and the
471
+ readthedocs theme.
472
+
473
+ ```bash
474
+ cd docs/
475
+ pip install -r requirements.txt
476
+ make html
477
+ make serve
478
+ ```
479
+
480
+ Run `make` to get a list of all available output formats.
481
+
482
+ If you get a katex error run `npm install katex`. If it persists, try
483
+ `npm install -g katex`
484
+
485
+ > Note: if you installed `nodejs` with a different package manager (e.g.,
486
+ `conda`) then `npm` will probably install a version of `katex` that is not
487
+ compatible with your version of `nodejs` and doc builds will fail.
488
+ A combination of versions that is known to work is `[email protected]` and
489
+ `[email protected]`. To install the latter with `npm` you can run
490
+ ```npm install -g [email protected]```
491
+
492
+ ### Previous Versions
493
+
494
+ Installation instructions and binaries for previous PyTorch versions may be found
495
+ on [our website](https://pytorch.org/previous-versions).
496
+
497
+
498
+ ## Getting Started
499
+
500
+ Three-pointers to get you started:
501
+ - [Tutorials: get you started with understanding and using PyTorch](https://pytorch.org/tutorials/)
502
+ - [Examples: easy to understand PyTorch code across all domains](https://github.com/pytorch/examples)
503
+ - [The API Reference](https://pytorch.org/docs/)
504
+ - [Glossary](https://github.com/pytorch/pytorch/blob/main/GLOSSARY.md)
505
+
506
+ ## Resources
507
+
508
+ * [PyTorch.org](https://pytorch.org/)
509
+ * [PyTorch Tutorials](https://pytorch.org/tutorials/)
510
+ * [PyTorch Examples](https://github.com/pytorch/examples)
511
+ * [PyTorch Models](https://pytorch.org/hub/)
512
+ * [Intro to Deep Learning with PyTorch from Udacity](https://www.udacity.com/course/deep-learning-pytorch--ud188)
513
+ * [Intro to Machine Learning with PyTorch from Udacity](https://www.udacity.com/course/intro-to-machine-learning-nanodegree--nd229)
514
+ * [Deep Neural Networks with PyTorch from Coursera](https://www.coursera.org/learn/deep-neural-networks-with-pytorch)
515
+ * [PyTorch Twitter](https://twitter.com/PyTorch)
516
+ * [PyTorch Blog](https://pytorch.org/blog/)
517
+ * [PyTorch YouTube](https://www.youtube.com/channel/UCWXI5YeOsh03QvJ59PMaXFw)
518
+
519
+ ## Communication
520
+ * Forums: Discuss implementations, research, etc. https://discuss.pytorch.org
521
+ * GitHub Issues: Bug reports, feature requests, install issues, RFCs, thoughts, etc.
522
+ * Slack: The [PyTorch Slack](https://pytorch.slack.com/) hosts a primary audience of moderate to experienced PyTorch users and developers for general chat, online discussions, collaboration, etc. If you are a beginner looking for help, the primary medium is [PyTorch Forums](https://discuss.pytorch.org). If you need a slack invite, please fill this form: https://goo.gl/forms/PP1AGvNHpSaJP8to1
523
+ * Newsletter: No-noise, a one-way email newsletter with important announcements about PyTorch. You can sign-up here: https://eepurl.com/cbG0rv
524
+ * Facebook Page: Important announcements about PyTorch. https://www.facebook.com/pytorch
525
+ * For brand guidelines, please visit our website at [pytorch.org](https://pytorch.org/)
526
+
527
+ ## Releases and Contributing
528
+
529
+ Typically, PyTorch has three minor releases a year. Please let us know if you encounter a bug by [filing an issue](https://github.com/pytorch/pytorch/issues).
530
+
531
+ We appreciate all contributions. If you are planning to contribute back bug-fixes, please do so without any further discussion.
532
+
533
+ If you plan to contribute new features, utility functions, or extensions to the core, please first open an issue and discuss the feature with us.
534
+ Sending a PR without discussion might end up resulting in a rejected PR because we might be taking the core in a different direction than you might be aware of.
535
+
536
+ To learn more about making a contribution to Pytorch, please see our [Contribution page](CONTRIBUTING.md). For more information about PyTorch releases, see [Release page](RELEASE.md).
537
+
538
+ ## The Team
539
+
540
+ PyTorch is a community-driven project with several skillful engineers and researchers contributing to it.
541
+
542
+ PyTorch is currently maintained by [Soumith Chintala](http://soumith.ch), [Gregory Chanan](https://github.com/gchanan), [Dmytro Dzhulgakov](https://github.com/dzhulgakov), [Edward Yang](https://github.com/ezyang), and [Nikita Shulga](https://github.com/malfet) with major contributions coming from hundreds of talented individuals in various forms and means.
543
+ A non-exhaustive but growing list needs to mention: [Trevor Killeen](https://github.com/killeent), [Sasank Chilamkurthy](https://github.com/chsasank), [Sergey Zagoruyko](https://github.com/szagoruyko), [Adam Lerer](https://github.com/adamlerer), [Francisco Massa](https://github.com/fmassa), [Alykhan Tejani](https://github.com/alykhantejani), [Luca Antiga](https://github.com/lantiga), [Alban Desmaison](https://github.com/albanD), [Andreas Koepf](https://github.com/andreaskoepf), [James Bradbury](https://github.com/jamesb93), [Zeming Lin](https://github.com/ebetica), [Yuandong Tian](https://github.com/yuandong-tian), [Guillaume Lample](https://github.com/glample), [Marat Dukhan](https://github.com/Maratyszcza), [Natalia Gimelshein](https://github.com/ngimel), [Christian Sarofeen](https://github.com/csarofeen), [Martin Raison](https://github.com/martinraison), [Edward Yang](https://github.com/ezyang), [Zachary Devito](https://github.com/zdevito).
544
+
545
+ Note: This project is unrelated to [hughperkins/pytorch](https://github.com/hughperkins/pytorch) with the same name. Hugh is a valuable contributor to the Torch community and has helped with many things Torch and PyTorch.
546
+
547
+ ## License
548
+
549
+ PyTorch has a BSD-style license, as found in the [LICENSE](LICENSE) file.
NOTICE ADDED
@@ -0,0 +1,456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======================================================================
2
+ Software under third_party
3
+ =======================================================================
4
+ Software libraries under third_party are provided as github submodule
5
+ links, and their content is not part of the Caffe2 codebase. Their
6
+ licences can be found under the respective software repositories.
7
+
8
+ =======================================================================
9
+ Earlier BSD License
10
+ =======================================================================
11
+ Early development of Caffe2 in 2015 and early 2016 is licensed under the
12
+ BSD license. The license is attached below:
13
+
14
+ All contributions by Facebook:
15
+ Copyright (c) 2016 Facebook Inc.
16
+
17
+ All contributions by Google:
18
+ Copyright (c) 2015 Google Inc.
19
+ All rights reserved.
20
+
21
+ All contributions by Yangqing Jia:
22
+ Copyright (c) 2015 Yangqing Jia
23
+ All rights reserved.
24
+
25
+ All contributions by Kakao Brain:
26
+ Copyright 2019-2020 Kakao Brain
27
+
28
+ All other contributions:
29
+ Copyright(c) 2015, 2016 the respective contributors
30
+ All rights reserved.
31
+
32
+ Redistribution and use in source and binary forms, with or without
33
+ modification, are permitted provided that the following conditions are met:
34
+
35
+ 1. Redistributions of source code must retain the above copyright notice, this
36
+ list of conditions and the following disclaimer.
37
+ 2. Redistributions in binary form must reproduce the above copyright notice,
38
+ this list of conditions and the following disclaimer in the documentation
39
+ and/or other materials provided with the distribution.
40
+
41
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
42
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
43
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
45
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
+
52
+
53
+ =======================================================================
54
+ Caffe's BSD License
55
+ =======================================================================
56
+ Some parts of the caffe2 code is derived from the original Caffe code, which is
57
+ created by Yangqing Jia and is now a BSD-licensed open-source project. The Caffe
58
+ license is as follows:
59
+
60
+ COPYRIGHT
61
+
62
+ All contributions by the University of California:
63
+ Copyright (c) 2014, The Regents of the University of California (Regents)
64
+ All rights reserved.
65
+
66
+ All other contributions:
67
+ Copyright (c) 2014, the respective contributors
68
+ All rights reserved.
69
+
70
+ Caffe uses a shared copyright model: each contributor holds copyright over
71
+ their contributions to Caffe. The project versioning records all such
72
+ contribution and copyright details. If a contributor wants to further mark
73
+ their specific copyright on a particular contribution, they should indicate
74
+ their copyright solely in the commit message of the change when it is
75
+ committed.
76
+
77
+ LICENSE
78
+
79
+ Redistribution and use in source and binary forms, with or without
80
+ modification, are permitted provided that the following conditions are met:
81
+
82
+ 1. Redistributions of source code must retain the above copyright notice, this
83
+ list of conditions and the following disclaimer.
84
+ 2. Redistributions in binary form must reproduce the above copyright notice,
85
+ this list of conditions and the following disclaimer in the documentation
86
+ and/or other materials provided with the distribution.
87
+
88
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
89
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
90
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
91
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
92
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
93
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
94
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
95
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
96
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
97
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
98
+
99
+ CONTRIBUTION AGREEMENT
100
+
101
+ By contributing to the BVLC/caffe repository through pull-request, comment,
102
+ or otherwise, the contributor releases their content to the
103
+ license and copyright terms herein.
104
+
105
+ =======================================================================
106
+ Caffe2's Apache License
107
+ =======================================================================
108
+
109
+ This repo contains Caffe2 code, which was previously licensed under
110
+ Apache License Version 2.0:
111
+
112
+ Apache License
113
+ Version 2.0, January 2004
114
+ http://www.apache.org/licenses/
115
+
116
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
117
+
118
+ 1. Definitions.
119
+
120
+ "License" shall mean the terms and conditions for use, reproduction,
121
+ and distribution as defined by Sections 1 through 9 of this document.
122
+
123
+ "Licensor" shall mean the copyright owner or entity authorized by
124
+ the copyright owner that is granting the License.
125
+
126
+ "Legal Entity" shall mean the union of the acting entity and all
127
+ other entities that control, are controlled by, or are under common
128
+ control with that entity. For the purposes of this definition,
129
+ "control" means (i) the power, direct or indirect, to cause the
130
+ direction or management of such entity, whether by contract or
131
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
132
+ outstanding shares, or (iii) beneficial ownership of such entity.
133
+
134
+ "You" (or "Your") shall mean an individual or Legal Entity
135
+ exercising permissions granted by this License.
136
+
137
+ "Source" form shall mean the preferred form for making modifications,
138
+ including but not limited to software source code, documentation
139
+ source, and configuration files.
140
+
141
+ "Object" form shall mean any form resulting from mechanical
142
+ transformation or translation of a Source form, including but
143
+ not limited to compiled object code, generated documentation,
144
+ and conversions to other media types.
145
+
146
+ "Work" shall mean the work of authorship, whether in Source or
147
+ Object form, made available under the License, as indicated by a
148
+ copyright notice that is included in or attached to the work
149
+ (an example is provided in the Appendix below).
150
+
151
+ "Derivative Works" shall mean any work, whether in Source or Object
152
+ form, that is based on (or derived from) the Work and for which the
153
+ editorial revisions, annotations, elaborations, or other modifications
154
+ represent, as a whole, an original work of authorship. For the purposes
155
+ of this License, Derivative Works shall not include works that remain
156
+ separable from, or merely link (or bind by name) to the interfaces of,
157
+ the Work and Derivative Works thereof.
158
+
159
+ "Contribution" shall mean any work of authorship, including
160
+ the original version of the Work and any modifications or additions
161
+ to that Work or Derivative Works thereof, that is intentionally
162
+ submitted to Licensor for inclusion in the Work by the copyright owner
163
+ or by an individual or Legal Entity authorized to submit on behalf of
164
+ the copyright owner. For the purposes of this definition, "submitted"
165
+ means any form of electronic, verbal, or written communication sent
166
+ to the Licensor or its representatives, including but not limited to
167
+ communication on electronic mailing lists, source code control systems,
168
+ and issue tracking systems that are managed by, or on behalf of, the
169
+ Licensor for the purpose of discussing and improving the Work, but
170
+ excluding communication that is conspicuously marked or otherwise
171
+ designated in writing by the copyright owner as "Not a Contribution."
172
+
173
+ "Contributor" shall mean Licensor and any individual or Legal Entity
174
+ on behalf of whom a Contribution has been received by Licensor and
175
+ subsequently incorporated within the Work.
176
+
177
+ 2. Grant of Copyright License. Subject to the terms and conditions of
178
+ this License, each Contributor hereby grants to You a perpetual,
179
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
180
+ copyright license to reproduce, prepare Derivative Works of,
181
+ publicly display, publicly perform, sublicense, and distribute the
182
+ Work and such Derivative Works in Source or Object form.
183
+
184
+ 3. Grant of Patent License. Subject to the terms and conditions of
185
+ this License, each Contributor hereby grants to You a perpetual,
186
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
187
+ (except as stated in this section) patent license to make, have made,
188
+ use, offer to sell, sell, import, and otherwise transfer the Work,
189
+ where such license applies only to those patent claims licensable
190
+ by such Contributor that are necessarily infringed by their
191
+ Contribution(s) alone or by combination of their Contribution(s)
192
+ with the Work to which such Contribution(s) was submitted. If You
193
+ institute patent litigation against any entity (including a
194
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
195
+ or a Contribution incorporated within the Work constitutes direct
196
+ or contributory patent infringement, then any patent licenses
197
+ granted to You under this License for that Work shall terminate
198
+ as of the date such litigation is filed.
199
+
200
+ 4. Redistribution. You may reproduce and distribute copies of the
201
+ Work or Derivative Works thereof in any medium, with or without
202
+ modifications, and in Source or Object form, provided that You
203
+ meet the following conditions:
204
+
205
+ (a) You must give any other recipients of the Work or
206
+ Derivative Works a copy of this License; and
207
+
208
+ (b) You must cause any modified files to carry prominent notices
209
+ stating that You changed the files; and
210
+
211
+ (c) You must retain, in the Source form of any Derivative Works
212
+ that You distribute, all copyright, patent, trademark, and
213
+ attribution notices from the Source form of the Work,
214
+ excluding those notices that do not pertain to any part of
215
+ the Derivative Works; and
216
+
217
+ (d) If the Work includes a "NOTICE" text file as part of its
218
+ distribution, then any Derivative Works that You distribute must
219
+ include a readable copy of the attribution notices contained
220
+ within such NOTICE file, excluding those notices that do not
221
+ pertain to any part of the Derivative Works, in at least one
222
+ of the following places: within a NOTICE text file distributed
223
+ as part of the Derivative Works; within the Source form or
224
+ documentation, if provided along with the Derivative Works; or,
225
+ within a display generated by the Derivative Works, if and
226
+ wherever such third-party notices normally appear. The contents
227
+ of the NOTICE file are for informational purposes only and
228
+ do not modify the License. You may add Your own attribution
229
+ notices within Derivative Works that You distribute, alongside
230
+ or as an addendum to the NOTICE text from the Work, provided
231
+ that such additional attribution notices cannot be construed
232
+ as modifying the License.
233
+
234
+ You may add Your own copyright statement to Your modifications and
235
+ may provide additional or different license terms and conditions
236
+ for use, reproduction, or distribution of Your modifications, or
237
+ for any such Derivative Works as a whole, provided Your use,
238
+ reproduction, and distribution of the Work otherwise complies with
239
+ the conditions stated in this License.
240
+
241
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
242
+ any Contribution intentionally submitted for inclusion in the Work
243
+ by You to the Licensor shall be under the terms and conditions of
244
+ this License, without any additional terms or conditions.
245
+ Notwithstanding the above, nothing herein shall supersede or modify
246
+ the terms of any separate license agreement you may have executed
247
+ with Licensor regarding such Contributions.
248
+
249
+ 6. Trademarks. This License does not grant permission to use the trade
250
+ names, trademarks, service marks, or product names of the Licensor,
251
+ except as required for reasonable and customary use in describing the
252
+ origin of the Work and reproducing the content of the NOTICE file.
253
+
254
+ 7. Disclaimer of Warranty. Unless required by applicable law or
255
+ agreed to in writing, Licensor provides the Work (and each
256
+ Contributor provides its Contributions) on an "AS IS" BASIS,
257
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
258
+ implied, including, without limitation, any warranties or conditions
259
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
260
+ PARTICULAR PURPOSE. You are solely responsible for determining the
261
+ appropriateness of using or redistributing the Work and assume any
262
+ risks associated with Your exercise of permissions under this License.
263
+
264
+ 8. Limitation of Liability. In no event and under no legal theory,
265
+ whether in tort (including negligence), contract, or otherwise,
266
+ unless required by applicable law (such as deliberate and grossly
267
+ negligent acts) or agreed to in writing, shall any Contributor be
268
+ liable to You for damages, including any direct, indirect, special,
269
+ incidental, or consequential damages of any character arising as a
270
+ result of this License or out of the use or inability to use the
271
+ Work (including but not limited to damages for loss of goodwill,
272
+ work stoppage, computer failure or malfunction, or any and all
273
+ other commercial damages or losses), even if such Contributor
274
+ has been advised of the possibility of such damages.
275
+
276
+ 9. Accepting Warranty or Additional Liability. While redistributing
277
+ the Work or Derivative Works thereof, You may choose to offer,
278
+ and charge a fee for, acceptance of support, warranty, indemnity,
279
+ or other liability obligations and/or rights consistent with this
280
+ License. However, in accepting such obligations, You may act only
281
+ on Your own behalf and on Your sole responsibility, not on behalf
282
+ of any other Contributor, and only if You agree to indemnify,
283
+ defend, and hold each Contributor harmless for any liability
284
+ incurred by, or claims asserted against, such Contributor by reason
285
+ of your accepting any such warranty or additional liability.
286
+
287
+ =======================================================================
288
+ Cephes's 3-Clause BSD License
289
+ =======================================================================
290
+
291
+ Code derived from implementations in the Cephes Math Library should mention
292
+ its derivation and reference the following license:
293
+
294
+ 3-Clause BSD License for the Cephes Math Library
295
+ Copyright (c) 2018, Steven Moshier
296
+ All rights reserved.
297
+
298
+ Redistribution and use in source and binary forms, with or without
299
+ modification, are permitted provided that the following conditions are met:
300
+
301
+ * Redistributions of source code must retain the above copyright
302
+ notice, this list of conditions and the following disclaimer.
303
+
304
+ * Redistributions in binary form must reproduce the above copyright
305
+ notice, this list of conditions and the following disclaimer in the
306
+ documentation and/or other materials provided with the distribution.
307
+
308
+ * Neither the name of the nor the
309
+ names of its contributors may be used to endorse or promote products
310
+ derived from this software without specific prior written permission.
311
+
312
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
313
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
314
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
315
+ DISCLAIMED. IN NO EVENT SHALL Steven Moshier BE LIABLE FOR ANY
316
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
317
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
318
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
319
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
320
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
321
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322
+
323
+
324
+ =======================================================================
325
+ SciPy's 3-Clause BSD License
326
+ =======================================================================
327
+
328
+ Code derived from implementations in SciPy should mention its derivation
329
+ and reference the following license:
330
+
331
+ Copyright (c) 2001-2002 Enthought, Inc. 2003-2019, SciPy Developers.
332
+ All rights reserved.
333
+
334
+ Redistribution and use in source and binary forms, with or without
335
+ modification, are permitted provided that the following conditions
336
+ are met:
337
+
338
+ 1. Redistributions of source code must retain the above copyright
339
+ notice, this list of conditions and the following disclaimer.
340
+
341
+ 2. Redistributions in binary form must reproduce the above
342
+ copyright notice, this list of conditions and the following
343
+ disclaimer in the documentation and/or other materials provided
344
+ with the distribution.
345
+
346
+ 3. Neither the name of the copyright holder nor the names of its
347
+ contributors may be used to endorse or promote products derived
348
+ from this software without specific prior written permission.
349
+
350
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
351
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
352
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
353
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
354
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
355
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
356
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
357
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
358
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
359
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
360
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
361
+
362
+ =======================================================================
363
+ Boost's 1.0 Software License
364
+ =======================================================================
365
+
366
+ Code derived from implementations in Boost 1.0 should mention its
367
+ derivation and reference the following license:
368
+
369
+ Boost Software License - Version 1.0 - August 17th, 2003
370
+
371
+ Permission is hereby granted, free of charge, to any person or organization
372
+ obtaining a copy of the software and accompanying documentation covered by
373
+ this license (the "Software") to use, reproduce, display, distribute,
374
+ execute, and transmit the Software, and to prepare derivative works of the
375
+ Software, and to permit third-parties to whom the Software is furnished to
376
+ do so, all subject to the following:
377
+
378
+ The copyright notices in the Software and this entire statement, including
379
+ the above license grant, this restriction and the following disclaimer,
380
+ must be included in all copies of the Software, in whole or in part, and
381
+ all derivative works of the Software, unless such copies or derivative
382
+ works are solely in the form of machine-executable object code generated by
383
+ a source language processor.
384
+
385
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
386
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
387
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
388
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
389
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
390
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
391
+ DEALINGS IN THE SOFTWARE.
392
+
393
+ END OF TERMS AND CONDITIONS
394
+
395
+ APPENDIX: How to apply the Apache License to your work.
396
+
397
+ To apply the Apache License to your work, attach the following
398
+ boilerplate notice, with the fields enclosed by brackets "[]"
399
+ replaced with your own identifying information. (Don't include
400
+ the brackets!) The text should be enclosed in the appropriate
401
+ comment syntax for the file format. We also recommend that a
402
+ file or class name and description of purpose be included on the
403
+ same "printed page" as the copyright notice for easier
404
+ identification within third-party archives.
405
+
406
+ Copyright [yyyy] [name of copyright owner]
407
+
408
+ Licensed under the Apache License, Version 2.0 (the "License");
409
+ you may not use this file except in compliance with the License.
410
+ You may obtain a copy of the License at
411
+
412
+ http://www.apache.org/licenses/LICENSE-2.0
413
+
414
+ Unless required by applicable law or agreed to in writing, software
415
+ distributed under the License is distributed on an "AS IS" BASIS,
416
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
417
+ See the License for the specific language governing permissions and
418
+ limitations under the License.
419
+
420
+ =======================================================================
421
+ PILLOW-SIMD Software License
422
+ =======================================================================
423
+
424
+ Code derived from implementations in PILLOW-SIMD should mention its derivation
425
+ and reference the following license:
426
+
427
+ The Python Imaging Library (PIL) is
428
+
429
+ Copyright © 1997-2011 by Secret Labs AB
430
+ Copyright © 1995-2011 by Fredrik Lundh
431
+
432
+ Pillow is the friendly PIL fork. It is
433
+
434
+ Copyright © 2010-2022 by Alex Clark and contributors
435
+
436
+ Like PIL, Pillow is licensed under the open source HPND License:
437
+
438
+ By obtaining, using, and/or copying this software and/or its associated
439
+ documentation, you agree that you have read, understood, and will comply
440
+ with the following terms and conditions:
441
+
442
+ Permission to use, copy, modify, and distribute this software and its
443
+ associated documentation for any purpose and without fee is hereby granted,
444
+ provided that the above copyright notice appears in all copies, and that
445
+ both that copyright notice and this permission notice appear in supporting
446
+ documentation, and that the name of Secret Labs AB or the author not be
447
+ used in advertising or publicity pertaining to distribution of the software
448
+ without specific, written prior permission.
449
+
450
+ SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
451
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
452
+ IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
453
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
454
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
455
+ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
456
+ PERFORMANCE OF THIS SOFTWARE.
RECORD ADDED
The diff for this file is too large to render. See raw diff
 
REQUESTED ADDED
File without changes
WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (72.1.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-win_amd64
5
+
__init__.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ """torchgen
2
+
3
+ This module contains codegeneration utilities for PyTorch. It is used to
4
+ build PyTorch from source, but may also be used for out-of-tree projects
5
+ that extend PyTorch.
6
+
7
+ Note well that we provide no BC guarantees for torchgen. If you're interested
8
+ in using torchgen and want the PyTorch team to be aware, please reach out
9
+ on GitHub.
10
+ """
activate ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file must be used with "source bin/activate" *from bash*
2
+ # You cannot run it directly
3
+
4
+ deactivate () {
5
+ # reset old environment variables
6
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
7
+ PATH="${_OLD_VIRTUAL_PATH:-}"
8
+ export PATH
9
+ unset _OLD_VIRTUAL_PATH
10
+ fi
11
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
12
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
13
+ export PYTHONHOME
14
+ unset _OLD_VIRTUAL_PYTHONHOME
15
+ fi
16
+
17
+ # Call hash to forget past commands. Without forgetting
18
+ # past commands the $PATH changes we made may not be respected
19
+ hash -r 2> /dev/null
20
+
21
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
22
+ PS1="${_OLD_VIRTUAL_PS1:-}"
23
+ export PS1
24
+ unset _OLD_VIRTUAL_PS1
25
+ fi
26
+
27
+ unset VIRTUAL_ENV
28
+ unset VIRTUAL_ENV_PROMPT
29
+ if [ ! "${1:-}" = "nondestructive" ] ; then
30
+ # Self destruct!
31
+ unset -f deactivate
32
+ fi
33
+ }
34
+
35
+ # unset irrelevant variables
36
+ deactivate nondestructive
37
+
38
+ # on Windows, a path can contain colons and backslashes and has to be converted:
39
+ if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
40
+ # transform D:\path\to\venv to /d/path/to/venv on MSYS
41
+ # and to /cygdrive/d/path/to/venv on Cygwin
42
+ export VIRTUAL_ENV=$(cygpath "C:\Users\migue\Downloads\Codigo\AI\HuggingModelAI\IAservicies\myenv")
43
+ else
44
+ # use the path as-is
45
+ export VIRTUAL_ENV="C:\Users\migue\Downloads\Codigo\AI\HuggingModelAI\IAservicies\myenv"
46
+ fi
47
+
48
+ _OLD_VIRTUAL_PATH="$PATH"
49
+ PATH="$VIRTUAL_ENV/Scripts:$PATH"
50
+ export PATH
51
+
52
+ # unset PYTHONHOME if set
53
+ # this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
54
+ # could use `if (set -u; : $PYTHONHOME) ;` in bash
55
+ if [ -n "${PYTHONHOME:-}" ] ; then
56
+ _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
57
+ unset PYTHONHOME
58
+ fi
59
+
60
+ if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
61
+ _OLD_VIRTUAL_PS1="${PS1:-}"
62
+ PS1="(myenv) ${PS1:-}"
63
+ export PS1
64
+ VIRTUAL_ENV_PROMPT="(myenv) "
65
+ export VIRTUAL_ENV_PROMPT
66
+ fi
67
+
68
+ # Call hash to forget past commands. Without forgetting
69
+ # past commands the $PATH changes we made may not be respected
70
+ hash -r 2> /dev/null
activate.bat ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+
3
+ rem This file is UTF-8 encoded, so we need to update the current code page while executing it
4
+ for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do (
5
+ set _OLD_CODEPAGE=%%a
6
+ )
7
+ if defined _OLD_CODEPAGE (
8
+ "%SystemRoot%\System32\chcp.com" 65001 > nul
9
+ )
10
+
11
+ set VIRTUAL_ENV=C:\Users\migue\Downloads\Codigo\AI\HuggingModelAI\IAservicies\myenv
12
+
13
+ if not defined PROMPT set PROMPT=$P$G
14
+
15
+ if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT%
16
+ if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%
17
+
18
+ set _OLD_VIRTUAL_PROMPT=%PROMPT%
19
+ set PROMPT=(myenv) %PROMPT%
20
+
21
+ if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%
22
+ set PYTHONHOME=
23
+
24
+ if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%
25
+ if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH%
26
+
27
+ set PATH=%VIRTUAL_ENV%\Scripts;%PATH%
28
+ set VIRTUAL_ENV_PROMPT=(myenv)
29
+
30
+ :END
31
+ if defined _OLD_CODEPAGE (
32
+ "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul
33
+ set _OLD_CODEPAGE=
34
+ )
code_template.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import TYPE_CHECKING
5
+
6
+
7
+ if TYPE_CHECKING:
8
+ from collections.abc import Mapping, Sequence
9
+
10
+
11
+ # match $identifier or ${identifier} and replace with value in env
12
+ # If this identifier is at the beginning of whitespace on a line
13
+ # and its value is a list then it is treated as
14
+ # block substitution by indenting to that depth and putting each element
15
+ # of the list on its own line
16
+ # if the identifier is on a line starting with non-whitespace and a list
17
+ # then it is comma separated ${,foo} will insert a comma before the list
18
+ # if this list is not empty and ${foo,} will insert one after.
19
+
20
+
21
+ class CodeTemplate:
22
+ substitution_str = r"(^[^\n\S]*)?\$([^\d\W]\w*|\{,?[^\d\W]\w*\,?})"
23
+ substitution = re.compile(substitution_str, re.MULTILINE)
24
+
25
+ pattern: str
26
+ filename: str
27
+
28
+ @staticmethod
29
+ def from_file(filename: str) -> CodeTemplate:
30
+ with open(filename) as f:
31
+ return CodeTemplate(f.read(), filename)
32
+
33
+ def __init__(self, pattern: str, filename: str = "") -> None:
34
+ self.pattern = pattern
35
+ self.filename = filename
36
+
37
+ def substitute(
38
+ self, env: Mapping[str, object] | None = None, **kwargs: object
39
+ ) -> str:
40
+ if env is None:
41
+ env = {}
42
+
43
+ def lookup(v: str) -> object:
44
+ assert env is not None
45
+ return kwargs[v] if v in kwargs else env[v]
46
+
47
+ def indent_lines(indent: str, v: Sequence[object]) -> str:
48
+ return "".join(
49
+ [indent + l + "\n" for e in v for l in str(e).splitlines()]
50
+ ).rstrip()
51
+
52
+ def replace(match: re.Match[str]) -> str:
53
+ indent = match.group(1)
54
+ key = match.group(2)
55
+ comma_before = ""
56
+ comma_after = ""
57
+ if key[0] == "{":
58
+ key = key[1:-1]
59
+ if key[0] == ",":
60
+ comma_before = ", "
61
+ key = key[1:]
62
+ if key[-1] == ",":
63
+ comma_after = ", "
64
+ key = key[:-1]
65
+ v = lookup(key)
66
+ if indent is not None:
67
+ if not isinstance(v, list):
68
+ v = [v]
69
+ return indent_lines(indent, v)
70
+ elif isinstance(v, list):
71
+ middle = ", ".join([str(x) for x in v])
72
+ if len(v) == 0:
73
+ return middle
74
+ return comma_before + middle + comma_after
75
+ else:
76
+ return str(v)
77
+
78
+ return self.substitution.sub(replace, self.pattern)
79
+
80
+
81
+ if __name__ == "__main__":
82
+ c = CodeTemplate(
83
+ """\
84
+ int foo($args) {
85
+
86
+ $bar
87
+ $bar
88
+ $a+$b
89
+ }
90
+ int commatest(int a${,stuff})
91
+ int notest(int a${,empty,})
92
+ """
93
+ )
94
+ print(
95
+ c.substitute(
96
+ args=["hi", 8],
97
+ bar=["what", 7],
98
+ a=3,
99
+ b=4,
100
+ stuff=["things...", "others"],
101
+ empty=[],
102
+ )
103
+ )
context.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ import functools
5
+ from typing import Any, Callable, Optional, TYPE_CHECKING, TypeVar, Union
6
+
7
+ import torchgen.local as local
8
+ from torchgen.model import (
9
+ BackendIndex,
10
+ DispatchKey,
11
+ NativeFunction,
12
+ NativeFunctionsGroup,
13
+ NativeFunctionsViewGroup,
14
+ )
15
+ from torchgen.utils import context, S, T
16
+
17
+
18
+ if TYPE_CHECKING:
19
+ from collections.abc import Iterator
20
+
21
+
22
+ # Helper functions for defining generators on things in the model
23
+
24
+ F = TypeVar(
25
+ "F",
26
+ NativeFunction,
27
+ NativeFunctionsGroup,
28
+ NativeFunctionsViewGroup,
29
+ Union[NativeFunction, NativeFunctionsGroup],
30
+ Union[NativeFunction, NativeFunctionsViewGroup],
31
+ )
32
+
33
+ F2 = TypeVar(
34
+ "F2",
35
+ NativeFunction,
36
+ NativeFunctionsGroup,
37
+ Optional[NativeFunction],
38
+ bool,
39
+ str,
40
+ )
41
+
42
+ F3 = TypeVar("F3", tuple[NativeFunction, Any], list[NativeFunction])
43
+
44
+
45
+ @contextlib.contextmanager
46
+ def native_function_manager(
47
+ g: NativeFunctionsGroup | NativeFunctionsViewGroup | NativeFunction,
48
+ ) -> Iterator[None]:
49
+ if isinstance(g, NativeFunctionsGroup):
50
+ # By default, we associate all errors with structured native functions
51
+ # with the out variant. In some cases, it might be better to have
52
+ # a more specific place to hang things; if so, use
53
+ # native_function_manager again on the inside
54
+ f = g.out
55
+ elif isinstance(g, NativeFunctionsViewGroup):
56
+ # We associate errors with the view operator
57
+ f = g.view
58
+ else:
59
+ f = g
60
+ with context(lambda: f"in native_functions.yaml line {f.loc}:\n {f.func}"):
61
+ with local.parametrize(
62
+ use_const_ref_for_mutable_tensors=f.use_const_ref_for_mutable_tensors,
63
+ use_ilistref_for_tensor_lists=f.part_of_structured_group,
64
+ ):
65
+ yield
66
+
67
+
68
+ # Given a function that operates on NativeFunction, wrap it into a new function
69
+ # that sets some appropriate context managers for that native function.
70
+ # YOU MUST WRAP FUNCTIONS IN THIS for calls to api modules to be sound
71
+ # (you will get an error if we try to access the local variables without having
72
+ # set them).
73
+ def with_native_function(func: Callable[[F], T]) -> Callable[[F], T]:
74
+ @functools.wraps(func)
75
+ def wrapper(f: F) -> T:
76
+ with native_function_manager(f):
77
+ return func(f)
78
+
79
+ return wrapper
80
+
81
+
82
+ def with_native_function_and(func: Callable[[F, F2], T]) -> Callable[[F, F2], T]:
83
+ @functools.wraps(func)
84
+ def wrapper(f: F, f2: F2) -> T:
85
+ # The first native_function is assumed to be the one with the appropriate context.
86
+ with native_function_manager(f):
87
+ return func(f, f2)
88
+
89
+ return wrapper
90
+
91
+
92
+ def method_with_native_function(func: Callable[[S, F], T]) -> Callable[[S, F], T]:
93
+ @functools.wraps(func)
94
+ def wrapper(slf: S, f: F) -> T:
95
+ with native_function_manager(f):
96
+ return func(slf, f)
97
+
98
+ return wrapper
99
+
100
+
101
+ def method_with_nested_native_function(
102
+ func: Callable[[S, F3], T],
103
+ ) -> Callable[[S, F3], T]:
104
+ @functools.wraps(func)
105
+ def wrapper(slf: S, f: F3) -> T:
106
+ with native_function_manager(f[0]):
107
+ return func(slf, f)
108
+
109
+ return wrapper
110
+
111
+
112
+ # Convenience decorator for functions that explicitly take in a BackendIndex,
113
+ # instead of indirectly taking one in as a closure
114
+ def with_native_function_and_index(
115
+ func: Callable[[F, BackendIndex], T],
116
+ ) -> Callable[[F, BackendIndex], T]:
117
+ @functools.wraps(func)
118
+ def wrapper(f: F, backend_index: BackendIndex) -> T:
119
+ with native_function_manager(f):
120
+ return func(f, backend_index)
121
+
122
+ return wrapper
123
+
124
+
125
+ # Convenience decorator for functions that explicitly take in a Dict of BackendIndices
126
+ def with_native_function_and_indices(
127
+ func: Callable[[F, dict[DispatchKey, BackendIndex]], T],
128
+ ) -> Callable[[F, dict[DispatchKey, BackendIndex]], T]:
129
+ @functools.wraps(func)
130
+ def wrapper(f: F, backend_indices: dict[DispatchKey, BackendIndex]) -> T:
131
+ with native_function_manager(f):
132
+ return func(f, backend_indices)
133
+
134
+ return wrapper
datasets-cli.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8ecc3f2798b65a5b9ee125a1bf86f62d05a56e9210e70dddff9a6895fae506a5
3
+ size 108451
deactivate.bat ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+
3
+ if defined _OLD_VIRTUAL_PROMPT (
4
+ set "PROMPT=%_OLD_VIRTUAL_PROMPT%"
5
+ )
6
+ set _OLD_VIRTUAL_PROMPT=
7
+
8
+ if defined _OLD_VIRTUAL_PYTHONHOME (
9
+ set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%"
10
+ set _OLD_VIRTUAL_PYTHONHOME=
11
+ )
12
+
13
+ if defined _OLD_VIRTUAL_PATH (
14
+ set "PATH=%_OLD_VIRTUAL_PATH%"
15
+ )
16
+
17
+ set _OLD_VIRTUAL_PATH=
18
+
19
+ set VIRTUAL_ENV=
20
+ set VIRTUAL_ENV_PROMPT=
21
+
22
+ :END
distutils-precedence.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2638ce9e2500e572a5e0de7faed6661eb569d1b696fcba07b0dd223da5f5d224
3
+ size 151
entry_points.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ [console_scripts]
2
+ torchfrtrace = tools.flight_recorder.fr_trace:main
3
+ torchrun = torch.distributed.run:main
4
+
5
+ [torchrun.logs_specs]
6
+ default = torch.distributed.elastic.multiprocessing:DefaultLogsSpecs
f2py.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5463826983b536494b9bf027c1fab304632aefe10c03e89f0145a7543cb69d16
3
+ size 108440
gen.py ADDED
The diff for this file is too large to render. See raw diff
 
gen_aoti_c_shim.py ADDED
@@ -0,0 +1,508 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import textwrap
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING
6
+
7
+ from torchgen.api.types import DispatcherSignature
8
+ from torchgen.api.types.signatures import CppSignature, CppSignatureGroup
9
+ from torchgen.context import method_with_native_function
10
+ from torchgen.model import (
11
+ Argument,
12
+ BackendIndex,
13
+ BaseTy,
14
+ BaseType,
15
+ DispatchKey,
16
+ FunctionSchema,
17
+ ListType,
18
+ NativeFunction,
19
+ NativeFunctionsGroup,
20
+ OperatorName,
21
+ OptionalType,
22
+ Type,
23
+ )
24
+ from torchgen.utils import mapMaybe
25
+
26
+
27
+ if TYPE_CHECKING:
28
+ from collections.abc import Sequence
29
+
30
+
31
+ base_type_to_c_type = {
32
+ BaseTy.Tensor: "AtenTensorHandle",
33
+ BaseTy.bool: "int32_t", # Use int to pass bool
34
+ BaseTy.int: "int64_t",
35
+ BaseTy.SymInt: "int64_t", # Inductor-generated code won't see a SymInt
36
+ BaseTy.Scalar: "double", # Use double to pass both integer and floating point
37
+ BaseTy.float: "double", # TODO: how about other floating point types?
38
+ BaseTy.str: "const char*",
39
+ BaseTy.DeviceIndex: "int32_t",
40
+ BaseTy.Layout: "int32_t", # Represent enum as int
41
+ BaseTy.MemoryFormat: "int32_t", # Represent enum as int
42
+ BaseTy.ScalarType: "int32_t", # Represent enum as int
43
+ BaseTy.Generator: "AtenGeneratorHandle",
44
+ }
45
+
46
+ base_type_to_aten_type = {
47
+ BaseTy.Tensor: "at::Tensor",
48
+ BaseTy.bool: "bool",
49
+ BaseTy.int: "int64_t",
50
+ BaseTy.SymInt: "c10::SymInt",
51
+ BaseTy.Scalar: "c10::Scalar",
52
+ BaseTy.float: "double",
53
+ BaseTy.str: "c10::string_view",
54
+ BaseTy.DeviceIndex: "c10::DeviceIndex",
55
+ BaseTy.Layout: "c10::Layout",
56
+ BaseTy.MemoryFormat: "c10::MemoryFormat",
57
+ BaseTy.ScalarType: "c10::ScalarType",
58
+ BaseTy.Generator: "at::Generator",
59
+ }
60
+
61
+ base_type_to_callsite_expr = {
62
+ BaseTy.Tensor: "*tensor_handle_to_tensor_pointer",
63
+ BaseTy.bool: "",
64
+ BaseTy.int: "",
65
+ BaseTy.SymInt: "",
66
+ BaseTy.Scalar: "",
67
+ BaseTy.float: "",
68
+ BaseTy.str: "",
69
+ BaseTy.DeviceIndex: "static_cast<c10::DeviceIndex>",
70
+ BaseTy.Layout: "static_cast<c10::Layout>",
71
+ BaseTy.MemoryFormat: "static_cast<c10::MemoryFormat>",
72
+ BaseTy.ScalarType: "static_cast<c10::ScalarType>",
73
+ BaseTy.Generator: "*generator_handle_to_generator_pointer",
74
+ }
75
+
76
+
77
+ # convert args to C types, names in declarations, and expressions in function bodies
78
+ def convert_arg_type_and_name( # type: ignore[return]
79
+ typ: Type,
80
+ name: str,
81
+ ) -> tuple[list[str], list[str], list[str], list[str]]:
82
+ if isinstance(typ, BaseType):
83
+ if typ.name in base_type_to_c_type:
84
+ return (
85
+ [base_type_to_c_type[typ.name]],
86
+ [name],
87
+ [base_type_to_aten_type[typ.name]],
88
+ [
89
+ f"{base_type_to_callsite_expr[typ.name]}({name})"
90
+ if base_type_to_callsite_expr[typ.name]
91
+ else name
92
+ ],
93
+ )
94
+ elif typ.name == BaseTy.Device:
95
+ return (
96
+ ["int32_t", "int32_t"],
97
+ [name, name + "_index_"],
98
+ ["c10::Device"],
99
+ [
100
+ f"c10::Device(static_cast<c10::DeviceType>({name}), static_cast<c10::DeviceIndex>({name}_index_))"
101
+ ],
102
+ )
103
+ else:
104
+ # TODO: BaseTy.Dimname, etc.
105
+ raise NotImplementedError(f"TODO: add support for arg type {repr(typ)}")
106
+ elif isinstance(typ, OptionalType):
107
+ c_types, names, aten_types, callsite_exprs = convert_arg_type_and_name(
108
+ typ.elem, name
109
+ )
110
+ j = 0 # index for names
111
+ new_aten_types = []
112
+ new_callsite_exprs = []
113
+ for aten_type in aten_types:
114
+ # Use pointer to denote optional type
115
+ c_types[j] = c_types[j] + "*"
116
+ if aten_type.startswith("c10::ArrayRef<"):
117
+ # ArrayRef is passed as pointer + size, but no need to add "*" to the size argument
118
+ new_aten_types.append(f"::std::optional<{aten_type}>")
119
+ base_type = aten_type[len("c10::ArrayRef<") : -1]
120
+ new_callsite_exprs.append(
121
+ f"pointer_to_optional_list<{base_type}>({names[j]}, {names[j + 1]})"
122
+ )
123
+ j += 2
124
+ elif aten_type == "c10::Device":
125
+ # Device is passed as device_type + device_index
126
+ new_aten_types.append("::std::optional<c10::Device>")
127
+ new_callsite_exprs.append(
128
+ f"pointer_to_optional_device({names[j]}, {names[j + 1]})"
129
+ )
130
+ j += 2
131
+ else:
132
+ new_aten_types.append(f"::std::optional<{aten_type}>")
133
+ new_callsite_exprs.append(
134
+ f"pointer_to_optional<{aten_type}>({names[j]})"
135
+ )
136
+ j += 1
137
+
138
+ return (
139
+ c_types,
140
+ names,
141
+ new_aten_types,
142
+ new_callsite_exprs,
143
+ )
144
+ elif isinstance(typ, ListType):
145
+ # Need to explictly pass the list as pointer + length
146
+ c_types, names, aten_types, _ = convert_arg_type_and_name(typ.elem, name)
147
+ assert len(c_types) == 1, "ListType with unsupported element type " + repr(typ)
148
+
149
+ # The list content should never be modified
150
+ c_types[0] = f"const {c_types[0]}*"
151
+ c_types.append("int64_t")
152
+ name = names[0]
153
+ names.append(name + "_len_")
154
+
155
+ atype = aten_types[0]
156
+ callsite_exprs = []
157
+ if atype == "bool":
158
+ # no converter from std::vector<bool> to c10::ArrayRef<bool>
159
+ # construct std::array<bool, N> instead
160
+ assert typ.size is not None
161
+ callsite_exprs.append(f"pointer_to_list<{typ.size}>({name})")
162
+ elif atype == "::std::optional<at::Tensor>":
163
+ # convert from std::vector<::std::optional<at::Tensor>> to c10::List<::std::optional<at::Tensor>>
164
+ callsite_exprs.append(
165
+ f"c10::List<{atype}>(c10::ArrayRef<{atype}>(pointer_to_list<{atype}>({name}, {name}_len_)))"
166
+ )
167
+ else:
168
+ callsite_exprs.append(f"pointer_to_list<{atype}>({name}, {name}_len_)")
169
+
170
+ aten_types = [f"c10::ArrayRef<{t}>" for t in aten_types]
171
+ return (
172
+ c_types,
173
+ names,
174
+ aten_types,
175
+ callsite_exprs,
176
+ )
177
+
178
+
179
+ def zip_type_and_name(types: list[str], names: list[str]) -> list[str]:
180
+ return [typ + " " + name for typ, name in zip(types, names)]
181
+
182
+
183
+ # Generate argument declarations and callsite expressions
184
+ def gen_arguments(flat_arguments: Sequence[Argument]) -> tuple[list[str], list[str]]:
185
+ types = []
186
+ new_names = []
187
+ callsite_exprs = []
188
+ for arg in flat_arguments:
189
+ new_types, names, _, new_callsite_exprs = convert_arg_type_and_name(
190
+ arg.type, arg.name
191
+ )
192
+ types.extend(new_types)
193
+ new_names.extend(names)
194
+ callsite_exprs.extend(new_callsite_exprs)
195
+ return zip_type_and_name(types, new_names), callsite_exprs
196
+
197
+
198
+ # Return values are passed out as pointer arguments because all the C shim functions
199
+ # are expected to return AOTITorchError.
200
+ # Generate returns as declarations and callsite expressions
201
+ def gen_returns(schema: FunctionSchema) -> tuple[list[str], list[str]]:
202
+ types = []
203
+ names = []
204
+ for idx, ret in enumerate(schema.returns):
205
+ names.append(f"ret{idx}")
206
+ if isinstance(ret.type, BaseType) and ret.type.name in base_type_to_c_type:
207
+ types.append(base_type_to_c_type[ret.type.name] + "*")
208
+ else:
209
+ raise NotImplementedError(
210
+ f"TODO: add support for return type {repr(ret.type)}"
211
+ )
212
+
213
+ def convert_return(typ: BaseType, val: str) -> str:
214
+ if typ.name == BaseTy.Tensor:
215
+ return f"new_tensor_handle(std::move({val}));"
216
+ elif typ.name == BaseTy.SymInt:
217
+ return f"{val}.expect_int()"
218
+ elif typ.name == BaseTy.Scalar:
219
+ return f"{val}.toDouble()"
220
+ else:
221
+ return val
222
+
223
+ ret_pointer_can_be_null = False
224
+ unambiguous_name = schema.name.unambiguous_name()
225
+ for name in [
226
+ "_scaled_dot_product_flash_attention",
227
+ "_scaled_dot_product_efficient_attention",
228
+ "_scaled_dot_product_cudnn_attention",
229
+ "convolution_backward",
230
+ ]:
231
+ if name in unambiguous_name:
232
+ ret_pointer_can_be_null = True
233
+ break
234
+
235
+ callsite_exprs: list[str] = []
236
+ for idx, ret in enumerate(schema.returns):
237
+ tmp = "tmp_result" if len(names) == 1 else f"std::get<{idx}>(tmp_result)"
238
+ assert isinstance(ret.type, BaseType)
239
+ rval = convert_return(ret.type, tmp)
240
+ if ret_pointer_can_be_null:
241
+ callsite_exprs.append(f"if ({names[idx]}) {{ *{names[idx]} = {rval}; }}")
242
+ else:
243
+ callsite_exprs.append(f"*{names[idx]} = {rval};")
244
+
245
+ return zip_type_and_name(types, names), callsite_exprs
246
+
247
+
248
+ # gen.py generates header first and then src, so caching the result here to avoid duplicate work
249
+ declaration_definition_cache: dict[tuple[str, str, str], tuple[str, str]] = {}
250
+
251
+
252
+ def gen_declaration_and_definition(
253
+ schema: FunctionSchema, device: str, backend_call: str
254
+ ) -> tuple[str, str]:
255
+ func_name = schema.name.unambiguous_name()
256
+
257
+ global declaration_definition_cache
258
+ if (func_name, device, backend_call) in declaration_definition_cache:
259
+ return declaration_definition_cache[(func_name, device, backend_call)]
260
+
261
+ if schema.is_out_fn():
262
+ # out_variant has out arguments in the front, and it's ok to ignore return values
263
+ # because C shim functions only return AOTITorchError
264
+ args, callsite_exprs = gen_arguments(
265
+ [*schema.arguments.out, *schema.arguments.flat_non_out]
266
+ )
267
+ ret_assignments: list[str] = []
268
+ else:
269
+ args, callsite_exprs = gen_arguments(schema.arguments.flat_all)
270
+ # ignore return values for inplace ops
271
+ ret_declarations, ret_assignments = (
272
+ ([], []) if schema.name.name.inplace else gen_returns(schema)
273
+ )
274
+ args.extend(ret_declarations)
275
+
276
+ declaration = f"AOTITorchError aoti_torch_{device}_{func_name}({', '.join(args)})"
277
+
278
+ tmp_result = "auto tmp_result = " if ret_assignments else ""
279
+ ret_assignments_str = "\n" + "\n".join(ret_assignments) if ret_assignments else ""
280
+ definition = f"""
281
+ {declaration} {{
282
+ AOTI_TORCH_CONVERT_EXCEPTION_TO_ERROR_CODE({{
283
+ {tmp_result}{backend_call}(
284
+ {textwrap.indent(', '.join(callsite_exprs), " ")}
285
+ );{textwrap.indent(ret_assignments_str, " ")}
286
+ }});
287
+ }}
288
+ """
289
+ declaration_definition_cache[(func_name, device, backend_call)] = (
290
+ declaration,
291
+ definition,
292
+ )
293
+ return declaration, definition
294
+
295
+
296
+ def gen_static_dispatch_backend_call_signature(
297
+ sig: CppSignature | DispatcherSignature,
298
+ f: NativeFunction,
299
+ ) -> CppSignature:
300
+ sig = DispatcherSignature.from_schema(f.func)
301
+ cpp_sigs = CppSignatureGroup.from_native_function(
302
+ f, method=False, fallback_binding=False
303
+ )
304
+ if sig.symint and f.func.has_symint():
305
+ cpp_sig = cpp_sigs.symint_signature
306
+ else:
307
+ cpp_sig = cpp_sigs.signature
308
+ assert cpp_sig is not None
309
+ return cpp_sig
310
+
311
+
312
+ def gen_static_dispatch_backend_call(
313
+ f: NativeFunction,
314
+ backend_index: BackendIndex,
315
+ ) -> str:
316
+ sig = DispatcherSignature.from_schema(f.func)
317
+ cpp_sig = gen_static_dispatch_backend_call_signature(sig, f)
318
+ return f"at::{backend_index.dispatch_key.lower()}::{cpp_sig.name()}"
319
+
320
+
321
+ def get_backend_index_for_aoti(
322
+ func: NativeFunction,
323
+ func_group_mapping: dict[OperatorName, NativeFunctionsGroup],
324
+ dispatch_key: DispatchKey,
325
+ backend_indices: dict[DispatchKey, BackendIndex],
326
+ extend_aoti_c_shim: bool,
327
+ ) -> BackendIndex | None:
328
+ backend_index = None
329
+ if backend_indices[dispatch_key].has_kernel(func) or (
330
+ func.structured_delegate is not None
331
+ and func.structured_delegate in func_group_mapping
332
+ and backend_indices[dispatch_key].has_kernel(
333
+ func_group_mapping[func.structured_delegate]
334
+ )
335
+ ):
336
+ backend_index = backend_indices[dispatch_key]
337
+ else:
338
+ # for the extend out-of-tree kernels, we don't need to
339
+ # duplicatly create C shim wrappers for other dispatch keys
340
+ if extend_aoti_c_shim:
341
+ return backend_index
342
+
343
+ elif backend_indices[DispatchKey.CompositeExplicitAutograd].has_kernel(func):
344
+ # We need to create C shim wrappers for CompositeExplicitAutograd kernels
345
+ backend_index = backend_indices[DispatchKey.CompositeExplicitAutograd]
346
+ elif backend_indices[
347
+ DispatchKey.CompositeExplicitAutogradNonFunctional
348
+ ].has_kernel(func):
349
+ # We need to create C shim wrappers for CompositeExplicitAutogradNonFunctional kernels
350
+ backend_index = backend_indices[
351
+ DispatchKey.CompositeExplicitAutogradNonFunctional
352
+ ]
353
+ elif backend_indices[DispatchKey.CompositeImplicitAutograd].has_kernel(func):
354
+ backend_index = backend_indices[DispatchKey.CompositeImplicitAutograd]
355
+
356
+ return backend_index
357
+
358
+
359
+ def get_header_for_aoti(
360
+ func: NativeFunction,
361
+ func_group_mapping: dict[OperatorName, NativeFunctionsGroup],
362
+ dispatch_key: DispatchKey,
363
+ backend_indices: dict[DispatchKey, BackendIndex],
364
+ extend_aoti_c_shim: bool,
365
+ ) -> str | None:
366
+ backend_index = get_backend_index_for_aoti(
367
+ func, func_group_mapping, dispatch_key, backend_indices, extend_aoti_c_shim
368
+ )
369
+ return (
370
+ None
371
+ if backend_index is None
372
+ else f"#include <ATen/ops/{func.root_name}_{backend_index.dispatch_key.lower()}_dispatch.h>"
373
+ )
374
+
375
+
376
+ def get_fallback_op_name(func: NativeFunction) -> str:
377
+ return (
378
+ f"{func.namespace}.{func.func.name.name}.{func.func.name.overload_name}"
379
+ if func.func.name.overload_name
380
+ else f"{func.namespace}.{func.func.name.name}.default"
381
+ )
382
+
383
+
384
+ def gen_c_shim(
385
+ func: NativeFunction,
386
+ func_group_mapping: dict[OperatorName, NativeFunctionsGroup],
387
+ dispatch_key: DispatchKey,
388
+ backend_indices: dict[DispatchKey, BackendIndex],
389
+ header: bool,
390
+ extend_aoti_c_shim: bool,
391
+ ) -> str | None:
392
+ backend_index = get_backend_index_for_aoti(
393
+ func, func_group_mapping, dispatch_key, backend_indices, extend_aoti_c_shim
394
+ )
395
+ if backend_index is None:
396
+ return None
397
+
398
+ schema = func.func
399
+ device = dispatch_key.lower()
400
+ backend_call = gen_static_dispatch_backend_call(
401
+ func,
402
+ backend_index,
403
+ )
404
+
405
+ try:
406
+ if header:
407
+ declaration, _ = gen_declaration_and_definition(
408
+ schema, device, backend_call
409
+ )
410
+ return f"AOTI_TORCH_EXPORT {declaration};"
411
+ else:
412
+ _, definition = gen_declaration_and_definition(schema, device, backend_call)
413
+ return definition
414
+
415
+ except NotImplementedError:
416
+ return None
417
+
418
+
419
+ @dataclass(frozen=True)
420
+ class ShimGenerator:
421
+ func_group_mapping: dict[OperatorName, NativeFunctionsGroup]
422
+ dispatch_key: DispatchKey
423
+ backend_indices: dict[DispatchKey, BackendIndex]
424
+ header: bool # True to generate .h and False to generate .cpp
425
+ extend_aoti_c_shim: bool
426
+
427
+ @method_with_native_function
428
+ def __call__(
429
+ self,
430
+ func: NativeFunction,
431
+ ) -> str | None:
432
+ result = gen_c_shim(
433
+ func,
434
+ self.func_group_mapping,
435
+ self.dispatch_key,
436
+ self.backend_indices,
437
+ self.header,
438
+ self.extend_aoti_c_shim,
439
+ )
440
+ return result
441
+
442
+
443
+ def gen_aoti_c_shim(
444
+ native_functions: Sequence[NativeFunction],
445
+ func_group_mapping: dict[OperatorName, NativeFunctionsGroup],
446
+ dispatch_key: DispatchKey,
447
+ backend_indices: dict[DispatchKey, BackendIndex],
448
+ header: bool,
449
+ extend_aoti_c_shim: bool,
450
+ includes: str = "",
451
+ ) -> str:
452
+ body = "\n".join(
453
+ list(
454
+ mapMaybe(
455
+ ShimGenerator(
456
+ func_group_mapping,
457
+ dispatch_key,
458
+ backend_indices,
459
+ header,
460
+ extend_aoti_c_shim,
461
+ ),
462
+ native_functions,
463
+ )
464
+ )
465
+ )
466
+ device = dispatch_key.lower()
467
+ warning = """
468
+ // WARNING: THIS FILE IS AUTOGENERATED BY torchgen. DO NOT MODIFY BY HAND.
469
+ // See https://github.com/pytorch/pytorch/blob/7e86a7c0155295539996e0cf422883571126073e/torchgen/gen.py#L2424-L2436 for details"""
470
+
471
+ if header:
472
+ return f"""
473
+ {warning}
474
+
475
+ #pragma once
476
+
477
+ #include <torch/csrc/inductor/aoti_torch/c/shim.h>
478
+
479
+ #ifdef __cplusplus
480
+ extern "C" {{
481
+ #endif
482
+
483
+ {body}
484
+
485
+ #ifdef __cplusplus
486
+ }} // extern "C"
487
+ #endif
488
+ """
489
+
490
+ else:
491
+ return f"""
492
+ {warning}
493
+
494
+ #include <torch/csrc/inductor/aoti_torch/generated/{"extend/" if extend_aoti_c_shim else ""}c_shim_{device}.h>
495
+ #include <torch/csrc/inductor/aoti_torch/utils.h>
496
+
497
+ #ifndef AT_PER_OPERATOR_HEADERS
498
+ #include <ATen/{str(dispatch_key)}Functions.h>
499
+ #include <ATen/CompositeExplicitAutogradFunctions.h>
500
+ #include <ATen/CompositeExplicitAutogradNonFunctionalFunctions.h>
501
+ #include <ATen/CompositeImplicitAutogradFunctions.h>
502
+ #else
503
+ {includes}
504
+ #endif
505
+
506
+ using namespace torch::aot_inductor;
507
+
508
+ {body}"""
gen_backend_stubs.py ADDED
@@ -0,0 +1,615 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import os
5
+ import re
6
+ from collections import Counter, defaultdict, namedtuple
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING
9
+
10
+ import yaml
11
+
12
+ import torchgen.api.dispatcher as dispatcher
13
+ import torchgen.dest as dest
14
+ from torchgen.api.types import DispatcherSignature
15
+ from torchgen.code_template import CodeTemplate
16
+ from torchgen.context import native_function_manager
17
+ from torchgen.gen import get_grouped_native_functions, parse_native_yaml
18
+ from torchgen.model import (
19
+ BackendIndex,
20
+ BackendMetadata,
21
+ DispatchKey,
22
+ NativeFunction,
23
+ NativeFunctionsGroup,
24
+ OperatorName,
25
+ )
26
+ from torchgen.selective_build.selector import SelectiveBuilder
27
+ from torchgen.utils import concatMap, context, FileManager, NamespaceHelper, Target
28
+ from torchgen.yaml_utils import YamlLoader
29
+
30
+
31
+ if TYPE_CHECKING:
32
+ from collections.abc import Sequence
33
+
34
+
35
+ # Parses the external backend's yaml, and adds a new BackendIndex for the backend's dispatch key.
36
+ # Returns a Tuple of (backend_key, autograd_key, cpp_namespace, updated BackendIndex mapping)
37
+ ParsedExternalYaml = namedtuple(
38
+ "ParsedExternalYaml",
39
+ ["backend_key", "autograd_key", "class_name", "cpp_namespace", "backend_indices"],
40
+ )
41
+
42
+
43
+ def parse_backend_yaml(
44
+ backend_yaml_path: str,
45
+ grouped_native_functions: Sequence[NativeFunction | NativeFunctionsGroup],
46
+ backend_indices: dict[DispatchKey, BackendIndex],
47
+ ) -> ParsedExternalYaml:
48
+ native_functions_map: dict[OperatorName, NativeFunction] = {
49
+ f.func.name: f
50
+ for f in concatMap(
51
+ lambda f: [f] if isinstance(f, NativeFunction) else list(f.functions()),
52
+ grouped_native_functions,
53
+ )
54
+ }
55
+
56
+ with open(backend_yaml_path) as f:
57
+ yaml_values = yaml.load(f, Loader=YamlLoader)
58
+ assert isinstance(yaml_values, dict)
59
+
60
+ valid_keys = [
61
+ "backend",
62
+ "class_name",
63
+ "cpp_namespace",
64
+ "extra_headers",
65
+ "supported",
66
+ "autograd",
67
+ "full_codegen",
68
+ "non_native",
69
+ "ir_gen",
70
+ "symint",
71
+ ]
72
+
73
+ backend = yaml_values.pop("backend", None)
74
+ assert backend is not None, 'You must provide a value for "backend"'
75
+
76
+ class_name = yaml_values.pop("class_name", None)
77
+
78
+ cpp_namespace = yaml_values.pop("cpp_namespace", None)
79
+ assert cpp_namespace is not None, 'You must provide a value for "cpp_namespace"'
80
+
81
+ # Mostly just defaulting to false to stick with LazyTensor convention.
82
+ use_out_as_primary = yaml_values.pop("use_out_as_primary", False)
83
+ assert isinstance(
84
+ use_out_as_primary, bool
85
+ ), f"You must provide either True or False for use_out_as_primary. Provided: {use_out_as_primary}"
86
+
87
+ use_device_guard = yaml_values.pop("device_guard", False)
88
+ assert isinstance(
89
+ use_device_guard, bool
90
+ ), f"You must provide either True or False for device_guard. Provided: {use_device_guard}"
91
+
92
+ supported = yaml_values.pop("supported", [])
93
+ if supported is None:
94
+ supported = [] # Allow an empty list of supported ops
95
+ assert isinstance(
96
+ supported, list
97
+ ), f'expected "supported" to be a list, but got: {supported} (of type {type(supported)})'
98
+
99
+ symint = yaml_values.pop("symint", [])
100
+ if symint is None:
101
+ symint = [] # Allow an empty list of symint ops
102
+ assert isinstance(
103
+ symint, list
104
+ ), f'expected "symint" to be a list, but got: {supported} (of type {type(supported)})'
105
+ symint_set = set(symint)
106
+
107
+ supported_autograd = yaml_values.pop("autograd", [])
108
+ assert isinstance(
109
+ supported_autograd, list
110
+ ), f'expected "autograd" to be a list, but got: {supported_autograd}'
111
+
112
+ # full_codegen is ignored by parse_backend_yaml, and re-parsed in gen_lazy_tensor.py
113
+ full_codegen = yaml_values.pop("full_codegen", [])
114
+ supported.extend(full_codegen)
115
+
116
+ # non_native is ignored by parse_backend_yaml, and re-parsed in gen_lazy_tensor.py
117
+ yaml_values.pop("non_native", {})
118
+
119
+ # ir_gen is ignored by parse_backend_yaml, and re-parsed in gen_lazy_tensor.py
120
+ yaml_values.pop("ir_gen", {})
121
+
122
+ assert (
123
+ len(yaml_values.keys()) == 0
124
+ ), f'{backend_yaml_path} contains unexpected keys: {", ".join(yaml_values.keys())}. \
125
+ Only the following keys are supported: {", ".join(valid_keys)}'
126
+
127
+ def create_backend_index(
128
+ backend_ops: list[str],
129
+ symint_ops: set[str],
130
+ dispatch_key: DispatchKey,
131
+ *,
132
+ use_out_as_primary: bool,
133
+ use_device_guard: bool,
134
+ ) -> BackendIndex:
135
+ metadata: dict[OperatorName, BackendMetadata] = {}
136
+ for op in backend_ops:
137
+ op_name = OperatorName.parse(op)
138
+ assert (
139
+ op_name in native_functions_map
140
+ ), f"Found an invalid operator name: {op_name}"
141
+ # See Note [External Backends Follow Dispatcher API]
142
+ kernel_name = dispatcher.name(native_functions_map[op_name].func)
143
+ if op in symint_ops:
144
+ kernel_name += "_symint"
145
+ # TODO: allow structured external backends later.
146
+ m = BackendMetadata(
147
+ kernel=kernel_name, structured=False, cpp_namespace=cpp_namespace
148
+ )
149
+ metadata[op_name] = m
150
+ return BackendIndex(
151
+ dispatch_key=dispatch_key,
152
+ use_out_as_primary=use_out_as_primary,
153
+ external=True,
154
+ device_guard=use_device_guard,
155
+ index=metadata,
156
+ )
157
+
158
+ backend_key: DispatchKey | None = None
159
+ if len(supported) > 0:
160
+ with context(
161
+ lambda: f'The provided value for "backend" must be a valid DispatchKey, but got {backend}.'
162
+ ):
163
+ backend_key = DispatchKey.parse(backend)
164
+
165
+ backend_idx = create_backend_index(
166
+ supported,
167
+ symint_set,
168
+ backend_key,
169
+ use_out_as_primary=use_out_as_primary,
170
+ use_device_guard=use_device_guard,
171
+ )
172
+ assert backend_key not in backend_indices
173
+ backend_indices[backend_key] = backend_idx
174
+
175
+ autograd_key: DispatchKey | None = None
176
+ if len(supported_autograd) > 0:
177
+ with context(
178
+ lambda: f'The "autograd" key was specified, which indicates that you would like to override \
179
+ the behavior of autograd for some operators on your backend. However "Autograd{backend}" is not a valid DispatchKey.'
180
+ ):
181
+ autograd_key = DispatchKey.parse(f"Autograd{backend}")
182
+
183
+ autograd_idx = create_backend_index(
184
+ supported_autograd,
185
+ symint_set,
186
+ autograd_key,
187
+ use_out_as_primary=use_out_as_primary,
188
+ use_device_guard=use_device_guard,
189
+ )
190
+ assert autograd_key not in backend_indices
191
+ backend_indices[autograd_key] = autograd_idx
192
+
193
+ for g in grouped_native_functions:
194
+ if isinstance(g, NativeFunction):
195
+ forward_kernels = (
196
+ []
197
+ if backend_key is None
198
+ else [
199
+ m
200
+ for m in [backend_indices[backend_key].get_kernel(g)]
201
+ if m is not None
202
+ ]
203
+ )
204
+ backward_kernels = (
205
+ []
206
+ if autograd_key is None
207
+ else [
208
+ m
209
+ for m in [backend_indices[autograd_key].get_kernel(g)]
210
+ if m is not None
211
+ ]
212
+ )
213
+ else:
214
+ forward_kernels = (
215
+ []
216
+ if backend_key is None
217
+ else [
218
+ m
219
+ for m in [
220
+ backend_indices[backend_key].get_kernel(f)
221
+ for f in g.functions()
222
+ ]
223
+ if m is not None
224
+ ]
225
+ )
226
+ backward_kernels = (
227
+ []
228
+ if autograd_key is None
229
+ else [
230
+ m
231
+ for m in [
232
+ backend_indices[autograd_key].get_kernel(f)
233
+ for f in g.functions()
234
+ ]
235
+ if m is not None
236
+ ]
237
+ )
238
+
239
+ forward_kernels = [f for f in forward_kernels if f is not None]
240
+ backward_kernels = [f for f in backward_kernels if f is not None]
241
+ assert (
242
+ len(forward_kernels) == 0 or len(backward_kernels) == 0
243
+ ), f'Currently, all variants of an op must either be registered to a backend key, or to a backend\'s \
244
+ autograd key. They cannot be mix and matched. If this is something you need, feel free to create an issue! \
245
+ {forward_kernels[0].kernel} is listed under "supported", but {backward_kernels[0].kernel} is listed under "autograd".'
246
+
247
+ return ParsedExternalYaml(
248
+ backend_key, autograd_key, class_name, cpp_namespace, backend_indices
249
+ )
250
+
251
+
252
+ def error_on_missing_kernels(
253
+ native_functions: Sequence[NativeFunction],
254
+ backend_indices: dict[DispatchKey, BackendIndex],
255
+ backend_key: DispatchKey,
256
+ autograd_key: DispatchKey | None,
257
+ class_name: str,
258
+ kernel_defn_file_path: str,
259
+ full_codegen: list[OperatorName] | None = None,
260
+ ) -> None:
261
+ try:
262
+ with open(kernel_defn_file_path) as f:
263
+ backend_defns = f.read()
264
+ except OSError as e:
265
+ raise AssertionError(
266
+ f"Unable to read from the specified impl_path file: {kernel_defn_file_path}"
267
+ ) from e
268
+
269
+ if full_codegen is None:
270
+ full_codegen = []
271
+
272
+ indices = [backend_indices[backend_key].index] + (
273
+ [] if autograd_key is None else [backend_indices[autograd_key].index]
274
+ )
275
+ # Quick mapping from each OperatorName used by the external backend
276
+ # to its backend kernel name
277
+ expected_backend_op_names: dict[OperatorName, str] = dict(
278
+ list(
279
+ concatMap(
280
+ lambda index: [
281
+ (op_name, metadata.kernel) for op_name, metadata in index.items()
282
+ ],
283
+ indices,
284
+ )
285
+ )
286
+ )
287
+ expected_backend_native_funcs: list[NativeFunction] = [
288
+ f
289
+ for f in native_functions
290
+ if f.func.name in expected_backend_op_names.keys()
291
+ and f.func.name not in full_codegen
292
+ ]
293
+ expected_backend_kernel_name_counts: dict[str, list[NativeFunction]] = defaultdict(
294
+ list
295
+ )
296
+ for native_f in expected_backend_native_funcs:
297
+ expected_backend_kernel_name_counts[
298
+ expected_backend_op_names[native_f.func.name]
299
+ ].append(native_f)
300
+
301
+ # This just looks for lines containing "foo(", and assumes that the kernel foo has been implemented.
302
+ # It might cause false negatives (we won't catch all cases), but that's ok - if we catch a missing kernel
303
+ # here, then we get a nicer error message. If we miss it, you get a linker error.
304
+ kernel_defn_regex = rf"(.*){class_name}::\s*([\w\d]*)\("
305
+ actual_backend_kernel_name_counts = Counter(
306
+ # A bit unwieldy (this could probably be moved into regex),
307
+ # but we don't want to include kernel names that come from function calls,
308
+ # like "return torch_xla::XLANativeFunctions::empty_strided_symint(...)".
309
+ # Easy check is to ignore any lines with colons before the class name.
310
+ [
311
+ y
312
+ for (x, y) in re.findall(kernel_defn_regex, backend_defns)
313
+ if not x.endswith(":")
314
+ ]
315
+ )
316
+
317
+ missing_kernels_err_msg = ""
318
+ for expected_name, funcs in expected_backend_kernel_name_counts.items():
319
+ expected_overload_count = len(funcs)
320
+ actual_overload_count = actual_backend_kernel_name_counts[expected_name]
321
+ if expected_overload_count != actual_overload_count:
322
+
323
+ def create_decl(f: NativeFunction) -> str:
324
+ with native_function_manager(f):
325
+ return DispatcherSignature.from_schema(f.func).decl()
326
+
327
+ expected_schemas_str = "\n".join([create_decl(f) for f in funcs])
328
+ missing_kernels_err_msg += f"""
329
+ {class_name} is missing a kernel definition for {expected_name}. We found {actual_overload_count} kernel(s) with that name,
330
+ but expected {expected_overload_count} kernel(s). The expected function schemas for the missing operator are:
331
+ {expected_schemas_str}
332
+
333
+ """
334
+ assert missing_kernels_err_msg == "", missing_kernels_err_msg
335
+
336
+
337
+ def main() -> None:
338
+ parser = argparse.ArgumentParser(description="Generate backend stub files")
339
+ parser.add_argument(
340
+ "-s",
341
+ "--source-yaml",
342
+ "--source_yaml",
343
+ help="path to source yaml file containing operator external definitions",
344
+ )
345
+ parser.add_argument("-o", "--output-dir", "--output_dir", help="output directory")
346
+ parser.add_argument(
347
+ "--dry-run", "--dry_run", type=bool, default=False, help="output directory"
348
+ )
349
+ parser.add_argument(
350
+ "--impl-path",
351
+ "--impl_path",
352
+ type=str,
353
+ default=None,
354
+ help="path to the source C++ file containing kernel definitions",
355
+ )
356
+ options = parser.parse_args()
357
+
358
+ run(options.source_yaml, options.output_dir, options.dry_run, options.impl_path)
359
+
360
+
361
+ def gen_dispatchkey_nativefunc_headers(
362
+ fm: FileManager,
363
+ class_name: str,
364
+ cpp_namespace: str,
365
+ backend_indices: dict[DispatchKey, BackendIndex],
366
+ grouped_native_functions: Sequence[NativeFunction | NativeFunctionsGroup],
367
+ backend_dispatch_key: DispatchKey,
368
+ autograd_dispatch_key: DispatchKey | None,
369
+ backend_name: str = "",
370
+ ) -> None:
371
+ assert class_name is not None
372
+ generated_comment = (
373
+ "Autogenerated file by gen_backend_stubs.py. Do not edit directly!"
374
+ )
375
+
376
+ # Convert to a set first to remove duplicate kernel names.
377
+ # Backends are allowed to repeat kernel names; only generate the declaration once!
378
+ # Sort for deterministic output.
379
+ backend_declarations = sorted(
380
+ set(
381
+ concatMap(
382
+ lambda f: dest.compute_native_function_declaration(
383
+ f, backend_indices[backend_dispatch_key]
384
+ ),
385
+ grouped_native_functions,
386
+ )
387
+ )
388
+ )
389
+ autograd_declarations = sorted(
390
+ set(
391
+ concatMap(
392
+ lambda f: []
393
+ if autograd_dispatch_key is None
394
+ else dest.compute_native_function_declaration(
395
+ f, backend_indices[autograd_dispatch_key]
396
+ ),
397
+ grouped_native_functions,
398
+ )
399
+ )
400
+ )
401
+
402
+ ns_helper = NamespaceHelper(cpp_namespace)
403
+ fm.write_with_template(
404
+ f"{backend_dispatch_key}NativeFunctions.h",
405
+ "DispatchKeyNativeFunctions.h",
406
+ lambda: {
407
+ "generated_comment": generated_comment,
408
+ "namespace_prologue": ns_helper.prologue,
409
+ "class_name": class_name,
410
+ "namespace_epilogue": ns_helper.epilogue,
411
+ "dispatch_declarations": backend_declarations + autograd_declarations,
412
+ "BackendName": backend_name,
413
+ "DispatchKey": backend_dispatch_key,
414
+ },
415
+ )
416
+
417
+
418
+ def gen_dispatcher_registrations(
419
+ fm: FileManager,
420
+ output_dir: str,
421
+ class_name: str,
422
+ backend_indices: dict[DispatchKey, BackendIndex],
423
+ grouped_native_functions: Sequence[NativeFunction | NativeFunctionsGroup],
424
+ backend_dispatch_key: DispatchKey,
425
+ dispatch_key: DispatchKey,
426
+ selector: SelectiveBuilder,
427
+ # build_in_tree is true for lazy TS backend and affects include paths, not used for external backends
428
+ build_in_tree: bool = False,
429
+ per_operator_headers: bool = False,
430
+ backend_name: str = "",
431
+ eager_registration: bool = True,
432
+ ) -> None:
433
+ headers = [
434
+ f"{output_dir}/{backend_dispatch_key}NativeFunctions.h",
435
+ ]
436
+ if build_in_tree:
437
+ external_backend_headers_str = "\n".join(f"#include <{h}>" for h in headers)
438
+ else:
439
+ external_backend_headers_str = "\n".join(f'#include "{h}"' for h in headers)
440
+
441
+ assert class_name is not None
442
+ backend_index = backend_indices[dispatch_key]
443
+
444
+ dispatch_registrations_body = list(
445
+ concatMap(
446
+ dest.RegisterDispatchKey(
447
+ backend_index,
448
+ Target.REGISTRATION,
449
+ selector,
450
+ rocm=False,
451
+ symint=True,
452
+ class_method_name=f"{class_name}",
453
+ skip_dispatcher_op_registration=False,
454
+ ),
455
+ grouped_native_functions,
456
+ )
457
+ )
458
+ newline = "\n"
459
+ ns_helper = NamespaceHelper(namespace_str="at")
460
+ deferred_dispatch_registrations = ""
461
+ static_init_dispatch_registrations = ""
462
+ if eager_registration:
463
+ static_template = CodeTemplate(
464
+ """\
465
+ TORCH_LIBRARY_IMPL(aten, $dispatch_key, m) {
466
+ $dispatch_registrations_body
467
+ }"""
468
+ )
469
+ static_init_dispatch_registrations = static_template.substitute(
470
+ dispatch_key=dispatch_key,
471
+ dispatch_registrations_body=dispatch_registrations_body,
472
+ )
473
+ else:
474
+ deferred_template = CodeTemplate(
475
+ """\
476
+ TORCH_API void Register${backend_name}${dispatch_key}NativeFunctions();
477
+ TORCH_API void Register${backend_name}${dispatch_key}NativeFunctions() {
478
+ static auto m = MAKE_TORCH_LIBRARY_IMPL(aten, $dispatch_key);
479
+ $dispatch_registrations_body
480
+ }"""
481
+ )
482
+ deferred_dispatch_registrations = deferred_template.substitute(
483
+ backend_name=backend_name,
484
+ dispatch_key=dispatch_key,
485
+ dispatch_registrations_body=dispatch_registrations_body,
486
+ )
487
+
488
+ fm.write_with_template(
489
+ f"Register{dispatch_key}.cpp",
490
+ "RegisterDispatchKey.cpp",
491
+ lambda: {
492
+ "extra_cuda_headers": "",
493
+ "external_backend_headers": external_backend_headers_str,
494
+ "ops_headers": "#include <ATen/Functions.h>"
495
+ if not per_operator_headers
496
+ else "",
497
+ "DispatchKey": dispatch_key,
498
+ "dispatch_namespace": dispatch_key.lower(),
499
+ "dispatch_headers": dest.gen_registration_headers(
500
+ backend_index, per_operator_headers=per_operator_headers, rocm=False
501
+ ),
502
+ "dispatch_definitions": fm.substitute_with_template(
503
+ "RegisterDispatchDefinitions.ini",
504
+ lambda: {
505
+ "ns_prologue": ns_helper.prologue,
506
+ "ns_epilogue": ns_helper.epilogue,
507
+ "static_init_dispatch_registrations": static_init_dispatch_registrations,
508
+ "deferred_dispatch_registrations": deferred_dispatch_registrations,
509
+ "dispatch_helpers": dest.gen_registration_helpers(backend_index),
510
+ "dispatch_namespace": dispatch_key.lower(),
511
+ "dispatch_namespaced_definitions": "",
512
+ "dispatch_anonymous_definitions": list(
513
+ concatMap(
514
+ dest.RegisterDispatchKey(
515
+ backend_index,
516
+ Target.ANONYMOUS_DEFINITION,
517
+ selector,
518
+ rocm=False,
519
+ symint=True,
520
+ class_method_name=f"{class_name}",
521
+ skip_dispatcher_op_registration=False,
522
+ ),
523
+ grouped_native_functions,
524
+ )
525
+ ),
526
+ },
527
+ ).split(newline),
528
+ },
529
+ )
530
+
531
+
532
+ def run(
533
+ source_yaml: str, output_dir: str, dry_run: bool, impl_path: str | None = None
534
+ ) -> None:
535
+ # Assumes that this file lives at PYTORCH_ROOT/torchgen/gen_backend_stubs.py
536
+ pytorch_root = Path(__file__).parent.parent.absolute()
537
+ template_dir = os.path.join(pytorch_root, "aten/src/ATen/templates")
538
+
539
+ def make_file_manager(install_dir: str) -> FileManager:
540
+ return FileManager(
541
+ install_dir=install_dir, template_dir=template_dir, dry_run=dry_run
542
+ )
543
+
544
+ fm = make_file_manager(output_dir)
545
+
546
+ native_yaml_path = os.path.join(
547
+ pytorch_root, "aten/src/ATen/native/native_functions.yaml"
548
+ )
549
+ tags_yaml_path = os.path.join(pytorch_root, "aten/src/ATen/native/tags.yaml")
550
+ parsed_yaml = parse_native_yaml(native_yaml_path, tags_yaml_path)
551
+ native_functions, backend_indices = (
552
+ parsed_yaml.native_functions,
553
+ parsed_yaml.backend_indices,
554
+ )
555
+ grouped_native_functions = get_grouped_native_functions(native_functions)
556
+ parsed_backend_yaml = parse_backend_yaml(
557
+ source_yaml, grouped_native_functions, backend_indices
558
+ )
559
+ backend_key = parsed_backend_yaml.backend_key
560
+ autograd_key = parsed_backend_yaml.autograd_key
561
+ cpp_namespace = parsed_backend_yaml.cpp_namespace
562
+ class_name = parsed_backend_yaml.class_name
563
+ backend_indices = parsed_backend_yaml.backend_indices
564
+
565
+ selector = SelectiveBuilder.get_nop_selector()
566
+
567
+ if backend_key is None:
568
+ # This could be useful if a backend wants to quickly set up a noop yaml file but doesn't have any kernels ready yet.
569
+ return
570
+
571
+ if class_name is None:
572
+ # class_name is an optional argument to backend yaml file.
573
+ # if specified it allows an external backend to override
574
+ # the name of the class that all generated kernel definitions live under.
575
+ # if not specified, its value is given as native_function_class_name.
576
+ class_name = backend_indices[backend_key].native_function_class_name()
577
+ assert class_name is not None
578
+
579
+ if impl_path is not None:
580
+ error_on_missing_kernels(
581
+ native_functions,
582
+ backend_indices,
583
+ backend_key,
584
+ autograd_key,
585
+ class_name,
586
+ impl_path,
587
+ )
588
+
589
+ gen_dispatchkey_nativefunc_headers(
590
+ fm,
591
+ class_name,
592
+ cpp_namespace,
593
+ backend_indices,
594
+ grouped_native_functions,
595
+ backend_key,
596
+ autograd_key,
597
+ )
598
+
599
+ for dispatch_key in (
600
+ [backend_key] if autograd_key is None else [backend_key, autograd_key]
601
+ ):
602
+ gen_dispatcher_registrations(
603
+ fm,
604
+ output_dir,
605
+ class_name,
606
+ backend_indices,
607
+ grouped_native_functions,
608
+ backend_key,
609
+ dispatch_key,
610
+ selector,
611
+ )
612
+
613
+
614
+ if __name__ == "__main__":
615
+ main()
gen_executorch.py ADDED
@@ -0,0 +1,1000 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import os
5
+ from collections import defaultdict
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Any, Callable, TextIO, TYPE_CHECKING
9
+
10
+ import yaml
11
+
12
+ # Parse native_functions.yaml into a sequence of NativeFunctions and Backend Indices.
13
+ from torchgen import dest
14
+ from torchgen.api import cpp as aten_cpp
15
+ from torchgen.api.types import CppSignature, CppSignatureGroup, CType, NamedCType
16
+ from torchgen.context import (
17
+ method_with_native_function,
18
+ method_with_nested_native_function,
19
+ with_native_function_and_index,
20
+ )
21
+ from torchgen.executorch.api import et_cpp
22
+ from torchgen.executorch.api.custom_ops import (
23
+ ComputeNativeFunctionStub,
24
+ gen_custom_ops_registration,
25
+ )
26
+ from torchgen.executorch.api.types import contextArg, ExecutorchCppSignature
27
+ from torchgen.executorch.api.unboxing import Unboxing
28
+ from torchgen.executorch.model import ETKernelIndex, ETKernelKey, ETParsedYaml
29
+ from torchgen.executorch.parse import ET_FIELDS, parse_et_yaml, parse_et_yaml_struct
30
+ from torchgen.gen import (
31
+ get_custom_build_selector,
32
+ get_native_function_declarations,
33
+ get_native_function_declarations_from_ns_grouped_kernels,
34
+ get_native_function_schema_registrations,
35
+ LineLoader,
36
+ parse_native_yaml,
37
+ )
38
+ from torchgen.model import (
39
+ BackendIndex,
40
+ BackendMetadata,
41
+ DEFAULT_KERNEL_NAMESPACE,
42
+ DispatchKey,
43
+ FunctionSchema,
44
+ Location,
45
+ NativeFunction,
46
+ NativeFunctionsGroup,
47
+ OperatorName,
48
+ Variant,
49
+ )
50
+ from torchgen.utils import (
51
+ context,
52
+ FileManager,
53
+ make_file_manager,
54
+ mapMaybe,
55
+ NamespaceHelper,
56
+ )
57
+
58
+
59
+ if TYPE_CHECKING:
60
+ from collections.abc import Sequence
61
+
62
+ from torchgen.selective_build.selector import SelectiveBuilder
63
+
64
+
65
+ def _sig_decl_wrapper(sig: CppSignature | ExecutorchCppSignature) -> str:
66
+ """
67
+ A wrapper function to basically get `sig.decl(include_context=True)`.
68
+ For ATen kernel, the codegen has no idea about ET contextArg, so we
69
+ use this wrapper to add it.
70
+ """
71
+ if isinstance(sig, ExecutorchCppSignature):
72
+ return sig.decl()
73
+
74
+ returns_type = aten_cpp.returns_type(sig.func.returns).cpp_type()
75
+ cpp_args = [a.decl() for a in sig.arguments()]
76
+ cpp_args_str = ", ".join([contextArg.decl()] + cpp_args)
77
+ sig_decl = f"{returns_type} {sig.name()}({cpp_args_str})"
78
+ return sig_decl
79
+
80
+
81
+ def static_dispatch(
82
+ sig: CppSignature | ExecutorchCppSignature,
83
+ f: NativeFunction,
84
+ backend_indices: list[BackendIndex],
85
+ ) -> str:
86
+ """
87
+ For a given `NativeFunction`, find out the corresponding native function and dispatch to it. If zero or more than one
88
+ native function exists, error out. A simplified version of register_dispatch_key.py
89
+ Arguments:
90
+ sig: A CppSignature for this native function we want to use.
91
+ f: NativeFunction to generate static dispatch.
92
+ backend_indices: All available backends.
93
+ Return:
94
+ C++ code to call backend-specific functions, e.g., "return at::native::add(self, other, scale);"
95
+ """
96
+ if len(backend_indices) == 0 or f.manual_kernel_registration:
97
+ return ""
98
+
99
+ backends = [b for b in backend_indices if b.has_kernel(f)]
100
+ static_block = None
101
+ if len(backends) == 1:
102
+ backend_metadata = backends[0].get_kernel(f)
103
+ if backend_metadata:
104
+ args = ", ".join(a.name for a in sig.arguments())
105
+ # Here we are assuming there's no difference between CppSignature and NativeSignature for Executorch.
106
+ static_block = f"return ::{backend_metadata.cpp_namespace}::{backend_metadata.kernel}({args});"
107
+ else:
108
+ static_block = f"""
109
+ ET_ASSERT_UNREACHABLE_MSG("The number of native function(s) binding to {f.func.name} is {len(backends)}.");
110
+ """
111
+ return f"""
112
+ // {f.namespace}::{f.func}
113
+ TORCH_API inline {_sig_decl_wrapper(sig)} {{
114
+ {static_block}
115
+ }}
116
+ """
117
+
118
+
119
+ # Generates Functions.h, which provides the functional public C++ API,
120
+ # and the scaffolding to call into the dispatcher from these functions.
121
+ @dataclass(frozen=True)
122
+ class ComputeFunction:
123
+ static_dispatch_backend_indices: list[BackendIndex]
124
+
125
+ selector: SelectiveBuilder
126
+
127
+ use_aten_lib: bool
128
+
129
+ is_custom_op: Callable[[NativeFunction], bool]
130
+
131
+ @method_with_native_function
132
+ def __call__(self, f: NativeFunction) -> str | None:
133
+ is_method_variant = False
134
+ if not self.selector.is_root_operator(f"{f.namespace}::{f.func.name}"):
135
+ return None
136
+
137
+ if Variant.function not in f.variants and Variant.method in f.variants:
138
+ is_method_variant = True
139
+
140
+ # only valid remaining case is only function is in f.variants
141
+ elif not (Variant.function in f.variants and Variant.method not in f.variants):
142
+ raise Exception( # noqa: TRY002
143
+ f"Can't handle native function {f.func} with the following variant specification {f.variants}."
144
+ )
145
+
146
+ sig: CppSignature | ExecutorchCppSignature = (
147
+ CppSignatureGroup.from_native_function(
148
+ f, method=False, fallback_binding=f.manual_cpp_binding
149
+ ).most_faithful_signature()
150
+ if self.use_aten_lib
151
+ else ExecutorchCppSignature.from_native_function(f)
152
+ )
153
+ if self.use_aten_lib and not self.is_custom_op(f):
154
+ comma = ", "
155
+
156
+ if is_method_variant:
157
+ return f"""
158
+ // {f.namespace}::{f.func}
159
+ TORCH_API inline {_sig_decl_wrapper(sig)} {{
160
+ return {sig.arguments()[0].name}.{sig.name()}({comma.join(e.name for e in sig.arguments()[1:])});
161
+ }}
162
+ """
163
+ else:
164
+ return f"""
165
+ // {f.namespace}::{f.func}
166
+ TORCH_API inline {_sig_decl_wrapper(sig)} {{
167
+ return at::{sig.name()}({comma.join(e.name for e in sig.arguments())});
168
+ }}
169
+ """
170
+
171
+ else:
172
+ return static_dispatch(
173
+ sig,
174
+ f,
175
+ backend_indices=self.static_dispatch_backend_indices,
176
+ )
177
+
178
+
179
+ # Generates RegisterCodegenUnboxedKernels.cpp.
180
+ @dataclass(frozen=True)
181
+ class ComputeCodegenUnboxedKernels:
182
+ selector: SelectiveBuilder
183
+
184
+ use_aten_lib: bool
185
+
186
+ @method_with_nested_native_function
187
+ def __call__(
188
+ self,
189
+ unbox_kernel_entry: tuple[NativeFunction, tuple[ETKernelKey, BackendMetadata]],
190
+ ) -> str:
191
+ f: NativeFunction = unbox_kernel_entry[0]
192
+ kernel_key: ETKernelKey | list[ETKernelKey] = unbox_kernel_entry[1][0]
193
+ kernel_meta: BackendMetadata = unbox_kernel_entry[1][1]
194
+
195
+ op_name = f"{f.namespace}::{f.func.name}"
196
+ if not self.selector.is_root_operator(op_name):
197
+ return ""
198
+
199
+ if not isinstance(kernel_key, list):
200
+ kernel_key = [kernel_key]
201
+ used_kernel_keys = self.selector.et_get_selected_kernels(
202
+ op_name, [k.to_native_string() for k in kernel_key]
203
+ )
204
+ if not used_kernel_keys:
205
+ return ""
206
+ sig: CppSignature | ExecutorchCppSignature
207
+ argument_type_gen: Callable[..., NamedCType]
208
+ return_type_gen: Callable[..., CType]
209
+ if self.use_aten_lib:
210
+ sig = CppSignatureGroup.from_native_function(
211
+ f, method=False, fallback_binding=f.manual_cpp_binding
212
+ ).most_faithful_signature()
213
+ argument_type_gen = aten_cpp.argumenttype_type
214
+ return_type_gen = aten_cpp.returns_type
215
+ arguments = sig.arguments()
216
+ kernel_call = f"torch::executor::{f.namespace}::{sig.name()}"
217
+ else:
218
+ sig = ExecutorchCppSignature.from_native_function(f)
219
+ argument_type_gen = et_cpp.argumenttype_type
220
+ return_type_gen = et_cpp.returns_type
221
+ arguments = sig.arguments(include_context=False)
222
+ kernel_call = f"{kernel_meta.cpp_namespace}::{kernel_meta.kernel}"
223
+ # parse arguments into C++ code
224
+ binding_list, code_list = Unboxing(
225
+ argument_type_gen=argument_type_gen
226
+ ).convert_arguments(arguments)
227
+
228
+ # for each C++ argument, generate the conversion code
229
+ code_connector = "\n\t"
230
+ arg_connector = ", "
231
+
232
+ args_str = f"{arg_connector.join(e.name for e in binding_list)}"
233
+ event_tracer_output_logging = ""
234
+ output_ids = []
235
+
236
+ if len(f.func.returns) == 0:
237
+ if len(f.func.arguments.out) == 0:
238
+ raise Exception( # noqa: TRY002
239
+ f"Can't handle native function {f.func} with no returns and no out yet."
240
+ )
241
+ out = f.func.arguments.out[0]
242
+ return_assignment = f"""stack[{len(binding_list)}] = &{out.name};"""
243
+ ret_prefix = ""
244
+ output_ids = [len(binding_list)]
245
+ else:
246
+ if len(f.func.arguments.out) == 0:
247
+ return_assignment = (
248
+ f"""*stack[{len(binding_list)}] = EValue(result_);"""
249
+ )
250
+ ret_prefix = return_type_gen(f.func.returns).cpp_type() + " result_ = "
251
+ output_ids = [len(binding_list)]
252
+ else:
253
+ return_assignment = ""
254
+ ret_prefix = ""
255
+ output_ids = [
256
+ len(binding_list) - (i + 1)
257
+ for i in reversed(range(len(f.func.arguments.out)))
258
+ ]
259
+
260
+ for output_id in output_ids:
261
+ event_tracer_output_logging += (
262
+ f"internal::event_tracer_log_evalue("
263
+ f"context.internal_event_tracer(), "
264
+ f"*stack[{output_id}]);\n"
265
+ )
266
+
267
+ newline = "\n "
268
+ return "\n".join(
269
+ [
270
+ f"""
271
+ Kernel(
272
+ "{f.namespace}::{f.func.name}",{newline + '"' + (k + '",') if k != 'default' else ''}
273
+ []({contextArg.defn()}, EValue** stack) {{
274
+ {code_connector.join(code_list)}
275
+
276
+ internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_{f.func.name}");
277
+ EXECUTORCH_SCOPE_PROF("native_call_{f.func.name}");
278
+ {ret_prefix}{kernel_call}(context, {args_str});
279
+ {event_tracer_output_logging}
280
+ {return_assignment}
281
+ }}
282
+ ),
283
+ """
284
+ for k in used_kernel_keys
285
+ ]
286
+ )
287
+
288
+
289
+ def gen_unboxing(
290
+ *,
291
+ native_functions: Sequence[NativeFunction],
292
+ cpu_fm: FileManager,
293
+ selector: SelectiveBuilder,
294
+ use_aten_lib: bool,
295
+ kernel_index: ETKernelIndex,
296
+ manual_registration: bool,
297
+ ) -> None:
298
+ # Iterable type for write_sharded is a Tuple of (native_function, (kernel_key, metadata))
299
+ def key_func(
300
+ item: tuple[NativeFunction, tuple[ETKernelKey, BackendMetadata]],
301
+ ) -> str:
302
+ return item[0].root_name + ":" + item[1][0].to_native_string()
303
+
304
+ items: list[tuple[NativeFunction, tuple[ETKernelKey, BackendMetadata]]] = [
305
+ (native_function, (kernel_key, metadata))
306
+ for native_function in native_functions
307
+ for kernel_key, metadata in kernel_index.get_kernels(native_function).items()
308
+ ]
309
+
310
+ header = ["Functions.h" if use_aten_lib else "NativeFunctions.h"]
311
+ filename = (
312
+ "RegisterKernels.cpp"
313
+ if manual_registration
314
+ else "RegisterCodegenUnboxedKernels.cpp"
315
+ )
316
+ cpu_fm.write_sharded(
317
+ filename,
318
+ items,
319
+ key_fn=key_func,
320
+ env_callable=lambda unbox_kernel_entry: {
321
+ "unboxed_kernels": [
322
+ ComputeCodegenUnboxedKernels(selector, use_aten_lib)(unbox_kernel_entry)
323
+ ],
324
+ "fn_header": header
325
+ if unbox_kernel_entry == items[0]
326
+ else [], # Only write header once
327
+ },
328
+ num_shards=1,
329
+ sharded_keys={"unboxed_kernels", "fn_header"},
330
+ )
331
+
332
+
333
+ @with_native_function_and_index # type: ignore[arg-type]
334
+ def compute_native_function_declaration(
335
+ g: NativeFunctionsGroup | NativeFunction, kernel_index: ETKernelIndex
336
+ ) -> list[str]:
337
+ assert isinstance(g, NativeFunction)
338
+ sig = ExecutorchCppSignature.from_native_function(f=g)
339
+ metadata_list = kernel_index.get_kernels(g).values()
340
+ if metadata_list is None:
341
+ return []
342
+
343
+ # for kernels in lean mode, we declare two versions, one with context and one without.
344
+ # In the end we will cleanup the unused one.
345
+ def gen_decl(metadata: BackendMetadata, include_context: bool) -> str:
346
+ return f"{sig.decl(name=metadata.kernel, include_context=include_context)};"
347
+
348
+ return [
349
+ gen_decl(metadata, include_context)
350
+ for include_context in [False, True]
351
+ for metadata in metadata_list
352
+ ]
353
+
354
+
355
+ def gen_functions_declarations(
356
+ *,
357
+ native_functions: Sequence[NativeFunction],
358
+ kernel_index: ETKernelIndex,
359
+ selector: SelectiveBuilder,
360
+ use_aten_lib: bool,
361
+ custom_ops_native_functions: Sequence[NativeFunction] | None = None,
362
+ ) -> str:
363
+ """
364
+ Generates namespace separated C++ function API inline declaration/definitions.
365
+ Native functions are grouped by namespaces and the generated code is wrapped inside
366
+ namespace blocks.
367
+
368
+ E.g., for `custom_1::foo.out` in yaml file we will generate a C++ API as a symbol
369
+ in `torch::executor::custom_1::foo_out`. This way we avoid symbol conflict when
370
+ the other `custom_2::foo.out` is available.
371
+ """
372
+
373
+ # convert kernel index to BackendIndex. This is because we can't handle ETKernelIndex yet.
374
+ # TODO larryliu: evaluate if this code is still needed. If yes let it handle ETKernelIndex.
375
+
376
+ backend_index = kernel_index._to_backend_index()
377
+
378
+ ns_grouped_functions = defaultdict(list)
379
+ for native_function in native_functions:
380
+ ns_grouped_functions[native_function.namespace].append(native_function)
381
+ functions_declarations = ""
382
+ newline = "\n"
383
+ for namespace in ns_grouped_functions:
384
+ ns_helper = NamespaceHelper(
385
+ namespace_str=namespace,
386
+ entity_name="",
387
+ max_level=3,
388
+ )
389
+ declarations = list(
390
+ mapMaybe(
391
+ ComputeFunction(
392
+ static_dispatch_backend_indices=[backend_index],
393
+ selector=selector,
394
+ use_aten_lib=use_aten_lib,
395
+ is_custom_op=lambda f: custom_ops_native_functions is not None
396
+ and f in custom_ops_native_functions,
397
+ ),
398
+ ns_grouped_functions[namespace],
399
+ )
400
+ )
401
+ functions_declarations += f"""
402
+ {ns_helper.prologue}
403
+ {newline.join(declarations)}
404
+ {ns_helper.epilogue}
405
+ """
406
+ return functions_declarations
407
+
408
+
409
+ def get_ns_grouped_kernels(
410
+ *,
411
+ native_functions: Sequence[NativeFunction],
412
+ kernel_index: ETKernelIndex,
413
+ native_function_decl_gen: Callable[
414
+ [
415
+ NativeFunctionsGroup | NativeFunction,
416
+ ETKernelIndex,
417
+ ],
418
+ list[str],
419
+ ],
420
+ ) -> dict[str, list[str]]:
421
+ ns_grouped_kernels: dict[str, list[str]] = defaultdict(list)
422
+ for f in native_functions:
423
+ native_function_namespaces = set()
424
+ op_kernels = kernel_index.get_kernels(f)
425
+ for backend_metadata in op_kernels.values():
426
+ if backend_metadata:
427
+ namespace = backend_metadata.cpp_namespace
428
+ native_function_namespaces.add(namespace)
429
+ else:
430
+ namespace = DEFAULT_KERNEL_NAMESPACE
431
+ assert (
432
+ len(native_function_namespaces) <= 1
433
+ ), f"Codegen only supports one namespace per operator, got {native_function_namespaces}"
434
+ ns_grouped_kernels[namespace].extend(
435
+ native_function_decl_gen(f, kernel_index)
436
+ )
437
+ return ns_grouped_kernels
438
+
439
+
440
+ def gen_headers(
441
+ *,
442
+ native_functions: Sequence[NativeFunction],
443
+ gen_custom_ops_header: bool,
444
+ custom_ops_native_functions: Sequence[NativeFunction],
445
+ selector: SelectiveBuilder,
446
+ kernel_index: ETKernelIndex,
447
+ cpu_fm: FileManager,
448
+ use_aten_lib: bool,
449
+ ) -> None:
450
+ """Generate headers.
451
+
452
+ Args:
453
+ native_functions (Sequence[NativeFunction]): a collection of NativeFunction for ATen ops.
454
+ gen_custom_ops_header (bool): whether we should generate CustomOpsNativeFunctions.h
455
+ custom_ops_native_functions (Sequence[NativeFunction]): a collection of NativeFunction for custom ops.
456
+ kernel_index (ETKernelIndex): kernel collection
457
+ cpu_fm (FileManager): file manager manages output stream
458
+ use_aten_lib (bool): whether we are generating for PyTorch types or Executorch types.
459
+ """
460
+ aten_headers = ["#include <ATen/Functions.h>"]
461
+ backend_indices = {DispatchKey.CPU: kernel_index._to_backend_index()}
462
+ if gen_custom_ops_header:
463
+ cpu_fm.write_with_template(
464
+ "CustomOpsNativeFunctions.h",
465
+ "NativeFunctions.h",
466
+ lambda: {
467
+ "nativeFunctions_declarations": get_native_function_declarations(
468
+ grouped_native_functions=custom_ops_native_functions,
469
+ backend_indices=backend_indices,
470
+ native_function_decl_gen=dest.compute_native_function_declaration,
471
+ ),
472
+ "headers": [
473
+ "#include <ATen/ATen.h>",
474
+ "#include <torch/torch.h>",
475
+ ],
476
+ },
477
+ )
478
+ aten_headers.append('#include "CustomOpsNativeFunctions.h"')
479
+ cpu_fm.write(
480
+ "Functions.h",
481
+ lambda: {
482
+ "static_dispatch_extra_headers": aten_headers
483
+ if use_aten_lib
484
+ else ['#include "NativeFunctions.h"'],
485
+ "Functions_declarations": gen_functions_declarations(
486
+ native_functions=native_functions,
487
+ kernel_index=kernel_index,
488
+ selector=selector,
489
+ use_aten_lib=use_aten_lib,
490
+ custom_ops_native_functions=custom_ops_native_functions,
491
+ ),
492
+ },
493
+ )
494
+ cpu_fm.write(
495
+ "RegisterKernels.h",
496
+ lambda: {
497
+ "generated_comment": "@" + "generated by torchgen/gen_executorch.py",
498
+ },
499
+ )
500
+ headers = {
501
+ "headers": [
502
+ "#include <executorch/runtime/core/exec_aten/exec_aten.h> // at::Tensor etc.",
503
+ "#include <executorch/runtime/kernel/kernel_runtime_context.h>",
504
+ ],
505
+ }
506
+ if use_aten_lib:
507
+ headers["headers"].append("#include <executorch/codegen/macros.h> // TORCH_API")
508
+ cpu_fm.write(
509
+ "NativeFunctions.h",
510
+ lambda: dict(
511
+ {
512
+ "nativeFunctions_declarations": get_native_function_declarations(
513
+ grouped_native_functions=native_functions,
514
+ backend_indices=backend_indices,
515
+ native_function_decl_gen=dest.compute_native_function_declaration,
516
+ ),
517
+ },
518
+ **headers,
519
+ ),
520
+ )
521
+ else:
522
+ ns_grouped_kernels = get_ns_grouped_kernels(
523
+ native_functions=native_functions,
524
+ kernel_index=kernel_index,
525
+ native_function_decl_gen=compute_native_function_declaration, # type: ignore[arg-type]
526
+ )
527
+ cpu_fm.write(
528
+ "NativeFunctions.h",
529
+ lambda: dict(
530
+ {
531
+ "nativeFunctions_declarations": get_native_function_declarations_from_ns_grouped_kernels(
532
+ ns_grouped_kernels=ns_grouped_kernels,
533
+ ),
534
+ },
535
+ **headers,
536
+ ),
537
+ )
538
+
539
+
540
+ def gen_custom_ops(
541
+ *,
542
+ native_functions: Sequence[NativeFunction],
543
+ selector: SelectiveBuilder,
544
+ kernel_index: ETKernelIndex,
545
+ cpu_fm: FileManager,
546
+ rocm: bool,
547
+ ) -> None:
548
+ dispatch_key = DispatchKey.CPU
549
+ (
550
+ anonymous_definition,
551
+ static_init_dispatch_registrations,
552
+ ) = gen_custom_ops_registration(
553
+ native_functions=native_functions,
554
+ selector=selector,
555
+ kernel_index=kernel_index,
556
+ rocm=rocm,
557
+ )
558
+ cpu_fm.write_with_template(
559
+ f"Register{dispatch_key}CustomOps.cpp",
560
+ "RegisterDispatchKeyCustomOps.cpp",
561
+ lambda: {
562
+ "ops_headers": '#include "CustomOpsNativeFunctions.h"',
563
+ "DispatchKey": dispatch_key,
564
+ "dispatch_namespace": dispatch_key.lower(),
565
+ "dispatch_namespaced_definitions": "",
566
+ "dispatch_anonymous_definitions": anonymous_definition,
567
+ "static_init_dispatch_registrations": static_init_dispatch_registrations,
568
+ },
569
+ )
570
+ cpu_fm.write_with_template(
571
+ f"Register{dispatch_key}Stub.cpp",
572
+ "RegisterDispatchKeyCustomOps.cpp",
573
+ lambda: {
574
+ "ops_headers": "",
575
+ "DispatchKey": dispatch_key,
576
+ "dispatch_namespace": dispatch_key.lower(),
577
+ "dispatch_namespaced_definitions": "",
578
+ "dispatch_anonymous_definitions": list(
579
+ mapMaybe(ComputeNativeFunctionStub(), native_functions)
580
+ ),
581
+ "static_init_dispatch_registrations": static_init_dispatch_registrations,
582
+ },
583
+ )
584
+
585
+ (
586
+ aten_schema_registrations,
587
+ schema_registrations,
588
+ ) = get_native_function_schema_registrations(
589
+ native_functions=native_functions,
590
+ schema_selector=selector,
591
+ )
592
+ cpu_fm.write(
593
+ "RegisterSchema.cpp",
594
+ lambda: {
595
+ "schema_registrations": schema_registrations,
596
+ "aten_schema_registrations": aten_schema_registrations,
597
+ },
598
+ )
599
+
600
+
601
+ def translate_native_yaml(
602
+ tags_yaml_path: str,
603
+ aten_yaml_path: str,
604
+ native_yaml_path: str | None,
605
+ use_aten_lib: bool,
606
+ out_file: TextIO,
607
+ ) -> None:
608
+ """Translates Executorch DSL dialect to use the same syntax as
609
+ native_functions.yaml. The major difference is that Executorch DSL dialect
610
+ supports "op" key, where it refers to the operator name in native_functions.yaml.
611
+
612
+ For example, a functions.yaml may have the following entry:
613
+
614
+ - op: add.out
615
+ ...
616
+
617
+ It needs to be translated to the following:
618
+
619
+ - func: add.out(Tensor self, Tensor other, *, Scalar alpha=1, Tensor(a!) out) -> Tensor(a!)
620
+ ...
621
+
622
+ We go in aten_yaml_path and find the operator schema for "add.out" and add it
623
+ to the original functions.yaml. We also add required field "variants", where for
624
+ Executorch it will always be "function".
625
+
626
+ For ATen mode we don't have to do the translation because native_yaml_path is
627
+ the same as native_functions.yaml.
628
+
629
+ Args:
630
+ tags_yaml_path: Path to a tags.yaml file to satisfy codegen parsing.
631
+ It is not optional.
632
+ aten_yaml_path: Path to ATen operator yaml file native_functions.yaml.
633
+ native_yaml_path: Path to a functions.yaml file to parse.
634
+ If the path does not exist in the filesystem, it is treated as an
635
+ empty file. If `custom_ops_yaml_path` exists, the contents of that
636
+ file are appended to the yaml input to be parsed.
637
+ use_aten_lib: We use this flag to determine if we want to generate native
638
+ functions. In ATen mode we should generate out= variants.
639
+ out_file: The IO object that we are writing into.
640
+ Returns:
641
+ None
642
+ """
643
+ if use_aten_lib:
644
+ with open(aten_yaml_path) as aten_yaml:
645
+ out_file.writelines(aten_yaml.readlines())
646
+ return
647
+
648
+ native_functions, persisted_fields = parse_et_yaml(
649
+ aten_yaml_path,
650
+ tags_yaml_path,
651
+ None,
652
+ skip_native_fns_gen=False,
653
+ )
654
+
655
+ func_to_scoped_name: dict[FunctionSchema, str] = {
656
+ f.func: f"{f.namespace}::{f.func.name}" for f in native_functions
657
+ }
658
+ op_to_scoped_name: dict[OperatorName, str] = {
659
+ func.name: name for func, name in func_to_scoped_name.items()
660
+ }
661
+
662
+ schema_dict = {name: str(func) for func, name in func_to_scoped_name.items()}
663
+ kernel_persist_dict: dict[str, dict[str, Any]] = {
664
+ op_to_scoped_name[op]: v for op, v in persisted_fields.items()
665
+ }
666
+
667
+ if (
668
+ not native_yaml_path
669
+ or not os.path.exists(native_yaml_path)
670
+ or os.stat(native_yaml_path).st_size == 0
671
+ ):
672
+ return
673
+ with open(native_yaml_path) as native_yaml:
674
+ native_es = yaml.load(native_yaml, Loader=LineLoader)
675
+ if not native_es:
676
+ return
677
+ for e in native_es:
678
+ assert isinstance(e.get("__line__"), int), e
679
+ loc = Location(native_yaml_path, e.pop("__line__"))
680
+ with context(lambda: f"in {loc}:\n "):
681
+ if "variants" not in e:
682
+ e["variants"] = "function"
683
+ if "func" in e:
684
+ continue
685
+ assert isinstance(e.get("op"), str), e
686
+ opname = e.pop("op")
687
+ if "::" not in opname:
688
+ opname = "aten::" + opname
689
+ assert opname in schema_dict
690
+ e["func"] = schema_dict.get(opname)
691
+
692
+ # Write out persisted kernel information
693
+ if opname in kernel_persist_dict:
694
+ for k, v in kernel_persist_dict[opname].items():
695
+ e[k] = v
696
+
697
+ yaml.dump(native_es, out_file, width=1000)
698
+
699
+
700
+ def parse_yaml(
701
+ path: str | None,
702
+ tags_yaml_path: str,
703
+ function_filter: Callable[[NativeFunction], bool],
704
+ skip_native_fns_gen: bool = False,
705
+ ) -> tuple[
706
+ list[NativeFunction],
707
+ dict[DispatchKey, dict[OperatorName, BackendMetadata]] | ETKernelIndex,
708
+ ]:
709
+ if path and os.path.exists(path) and os.stat(path).st_size > 0:
710
+ with open(path) as f:
711
+ es = yaml.load(f, Loader=LineLoader)
712
+
713
+ # Check for kernel index structure
714
+ kernel_index = (
715
+ parse_et_yaml_struct(es) if any("kernels" in e for e in es) else None
716
+ )
717
+
718
+ # Remove ET specific fields from entries for BC compatibility
719
+ for entry in es:
720
+ for field in ET_FIELDS:
721
+ entry.pop(field, None)
722
+
723
+ parsed_yaml = parse_native_yaml(
724
+ path,
725
+ tags_yaml_path,
726
+ None,
727
+ skip_native_fns_gen=skip_native_fns_gen,
728
+ loaded_yaml=es,
729
+ )
730
+ native_functions = list(filter(function_filter, parsed_yaml.native_functions))
731
+ op_names = [f.func.name for f in native_functions]
732
+
733
+ # (1) Return ETKernelIndex if kernel index is present
734
+ if kernel_index is not None:
735
+ filtered_index = {
736
+ op_name: kernel_mapping
737
+ for op_name, kernel_mapping in kernel_index.index.items()
738
+ if op_name in op_names
739
+ }
740
+ return native_functions, ETKernelIndex(index=filtered_index)
741
+
742
+ # (2) Return BackendIndices if kernel index is absent
743
+ def map_index(
744
+ m: dict[OperatorName, BackendMetadata],
745
+ ) -> dict[OperatorName, BackendMetadata]:
746
+ return {op: m[op] for op in m if op in op_names}
747
+
748
+ backend_indices = {
749
+ k: map_index(b.index) for (k, b) in parsed_yaml.backend_indices.items()
750
+ }
751
+
752
+ return native_functions, backend_indices
753
+ else:
754
+ return [], {}
755
+
756
+
757
+ def parse_yaml_files(
758
+ tags_yaml_path: str,
759
+ aten_yaml_path: str,
760
+ native_yaml_path: str | None,
761
+ custom_ops_yaml_path: str | None,
762
+ selector: SelectiveBuilder,
763
+ use_aten_lib: bool,
764
+ ) -> tuple[ETParsedYaml, ETParsedYaml | None]:
765
+ """Parses functions.yaml and custom_ops.yaml files.
766
+
767
+ Args:
768
+ tags_yaml_path: Path to a tags.yaml file to satisfy codegen parsing.
769
+ It is not optional.
770
+ aten_yaml_path: Path to ATen operator yaml file native_functions.yaml.
771
+ native_yaml_path: Path to a functions.yaml file to parse.
772
+ If the path does not exist in the filesystem, it is treated as an
773
+ empty file. If `custom_ops_yaml_path` exists, the contents of that
774
+ file are appended to the yaml input to be parsed.
775
+ custom_ops_yaml_path: Path to a custom_ops.yaml file to parse. If
776
+ the path does not exist in the filesystem, it is ignored.
777
+ selector: For selective build.
778
+ use_aten_lib: We use this flag to determine if we want to generate native
779
+ functions. In ATen mode we should generate out= variants.
780
+ Returns:
781
+ A tuple with two elements:
782
+ [0]: The parsed results of concatenating the contents of
783
+ `native_yaml_path` and `custom_ops_yaml_path`.
784
+ [1]: The parsed results of the contents of `custom_ops_yaml_path`, if
785
+ present. If not present, None.
786
+ """
787
+ import tempfile
788
+
789
+ # only include selected ops, this is because we want to avoid
790
+ def function_filter(f: NativeFunction) -> bool:
791
+ return selector.is_native_function_selected(f)
792
+
793
+ with tempfile.TemporaryDirectory() as tmpdirname:
794
+ translated_yaml_path = os.path.join(tmpdirname, "translated.yaml")
795
+ with open(translated_yaml_path, "w") as translated:
796
+ translate_native_yaml(
797
+ tags_yaml_path,
798
+ aten_yaml_path,
799
+ native_yaml_path,
800
+ use_aten_lib,
801
+ translated,
802
+ )
803
+
804
+ translated_functions, translated_indices = parse_yaml(
805
+ translated_yaml_path, tags_yaml_path, function_filter, not use_aten_lib
806
+ )
807
+ custom_ops_functions, custom_ops_indices = parse_yaml(
808
+ custom_ops_yaml_path, tags_yaml_path, function_filter, True
809
+ )
810
+
811
+ # Convert BackendIndices to ETKernelIndex
812
+ if not isinstance(translated_indices, ETKernelIndex):
813
+ translated_indices = ETKernelIndex.from_backend_indices(translated_indices)
814
+ if not isinstance(custom_ops_indices, ETKernelIndex):
815
+ custom_ops_indices = ETKernelIndex.from_backend_indices(custom_ops_indices)
816
+
817
+ combined_functions = translated_functions + custom_ops_functions
818
+ combined_kernel_index = ETKernelIndex.merge_indices(
819
+ translated_indices, custom_ops_indices
820
+ )
821
+ combined_yaml = ETParsedYaml(combined_functions, combined_kernel_index)
822
+ custom_ops_parsed_yaml = ETParsedYaml(custom_ops_functions, custom_ops_indices)
823
+
824
+ return combined_yaml, custom_ops_parsed_yaml
825
+
826
+
827
+ def main() -> None:
828
+ parser = argparse.ArgumentParser(description="Generate operator source files")
829
+ # Although we don't refer to --source-path directly, make_file_manager()
830
+ # expects it to point to a directory that contains a templates/ subdirectory
831
+ # containing the file templates.
832
+ parser.add_argument(
833
+ "-s",
834
+ "--source-path",
835
+ help="path to source directory for kernel templates",
836
+ )
837
+ parser.add_argument(
838
+ "--functions-yaml-path",
839
+ "--functions_yaml_path",
840
+ help="path to the functions.yaml file to use. Optional, but at least "
841
+ "one of --functions-yaml-path and --custom-ops-yaml-path must be "
842
+ "specified.",
843
+ )
844
+ parser.add_argument(
845
+ "--custom-ops-yaml-path",
846
+ "--custom_ops_yaml_path",
847
+ help="path to the custom_ops.yaml file to use. Optional, but at least "
848
+ "one of --functions-yaml-path and --custom-ops-yaml-path must be "
849
+ "specified.",
850
+ )
851
+ parser.add_argument(
852
+ "--aten-yaml-path",
853
+ "--aten_yaml_path",
854
+ help="path to native_functions.yaml file.",
855
+ )
856
+ # Note that make_file_manager() also looks at --install-dir.
857
+ parser.add_argument(
858
+ "-d",
859
+ "--install-dir",
860
+ "--install_dir",
861
+ help="output directory",
862
+ default="build/generated",
863
+ )
864
+ parser.add_argument(
865
+ "-o",
866
+ "--output-dependencies",
867
+ help="output a list of dependencies into the given file and exit",
868
+ )
869
+ # Although we don't refer to --dry-run directly, make_file_manager() looks
870
+ # for it.
871
+ parser.add_argument(
872
+ "--dry-run",
873
+ action="store_true",
874
+ help="run without writing any files (still updates outputs)",
875
+ )
876
+ parser.add_argument(
877
+ "--static-dispatch-backend",
878
+ "--static_dispatch_backend",
879
+ nargs="*",
880
+ help="generate static dispatch code for the specific backend (if set)",
881
+ )
882
+ parser.add_argument(
883
+ "--op-registration-whitelist",
884
+ "--op_registration_whitelist",
885
+ nargs="*",
886
+ help="filter op registrations by the whitelist (if set); "
887
+ "each item is `namespace`::`operator name` without overload name; "
888
+ "e.g.: aten::empty aten::conv2d ...",
889
+ )
890
+ parser.add_argument(
891
+ "--op-selection-yaml-path",
892
+ "--op_selection_yaml_path",
893
+ help="Provide a path to the operator selection (for custom build) YAML "
894
+ "that contains the information about the set of selected operators "
895
+ "and their categories (training, ...). Each operator is either a "
896
+ "full operator name with overload or just a bare operator name. "
897
+ "The operator names also contain the namespace prefix (e.g. aten::)",
898
+ )
899
+ parser.add_argument(
900
+ "--tags-path",
901
+ help="Path to tags.yaml. Required by yaml parsing in codegen system.",
902
+ )
903
+ parser.add_argument(
904
+ "--rocm",
905
+ action="store_true",
906
+ help="reinterpret CUDA as ROCm/HIP and adjust filepaths accordingly",
907
+ )
908
+ parser.add_argument(
909
+ "--use-aten-lib",
910
+ "--use_aten_lib",
911
+ action="store_true",
912
+ help="a boolean flag to indicate whether we use ATen kernels or not, in the future this flag will be per "
913
+ "operator",
914
+ )
915
+ parser.add_argument(
916
+ "--manual_registration",
917
+ "--manual-registration",
918
+ action="store_true",
919
+ help="a boolean flag to indicate whether we want to manually call"
920
+ "register_kernels() or rely on static init. ",
921
+ )
922
+ parser.add_argument(
923
+ "--generate",
924
+ type=str,
925
+ nargs="*",
926
+ choices=["headers", "sources"],
927
+ default=["headers", "sources"],
928
+ help="Generate only a subset of files",
929
+ )
930
+ options = parser.parse_args()
931
+ assert options.tags_path, "tags.yaml is required by codegen yaml parsing."
932
+
933
+ selector = get_custom_build_selector(
934
+ options.op_registration_whitelist,
935
+ options.op_selection_yaml_path,
936
+ )
937
+
938
+ parsed_yaml, custom_ops_parsed_yaml = parse_yaml_files(
939
+ aten_yaml_path=options.aten_yaml_path,
940
+ tags_yaml_path=options.tags_path,
941
+ native_yaml_path=options.functions_yaml_path,
942
+ custom_ops_yaml_path=options.custom_ops_yaml_path,
943
+ selector=selector,
944
+ use_aten_lib=options.use_aten_lib,
945
+ )
946
+ native_functions, kernel_index = (
947
+ parsed_yaml.native_functions,
948
+ parsed_yaml.kernel_index,
949
+ )
950
+ custom_ops_native_functions = (
951
+ custom_ops_parsed_yaml.native_functions if custom_ops_parsed_yaml else []
952
+ )
953
+
954
+ cpu_fm = make_file_manager(options=options)
955
+
956
+ if "headers" in options.generate:
957
+ # generate CustomOpsNativeFunctions.h when custom_ops.yaml is present, to match the build system.
958
+ gen_headers(
959
+ native_functions=native_functions,
960
+ gen_custom_ops_header=options.custom_ops_yaml_path,
961
+ custom_ops_native_functions=custom_ops_native_functions,
962
+ selector=selector,
963
+ kernel_index=kernel_index,
964
+ cpu_fm=cpu_fm,
965
+ use_aten_lib=options.use_aten_lib,
966
+ )
967
+
968
+ if "sources" in options.generate:
969
+ gen_unboxing(
970
+ native_functions=native_functions,
971
+ cpu_fm=cpu_fm,
972
+ selector=selector,
973
+ use_aten_lib=options.use_aten_lib,
974
+ kernel_index=kernel_index,
975
+ manual_registration=options.manual_registration,
976
+ )
977
+ if custom_ops_native_functions:
978
+ gen_custom_ops(
979
+ native_functions=custom_ops_native_functions,
980
+ selector=selector,
981
+ kernel_index=kernel_index,
982
+ cpu_fm=cpu_fm,
983
+ rocm=options.rocm,
984
+ )
985
+
986
+ if options.output_dependencies:
987
+ depfile_path = Path(options.output_dependencies).resolve()
988
+ depfile_name = depfile_path.name
989
+ depfile_stem = depfile_path.stem
990
+
991
+ for fm, prefix in [
992
+ (cpu_fm, ""),
993
+ ]:
994
+ varname = prefix + depfile_stem
995
+ path = depfile_path.parent / (prefix + depfile_name)
996
+ fm.write_outputs(varname, str(path))
997
+
998
+
999
+ if __name__ == "__main__":
1000
+ main()
gen_functionalization_type.py ADDED
@@ -0,0 +1,882 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Callable, TYPE_CHECKING
5
+
6
+ from torchgen.api import cpp, dispatcher
7
+ from torchgen.api.translate import translate
8
+ from torchgen.api.types import (
9
+ BaseCType,
10
+ Binding,
11
+ CType,
12
+ DispatcherSignature,
13
+ FunctionalizationLambda,
14
+ iTensorListRefT,
15
+ NativeSignature,
16
+ OptionalCType,
17
+ optionalSymIntArrayRefT,
18
+ symIntArrayRefT,
19
+ SymIntT,
20
+ tensorListT,
21
+ tensorT,
22
+ VectorCType,
23
+ ViewInverseSignature,
24
+ )
25
+ from torchgen.context import (
26
+ method_with_native_function,
27
+ native_function_manager,
28
+ with_native_function,
29
+ with_native_function_and,
30
+ )
31
+ from torchgen.model import (
32
+ Argument,
33
+ BackendIndex,
34
+ BaseTy,
35
+ BaseType,
36
+ FunctionSchema,
37
+ ListType,
38
+ NativeFunction,
39
+ NativeFunctionsGroup,
40
+ NativeFunctionsViewGroup,
41
+ Return,
42
+ SchemaKind,
43
+ SelfArgument,
44
+ TensorOptionsArguments,
45
+ )
46
+ from torchgen.native_function_generation import (
47
+ INPLACE_OPS_THAT_DONT_GET_GROUPED_PROPERLY,
48
+ MUTABLE_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT,
49
+ OUT_OPS_THAT_DONT_GET_GROUPED_PROPERLY,
50
+ )
51
+ from torchgen.utils import dataclass_repr
52
+
53
+
54
+ if TYPE_CHECKING:
55
+ from torchgen.selective_build.selector import SelectiveBuilder
56
+
57
+
58
+ # Note: [Mutable Ops Not Using Functionalization]
59
+ # Ops in this list currently do not work with functionalization and should be fixed.
60
+ MUTABLE_OPS_NOT_USING_FUNCTIONALIZATION = (
61
+ OUT_OPS_THAT_DONT_GET_GROUPED_PROPERLY
62
+ + MUTABLE_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT
63
+ + INPLACE_OPS_THAT_DONT_GET_GROUPED_PROPERLY
64
+ + [
65
+ # It will be BC-breaking, but we should fix their schemas.
66
+ # should be inplace?
67
+ "record_stream",
68
+ # See Note [resize_ in Functionalization]
69
+ "resize_",
70
+ "resize_as_",
71
+ # This function is used as for testing purposes only.
72
+ "_fill_mem_eff_dropout_mask_",
73
+ ]
74
+ )
75
+
76
+ # This file contains codegen that relates to the functionalization pass.
77
+ # It includes:
78
+ # - gen_functionalization_definition
79
+ # Generates dispatcher kernel definitions for the functionalization pass.
80
+ # - gen_functionalization_registration
81
+ # Generates dispatcher kernel registrations for the functionalization pass.
82
+ # - gen_functionalization_view_inverse_declaration
83
+ # Generates a declaration for an "inverse view", for every view op
84
+ # that is needed in functionalization. We manually implement their definitions.
85
+ # - gen_composite_view_copy_kernel
86
+ # Generates view_copy() composite kernels for all view_copy operators.
87
+
88
+
89
+ # Generates the body of the default composite C++ kernel for a {view}_copy NativeFunction
90
+ # See Note [view_copy NativeFunctions]
91
+ @dataclass(frozen=True)
92
+ class GenCompositeViewCopyKernel:
93
+ backend_index: BackendIndex
94
+
95
+ @method_with_native_function
96
+ def __call__(self, g: NativeFunctionsViewGroup) -> str | None:
97
+ if g.view_copy is None:
98
+ return None
99
+ elif g.view_copy.func.name.name.base != f"{g.view.func.name.name}_copy":
100
+ # If the view_copy doesn't match the standard naming scheme of <op>_copy,
101
+ # assume it already exists and doesn't need to be generated.
102
+ # Example: slice_inverse() with the copy variant named slice_scatter()
103
+ # instead of slice_inverse_copy()
104
+ return None
105
+
106
+ metadata = self.backend_index.get_kernel(g.view_copy)
107
+ assert metadata is not None
108
+
109
+ # We can make view_copy work in more cases by using reshape()
110
+ # when a normal view call would ordinarily fail.
111
+ # This also makes LTC more efficient, because they don't need to include
112
+ # clone() calls in their graph (which is normally needed by reshape).
113
+ if str(g.view_copy.func.name) == "view_copy":
114
+ assert metadata.kernel == "view_copy_symint"
115
+ return """\
116
+ at::Tensor view_copy_symint(const at::Tensor & self, at::SymIntArrayRef size) {
117
+ c10::SymDimVector shape = infer_size_dv(size, self.sym_numel());
118
+ if (!at::detail::computeStride(self.sym_sizes(), self.sym_strides(), shape).has_value()) {
119
+ return self.reshape_symint(size);
120
+ } else {
121
+ auto output = at::_ops::view::call(self, size);
122
+ return output.clone(/*memory_format=*/at::MemoryFormat::Contiguous);
123
+ }
124
+ }
125
+ """
126
+ # view_copy is a native signature, since we're generating an at::native:: kernel
127
+ # Functionalization always operates on symints though
128
+ view_copy_sig = NativeSignature(
129
+ g.view_copy.func, symint=metadata.supports_symint()
130
+ )
131
+
132
+ # view is a dispatcher signature, since we're calling into the at::_ops API
133
+ view_sig = DispatcherSignature(g.view.func)
134
+
135
+ view_api_name = g.view.func.name.unambiguous_name()
136
+ exprs = ", ".join(
137
+ [e.expr for e in translate(view_copy_sig.arguments(), view_sig.arguments())]
138
+ )
139
+
140
+ # view ops today always return either a Tensor or a list of Tensors
141
+ assert len(g.view.func.returns) == 1
142
+ assert g.view.func.returns[0].type == BaseType(
143
+ BaseTy.Tensor
144
+ ) or g.view.func.returns[0].type == ListType(BaseType(BaseTy.Tensor), None)
145
+
146
+ if g.view.func.returns[0].type == BaseType(BaseTy.Tensor):
147
+ return_cloned_output = """\
148
+ return output.clone(/*memory_format=*/at::MemoryFormat::Contiguous);"""
149
+ else:
150
+ # If the return type is a list, we need to clone each tensor in the list.
151
+ return_cloned_output = f"""\
152
+ {view_copy_sig.returns_type().cpp_type()} out_clone;
153
+ for (const auto i : c10::irange(output.size())) {{
154
+ out_clone.push_back(output[i].clone(/*memory_format=*/at::MemoryFormat::Contiguous));
155
+ }}
156
+ return out_clone;"""
157
+
158
+ # The default generated composite kernel for {view}_copy() operators just clones
159
+ # the input tensor, and runs the underlying view on the clone.
160
+ return f"""
161
+ {view_copy_sig.defn(name=metadata.kernel)} {{
162
+ auto output = at::_ops::{view_api_name}::call({exprs});
163
+ {return_cloned_output}
164
+ }}
165
+ """
166
+
167
+
168
+ def return_str(rets: tuple[Return, ...], names: list[str]) -> str:
169
+ assert len(rets) == len(names)
170
+ if len(rets) == 0:
171
+ return ""
172
+ elif len(rets) == 1:
173
+ return f"return {names[0]};"
174
+ else:
175
+ return f"return {dispatcher.returns_type(rets).cpp_type()}({', '.join(names)});"
176
+
177
+
178
+ def modifies_arguments(f: NativeFunction) -> bool:
179
+ return any(
180
+ a.annotation is not None and a.annotation.is_write
181
+ for a in f.func.arguments.flat_all
182
+ )
183
+
184
+
185
+ def wrapper_name(func: FunctionSchema) -> str:
186
+ if func.name.overload_name:
187
+ return f"{cpp.name(func)}_{func.name.overload_name}"
188
+ else:
189
+ return cpp.name(func)
190
+
191
+
192
+ def is_tensor_like(a: Argument | TensorOptionsArguments | SelfArgument) -> bool:
193
+ return isinstance(a, SelfArgument) or (
194
+ isinstance(a, Argument) and a.type.is_tensor_like()
195
+ )
196
+
197
+
198
+ # We need to wrap / unwrap various arguments from the op in the functionalization kernels.
199
+ # Some op schemas include non-owning types though (like TensorList),
200
+ # and when we unwrap them we expect to get out an owning type!.
201
+ # We also return a lambda that tells you how to conver the non-owning type argument into the owning type.
202
+ def get_owning_type(t: CType) -> tuple[CType, Callable[[str], str]]:
203
+ if t == BaseCType(tensorListT):
204
+ return VectorCType(BaseCType(tensorT)), lambda x: f"{x}.vec()"
205
+ if t == BaseCType(iTensorListRefT):
206
+ return VectorCType(BaseCType(tensorT)), lambda x: f"{{{x}.begin(), {x}.end()}}"
207
+ # There are technically other non-owning types out there (like IntArrayRef),
208
+ # but functionalization only actually cares about the ones involving tensors.
209
+ return t, lambda x: x
210
+
211
+
212
+ # unwraps all tensor-like arguments, returning:
213
+ # (1) a string containing all of the logic that does the unwrapping
214
+ # (2) a context, to be used by translate(), with all of the relevant bindings.
215
+ def unwrap_tensor_args(
216
+ sig: DispatcherSignature, *, is_view_op: bool
217
+ ) -> tuple[str, list[Binding]]:
218
+ context: list[Binding] = []
219
+ unwrapped_tensor_args: list[str] = []
220
+ for arg in sig.arguments():
221
+ if is_tensor_like(arg.argument):
222
+ # for tensor inputs, we want to unwrap them before passing them into the redispatch calls.
223
+ unwrapped_name = f"{arg.name}_"
224
+ # For most ops, the functionalization needs to sync any pending updates on the input tensors
225
+ # before calling the operator, since otherwise the operator will act on stale data.
226
+ # For view ops though, we can continue to defer syncing until the tensor is used by
227
+ # a non-view operator.
228
+ maybe_sync_input = (
229
+ "" if is_view_op else f"at::functionalization::impl::sync({arg.name});"
230
+ )
231
+ unwrapped_type, conversion_fn = get_owning_type(
232
+ arg.nctype.remove_const_ref().type
233
+ )
234
+ unwrapped_tensor_args.append(
235
+ f"""
236
+ {unwrapped_type.cpp_type()} {unwrapped_name};
237
+ if (at::functionalization::impl::isFunctionalTensor({arg.name})) {{
238
+ {maybe_sync_input}
239
+ {unwrapped_name} = at::functionalization::impl::from_functional_tensor({arg.name});
240
+ }} else {{
241
+ {unwrapped_name} = {conversion_fn(arg.name)};
242
+ }}"""
243
+ )
244
+ context.append(arg.with_name(unwrapped_name))
245
+ else:
246
+ # for non-tensor inputs, we want to pass them directly into the redispatch calls.
247
+ context.append(arg)
248
+ unwrap_tensor_args_str = "\n ".join(unwrapped_tensor_args)
249
+ return unwrap_tensor_args_str, context
250
+
251
+
252
+ # converts all tensor-like arguments to meta tensors, which are used to compute stride info. Returns:
253
+ # (1) a string containing all of the logic that does the conversions.
254
+ # (2) a context, to be used by translate(), with all of the relevant bindings.
255
+ def convert_to_meta_tensors(sig: DispatcherSignature) -> tuple[str, list[Binding]]:
256
+ context: list[Binding] = []
257
+ unwrapped_tensor_args: list[str] = []
258
+ for arg in sig.arguments():
259
+ if is_tensor_like(arg.argument):
260
+ # for tensor inputs, we want to unwrap them before passing them into the redispatch calls.
261
+ a_ = arg.name
262
+ unwrapped_name = f"{arg.name}_meta"
263
+ unwrapped_tensor_args.append(f"auto {unwrapped_name} = to_meta({a_});")
264
+ context.append(arg.with_name(unwrapped_name))
265
+ else:
266
+ # for non-tensor inputs, we want to pass them directly into the redispatch calls.
267
+ context.append(arg)
268
+ unwrap_tensor_args_str = "\n ".join(unwrapped_tensor_args)
269
+ return unwrap_tensor_args_str, context
270
+
271
+
272
+ # The functionalization codegen currently expects view op schemas to have this form:
273
+ # foo(Tensor(a), ...) -> Tensor(a) (e.g. transpose)
274
+ # foo(Tensor(a!), ...) -> Tensor(a!) (e.g. transpose_)
275
+ def assert_view_op_properties(func: FunctionSchema) -> None:
276
+ def is_alias(a: Argument) -> bool:
277
+ return a.annotation is not None
278
+
279
+ args = func.arguments.flat_non_out
280
+ # The first argument is a tensor with an alias semantics (annotations)
281
+ assert (
282
+ len(args) > 0 and args[0].type == BaseType(BaseTy.Tensor)
283
+ ), f"""In the functionalization codegen, we expect the first argument of every view operator to be a tensor,
284
+ but found an argument of type {str(args[0].type)} for operator: {str(func.name)}."""
285
+ # No other arguments have aliasing semantics
286
+ assert (
287
+ is_alias(args[0]) and not any(is_alias(a) for a in args[1:])
288
+ ), """In the functionalization codegen, we expect the first argument of every view operator to alias the output.
289
+ View operators with multiple aliasing inputs aren't supported yet. Found an operator that doesn't satisfy this constraint"""
290
+
291
+
292
+ # One-liner expression for checking if an expression expr of type type has any
293
+ # symbolic values.
294
+ def emit_expr_has_symbolic_values(expr: str, type: CType) -> str:
295
+ if type == BaseCType(SymIntT):
296
+ return f"{expr}.is_symbolic()"
297
+
298
+ if isinstance(type, OptionalCType):
299
+ innerexpr = f"(*{expr})"
300
+ return f"{expr}.has_value() ? {emit_expr_has_symbolic_values(innerexpr, type.elem)} : false"
301
+
302
+ if type == BaseCType(optionalSymIntArrayRefT):
303
+ return emit_expr_has_symbolic_values(
304
+ expr, OptionalCType(BaseCType(symIntArrayRefT))
305
+ )
306
+
307
+ if type in (BaseCType(symIntArrayRefT), VectorCType(BaseCType(SymIntT))):
308
+ argname = "arg"
309
+ lambda_check = emit_expr_has_symbolic_values(argname, BaseCType(SymIntT))
310
+ return (
311
+ "std::any_of("
312
+ f"{expr}.begin(), {expr}.end(), "
313
+ f"[=](auto& {argname}) {{ return {lambda_check}; }})"
314
+ )
315
+
316
+ raise ValueError(
317
+ "unsupported type for has_symbolic_values check. "
318
+ "It should be a SymInt or a collection of those. "
319
+ f"Got: {type.cpp_type()}"
320
+ )
321
+
322
+
323
+ # Detects whether any of the SymInt arguments are, in fact, symbolic values.
324
+ # This is used in the constructor of ViewMeta.
325
+ def emit_has_symbolic_inputs(sig: DispatcherSignature) -> tuple[str, str]:
326
+ name = "has_symbolic_inputs"
327
+ statements = [
328
+ f"{name} = {name} | ({emit_expr_has_symbolic_values(binding.name, binding.nctype.type)});"
329
+ for binding in sig.arguments()
330
+ if (
331
+ isinstance(binding.argument, Argument)
332
+ and binding.argument.type.is_symint_like()
333
+ )
334
+ ]
335
+ body = "\n ".join(statements)
336
+ return (
337
+ name,
338
+ f"""
339
+ bool {name} = false;
340
+ {body}""",
341
+ )
342
+
343
+
344
+ # Generates the Functionalization kernel for:
345
+ # - ops that create aliases (e.g. transpose())
346
+ # - ops that are views AND mutations (e.g. transpose_())
347
+ def emit_view_functionalization_body(
348
+ g: NativeFunctionsViewGroup, *, view_inplace: bool
349
+ ) -> str:
350
+ if view_inplace:
351
+ # This op is both an inplace op AND a view op.
352
+ # See Note [Functionalization Pass - Inplace View Ops] for details.
353
+ # I currently have the view meta call into the out-of-place variant of the view, to avoid
354
+ # having to define an extra ~20 inplace {view}_inverse_ functions.
355
+ # Most view ops don't have NativeFunctionGroup's both, because we don't define out= variants for view ops.
356
+ # I'm assuming that every inplace-view op has a corresponding out-of-place view op,
357
+ # with the same name but the trailing underscore removed.
358
+ # This is currently asserted at parse time in gen.py (see error_check_native_functions).
359
+ assert g.view_inplace is not None
360
+ f = g.view_inplace
361
+ else:
362
+ f = g.view
363
+
364
+ assert g.view_copy is not None
365
+ with native_function_manager(f):
366
+ call_sig = DispatcherSignature.from_schema(g.view_copy.func)
367
+
368
+ # the "view_copy" op name that the functionalization kernels need to call
369
+ api_name = g.view_copy.func.name.unambiguous_name()
370
+ # Sometimes the functionalization pass needs to no-op (e.g. if it was passed non-functional tensors)
371
+ # "no-op"ing in this context is just redispatching to the original op.
372
+ noop_api_name = f.func.name.unambiguous_name()
373
+
374
+ dispatcher_sig = DispatcherSignature.from_schema(f.func)
375
+ assert_view_op_properties(f.func)
376
+ view_tensor_name = dispatcher_sig.arguments()[0].name
377
+
378
+ return_type = dispatcher_sig.returns_type().remove_const_ref().cpp_type()
379
+
380
+ unwrap_tensor_args_str, unwrapped_args_ctx = unwrap_tensor_args(
381
+ dispatcher_sig, is_view_op=True
382
+ )
383
+ view_redispatch_args = [
384
+ e.expr
385
+ for e in translate(unwrapped_args_ctx, call_sig.arguments(), method=False)
386
+ ]
387
+
388
+ forward_lambda = FunctionalizationLambda.from_func(g, is_reverse=False)
389
+ reverse_lambda = FunctionalizationLambda.from_func(g, is_reverse=True)
390
+
391
+ # The meta API call should use the same arguments, but convert all tensors to meta tensors first.
392
+ meta_conversion_str, meta_call_ctx = convert_to_meta_tensors(dispatcher_sig)
393
+ meta_call_args = [
394
+ e.expr for e in translate(meta_call_ctx, call_sig.arguments(), method=False)
395
+ ]
396
+
397
+ (
398
+ symbolic_inputs_varname,
399
+ symbolic_inputs_check,
400
+ ) = emit_has_symbolic_inputs(call_sig)
401
+
402
+ if "inplace_view" in f.tags:
403
+ # See Note [Functionalization Pass - Inplace View Ops] for more details
404
+ return f"""
405
+ {dispatcher_sig.defn(name=wrapper_name(f.func), is_redispatching_fn=True)} {{
406
+ if (!at::functionalization::impl::isFunctionalTensor({view_tensor_name})) {{
407
+ // functionalization is re-entrant, but will no-op if it wasn't passed a FunctionalTensorWrapper.
408
+ {unwrap_tensor_args_str}
409
+ at::AutoDispatchSkipFunctionalize guard;
410
+ return at::_ops::{noop_api_name}::call({', '.join(view_redispatch_args)});
411
+ }}
412
+ auto reapply_views = at::functionalization::impl::getFunctionalizationReapplyViewsTLS();
413
+ auto inverse_return_mode = (
414
+ reapply_views ? at::functionalization::InverseReturnMode::ViewOrScatterInverse
415
+ : at::functionalization::InverseReturnMode::NeverView
416
+ );
417
+ {symbolic_inputs_check}
418
+ at::functionalization::ViewMeta view_meta = at::functionalization::ViewMeta(
419
+ {forward_lambda.decl()} {{
420
+ if (reapply_views) {{
421
+ return {forward_lambda.inner_call(reapply_views=True)}
422
+ }} else {{
423
+ return {forward_lambda.inner_call(reapply_views=False)}
424
+ }}
425
+ }},
426
+ {reverse_lambda.decl()} {{
427
+ return {reverse_lambda.inner_call()}
428
+ }},
429
+ /*has_symbolic_inputs=*/{symbolic_inputs_varname}
430
+ );
431
+ auto compute_reference_meta =
432
+ {view_tensor_name}.key_set().has_backend(c10::BackendComponent::XLABit) ||
433
+ {view_tensor_name}.key_set().has_backend(c10::BackendComponent::LazyBit);
434
+ {return_type} reference_tensor_output;
435
+ if (compute_reference_meta) {{
436
+ {meta_conversion_str}
437
+ at::AutoDispatchSkipFunctionalize func_guard;
438
+ c10::impl::ExcludeDispatchKeyGuard guard(exclude_keys_for_meta_dispatch);
439
+ reference_tensor_output = at::_ops::{noop_api_name}::call({', '.join(meta_call_args)});
440
+ }}
441
+ // This function adds the above view meta to the current tensor and replays them off the base,
442
+ // mutating the size/stride info of the current FunctionalTensorWrapper.
443
+ // Because of this, we need to make sure to run the reference shape function above,
444
+ // BEFORE doing this (otherwise we'll end up runnin the reference function using the wrong sizes/strides)
445
+ at::functionalization::impl::mutate_view_meta({view_tensor_name}, view_meta);
446
+ // See Note [Propagating strides in the functionalization pass]
447
+ // XLA/LTC don't implement the logic to propagate strides correctly, so we need to rely
448
+ // on a reference implementation here (instead of relying on the output from the forward lambda
449
+ // having the correct stride info)
450
+ if (compute_reference_meta) {{
451
+ at::functionalization::impl::set_sizes_strides_offset({view_tensor_name}, reference_tensor_output);
452
+ }}
453
+ return {view_tensor_name};
454
+ }}
455
+ """
456
+
457
+ else:
458
+ is_multi_output_view = isinstance(f.func.returns[0].type, ListType)
459
+ return f"""
460
+ {dispatcher_sig.defn(name=wrapper_name(f.func), is_redispatching_fn=True)} {{
461
+ {unwrap_tensor_args_str}
462
+ if (!at::functionalization::impl::isFunctionalTensor({view_tensor_name})) {{
463
+ // functionalization is re-entrant, but will no-op if it wasn't passed a FunctionalTensorWrapper.
464
+ at::AutoDispatchSkipFunctionalize guard;
465
+ return at::_ops::{noop_api_name}::call({', '.join(view_redispatch_args)});
466
+ }}
467
+ auto reapply_views = at::functionalization::impl::getFunctionalizationReapplyViewsTLS();
468
+ auto inverse_return_mode = (
469
+ reapply_views ? at::functionalization::InverseReturnMode::ViewOrScatterInverse
470
+ : at::functionalization::InverseReturnMode::NeverView
471
+ );
472
+ auto compute_reference_meta =
473
+ {view_tensor_name}.key_set().has_backend(c10::BackendComponent::XLABit) ||
474
+ {view_tensor_name}.key_set().has_backend(c10::BackendComponent::LazyBit);
475
+ {return_type} reference_tensor_output;
476
+ if (compute_reference_meta) {{
477
+ {meta_conversion_str}
478
+ at::AutoDispatchSkipFunctionalize func_guard;
479
+ c10::impl::ExcludeDispatchKeyGuard guard(exclude_keys_for_meta_dispatch);
480
+ reference_tensor_output = at::_ops::{noop_api_name}::call({', '.join(meta_call_args)});
481
+ }}
482
+ {return_type} tmp_output;
483
+ {{
484
+ at::AutoDispatchSkipFunctionalize guard;
485
+ if (reapply_views) {{
486
+ tmp_output = at::_ops::{noop_api_name}::call({', '.join(view_redispatch_args)});
487
+ }} else {{
488
+ tmp_output = at::_ops::{api_name}::call({', '.join(view_redispatch_args)});
489
+ }}
490
+ }}
491
+ {symbolic_inputs_check}
492
+ at::functionalization::ViewMeta view_meta = at::functionalization::ViewMeta(
493
+ {forward_lambda.decl()} {{
494
+ if (reapply_views) {{
495
+ return {forward_lambda.inner_call(reapply_views=True)}
496
+ }} else {{
497
+ return {forward_lambda.inner_call(reapply_views=False)}
498
+ }}
499
+ }},
500
+ {reverse_lambda.decl()} {{
501
+ return {reverse_lambda.inner_call()}
502
+ }},
503
+ /*has_symbolic_inputs=*/{symbolic_inputs_varname},
504
+ /*is_multi_output=*/{str(is_multi_output_view).lower()},
505
+ /*is_as_strided=*/{str(str(f.func.name) == 'as_strided').lower()}
506
+ );
507
+ auto out = at::functionalization::impl::create_functional_tensor_with_view_meta(tmp_output, {view_tensor_name}, view_meta);
508
+ // See Note [Propagating strides in the functionalization pass]
509
+ if (compute_reference_meta) {{
510
+ at::functionalization::impl::set_sizes_strides_offset(out, reference_tensor_output);
511
+ }}
512
+ return out;
513
+ }}
514
+ """
515
+
516
+
517
+ def maybe_create_output(f: NativeFunction, var_name: str) -> str:
518
+ if len(f.func.returns) == 0:
519
+ return ""
520
+ return_type = dispatcher.returns_type(f.func.returns).remove_const_ref().cpp_type()
521
+ return f"{return_type} {var_name} = "
522
+
523
+
524
+ # Given a NativeFunction, and a variable name corresponding to the output of redispatching on the function,
525
+ # this returns two lists of names, consisting of:
526
+ # - the names of returns corresponding to the original (mutable) inputs of the outer function
527
+ # - the names of returns corresponding to the (immutable) outputs of the inner redispatched function
528
+ def get_mutable_redispatch_return_names(
529
+ f: NativeFunction, inner_return_var: str
530
+ ) -> tuple[list[str], list[str]]:
531
+ aliased_returns = []
532
+ non_aliased_returns = []
533
+ for i, name in enumerate(f.func.aliased_return_names()):
534
+ if name is not None:
535
+ aliased_returns.append(name)
536
+ else:
537
+ non_aliased_returns.append(
538
+ inner_return_var
539
+ if len(f.func.returns) == 1
540
+ else f"std::get<{i}>({inner_return_var})"
541
+ )
542
+ return aliased_returns, non_aliased_returns
543
+
544
+
545
+ # When functionalization "no-op's" and redispatches on a mutable operator, we need to take care so that:
546
+ # - For fresh outputs, we return the result of the redispatch (without wrapping outputs)
547
+ # - For outputs that were aliased to inputs, we return the inputs directly (since some of them might have been wrapped)
548
+ def return_from_mutable_noop_redispatch(
549
+ f: NativeFunction, inner_return_var: str
550
+ ) -> str:
551
+ aliased, non_aliased = get_mutable_redispatch_return_names(f, inner_return_var)
552
+ # Just get all of the return names, and immediately return them
553
+ return return_str(f.func.returns, aliased + non_aliased)
554
+
555
+
556
+ def wrap_propagate_mutations_and_return(
557
+ f: NativeFunction, functional_op: NativeFunction, inner_return_var: str
558
+ ) -> str:
559
+ mutable_arg_names = f.func.arguments.mutable_arg_names()
560
+ (
561
+ aliased_outer_rets,
562
+ non_aliased_outer_rets,
563
+ ) = get_mutable_redispatch_return_names(f, inner_return_var)
564
+ _, non_aliased_inner_rets = get_mutable_redispatch_return_names(
565
+ functional_op, inner_return_var
566
+ )
567
+ # The outer function may have a mix of aliased and non-aliased outputs,
568
+ # But the inner functional op that we're transforming to should only have non-aliased outputs
569
+ assert len(mutable_arg_names) + len(non_aliased_outer_rets) == len(
570
+ non_aliased_inner_rets
571
+ )
572
+
573
+ # First, take all of the newly created outputs from the inner call and wrap them into functional tensors
574
+ updates = []
575
+ non_aliased_wrapped_ret_names = []
576
+ for i, inner_ret in enumerate(
577
+ non_aliased_inner_rets[: len(non_aliased_outer_rets)]
578
+ ):
579
+ ret_name = f"output_{i}"
580
+ updates.append(
581
+ f"""\
582
+ auto output_{i} = at::functionalization::impl::to_functional_tensor({inner_ret});"""
583
+ )
584
+ non_aliased_wrapped_ret_names.append(ret_name)
585
+
586
+ # Next, take all of the mutated outputs from the inner call corresponding to mutated inputs,
587
+ # and propagate the mutations
588
+ for outer_arg, inner_ret in zip(
589
+ mutable_arg_names, non_aliased_inner_rets[len(non_aliased_outer_rets) :]
590
+ ):
591
+ updates.append(
592
+ f"""\
593
+ auto {outer_arg}_inner = at::functionalization::impl::from_functional_tensor({outer_arg});
594
+ at::functionalization::impl::replace_({outer_arg}, {inner_ret});
595
+ at::functionalization::impl::commit_update({outer_arg});
596
+ at::functionalization::impl::sync({outer_arg});
597
+ auto {outer_arg}_inner_updated = at::functionalization::impl::from_functional_tensor({outer_arg});
598
+ at::functionalization::impl::propagate_xla_data_direct({outer_arg}_inner, {outer_arg}_inner_updated);"""
599
+ )
600
+
601
+ # Finally, we return:
602
+ # - Any mutable arguments that also returns
603
+ # - Any immutable returns that were created wrapping the output from the inner call
604
+ returns_str = return_str(
605
+ f.func.returns, aliased_outer_rets + non_aliased_wrapped_ret_names
606
+ )
607
+ updates_str = "\n".join(updates)
608
+ return f"""\
609
+ {updates_str}
610
+ {returns_str}"""
611
+
612
+
613
+ # Generates the Functionalization kernel for:
614
+ # - mutation ops (inplace and out= ops)
615
+ @with_native_function_and
616
+ def emit_inplace_functionalization_body(
617
+ f: NativeFunction, g: NativeFunctionsGroup
618
+ ) -> str:
619
+ # mutation case
620
+ assert modifies_arguments(f)
621
+
622
+ dispatcher_sig = DispatcherSignature.from_schema(f.func)
623
+
624
+ unwrap_tensor_args_str, unwrapped_args_ctx = unwrap_tensor_args(
625
+ dispatcher_sig, is_view_op=False
626
+ )
627
+
628
+ mutated_names = [
629
+ a.name
630
+ for a in f.func.arguments.flat_all
631
+ if a.type.is_tensor_like() and a.annotation is not None
632
+ ]
633
+ non_mutated_names = [
634
+ a.name
635
+ for a in f.func.arguments.flat_all
636
+ if a.type.is_tensor_like() and a.annotation is None
637
+ ]
638
+ non_mutated_tensor_names = [
639
+ a.name
640
+ for a in f.func.arguments.flat_all
641
+ if a.type == BaseType(BaseTy.Tensor) and a.annotation is None
642
+ ]
643
+ # all mutable inputs must be functional tensors in order to participate in functionalization
644
+ check_all_mutated_args_are_functional = " && ".join(
645
+ ["true"]
646
+ + [
647
+ f"at::functionalization::impl::isFunctionalTensor({a})"
648
+ for a in mutated_names
649
+ ]
650
+ )
651
+ check_any_non_mutated_args_are_functional = " || ".join(
652
+ ["false"]
653
+ + [
654
+ f"at::functionalization::impl::isFunctionalTensor({a})"
655
+ for a in non_mutated_names
656
+ ]
657
+ )
658
+
659
+ check_any_non_mutated_tensors_are_xla = " || ".join(
660
+ ["false"]
661
+ + [
662
+ f"{a}.device().type() == c10::DeviceType::XLA"
663
+ for a in non_mutated_tensor_names
664
+ ]
665
+ )
666
+ # These are used in the cases where we don't functionalize and redispatch to the inplace op
667
+ # case 1: we hit an inplace op that doesn't have an out-of-place equivalent
668
+ # case 2: we hit an inplace ops but our inputs are not functional tensors (in which case our kernel just no-ops)
669
+ inplace_exprs = [
670
+ e.expr
671
+ for e in translate(unwrapped_args_ctx, dispatcher_sig.arguments(), method=False)
672
+ ]
673
+
674
+ # call the out-of-place variant of the op
675
+ return_type = (
676
+ dispatcher.returns_type(g.functional.func.returns).remove_const_ref().cpp_type()
677
+ )
678
+ functional_sig = DispatcherSignature.from_schema(g.functional.func)
679
+ functional_exprs = [
680
+ e.expr
681
+ for e in translate(unwrapped_args_ctx, functional_sig.arguments(), method=False)
682
+ ]
683
+
684
+ if f.func.is_out_fn():
685
+ mutable_input_post_processing = "\n".join(
686
+ [
687
+ f"""
688
+ at::functionalization::impl::replace_(
689
+ {a.name}, {'std::get<' + str(i) + '>(tmp_output)' if len(f.func.returns) > 1 else 'tmp_output'});
690
+ at::functionalization::impl::commit_update({a.name});"""
691
+ for (i, a) in enumerate(f.func.arguments.out)
692
+ if a.annotation and a.annotation.is_write and a.type.is_tensor_like()
693
+ ]
694
+ )
695
+ else:
696
+ mutable_input_post_processing = "\n".join( # noqa: F841
697
+ [
698
+ f"""
699
+ at::functionalization::impl::replace_({a.name}, tmp_output);
700
+ at::functionalization::impl::commit_update({a.name});"""
701
+ for a in f.func.arguments.flat_all
702
+ if a.annotation and a.annotation.is_write and a.type.is_tensor_like()
703
+ ]
704
+ )
705
+
706
+ meta_conversion_str, meta_call_ctx = convert_to_meta_tensors(dispatcher_sig)
707
+ # We don't want to run the inplace meta func for ops like .set_(), because:
708
+ # (1) they're unnecessary: inplace meta checks are only useful for ops like add_(),
709
+ # where broadcasting will work for the out-of-place case but should fail on the inplace call
710
+ # (2) They'll also fail without adding extra infra: we'd need to convert the input storage argument
711
+ # into a meta storage
712
+ any_storage_args = any(
713
+ a.type == BaseType(BaseTy.Storage) for a in f.func.arguments.flat_all
714
+ )
715
+
716
+ return f"""
717
+ {dispatcher_sig.defn(name=wrapper_name(f.func), is_redispatching_fn=True)} {{
718
+ if ({str(not any_storage_args and f.func.kind() == SchemaKind.inplace).lower()}) {{
719
+ // Before converting the mutable op to its functional variant, run meta tensors through the original op.
720
+ // This will help us catch shape errors that apply to inplace ops that wouldn't apply to their functional variants.
721
+ // (We can only do this for inplace ops today though, because they technically all support meta tensors).
722
+ {meta_conversion_str}
723
+ at::AutoDispatchSkipFunctionalize func_guard;
724
+ c10::impl::ExcludeDispatchKeyGuard guard(exclude_keys_for_meta_dispatch);
725
+ at::_ops::{f.func.name.unambiguous_name()}::call({', '.join(a.name for a in meta_call_ctx)});
726
+ }}
727
+ {unwrap_tensor_args_str}
728
+ if (!({check_all_mutated_args_are_functional})) {{
729
+ // We want to disable this check if there are any XLA tensors.
730
+ // cpu_tensor.copy_(xla_tensor) is valid code.
731
+ if (!({check_any_non_mutated_tensors_are_xla}) && ({check_any_non_mutated_args_are_functional})) {{
732
+ // case 1: trying to mutate a non functional tensor with a functional tensor is an error
733
+ TORCH_INTERNAL_ASSERT(false,
734
+ "mutating a non-functional tensor with a functional tensor is not allowed.",
735
+ " Please ensure that all of your inputs are wrapped inside of a functionalize() call.");
736
+ }} else {{
737
+ // case 2: arguments are not functional tensors, so we no-op and redispatch.
738
+ at::AutoDispatchSkipFunctionalize guard;
739
+ {maybe_create_output(f, 'tmp_output')}at::_ops::{f.func.name.unambiguous_name()}::call({', '.join(inplace_exprs)});
740
+ {return_from_mutable_noop_redispatch(f, 'tmp_output')}
741
+ }}
742
+ }} else {{
743
+ {return_type} tmp_output;
744
+ {{
745
+ at::AutoDispatchSkipFunctionalize guard;
746
+ tmp_output = at::_ops::{g.functional.func.name.unambiguous_name()}::call({', '.join(functional_exprs)});
747
+ }}
748
+ {wrap_propagate_mutations_and_return(f, g.functional, 'tmp_output')}
749
+ }}
750
+ }}"""
751
+
752
+
753
+ # The below functions generate RegisterFunctionalization.cpp
754
+ # These files provide the kernels that run the functionalization pass, which can be opted into
755
+ # per backend (e.g. XLA or Vulkan), or as a composable transform (functionalize() in functorch).
756
+
757
+
758
+ # See Note [Functionalization Pass: View Inverses].
759
+ def gen_functionalization_view_inverse_declaration(
760
+ selector: SelectiveBuilder, g: NativeFunctionsViewGroup
761
+ ) -> str | None:
762
+ # For every (non-composite) view op, we need a corresponding "inverse view" function.
763
+ # This generates the declarations so we get a good compiler error when someone adds a new view.
764
+ @with_native_function
765
+ def emit_decl_helper(g: NativeFunctionsViewGroup) -> str | None:
766
+ if g.view.has_composite_implicit_autograd_kernel:
767
+ return None
768
+ view_inverse_sig = ViewInverseSignature(g)
769
+ return view_inverse_sig.decl()
770
+
771
+ return emit_decl_helper(g)
772
+
773
+
774
+ def gen_functionalization_registration(
775
+ selector: SelectiveBuilder,
776
+ g: NativeFunction | NativeFunctionsGroup | NativeFunctionsViewGroup,
777
+ composite_implicit_autograd_index: BackendIndex,
778
+ ) -> list[str]:
779
+ @with_native_function
780
+ def emit_registration_helper(f: NativeFunction) -> str:
781
+ assert not f.has_composite_implicit_autograd_kernel
782
+ registration_str = f"TORCH_FN(functionalization::{wrapper_name(f.func)})"
783
+ return f'm.impl("{f.func.name}", {registration_str});'
784
+
785
+ # Don't generate kernels in mobile build
786
+ if not selector.include_all_operators:
787
+ return []
788
+
789
+ if isinstance(g, NativeFunctionsViewGroup):
790
+ # functionalization needs to register kernels for view + view_inplace ops
791
+ # See Note [Functionalization <> torch.Tensor constructor]
792
+ if str(g.view.func.name) == "lift_fresh":
793
+ return []
794
+ view_str = []
795
+ if not g.view.has_composite_implicit_autograd_kernel:
796
+ view_str.append(emit_registration_helper(g.view))
797
+ if (
798
+ g.view_inplace is not None
799
+ and not g.view_inplace.has_composite_implicit_autograd_kernel
800
+ ):
801
+ assert g.view_inplace.is_view_op
802
+ view_str.append(emit_registration_helper(g.view_inplace))
803
+ return view_str
804
+
805
+ elif isinstance(g, NativeFunctionsGroup):
806
+ # Gets a hand-written functionalization kernel
807
+ if g.inplace is not None and str(g.inplace.func.name) == "set_.source_Tensor":
808
+ fns = []
809
+ else:
810
+ fns = list(g.functions())
811
+ else:
812
+ if str(g.func.name) in MUTABLE_OPS_NOT_USING_FUNCTIONALIZATION:
813
+ return []
814
+ fns = [g]
815
+
816
+ registrations = []
817
+ for f in fns:
818
+ if f.has_composite_implicit_autograd_kernel:
819
+ continue
820
+ if str(f.func.name) == "lift":
821
+ # See Note [Functionalization <> torch.Tensor constructor]
822
+ return []
823
+ if str(f.func.name) == "resize_":
824
+ # See Note [resize_ in Functionalization]
825
+ return []
826
+ if str(f.func.name.name) != "set_":
827
+ assert not f.is_view_op
828
+ # functionalization needs to generate and register kernels for inplace ops.
829
+ # We *also* need to directly register CompositeImplicitAUtograd kernels
830
+ # so that they decompose properly before functioanlization.
831
+ if modifies_arguments(f):
832
+ registrations.append(emit_registration_helper(f))
833
+ return registrations
834
+
835
+
836
+ def gen_functionalization_definition(
837
+ selector: SelectiveBuilder,
838
+ # Note: Ideally this code should never have to look at NativeFunction
839
+ # (and instead only need to operate on grouped NativeFunctions).
840
+ # The only reason currently is because we need to emit direct dispatch registrations
841
+ # For CompositeImplicitAutograd operators, which are potentially ungrouped.
842
+ g: NativeFunction | NativeFunctionsGroup | NativeFunctionsViewGroup,
843
+ ) -> list[str]:
844
+ # Don't generate kernels in mobile build
845
+ if not selector.include_all_operators:
846
+ return []
847
+
848
+ if isinstance(g, NativeFunctionsViewGroup):
849
+ # Case 1: emit view -> view_copy kernels for the functionalization pass
850
+ view_defs = []
851
+ if not g.composite:
852
+ # invariant: NativeFunctionsViewGroup's always have a view_copy operator
853
+ # if the view is not composite (implicit autograd)
854
+ assert g.view_copy is not None, dataclass_repr(g, indent=1)
855
+ view_defs.append(emit_view_functionalization_body(g, view_inplace=False))
856
+ if g.view_inplace is not None:
857
+ view_defs.append(emit_view_functionalization_body(g, view_inplace=True))
858
+ return view_defs
859
+ elif isinstance(g, NativeFunction):
860
+ # Invariant: all mutable operators that we need to handle in functionalization
861
+ # should have been properly grouped up.
862
+ # TODO: The below ops all have "problematic" schemas that prevent them from
863
+ # getting functionalized. Instead of bending over backwards to get things to work,
864
+ # I think we should either:
865
+ # (1) fix their schemas (BC-breaking)
866
+ # (2) hand-write their functionalization kernels
867
+ if (
868
+ str(g.func.name) not in MUTABLE_OPS_NOT_USING_FUNCTIONALIZATION
869
+ and str(g.func.name.name) not in MUTABLE_OPS_NOT_USING_FUNCTIONALIZATION
870
+ ):
871
+ assert g.has_composite_implicit_autograd_kernel or not modifies_arguments(g)
872
+ return []
873
+ else:
874
+ # Case 2: emit inplace -> out-of-place kernels for the functionalization pass
875
+ mutation_defs = []
876
+ mutation_defs.append(emit_inplace_functionalization_body(g.out, g))
877
+ if g.inplace is not None:
878
+ mutation_defs.append(emit_inplace_functionalization_body(g.inplace, g))
879
+ if g.mutable is not None:
880
+ mutation_defs.append(emit_inplace_functionalization_body(g.mutable, g))
881
+ return mutation_defs
882
+ return []
gen_lazy_tensor.py ADDED
@@ -0,0 +1,585 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import os
5
+ from collections import namedtuple
6
+ from pathlib import Path
7
+ from typing import Any, Callable, TYPE_CHECKING
8
+
9
+ import yaml
10
+
11
+ import torchgen.dest as dest
12
+ from torchgen.api.lazy import setValueT
13
+ from torchgen.api.types import BaseCppType
14
+ from torchgen.dest.lazy_ir import GenLazyIR, GenLazyNativeFuncDefinition, GenTSLazyIR
15
+ from torchgen.gen import get_grouped_native_functions, parse_native_yaml
16
+ from torchgen.gen_backend_stubs import (
17
+ error_on_missing_kernels,
18
+ gen_dispatcher_registrations,
19
+ gen_dispatchkey_nativefunc_headers,
20
+ parse_backend_yaml,
21
+ )
22
+ from torchgen.model import NativeFunction, NativeFunctionsGroup, OperatorName
23
+ from torchgen.selective_build.selector import SelectiveBuilder
24
+ from torchgen.utils import FileManager, NamespaceHelper
25
+ from torchgen.yaml_utils import YamlLoader
26
+
27
+
28
+ if TYPE_CHECKING:
29
+ from collections.abc import Iterable, Iterator, Sequence
30
+
31
+
32
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
33
+ #
34
+ # Lazy Tensor Codegen
35
+ #
36
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
37
+ # Overview
38
+ # ~~~~~~~~
39
+ #
40
+ # This codegen script builds on existing data models and helpers used
41
+ # by all ATen backends, and adds new functionality specific to lazy
42
+ # tensor backends.
43
+ #
44
+ # Inputs:
45
+ # - <backend>_native_functions.yaml: controls which operators are
46
+ # supported by the backend.
47
+ #
48
+ # Outputs:
49
+ # (for all backends)
50
+ # <DispatchKey>Ir.h defines Lazy IR classes to be constructed during tracing
51
+ # - opt-in: also generate 'lowering' methods for the TorchScript backend only
52
+ # <DispatchKey>NativeFunctions.cpp defines implementations of native functions which perform lazy tracing
53
+ # - opt-in: 'full_codegen' section of backend yaml; 'supported' section omits these implementations
54
+ # <DispatchKey>NativeFunctions.h declares implementations of native functions for both 'supported' and 'full_codegen'
55
+ # ops
56
+ #
57
+ # Register<DispatchKey>.cpp registers all op implementations with the dispatcher
58
+ # RegisterAutograd<DispatchKey>.cpp registers all autograd implementations with the dispatcher
59
+ #
60
+ # Validation Helpers:
61
+ # - Shape Inference: errs if any ops in backend yaml require shape inference not provided by meta kernels or
62
+ # implementations in torch/csrc/lazy/core/shape_inference.*
63
+ # - native function impls: errs if any 'supported' ops do not have an implementation defined in the backend
64
+ # (non-codegen) implementation file
65
+ #
66
+ #
67
+ # About the Data Model
68
+ # ~~~~~~~~~~~~~~~~~~~~
69
+ #
70
+ # Modeled after ATen codegen, the first step is to parse yaml and build a data model for the operators
71
+ # we care about. In this case, the <backend>_native_functions yaml defines a subset of the core operators
72
+ # (defined in more detail in the main native_functions.yaml), which will be supported by your backend.
73
+ # Backends can list ops in two categories:
74
+ # - `supported` ops require hand-implementations but still get codegenned declarations and registrations
75
+ # - `full_codegen` ops get implementations (and IR classes) generated too
76
+ #
77
+ # Each native function is modeled as an object with a schema, and each schema has objects representing their
78
+ # arguments. Much of the codegen is manipulation of the arguments and their types. For example, lazy tensor
79
+ # backends need to transform 'at::Tensor' arguments into 'lazy::Value' objects, as well as replacing reference
80
+ # types (stringref) with actual string objects, and this is done by manipulating the data model objects.
81
+ # - see api/lazy.py for the lazy data model
82
+ #
83
+ # Once the data model is set up, the rest of this script processes a number of templates for output CPP file
84
+ # and fills in the template values using helpers in `dest/lazy_ir.py` and `dest/lazy_ts_lowering.py`. These
85
+ # helpers mostly iterate over functions and their arguments, outputting different c++ snippets.
86
+ #
87
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
88
+
89
+
90
+ # Parses the external backend's yaml, and adds a new BackendIndex for the backend's dispatch key.
91
+ # Returns a Tuple of (backend_key, autograd_key, cpp_namespace, updated BackendIndex mapping, full_codegen)
92
+ ParsedExternalYaml = namedtuple(
93
+ "ParsedExternalYaml",
94
+ ["backend_key", "autograd_key", "cpp_namespace", "backend_indices", "full_codegen"],
95
+ )
96
+
97
+
98
+ def parse_native_functions_keys(
99
+ backend_yaml_path: str,
100
+ grouped_native_functions: Sequence[NativeFunction | NativeFunctionsGroup],
101
+ ) -> tuple[list[OperatorName], list[Any], list[OperatorName]]:
102
+ with open(backend_yaml_path) as f:
103
+ yaml_values = yaml.load(f, Loader=YamlLoader)
104
+ assert isinstance(yaml_values, dict)
105
+
106
+ full_codegen = yaml_values.pop("full_codegen", [])
107
+ non_native = yaml_values.pop("non_native", [])
108
+ ir_gen = yaml_values.pop("ir_gen", [])
109
+ assert isinstance(full_codegen, list)
110
+ assert isinstance(non_native, list)
111
+ assert isinstance(ir_gen, list)
112
+ full_codegen_opnames = [OperatorName.parse(name) for name in full_codegen]
113
+ ir_gen_opnames = [OperatorName.parse(name) for name in ir_gen]
114
+ return full_codegen_opnames, non_native, ir_gen_opnames
115
+
116
+
117
+ def validate_shape_inference_header(
118
+ shape_inference_hdr: str, expected_shape_infr_decls: list[str]
119
+ ) -> None:
120
+ try:
121
+ with open(shape_inference_hdr) as f:
122
+ shape_infr_decls = f.read()
123
+ shape_infr_decl_lines = set(shape_infr_decls.split("\n"))
124
+ except OSError as e:
125
+ raise AssertionError(
126
+ f"Unable to read from the specified shape_inference_hdr file: {shape_inference_hdr}"
127
+ ) from e
128
+
129
+ # TODO(whc) add a check for shape inference functions that have meta kernels implement and should be retired.
130
+
131
+ missing_decls = [
132
+ decl for decl in expected_shape_infr_decls if decl not in shape_infr_decl_lines
133
+ ]
134
+ if missing_decls:
135
+ raise Exception( # noqa: TRY002
136
+ f"""Missing shape inference function.\n
137
+ Please add declare this function in {shape_inference_hdr}:\n
138
+ and implement it in the corresponding shape_inference.cpp file.\n
139
+ {os.linesep.join(missing_decls)}"""
140
+ )
141
+
142
+
143
+ # Some helper functions for the codegen.
144
+ def get_ltc_helper_fns() -> str:
145
+ return """\
146
+ at::Tensor to_meta(const at::Tensor& tensor) {
147
+ // undefined tensors can't be converted to the meta device, since they don't have sizes/strides
148
+ if (!tensor.defined()) return tensor;
149
+ auto out = at::native::empty_strided_meta_symint(tensor.sym_sizes(), tensor.sym_strides(), \
150
+ /*dtype=*/tensor.scalar_type(), /*layout=*/tensor.layout(), \
151
+ /*device=*/c10::Device(c10::kMeta), /*pin_memory=*/std::nullopt);
152
+ // needs to handle wrapped numbers, so dtype promotion works properly.
153
+ if (tensor.unsafeGetTensorImpl()->is_wrapped_number()) {
154
+ out.unsafeGetTensorImpl()->set_wrapped_number(true);
155
+ }
156
+ return out;
157
+ }
158
+ std::optional<at::Tensor> to_meta(const std::optional<at::Tensor>& tensor) {
159
+ if (tensor.has_value()) {
160
+ return to_meta(*tensor);
161
+ }
162
+ return std::nullopt;
163
+ }
164
+
165
+ std::vector<at::Tensor> to_meta(at::ITensorListRef t_list) {
166
+ std::vector<at::Tensor> outs;
167
+ outs.reserve(t_list.size());
168
+ for (const auto& tensor : t_list) {
169
+ outs.push_back(to_meta(tensor));
170
+ }
171
+ return outs;
172
+ }
173
+ """
174
+
175
+
176
+ class default_args:
177
+ node_base: str = "Node"
178
+ node_base_hdr: str | None = None
179
+ shape_inference_hdr: str = "torch/csrc/lazy/core/shape_inference.h"
180
+ tensor_class: str = "torch::lazy::LazyTensor"
181
+ tensor_class_hdr: str = "torch/csrc/lazy/core/tensor.h"
182
+ lazy_ir_generator: type[GenLazyIR] = GenLazyIR
183
+ native_func_definition_generator: type[GenLazyNativeFuncDefinition] = (
184
+ GenLazyNativeFuncDefinition
185
+ )
186
+ backend_name: str = "TorchScript"
187
+
188
+
189
+ def main() -> None:
190
+ parser = argparse.ArgumentParser(description="Generate Lazy Tensor backend files")
191
+ parser.add_argument(
192
+ "-s",
193
+ "--source-yaml",
194
+ "--source_yaml",
195
+ help="path to source yaml file containing operator external definitions",
196
+ )
197
+ parser.add_argument("-o", "--output-dir", "--output_dir", help="output directory")
198
+ parser.add_argument(
199
+ "--dry-run", "--dry_run", type=bool, default=False, help="output directory"
200
+ )
201
+ parser.add_argument(
202
+ "--impl-path",
203
+ "--impl_path",
204
+ type=str,
205
+ default=None,
206
+ help="path to the source C++ file containing kernel definitions",
207
+ )
208
+ parser.add_argument(
209
+ "--gen-ts-lowerings",
210
+ "--gen_ts_lowerings",
211
+ action="store_true",
212
+ help="Generate TorchScript lowerings in addition to Lazy IR and NativeFunctions",
213
+ )
214
+ parser.add_argument(
215
+ "--node-base",
216
+ "--node_base",
217
+ type=str,
218
+ default=default_args.node_base,
219
+ help="Name of backend specific custom Lazy IR Node base class",
220
+ )
221
+ parser.add_argument(
222
+ "--node-base-hdr",
223
+ "--node_base_hdr",
224
+ type=str,
225
+ default=default_args.node_base_hdr,
226
+ help="Path to header file defining custom Lazy IR Node base class",
227
+ )
228
+ parser.add_argument(
229
+ "--shape-inference-hdr",
230
+ "--shape_inference_hdr",
231
+ type=str,
232
+ default=default_args.shape_inference_hdr,
233
+ help="Path to header file defining custom Lazy shape inference functions",
234
+ )
235
+ parser.add_argument(
236
+ "--tensor-class",
237
+ "--tensor_class",
238
+ type=str,
239
+ default=default_args.tensor_class,
240
+ help="Name of backend specific custom Lazy Tensor class",
241
+ )
242
+ parser.add_argument(
243
+ "--tensor-class-hdr",
244
+ "--tensor_class_hdr",
245
+ type=str,
246
+ default=default_args.tensor_class_hdr,
247
+ help="Path to header file defining custom Lazy Tensor class",
248
+ )
249
+ parser.add_argument(
250
+ "--backend-name",
251
+ "--backend_name",
252
+ type=str,
253
+ default=default_args.backend_name,
254
+ help="Name of the backend to generate",
255
+ )
256
+ options = parser.parse_args()
257
+
258
+ # Assumes that this file lives at PYTORCH_ROOT/torchgen/gen_backend_stubs.py
259
+ torch_root = Path(__file__).parent.parent.parent.absolute()
260
+ aten_path = str(torch_root / "aten" / "src" / "ATen")
261
+ lazy_ir_generator: type[GenLazyIR] = default_args.lazy_ir_generator
262
+ if options.gen_ts_lowerings:
263
+ lazy_ir_generator = GenTSLazyIR
264
+ native_func_definition_generator: type[GenLazyNativeFuncDefinition] = (
265
+ default_args.native_func_definition_generator
266
+ )
267
+
268
+ run_gen_lazy_tensor(
269
+ aten_path,
270
+ options.source_yaml,
271
+ options.output_dir,
272
+ options.dry_run,
273
+ options.impl_path,
274
+ options.node_base,
275
+ options.node_base_hdr,
276
+ options.tensor_class,
277
+ options.tensor_class_hdr,
278
+ options.shape_inference_hdr,
279
+ lazy_ir_generator,
280
+ native_func_definition_generator,
281
+ options.backend_name,
282
+ )
283
+
284
+
285
+ def run_gen_lazy_tensor(
286
+ aten_path: str,
287
+ source_yaml: str,
288
+ output_dir: str,
289
+ dry_run: bool,
290
+ impl_path: str | None,
291
+ node_base: str = default_args.node_base,
292
+ node_base_hdr: str | None = default_args.node_base_hdr,
293
+ tensor_class: str = default_args.tensor_class,
294
+ tensor_class_hdr: str = default_args.tensor_class_hdr,
295
+ shape_inference_hdr: str = default_args.shape_inference_hdr,
296
+ lazy_ir_generator: type[GenLazyIR] = default_args.lazy_ir_generator,
297
+ native_func_definition_generator: type[
298
+ GenLazyNativeFuncDefinition
299
+ ] = default_args.native_func_definition_generator,
300
+ # build_in_tree is true for TS backend and affects include paths
301
+ build_in_tree: bool = False,
302
+ # per_operator_headers changes whether ATen/Functions.h or individual operator headers are used
303
+ # it must match how ATen was built
304
+ per_operator_headers: bool = False,
305
+ backend_name: str = default_args.backend_name,
306
+ gen_forced_fallback_code: bool = False,
307
+ use_lazy_shape: bool = True,
308
+ # the following arguments are temporary customization points for xla backend migration.
309
+ # do not rely on them otherwise, they should be removed once migration is complete
310
+ backend_namespace: str = "torch::lazy",
311
+ get_tensorlist: str = "GetTensorList",
312
+ get_tensor_or_wrap_number: str = "GetLtcTensorOrCreateForWrappedNumber",
313
+ try_get_tensor: str = "TryGetLtcTensor",
314
+ metrics_counter: str = 'TORCH_LAZY_FN_COUNTER("lazy::")',
315
+ create_tensor: str = "LazyTensor::Create",
316
+ create_from_first_tensor: bool = False,
317
+ create_aten_from_ltc_tensor: str = "torch::lazy::CreateAtenFromLtcTensor",
318
+ tuple_aten_from_ltc_tensors: str = "torch::lazy::TupleAtenFromLtcTensors",
319
+ lazy_value_class: str = "torch::lazy::Value",
320
+ lazy_tensor_ptr: str = "LazyTensorPtr",
321
+ get_device_fn: str = "torch::lazy::GetBackendDevice",
322
+ ) -> None:
323
+ lv_tokens = lazy_value_class.split("::")
324
+ lv_class = lv_tokens[-1]
325
+ lv_ns = "::".join(lv_tokens[:-1])
326
+ setValueT(BaseCppType(lv_ns, lv_class))
327
+ template_dir = os.path.join(aten_path, "templates")
328
+
329
+ def make_file_manager(install_dir: str) -> FileManager:
330
+ return FileManager(
331
+ install_dir=install_dir, template_dir=template_dir, dry_run=dry_run
332
+ )
333
+
334
+ fm = make_file_manager(output_dir)
335
+
336
+ native_yaml_path = os.path.join(aten_path, "native/native_functions.yaml")
337
+ tags_yaml_path = os.path.join(aten_path, "native/tags.yaml")
338
+ parsed_yaml = parse_native_yaml(native_yaml_path, tags_yaml_path)
339
+ native_functions, backend_indices = (
340
+ parsed_yaml.native_functions,
341
+ parsed_yaml.backend_indices,
342
+ )
343
+ grouped_native_functions = get_grouped_native_functions(native_functions)
344
+
345
+ def sort_native_function(f: NativeFunctionsGroup | NativeFunction) -> str:
346
+ """
347
+ We sort the native function because of the note in concat_map_codegen.
348
+ TODO(alanwaketan): Remove this sorting hack once all ops are grouped properly.
349
+ """
350
+ func = f.functional.func if isinstance(f, NativeFunctionsGroup) else f.func
351
+ return str(func.name.name)
352
+
353
+ grouped_native_functions = sorted(
354
+ grouped_native_functions, key=sort_native_function
355
+ )
356
+
357
+ parsed_backend_yaml = parse_backend_yaml(
358
+ source_yaml, grouped_native_functions, backend_indices
359
+ )
360
+ backend_key = parsed_backend_yaml.backend_key
361
+ autograd_key = parsed_backend_yaml.autograd_key
362
+ cpp_namespace = parsed_backend_yaml.cpp_namespace
363
+ backend_indices = parsed_backend_yaml.backend_indices
364
+ # the following 3 keys are all processed differently
365
+ # for full_codegen, we generate IR, kernels, etc
366
+ # for ir_gen, we generate only IR
367
+ # non_native is used to register kernels not declared in
368
+ # native_functions.yaml
369
+ full_codegen, non_native, ir_gen = parse_native_functions_keys(
370
+ source_yaml, grouped_native_functions
371
+ )
372
+
373
+ def concat_map_codegen(
374
+ func: Callable[[NativeFunction], Sequence[str]],
375
+ xs: Iterable[NativeFunctionsGroup | NativeFunction],
376
+ ops_list: list[OperatorName] = full_codegen,
377
+ ) -> Iterator[str]:
378
+ """
379
+ We code-gen for the functional variant, which is all we need for IR classes/lowerings/shape inferences, but we
380
+ only code-gen additional entries for the inplace variant for the native functions.
381
+ """
382
+
383
+ for x in xs:
384
+ fs = list(x.functions()) if isinstance(x, NativeFunctionsGroup) else [x]
385
+ for f in fs:
386
+ if f.func.name in ops_list:
387
+ yield from func(f)
388
+
389
+ selector = SelectiveBuilder.get_nop_selector()
390
+
391
+ assert backend_key is not None
392
+ class_name = backend_indices[backend_key].native_function_class_name()
393
+
394
+ if impl_path is not None:
395
+ error_on_missing_kernels(
396
+ native_functions,
397
+ backend_indices,
398
+ backend_key,
399
+ autograd_key,
400
+ class_name,
401
+ impl_path,
402
+ full_codegen,
403
+ )
404
+
405
+ """ Validate Shape Inference Definitions
406
+
407
+ Generated lazy native functions all perform shape inference, by first using a meta:: kernel
408
+ if available for that op, and otherwise using a 'compute_shape_{op}' function instead. The generator
409
+ knows the call signature for compute_shape_{op} because it matches the nativefunction (and meta::) signature,
410
+ so it just has to check whether the op is structured and generate a call for one or the other. It's up to the dev
411
+ to supply the missing compute_shape_{op} function, but the codegen at least warns you about this and provides
412
+ the expected signature which can be copy-pasted into shape_inference.h.
413
+
414
+ compute_shape_{op} functions are handwritten and should be replaced over time as ops get ported
415
+ to structured kernels.
416
+
417
+ See torch/csrc/lazy/core/shape_inference.cpp #READ THIS! for more information.
418
+ """
419
+ if shape_inference_hdr is not None:
420
+ expected_shape_infr_decls = list(
421
+ concat_map_codegen(
422
+ dest.GenLazyShapeInferenceDefinition(
423
+ backend_indices[backend_key], tensor_class
424
+ ),
425
+ grouped_native_functions,
426
+ )
427
+ )
428
+
429
+ validate_shape_inference_header(shape_inference_hdr, expected_shape_infr_decls)
430
+ assert class_name is not None
431
+
432
+ # Generate nativefunction declarations
433
+ # Note, eager registrations is set to False for the lazy TS backend as another LTC backend
434
+ # may want to register their own lazy kernels instead of registering the TS ones.
435
+ # The registration will lazily happen when init_ts_backend is called.
436
+ gen_dispatchkey_nativefunc_headers(
437
+ fm,
438
+ class_name,
439
+ cpp_namespace,
440
+ backend_indices,
441
+ grouped_native_functions,
442
+ backend_key,
443
+ autograd_key,
444
+ backend_name,
445
+ )
446
+
447
+ # Generate Dispatcher registrations which hook up the nativefunctions
448
+ for dispatch_key in (
449
+ [backend_key] if autograd_key is None else [backend_key, autograd_key]
450
+ ):
451
+ gen_dispatcher_registrations(
452
+ fm,
453
+ output_dir,
454
+ class_name,
455
+ backend_indices,
456
+ grouped_native_functions,
457
+ backend_key,
458
+ dispatch_key,
459
+ selector,
460
+ build_in_tree=build_in_tree,
461
+ per_operator_headers=per_operator_headers,
462
+ backend_name=backend_name,
463
+ eager_registration=False,
464
+ )
465
+
466
+ # Generate native function impls that build IR nodes
467
+ ns_helper = NamespaceHelper(cpp_namespace)
468
+ fm.write_with_template(
469
+ f"{backend_key}NativeFunctions.cpp",
470
+ "DispatchKeyNativeFunctions.cpp",
471
+ lambda: {
472
+ "includes": [
473
+ f"#include <{path}>"
474
+ for path in [
475
+ tensor_class_hdr,
476
+ shape_inference_hdr,
477
+ "ATen/Functions.h",
478
+ "ATen/native/TensorConversions.h",
479
+ "ATen/NativeFunctions.h",
480
+ "ATen/CompositeExplicitAutogradNonFunctionalFunctions.h",
481
+ "ATen/MetaFunctions.h",
482
+ "ATen/Operators.h",
483
+ "ATen/native/CPUFallback.h",
484
+ "torch/csrc/lazy/core/ir_builder.h",
485
+ "torch/csrc/lazy/core/lazy_graph_executor.h",
486
+ "torch/csrc/lazy/core/metrics.h",
487
+ "torch/csrc/lazy/core/shape.h",
488
+ f"{output_dir}/{backend_key}NativeFunctions.h",
489
+ f"{output_dir}/LazyIr.h",
490
+ ]
491
+ + (
492
+ ["torch/csrc/lazy/ts_backend/ts_eager_fallback.h"]
493
+ if gen_forced_fallback_code
494
+ else []
495
+ )
496
+ ],
497
+ "helper_fns": get_ltc_helper_fns(),
498
+ "native_functions_include": "",
499
+ "namespace_prologue": ns_helper.prologue,
500
+ "namespace_epilogue": ns_helper.epilogue,
501
+ "native_function_definitions": list(
502
+ concat_map_codegen(
503
+ native_func_definition_generator(
504
+ f"{backend_key}NativeFunctions",
505
+ backend_indices[backend_key],
506
+ tensor_class,
507
+ gen_forced_fallback_code,
508
+ backend_namespace,
509
+ get_tensorlist,
510
+ get_tensor_or_wrap_number,
511
+ try_get_tensor,
512
+ metrics_counter,
513
+ create_tensor,
514
+ create_from_first_tensor,
515
+ create_aten_from_ltc_tensor,
516
+ tuple_aten_from_ltc_tensors,
517
+ lazy_tensor_ptr,
518
+ get_device_fn,
519
+ ),
520
+ grouped_native_functions,
521
+ )
522
+ ),
523
+ },
524
+ )
525
+ # Generate IR node classes
526
+ lazy_ir_obj = lazy_ir_generator(
527
+ backend_indices[backend_key], backend_name, node_base, use_lazy_shape
528
+ )
529
+
530
+ fm.write_with_template(
531
+ "LazyIr.h",
532
+ "LazyIr.h",
533
+ lambda: {
534
+ "lazy_ir_sysinc": [
535
+ f"#include <{path}>"
536
+ for path in [
537
+ "ATen/core/Formatting.h",
538
+ "c10/core/ScalarType.h",
539
+ "torch/csrc/lazy/core/hash.h",
540
+ "torch/csrc/lazy/core/ir.h",
541
+ "torch/csrc/lazy/core/shape.h",
542
+ "optional",
543
+ "vector",
544
+ ]
545
+ ],
546
+ "lazy_ir_inc": [f'#include "{node_base_hdr}"']
547
+ if node_base_hdr is not None
548
+ else [],
549
+ "ir_declarations": list(
550
+ concat_map_codegen(
551
+ lazy_ir_obj, grouped_native_functions, full_codegen + ir_gen
552
+ )
553
+ ),
554
+ "namespace_prologue": ns_helper.prologue,
555
+ "namespace_epilogue": ns_helper.epilogue,
556
+ },
557
+ )
558
+
559
+ # Generate Non Native IR Node classes
560
+ fm.write_with_template(
561
+ "LazyNonNativeIr.h",
562
+ "LazyNonNativeIr.h",
563
+ lambda: {
564
+ "lazy_non_native_ir_inc": [
565
+ f"#include <{path}>"
566
+ for path in [
567
+ "torch/csrc/lazy/core/ir.h",
568
+ "torch/csrc/lazy/core/ir_builder.h",
569
+ "torch/csrc/lazy/core/internal_ops/ltc_ops.h",
570
+ "torch/csrc/lazy/core/shape_inference.h",
571
+ ]
572
+ + ([node_base_hdr] if node_base_hdr else [])
573
+ if path
574
+ ],
575
+ "non_native_ir_nodes": dest.generate_non_native_lazy_ir_nodes(
576
+ non_native, lazy_ir_obj
577
+ ),
578
+ "namespace_prologue": ns_helper.prologue,
579
+ "namespace_epilogue": ns_helper.epilogue,
580
+ },
581
+ )
582
+
583
+
584
+ if __name__ == "__main__":
585
+ main()
gen_schema_utils.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Optional, Union
2
+
3
+ from torchgen.model import (
4
+ Annotation,
5
+ Argument,
6
+ Arguments,
7
+ BaseOperatorName,
8
+ BaseTy,
9
+ BaseType,
10
+ CustomClassType,
11
+ FunctionSchema,
12
+ ListType,
13
+ OperatorName,
14
+ Return,
15
+ )
16
+
17
+
18
+ # Note: These aren't actually used in torchgen, they're some utilities for generating a schema
19
+ # from real arguments. For example, this is used to generate HigherOrderOperators' schema since
20
+ # their schemas can vary for different instances of the same HOP.
21
+
22
+
23
+ class TypeGen:
24
+ convert_to_base_ty = {
25
+ int: BaseTy.int,
26
+ float: BaseTy.float,
27
+ str: BaseTy.str,
28
+ bool: BaseTy.bool,
29
+ }
30
+
31
+ @staticmethod
32
+ def from_example(obj: Any) -> Union[BaseType, ListType, CustomClassType]:
33
+ import torch
34
+
35
+ if isinstance(obj, torch.fx.GraphModule):
36
+ return BaseType(BaseTy.GraphModule)
37
+ elif isinstance(obj, torch.Tensor):
38
+ return BaseType(BaseTy.Tensor)
39
+ elif isinstance(obj, torch.SymInt):
40
+ return BaseType(BaseTy.SymInt)
41
+ elif isinstance(obj, torch.SymBool):
42
+ return BaseType(BaseTy.SymBool)
43
+ elif isinstance(obj, torch.ScriptObject):
44
+ return CustomClassType(obj._type().name()) # type: ignore[attr-defined]
45
+ elif isinstance(obj, (list, tuple)):
46
+ assert len(obj) > 0
47
+ all_base_tys = [TypeGen.from_example(x) for x in obj]
48
+ if len(set(all_base_tys)) > 1:
49
+ raise RuntimeError(
50
+ f"Cannot generate schema for a seqeunce of args of heterogeneous types: {all_base_tys}. "
51
+ "Consider unpacking the argument and give proper names to them if possible "
52
+ "instead of using *args."
53
+ )
54
+ return ListType(all_base_tys[0], len(obj))
55
+ tp = type(obj)
56
+ if tp not in TypeGen.convert_to_base_ty:
57
+ raise RuntimeError(f"unsupported type {tp}")
58
+ return BaseType(TypeGen.convert_to_base_ty[tp])
59
+
60
+
61
+ class ReturnGen:
62
+ @staticmethod
63
+ def from_example(
64
+ name: Optional[str], obj: Any, annotation: Optional[Annotation]
65
+ ) -> Return:
66
+ return Return(name, TypeGen.from_example(obj), annotation)
67
+
68
+
69
+ class ArgumentGen:
70
+ @staticmethod
71
+ def from_example(
72
+ name: str, obj: Any, default: Optional[str], annotation: Optional[Annotation]
73
+ ) -> Argument:
74
+ return Argument(
75
+ name, TypeGen.from_example(obj), default=default, annotation=annotation
76
+ )
77
+
78
+
79
+ class FunctionSchemaGen:
80
+ @staticmethod
81
+ def from_example(
82
+ op_name: str,
83
+ example_inputs: tuple[tuple[str, Any], ...],
84
+ example_outputs: tuple[Any, ...],
85
+ ) -> FunctionSchema:
86
+ args = []
87
+ for name, inp in example_inputs:
88
+ args.append(ArgumentGen.from_example(name, inp, None, None))
89
+ # ignore the annotations and other attributes for now, we could add more when needed.
90
+ arguments = Arguments(
91
+ tuple(), None, tuple(args), tuple(), None, tuple(), tuple()
92
+ )
93
+ returns = tuple(
94
+ ReturnGen.from_example(None, out, None) for out in example_outputs
95
+ )
96
+ op_name = OperatorName(BaseOperatorName(op_name, False, False, False), "")
97
+ return FunctionSchema(op_name, arguments, returns)
gen_vmap_plumbing.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import textwrap
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING
6
+
7
+ from torchgen.api.translate import translate
8
+ from torchgen.api.types import DispatcherSignature
9
+ from torchgen.context import method_with_native_function
10
+ from torchgen.model import (
11
+ Argument,
12
+ BaseTy,
13
+ BaseType,
14
+ FunctionSchema,
15
+ ListType,
16
+ NativeFunction,
17
+ OptionalType,
18
+ Return,
19
+ SchemaKind,
20
+ Type,
21
+ )
22
+ from torchgen.utils import mapMaybe
23
+
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Sequence
27
+
28
+
29
+ def is_tensor(typ: Type) -> bool:
30
+ return isinstance(typ, BaseType) and typ.name == BaseTy.Tensor
31
+
32
+
33
+ def is_optional_tensor(typ: Type) -> bool:
34
+ return isinstance(typ, OptionalType) and is_tensor(typ.elem)
35
+
36
+
37
+ def is_tensor_list(typ: Type) -> bool:
38
+ return isinstance(typ, ListType) and is_tensor(typ.elem)
39
+
40
+
41
+ def unwrap_tensor(name: str, cur_level_var: str) -> list[str]:
42
+ result = f"""\
43
+ auto [{name}_value, {name}_bdim] = unwrapTensorAtLevel({name}, {cur_level_var});"""
44
+ return textwrap.dedent(result).split("\n")
45
+
46
+
47
+ def unwrap_optional_tensor(name: str, cur_level_var: str) -> list[str]:
48
+ result = f"""\
49
+ std::optional<Tensor> {name}_value;
50
+ std::optional<int64_t> {name}_bdim;
51
+ if ({name}) {{
52
+ std::tie({name}_value, {name}_bdim) = unwrapTensorAtLevel({name}.value(), {cur_level_var});
53
+ }}"""
54
+ return textwrap.dedent(result).split("\n")
55
+
56
+
57
+ def gen_unwraps(
58
+ flat_arguments: Sequence[Argument], cur_level_var: str
59
+ ) -> tuple[str, list[str]]:
60
+ arg_names = [a.name for a in flat_arguments]
61
+ arg_types = [a.type for a in flat_arguments]
62
+
63
+ tensors = [name for typ, name in zip(arg_types, arg_names) if is_tensor(typ)]
64
+ optional_tensors = [
65
+ name for typ, name in zip(arg_types, arg_names) if is_optional_tensor(typ)
66
+ ]
67
+
68
+ unwraps = []
69
+ for tensor in tensors:
70
+ unwraps += unwrap_tensor(tensor, cur_level_var)
71
+
72
+ for opt_tensor in optional_tensors:
73
+ unwraps += unwrap_optional_tensor(opt_tensor, cur_level_var)
74
+ unwrap_code = "\n".join(unwraps)
75
+
76
+ unwrapped_arg_list = []
77
+ for arg in arg_names:
78
+ if arg in tensors or arg in optional_tensors:
79
+ unwrapped_arg_list += [f"{arg}_value", f"{arg}_bdim"]
80
+ else:
81
+ unwrapped_arg_list.append(arg)
82
+ return unwrap_code, unwrapped_arg_list
83
+
84
+
85
+ def gen_case_where_all_bdims_are_none(
86
+ outer_sig: DispatcherSignature, schema: FunctionSchema, cur_level_var: str
87
+ ) -> str:
88
+ conditions = []
89
+ flat_args = schema.arguments.flat_all
90
+ for arg in flat_args:
91
+ if not arg.type.is_tensor_like():
92
+ continue
93
+ conditions.append(f"!isBatchedAtLevel({arg.name}, {cur_level_var})")
94
+
95
+ sig = DispatcherSignature.from_schema(schema)
96
+ translated_args = ", ".join(
97
+ e.expr for e in translate(outer_sig.arguments(), sig.arguments())
98
+ )
99
+ return f"""\
100
+ if ({' && '.join(conditions)}) {{
101
+ return at::_ops::{sig.func.name.unambiguous_name()}::call({translated_args});
102
+ }}"""
103
+
104
+
105
+ def gen_returns(
106
+ returns: tuple[Return, ...], cur_level_var: str, results_var: str
107
+ ) -> str:
108
+ idx = 0
109
+ wrapped_returns = []
110
+ for ret in returns:
111
+ if is_tensor(ret.type):
112
+ wrapped_returns.append(
113
+ f"makeBatched(std::get<{idx}>({results_var}), std::get<{idx + 1}>({results_var}), {cur_level_var})"
114
+ )
115
+ idx += 2
116
+ elif is_tensor_list(ret.type):
117
+ wrapped_returns.append(
118
+ f"makeBatchedVector(std::get<{idx}>({results_var}), std::get<{idx + 1}>({results_var}), {cur_level_var})"
119
+ )
120
+ idx += 2
121
+ else:
122
+ wrapped_returns.append(f"std::get<{idx}>({results_var})")
123
+ idx += 1
124
+ if len(wrapped_returns) == 1:
125
+ result = f"return {wrapped_returns[0]};"
126
+ else:
127
+ result = f'return std::make_tuple({", ".join(wrapped_returns)});'
128
+ return result
129
+
130
+
131
+ def accepts_at_least_one_tensor_input(schema: FunctionSchema) -> bool:
132
+ return any(a.type.is_tensor_like() for a in schema.arguments.flat_all)
133
+
134
+
135
+ def is_mutated_arg(argument: Argument) -> bool:
136
+ return argument.annotation is not None and argument.annotation.is_write
137
+
138
+
139
+ def gen_vmap_inplace_plumbing(native_function: NativeFunction) -> str | None:
140
+ # Assumptions:
141
+ # - only one argument is being modified in-place
142
+ # - the argument that is being modified in-place is the first argument
143
+ # - all returns are either Tensor, tuple of Tensor, or TensorList
144
+ schema = native_function.func
145
+ sig = DispatcherSignature.from_schema(schema)
146
+ returns = schema.returns
147
+
148
+ # Check assumptions. If these are invalid we return None
149
+ # and punt the work to handle them to the future.
150
+ assert schema.kind() == SchemaKind.inplace
151
+ if not is_mutated_arg(schema.arguments.flat_all[0]):
152
+ return None
153
+ if not len([arg for arg in schema.arguments.flat_all if is_mutated_arg(arg)]) == 1:
154
+ return None
155
+
156
+ # Only support cases where all returns are Tensors or vector<Tensor>
157
+ if len(returns) == 0:
158
+ return None
159
+ if not all(is_tensor(ret.type) or is_tensor_list(ret.type) for ret in returns):
160
+ return None
161
+ if not accepts_at_least_one_tensor_input(schema):
162
+ return None
163
+
164
+ cur_level_var = "cur_level"
165
+
166
+ unwraps, unwrapped_arg_list = gen_unwraps(schema.arguments.flat_all, cur_level_var)
167
+ bdims_all_none_case = gen_case_where_all_bdims_are_none(sig, schema, cur_level_var)
168
+
169
+ return f"""\
170
+ template <typename batch_rule_t, batch_rule_t batch_rule>
171
+ {sig.decl(name=schema.name.unambiguous_name() + '_generated_plumbing')} {{
172
+ c10::impl::ExcludeDispatchKeyGuard guard(DispatchKey::FuncTorchBatched);
173
+ auto maybe_layer = maybeCurrentDynamicLayer();
174
+ vmap_check_escaped(maybe_layer, "gen_vmap_inplace_plumbing");
175
+ int64_t {cur_level_var} = maybe_layer->layerId();
176
+ {textwrap.indent(bdims_all_none_case, " ")}
177
+ {textwrap.indent(unwraps, " ")}
178
+ batch_rule({', '.join(unwrapped_arg_list)});
179
+ return {schema.arguments.flat_all[0].name};
180
+ }}"""
181
+
182
+
183
+ def gen_vmap_plumbing_no_returns(native_function: NativeFunction) -> str:
184
+ schema = native_function.func
185
+ sig = DispatcherSignature.from_schema(schema)
186
+ cur_level_var = "cur_level"
187
+
188
+ unwraps, unwrapped_arg_list = gen_unwraps(schema.arguments.flat_all, cur_level_var)
189
+ bdims_all_none_case = gen_case_where_all_bdims_are_none(sig, schema, cur_level_var)
190
+
191
+ return f"""\
192
+ template <typename batch_rule_t, batch_rule_t batch_rule>
193
+ {sig.decl(name=schema.name.unambiguous_name() + '_generated_plumbing')} {{
194
+ c10::impl::ExcludeDispatchKeyGuard guard(DispatchKey::FuncTorchBatched);
195
+ auto maybe_layer = maybeCurrentDynamicLayer();
196
+ vmap_check_escaped(maybe_layer, "gen_vmap_plumbing_no_returns");
197
+ int64_t {cur_level_var} = maybe_layer->layerId();
198
+ {textwrap.indent(bdims_all_none_case, " ")}
199
+ {textwrap.indent(unwraps, " ")}
200
+ batch_rule({', '.join(unwrapped_arg_list)});
201
+ }}"""
202
+
203
+
204
+ def gen_vmap_plumbing(native_function: NativeFunction) -> str | None:
205
+ schema = native_function.func
206
+ sig = DispatcherSignature.from_schema(schema)
207
+ returns = schema.returns
208
+
209
+ # Only support cases where all returns are Tensors or vector<Tensor>
210
+ if not accepts_at_least_one_tensor_input(schema):
211
+ return None
212
+ if len(returns) == 0:
213
+ return gen_vmap_plumbing_no_returns(native_function)
214
+ return_symint_overrides = [
215
+ "_scaled_dot_product_flash_attention",
216
+ "_scaled_dot_product_cudnn_attention",
217
+ ]
218
+ if (
219
+ not all(ret.type.is_tensor_like() for ret in returns)
220
+ and schema.name.unambiguous_name() not in return_symint_overrides
221
+ ):
222
+ return None
223
+ # in-place views need special handling
224
+ if "inplace_view" in native_function.tags:
225
+ return None
226
+
227
+ if schema.kind() == SchemaKind.inplace:
228
+ return gen_vmap_inplace_plumbing(native_function)
229
+
230
+ # Don't support these (mutable, out, scratch)
231
+ if schema.kind() != SchemaKind.functional:
232
+ return None
233
+
234
+ results_var = "results"
235
+ cur_level_var = "cur_level"
236
+
237
+ unwraps, unwrapped_arg_list = gen_unwraps(schema.arguments.flat_all, cur_level_var)
238
+ bdims_all_none_case = gen_case_where_all_bdims_are_none(sig, schema, cur_level_var)
239
+
240
+ wrapped_returns = gen_returns(returns, cur_level_var, results_var)
241
+ return f"""\
242
+ template <typename batch_rule_t, batch_rule_t batch_rule>
243
+ {sig.decl(name=schema.name.unambiguous_name() + '_generated_plumbing')} {{
244
+ c10::impl::ExcludeDispatchKeyGuard guard(DispatchKey::FuncTorchBatched);
245
+ auto maybe_layer = maybeCurrentDynamicLayer();
246
+ vmap_check_escaped(maybe_layer, "gen_vmap_plumbing");
247
+ int64_t {cur_level_var} = maybe_layer->layerId();
248
+ {textwrap.indent(bdims_all_none_case, " ")}
249
+ {textwrap.indent(unwraps, " ")}
250
+ auto {results_var} = batch_rule({', '.join(unwrapped_arg_list)});
251
+ {wrapped_returns}
252
+ }}"""
253
+
254
+
255
+ @dataclass(frozen=True)
256
+ class ComputeBatchRulePlumbing:
257
+ @method_with_native_function
258
+ def __call__(self, f: NativeFunction) -> str | None:
259
+ result = gen_vmap_plumbing(f)
260
+ return result
261
+
262
+
263
+ def gen_all_vmap_plumbing(native_functions: Sequence[NativeFunction]) -> str:
264
+ body = "\n".join(list(mapMaybe(ComputeBatchRulePlumbing(), native_functions)))
265
+ return f"""
266
+ #pragma once
267
+ #include <ATen/Operators.h>
268
+ #include <ATen/functorch/PlumbingHelper.h>
269
+
270
+ namespace at {{ namespace functorch {{
271
+
272
+ {body}
273
+
274
+ }}}} // namespace at::functorch
275
+ """
get_gprof ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!C:\Users\migue\Downloads\Codigo\AI\HuggingModelAI\IAservicies\myenv\Scripts\python.exe
2
+ #
3
+ # Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
4
+ # Copyright (c) 2008-2016 California Institute of Technology.
5
+ # Copyright (c) 2016-2024 The Uncertainty Quantification Foundation.
6
+ # License: 3-clause BSD. The full license text is available at:
7
+ # - https://github.com/uqfoundation/dill/blob/master/LICENSE
8
+ '''
9
+ build profile graph for the given instance
10
+
11
+ running:
12
+ $ get_gprof <args> <instance>
13
+
14
+ executes:
15
+ gprof2dot -f pstats <args> <type>.prof | dot -Tpng -o <type>.call.png
16
+
17
+ where:
18
+ <args> are arguments for gprof2dot, such as "-n 5 -e 5"
19
+ <instance> is code to create the instance to profile
20
+ <type> is the class of the instance (i.e. type(instance))
21
+
22
+ For example:
23
+ $ get_gprof -n 5 -e 1 "import numpy; numpy.array([1,2])"
24
+
25
+ will create 'ndarray.call.png' with the profile graph for numpy.array([1,2]),
26
+ where '-n 5' eliminates nodes below 5% threshold, similarly '-e 1' eliminates
27
+ edges below 1% threshold
28
+ '''
29
+
30
+ if __name__ == "__main__":
31
+ import sys
32
+ if len(sys.argv) < 2:
33
+ print ("Please provide an object instance (e.g. 'import math; math.pi')")
34
+ sys.exit()
35
+ # grab args for gprof2dot
36
+ args = sys.argv[1:-1]
37
+ args = ' '.join(args)
38
+ # last arg builds the object
39
+ obj = sys.argv[-1]
40
+ obj = obj.split(';')
41
+ # multi-line prep for generating an instance
42
+ for line in obj[:-1]:
43
+ exec(line)
44
+ # one-line generation of an instance
45
+ try:
46
+ obj = eval(obj[-1])
47
+ except Exception:
48
+ print ("Error processing object instance")
49
+ sys.exit()
50
+
51
+ # get object 'name'
52
+ objtype = type(obj)
53
+ name = getattr(objtype, '__name__', getattr(objtype, '__class__', objtype))
54
+
55
+ # profile dumping an object
56
+ import dill
57
+ import os
58
+ import cProfile
59
+ #name = os.path.splitext(os.path.basename(__file__))[0]
60
+ cProfile.run("dill.dumps(obj)", filename="%s.prof" % name)
61
+ msg = "gprof2dot -f pstats %s %s.prof | dot -Tpng -o %s.call.png" % (args, name, name)
62
+ try:
63
+ res = os.system(msg)
64
+ except Exception:
65
+ print ("Please verify install of 'gprof2dot' to view profile graphs")
66
+ if res:
67
+ print ("Please verify install of 'gprof2dot' to view profile graphs")
68
+
69
+ # get stats
70
+ f_prof = "%s.prof" % name
71
+ import pstats
72
+ stats = pstats.Stats(f_prof, stream=sys.stdout)
73
+ stats.strip_dirs().sort_stats('cumtime')
74
+ stats.print_stats(20) #XXX: save to file instead of print top 20?
75
+ os.remove(f_prof)
get_objgraph ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!C:\Users\migue\Downloads\Codigo\AI\HuggingModelAI\IAservicies\myenv\Scripts\python.exe
2
+ #
3
+ # Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
4
+ # Copyright (c) 2008-2016 California Institute of Technology.
5
+ # Copyright (c) 2016-2024 The Uncertainty Quantification Foundation.
6
+ # License: 3-clause BSD. The full license text is available at:
7
+ # - https://github.com/uqfoundation/dill/blob/master/LICENSE
8
+ """
9
+ display the reference paths for objects in ``dill.types`` or a .pkl file
10
+
11
+ Notes:
12
+ the generated image is useful in showing the pointer references in
13
+ objects that are or can be pickled. Any object in ``dill.objects``
14
+ listed in ``dill.load_types(picklable=True, unpicklable=True)`` works.
15
+
16
+ Examples::
17
+
18
+ $ get_objgraph ArrayType
19
+ Image generated as ArrayType.png
20
+ """
21
+
22
+ import dill as pickle
23
+ #pickle.debug.trace(True)
24
+ #import pickle
25
+
26
+ # get all objects for testing
27
+ from dill import load_types
28
+ load_types(pickleable=True,unpickleable=True)
29
+ from dill import objects
30
+
31
+ if __name__ == "__main__":
32
+ import sys
33
+ if len(sys.argv) != 2:
34
+ print ("Please provide exactly one file or type name (e.g. 'IntType')")
35
+ msg = "\n"
36
+ for objtype in list(objects.keys())[:40]:
37
+ msg += objtype + ', '
38
+ print (msg + "...")
39
+ else:
40
+ objtype = str(sys.argv[-1])
41
+ try:
42
+ obj = objects[objtype]
43
+ except KeyError:
44
+ obj = pickle.load(open(objtype,'rb'))
45
+ import os
46
+ objtype = os.path.splitext(objtype)[0]
47
+ try:
48
+ import objgraph
49
+ objgraph.show_refs(obj, filename=objtype+'.png')
50
+ except ImportError:
51
+ print ("Please install 'objgraph' to view object graphs")
52
+
53
+
54
+ # EOF
huggingface-cli.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c574193300d5f23639772059c556e84d222138dd251cf9ddee95eb5a4663f37c
3
+ size 108461
import_pb_to_tensorboard.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5c8bab1d9edcde78e2e8158df29baa25eff6ed268a881514bb24f6b6a52849fd
3
+ size 108471
isympy.1 ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '\" -*- coding: us-ascii -*-
2
+ .if \n(.g .ds T< \\FC
3
+ .if \n(.g .ds T> \\F[\n[.fam]]
4
+ .de URL
5
+ \\$2 \(la\\$1\(ra\\$3
6
+ ..
7
+ .if \n(.g .mso www.tmac
8
+ .TH isympy 1 2007-10-8 "" ""
9
+ .SH NAME
10
+ isympy \- interactive shell for SymPy
11
+ .SH SYNOPSIS
12
+ 'nh
13
+ .fi
14
+ .ad l
15
+ \fBisympy\fR \kx
16
+ .if (\nx>(\n(.l/2)) .nr x (\n(.l/5)
17
+ 'in \n(.iu+\nxu
18
+ [\fB-c\fR | \fB--console\fR] [\fB-p\fR ENCODING | \fB--pretty\fR ENCODING] [\fB-t\fR TYPE | \fB--types\fR TYPE] [\fB-o\fR ORDER | \fB--order\fR ORDER] [\fB-q\fR | \fB--quiet\fR] [\fB-d\fR | \fB--doctest\fR] [\fB-C\fR | \fB--no-cache\fR] [\fB-a\fR | \fB--auto\fR] [\fB-D\fR | \fB--debug\fR] [
19
+ -- | PYTHONOPTIONS]
20
+ 'in \n(.iu-\nxu
21
+ .ad b
22
+ 'hy
23
+ 'nh
24
+ .fi
25
+ .ad l
26
+ \fBisympy\fR \kx
27
+ .if (\nx>(\n(.l/2)) .nr x (\n(.l/5)
28
+ 'in \n(.iu+\nxu
29
+ [
30
+ {\fB-h\fR | \fB--help\fR}
31
+ |
32
+ {\fB-v\fR | \fB--version\fR}
33
+ ]
34
+ 'in \n(.iu-\nxu
35
+ .ad b
36
+ 'hy
37
+ .SH DESCRIPTION
38
+ isympy is a Python shell for SymPy. It is just a normal python shell
39
+ (ipython shell if you have the ipython package installed) that executes
40
+ the following commands so that you don't have to:
41
+ .PP
42
+ .nf
43
+ \*(T<
44
+ >>> from __future__ import division
45
+ >>> from sympy import *
46
+ >>> x, y, z = symbols("x,y,z")
47
+ >>> k, m, n = symbols("k,m,n", integer=True)
48
+ \*(T>
49
+ .fi
50
+ .PP
51
+ So starting isympy is equivalent to starting python (or ipython) and
52
+ executing the above commands by hand. It is intended for easy and quick
53
+ experimentation with SymPy. For more complicated programs, it is recommended
54
+ to write a script and import things explicitly (using the "from sympy
55
+ import sin, log, Symbol, ..." idiom).
56
+ .SH OPTIONS
57
+ .TP
58
+ \*(T<\fB\-c \fR\*(T>\fISHELL\fR, \*(T<\fB\-\-console=\fR\*(T>\fISHELL\fR
59
+ Use the specified shell (python or ipython) as
60
+ console backend instead of the default one (ipython
61
+ if present or python otherwise).
62
+
63
+ Example: isympy -c python
64
+
65
+ \fISHELL\fR could be either
66
+ \&'ipython' or 'python'
67
+ .TP
68
+ \*(T<\fB\-p \fR\*(T>\fIENCODING\fR, \*(T<\fB\-\-pretty=\fR\*(T>\fIENCODING\fR
69
+ Setup pretty printing in SymPy. By default, the most pretty, unicode
70
+ printing is enabled (if the terminal supports it). You can use less
71
+ pretty ASCII printing instead or no pretty printing at all.
72
+
73
+ Example: isympy -p no
74
+
75
+ \fIENCODING\fR must be one of 'unicode',
76
+ \&'ascii' or 'no'.
77
+ .TP
78
+ \*(T<\fB\-t \fR\*(T>\fITYPE\fR, \*(T<\fB\-\-types=\fR\*(T>\fITYPE\fR
79
+ Setup the ground types for the polys. By default, gmpy ground types
80
+ are used if gmpy2 or gmpy is installed, otherwise it falls back to python
81
+ ground types, which are a little bit slower. You can manually
82
+ choose python ground types even if gmpy is installed (e.g., for testing purposes).
83
+
84
+ Note that sympy ground types are not supported, and should be used
85
+ only for experimental purposes.
86
+
87
+ Note that the gmpy1 ground type is primarily intended for testing; it the
88
+ use of gmpy even if gmpy2 is available.
89
+
90
+ This is the same as setting the environment variable
91
+ SYMPY_GROUND_TYPES to the given ground type (e.g.,
92
+ SYMPY_GROUND_TYPES='gmpy')
93
+
94
+ The ground types can be determined interactively from the variable
95
+ sympy.polys.domains.GROUND_TYPES inside the isympy shell itself.
96
+
97
+ Example: isympy -t python
98
+
99
+ \fITYPE\fR must be one of 'gmpy',
100
+ \&'gmpy1' or 'python'.
101
+ .TP
102
+ \*(T<\fB\-o \fR\*(T>\fIORDER\fR, \*(T<\fB\-\-order=\fR\*(T>\fIORDER\fR
103
+ Setup the ordering of terms for printing. The default is lex, which
104
+ orders terms lexicographically (e.g., x**2 + x + 1). You can choose
105
+ other orderings, such as rev-lex, which will use reverse
106
+ lexicographic ordering (e.g., 1 + x + x**2).
107
+
108
+ Note that for very large expressions, ORDER='none' may speed up
109
+ printing considerably, with the tradeoff that the order of the terms
110
+ in the printed expression will have no canonical order
111
+
112
+ Example: isympy -o rev-lax
113
+
114
+ \fIORDER\fR must be one of 'lex', 'rev-lex', 'grlex',
115
+ \&'rev-grlex', 'grevlex', 'rev-grevlex', 'old', or 'none'.
116
+ .TP
117
+ \*(T<\fB\-q\fR\*(T>, \*(T<\fB\-\-quiet\fR\*(T>
118
+ Print only Python's and SymPy's versions to stdout at startup, and nothing else.
119
+ .TP
120
+ \*(T<\fB\-d\fR\*(T>, \*(T<\fB\-\-doctest\fR\*(T>
121
+ Use the same format that should be used for doctests. This is
122
+ equivalent to '\fIisympy -c python -p no\fR'.
123
+ .TP
124
+ \*(T<\fB\-C\fR\*(T>, \*(T<\fB\-\-no\-cache\fR\*(T>
125
+ Disable the caching mechanism. Disabling the cache may slow certain
126
+ operations down considerably. This is useful for testing the cache,
127
+ or for benchmarking, as the cache can result in deceptive benchmark timings.
128
+
129
+ This is the same as setting the environment variable SYMPY_USE_CACHE
130
+ to 'no'.
131
+ .TP
132
+ \*(T<\fB\-a\fR\*(T>, \*(T<\fB\-\-auto\fR\*(T>
133
+ Automatically create missing symbols. Normally, typing a name of a
134
+ Symbol that has not been instantiated first would raise NameError,
135
+ but with this option enabled, any undefined name will be
136
+ automatically created as a Symbol. This only works in IPython 0.11.
137
+
138
+ Note that this is intended only for interactive, calculator style
139
+ usage. In a script that uses SymPy, Symbols should be instantiated
140
+ at the top, so that it's clear what they are.
141
+
142
+ This will not override any names that are already defined, which
143
+ includes the single character letters represented by the mnemonic
144
+ QCOSINE (see the "Gotchas and Pitfalls" document in the
145
+ documentation). You can delete existing names by executing "del
146
+ name" in the shell itself. You can see if a name is defined by typing
147
+ "'name' in globals()".
148
+
149
+ The Symbols that are created using this have default assumptions.
150
+ If you want to place assumptions on symbols, you should create them
151
+ using symbols() or var().
152
+
153
+ Finally, this only works in the top level namespace. So, for
154
+ example, if you define a function in isympy with an undefined
155
+ Symbol, it will not work.
156
+ .TP
157
+ \*(T<\fB\-D\fR\*(T>, \*(T<\fB\-\-debug\fR\*(T>
158
+ Enable debugging output. This is the same as setting the
159
+ environment variable SYMPY_DEBUG to 'True'. The debug status is set
160
+ in the variable SYMPY_DEBUG within isympy.
161
+ .TP
162
+ -- \fIPYTHONOPTIONS\fR
163
+ These options will be passed on to \fIipython (1)\fR shell.
164
+ Only supported when ipython is being used (standard python shell not supported).
165
+
166
+ Two dashes (--) are required to separate \fIPYTHONOPTIONS\fR
167
+ from the other isympy options.
168
+
169
+ For example, to run iSymPy without startup banner and colors:
170
+
171
+ isympy -q -c ipython -- --colors=NoColor
172
+ .TP
173
+ \*(T<\fB\-h\fR\*(T>, \*(T<\fB\-\-help\fR\*(T>
174
+ Print help output and exit.
175
+ .TP
176
+ \*(T<\fB\-v\fR\*(T>, \*(T<\fB\-\-version\fR\*(T>
177
+ Print isympy version information and exit.
178
+ .SH FILES
179
+ .TP
180
+ \*(T<\fI${HOME}/.sympy\-history\fR\*(T>
181
+ Saves the history of commands when using the python
182
+ shell as backend.
183
+ .SH BUGS
184
+ The upstreams BTS can be found at \(lahttps://github.com/sympy/sympy/issues\(ra
185
+ Please report all bugs that you find in there, this will help improve
186
+ the overall quality of SymPy.
187
+ .SH "SEE ALSO"
188
+ \fBipython\fR(1), \fBpython\fR(1)
isympy.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c5b00e29646484644b74c45d8d9469b294cbe12de1ec5a9f23483ad98cf8ee2b
3
+ size 108427
isympy.py ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Python shell for SymPy.
3
+
4
+ This is just a normal Python shell (IPython shell if you have the
5
+ IPython package installed), that executes the following commands for
6
+ the user:
7
+
8
+ >>> from __future__ import division
9
+ >>> from sympy import *
10
+ >>> x, y, z, t = symbols('x y z t')
11
+ >>> k, m, n = symbols('k m n', integer=True)
12
+ >>> f, g, h = symbols('f g h', cls=Function)
13
+ >>> init_printing()
14
+
15
+ So starting 'isympy' is equivalent to starting Python (or IPython) and
16
+ executing the above commands by hand. It is intended for easy and quick
17
+ experimentation with SymPy. isympy is a good way to use SymPy as an
18
+ interactive calculator. If you have IPython and Matplotlib installed, then
19
+ interactive plotting is enabled by default.
20
+
21
+ COMMAND LINE OPTIONS
22
+ --------------------
23
+
24
+ -c CONSOLE, --console=CONSOLE
25
+
26
+ Use the specified shell (Python or IPython) shell as the console
27
+ backend instead of the default one (IPython if present, Python
28
+ otherwise), e.g.:
29
+
30
+ $isympy -c python
31
+
32
+ CONSOLE must be one of 'ipython' or 'python'
33
+
34
+ -p PRETTY, --pretty PRETTY
35
+
36
+ Setup pretty-printing in SymPy. When pretty-printing is enabled,
37
+ expressions can be printed with Unicode or ASCII. The default is
38
+ to use pretty-printing (with Unicode if the terminal supports it).
39
+ When this option is 'no', expressions will not be pretty-printed
40
+ and ASCII will be used:
41
+
42
+ $isympy -p no
43
+
44
+ PRETTY must be one of 'unicode', 'ascii', or 'no'
45
+
46
+ -t TYPES, --types=TYPES
47
+
48
+ Setup the ground types for the polys. By default, gmpy ground types
49
+ are used if gmpy2 or gmpy is installed, otherwise it falls back to python
50
+ ground types, which are a little bit slower. You can manually
51
+ choose python ground types even if gmpy is installed (e.g., for
52
+ testing purposes):
53
+
54
+ $isympy -t python
55
+
56
+ TYPES must be one of 'gmpy', 'gmpy1' or 'python'
57
+
58
+ Note that the ground type gmpy1 is primarily intended for testing; it
59
+ forces the use of gmpy version 1 even if gmpy2 is available.
60
+
61
+ This is the same as setting the environment variable
62
+ SYMPY_GROUND_TYPES to the given ground type (e.g.,
63
+ SYMPY_GROUND_TYPES='gmpy')
64
+
65
+ The ground types can be determined interactively from the variable
66
+ sympy.polys.domains.GROUND_TYPES.
67
+
68
+ -o ORDER, --order ORDER
69
+
70
+ Setup the ordering of terms for printing. The default is lex, which
71
+ orders terms lexicographically (e.g., x**2 + x + 1). You can choose
72
+ other orderings, such as rev-lex, which will use reverse
73
+ lexicographic ordering (e.g., 1 + x + x**2):
74
+
75
+ $isympy -o rev-lex
76
+
77
+ ORDER must be one of 'lex', 'rev-lex', 'grlex', 'rev-grlex',
78
+ 'grevlex', 'rev-grevlex', 'old', or 'none'.
79
+
80
+ Note that for very large expressions, ORDER='none' may speed up
81
+ printing considerably but the terms will have no canonical order.
82
+
83
+ -q, --quiet
84
+
85
+ Print only Python's and SymPy's versions to stdout at startup.
86
+
87
+ -d, --doctest
88
+
89
+ Use the same format that should be used for doctests. This is
90
+ equivalent to -c python -p no.
91
+
92
+ -C, --no-cache
93
+
94
+ Disable the caching mechanism. Disabling the cache may slow certain
95
+ operations down considerably. This is useful for testing the cache,
96
+ or for benchmarking, as the cache can result in deceptive timings.
97
+
98
+ This is equivalent to setting the environment variable
99
+ SYMPY_USE_CACHE to 'no'.
100
+
101
+ -a, --auto-symbols (requires at least IPython 0.11)
102
+
103
+ Automatically create missing symbols. Normally, typing a name of a
104
+ Symbol that has not been instantiated first would raise NameError,
105
+ but with this option enabled, any undefined name will be
106
+ automatically created as a Symbol.
107
+
108
+ Note that this is intended only for interactive, calculator style
109
+ usage. In a script that uses SymPy, Symbols should be instantiated
110
+ at the top, so that it's clear what they are.
111
+
112
+ This will not override any names that are already defined, which
113
+ includes the single character letters represented by the mnemonic
114
+ QCOSINE (see the "Gotchas and Pitfalls" document in the
115
+ documentation). You can delete existing names by executing "del
116
+ name". If a name is defined, typing "'name' in dir()" will return True.
117
+
118
+ The Symbols that are created using this have default assumptions.
119
+ If you want to place assumptions on symbols, you should create them
120
+ using symbols() or var().
121
+
122
+ Finally, this only works in the top level namespace. So, for
123
+ example, if you define a function in isympy with an undefined
124
+ Symbol, it will not work.
125
+
126
+ See also the -i and -I options.
127
+
128
+ -i, --int-to-Integer (requires at least IPython 0.11)
129
+
130
+ Automatically wrap int literals with Integer. This makes it so that
131
+ things like 1/2 will come out as Rational(1, 2), rather than 0.5. This
132
+ works by preprocessing the source and wrapping all int literals with
133
+ Integer. Note that this will not change the behavior of int literals
134
+ assigned to variables, and it also won't change the behavior of functions
135
+ that return int literals.
136
+
137
+ If you want an int, you can wrap the literal in int(), e.g. int(3)/int(2)
138
+ gives 1.5 (with division imported from __future__).
139
+
140
+ -I, --interactive (requires at least IPython 0.11)
141
+
142
+ This is equivalent to --auto-symbols --int-to-Integer. Future options
143
+ designed for ease of interactive use may be added to this.
144
+
145
+ -D, --debug
146
+
147
+ Enable debugging output. This is the same as setting the
148
+ environment variable SYMPY_DEBUG to 'True'. The debug status is set
149
+ in the variable SYMPY_DEBUG within isympy.
150
+
151
+ -- IPython options
152
+
153
+ Additionally you can pass command line options directly to the IPython
154
+ interpreter (the standard Python shell is not supported). However you
155
+ need to add the '--' separator between two types of options, e.g the
156
+ startup banner option and the colors option. You need to enter the
157
+ options as required by the version of IPython that you are using, too:
158
+
159
+ in IPython 0.11,
160
+
161
+ $isympy -q -- --colors=NoColor
162
+
163
+ or older versions of IPython,
164
+
165
+ $isympy -q -- -colors NoColor
166
+
167
+ See also isympy --help.
168
+ """
169
+
170
+ import os
171
+ import sys
172
+
173
+ # DO NOT IMPORT SYMPY HERE! Or the setting of the sympy environment variables
174
+ # by the command line will break.
175
+
176
+ def main() -> None:
177
+ from argparse import ArgumentParser, RawDescriptionHelpFormatter
178
+
179
+ VERSION = None
180
+ if '--version' in sys.argv:
181
+ # We cannot import sympy before this is run, because flags like -C and
182
+ # -t set environment variables that must be set before SymPy is
183
+ # imported. The only thing we need to import it for is to get the
184
+ # version, which only matters with the --version flag.
185
+ import sympy
186
+ VERSION = sympy.__version__
187
+
188
+ usage = 'isympy [options] -- [ipython options]'
189
+ parser = ArgumentParser(
190
+ usage=usage,
191
+ description=__doc__,
192
+ formatter_class=RawDescriptionHelpFormatter,
193
+ )
194
+
195
+ parser.add_argument('--version', action='version', version=VERSION)
196
+
197
+ parser.add_argument(
198
+ '-c', '--console',
199
+ dest='console',
200
+ action='store',
201
+ default=None,
202
+ choices=['ipython', 'python'],
203
+ metavar='CONSOLE',
204
+ help='select type of interactive session: ipython | python; defaults '
205
+ 'to ipython if IPython is installed, otherwise python')
206
+
207
+ parser.add_argument(
208
+ '-p', '--pretty',
209
+ dest='pretty',
210
+ action='store',
211
+ default=None,
212
+ metavar='PRETTY',
213
+ choices=['unicode', 'ascii', 'no'],
214
+ help='setup pretty printing: unicode | ascii | no; defaults to '
215
+ 'unicode printing if the terminal supports it, otherwise ascii')
216
+
217
+ parser.add_argument(
218
+ '-t', '--types',
219
+ dest='types',
220
+ action='store',
221
+ default=None,
222
+ metavar='TYPES',
223
+ choices=['gmpy', 'gmpy1', 'python'],
224
+ help='setup ground types: gmpy | gmpy1 | python; defaults to gmpy if gmpy2 '
225
+ 'or gmpy is installed, otherwise python')
226
+
227
+ parser.add_argument(
228
+ '-o', '--order',
229
+ dest='order',
230
+ action='store',
231
+ default=None,
232
+ metavar='ORDER',
233
+ choices=['lex', 'grlex', 'grevlex', 'rev-lex', 'rev-grlex', 'rev-grevlex', 'old', 'none'],
234
+ help='setup ordering of terms: [rev-]lex | [rev-]grlex | [rev-]grevlex | old | none; defaults to lex')
235
+
236
+ parser.add_argument(
237
+ '-q', '--quiet',
238
+ dest='quiet',
239
+ action='store_true',
240
+ default=False,
241
+ help='print only version information at startup')
242
+
243
+ parser.add_argument(
244
+ '-d', '--doctest',
245
+ dest='doctest',
246
+ action='store_true',
247
+ default=False,
248
+ help='use the doctest format for output (you can just copy and paste it)')
249
+
250
+ parser.add_argument(
251
+ '-C', '--no-cache',
252
+ dest='cache',
253
+ action='store_false',
254
+ default=True,
255
+ help='disable caching mechanism')
256
+
257
+ parser.add_argument(
258
+ '-a', '--auto-symbols',
259
+ dest='auto_symbols',
260
+ action='store_true',
261
+ default=False,
262
+ help='automatically construct missing symbols')
263
+
264
+ parser.add_argument(
265
+ '-i', '--int-to-Integer',
266
+ dest='auto_int_to_Integer',
267
+ action='store_true',
268
+ default=False,
269
+ help="automatically wrap int literals with Integer")
270
+
271
+ parser.add_argument(
272
+ '-I', '--interactive',
273
+ dest='interactive',
274
+ action='store_true',
275
+ default=False,
276
+ help="equivalent to -a -i")
277
+
278
+ parser.add_argument(
279
+ '-D', '--debug',
280
+ dest='debug',
281
+ action='store_true',
282
+ default=False,
283
+ help='enable debugging output')
284
+
285
+ (options, ipy_args) = parser.parse_known_args()
286
+ if '--' in ipy_args:
287
+ ipy_args.remove('--')
288
+
289
+ if not options.cache:
290
+ os.environ['SYMPY_USE_CACHE'] = 'no'
291
+
292
+ if options.types:
293
+ os.environ['SYMPY_GROUND_TYPES'] = options.types
294
+
295
+ if options.debug:
296
+ os.environ['SYMPY_DEBUG'] = str(options.debug)
297
+
298
+ if options.doctest:
299
+ options.pretty = 'no'
300
+ options.console = 'python'
301
+
302
+ session = options.console
303
+
304
+ if session is not None:
305
+ ipython = session == 'ipython'
306
+ else:
307
+ try:
308
+ import IPython
309
+ ipython = True
310
+ except ImportError:
311
+ if not options.quiet:
312
+ from sympy.interactive.session import no_ipython
313
+ print(no_ipython)
314
+ ipython = False
315
+
316
+ args = {
317
+ 'pretty_print': True,
318
+ 'use_unicode': None,
319
+ 'use_latex': None,
320
+ 'order': None,
321
+ 'argv': ipy_args,
322
+ }
323
+
324
+ if options.pretty == 'unicode':
325
+ args['use_unicode'] = True
326
+ elif options.pretty == 'ascii':
327
+ args['use_unicode'] = False
328
+ elif options.pretty == 'no':
329
+ args['pretty_print'] = False
330
+
331
+ if options.order is not None:
332
+ args['order'] = options.order
333
+
334
+ args['quiet'] = options.quiet
335
+ args['auto_symbols'] = options.auto_symbols or options.interactive
336
+ args['auto_int_to_Integer'] = options.auto_int_to_Integer or options.interactive
337
+
338
+ from sympy.interactive import init_session
339
+ init_session(ipython, **args)
340
+
341
+ if __name__ == "__main__":
342
+ main()
local.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import threading
4
+ from contextlib import contextmanager
5
+ from typing import TYPE_CHECKING
6
+
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Iterator
10
+
11
+
12
+ # Simple dynamic scoping implementation. The name "parametrize" comes
13
+ # from Racket.
14
+ #
15
+ # WARNING WARNING: LOOKING TO EDIT THIS FILE? Think carefully about
16
+ # why you need to add a toggle to the global behavior of code
17
+ # generation. The parameters here should really only be used
18
+ # for "temporary" situations, where we need to temporarily change
19
+ # the codegen in some cases because we cannot conveniently update
20
+ # all call sites, and are slated to be eliminated once all call
21
+ # sites are eliminated. If you don't have a plan for how to get there,
22
+ # DON'T add a new entry here.
23
+
24
+
25
+ class Locals(threading.local):
26
+ use_const_ref_for_mutable_tensors: bool | None = None
27
+ use_ilistref_for_tensor_lists: bool | None = None
28
+
29
+
30
+ _locals = Locals()
31
+
32
+
33
+ def use_const_ref_for_mutable_tensors() -> bool:
34
+ assert _locals.use_const_ref_for_mutable_tensors is not None, (
35
+ "need to initialize local.use_const_ref_for_mutable_tensors with "
36
+ "local.parametrize"
37
+ )
38
+ return _locals.use_const_ref_for_mutable_tensors
39
+
40
+
41
+ def use_ilistref_for_tensor_lists() -> bool:
42
+ assert _locals.use_ilistref_for_tensor_lists is not None, (
43
+ "need to initialize local.use_ilistref_for_tensor_lists with "
44
+ "local.parametrize"
45
+ )
46
+ return _locals.use_ilistref_for_tensor_lists
47
+
48
+
49
+ @contextmanager
50
+ def parametrize(
51
+ *, use_const_ref_for_mutable_tensors: bool, use_ilistref_for_tensor_lists: bool
52
+ ) -> Iterator[None]:
53
+ old_use_const_ref_for_mutable_tensors = _locals.use_const_ref_for_mutable_tensors
54
+ old_use_ilistref_for_tensor_lists = _locals.use_ilistref_for_tensor_lists
55
+ try:
56
+ _locals.use_const_ref_for_mutable_tensors = use_const_ref_for_mutable_tensors
57
+ _locals.use_ilistref_for_tensor_lists = use_ilistref_for_tensor_lists
58
+ yield
59
+ finally:
60
+ _locals.use_const_ref_for_mutable_tensors = (
61
+ old_use_const_ref_for_mutable_tensors
62
+ )
63
+ _locals.use_ilistref_for_tensor_lists = old_use_ilistref_for_tensor_lists
markdown-it.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:11d8735f26e48e2a2f578c86866dd60b5c4e99c0afa7e7904bbc1c3a213003f9
3
+ size 108444
markdown_py.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:eb545c7705c5f8f2fc008a81c5848028645bf057f596c6340d1dfa6f115d2eb8
3
+ size 108438
model.py ADDED
The diff for this file is too large to render. See raw diff
 
native_function_generation.py ADDED
@@ -0,0 +1,651 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import string
4
+ from collections import defaultdict
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torchgen.api.dispatcher as dispatcher
8
+ from torchgen.api.translate import translate
9
+ from torchgen.api.types import Binding, DispatcherSignature, Expr
10
+ from torchgen.context import with_native_function
11
+ from torchgen.model import (
12
+ Annotation,
13
+ Argument,
14
+ BackendIndex,
15
+ BackendMetadata,
16
+ BaseOperatorName,
17
+ BaseTy,
18
+ BaseType,
19
+ DEFAULT_KERNEL_NAMESPACE,
20
+ DeviceCheckType,
21
+ DispatchKey,
22
+ FunctionSchema,
23
+ NativeFunction,
24
+ NativeFunctionsGroup,
25
+ OperatorName,
26
+ Return,
27
+ SchemaKind,
28
+ Variant,
29
+ )
30
+ from torchgen.utils import concatMap
31
+
32
+
33
+ if TYPE_CHECKING:
34
+ from collections.abc import Sequence
35
+
36
+
37
+ # See Note: [Out ops with functional variants that don't get grouped properly]
38
+ OUT_OPS_THAT_DONT_GET_GROUPED_PROPERLY = [
39
+ # This has a functional variant, but it's currently marked private.
40
+ # This function should be marked private as well (*_backward ops aren't exposed to python anyway).
41
+ "adaptive_avg_pool3d_backward.grad_input",
42
+ # There's a functional variant, _slow_conv2d_backward.output_mask, that isn't grouped properly.
43
+ # Maybe we can kill this operator in favor of convolution_backward?
44
+ "_slow_conv2d_backward.grad_input",
45
+ ]
46
+
47
+
48
+ # See Note: [Mutable ops that cannot get an out variant]
49
+ MUTABLE_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT = [
50
+ # should be out=?
51
+ "_cummax_helper",
52
+ # should be out=?
53
+ "_cummin_helper",
54
+ ]
55
+
56
+ # All of these operators don't have any tensor like returns
57
+ FUNCTIONAL_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT = [
58
+ "_assert_async", # no return
59
+ "_assert_async.msg", # no return
60
+ "_assert_tensor_metadata", # no return
61
+ "_cslt_sparse_mm_search", # returns an int
62
+ "_assert_scalar", # no return
63
+ "_dimI", # returns an int
64
+ "_dimV", # returns an int
65
+ "_has_same_storage_numel", # returns a boolean
66
+ "_linalg_check_errors", # no return
67
+ "_local_scalar_dense", # returns a Scalar
68
+ "_nested_tensor_from_mask_left_aligned", # returns a boolean
69
+ "_nnz", # returns an int
70
+ "_use_cudnn_ctc_loss", # returns a boolean
71
+ "_use_cudnn_ctc_loss.Tensor", # returns a boolean
72
+ "_validate_compressed_sparse_indices", # no return
73
+ "allclose", # returns a boolean
74
+ "dense_dim", # returns an int
75
+ "equal", # returns a boolean
76
+ "is_coalesced", # returns an boolean
77
+ "is_pinned", # returns a boolean
78
+ "is_same_size", # returns a boolean
79
+ "is_set_to", # returns a boolean
80
+ "q_per_channel_axis", # returns an int
81
+ "q_scale", # returns a float
82
+ "q_zero_point", # returns an int
83
+ "qscheme", # returns a QScheme
84
+ "record_stream", # no return
85
+ "sparse_dim", # returns an int
86
+ "sym_constrain_range", # no return
87
+ "sym_constrain_range_for_size", # no return
88
+ "_nested_tensor_storage_offsets", # returns a vector of ints
89
+ "_chunk_grad_outputs_efficient_attention", # returns a bool
90
+ "_fused_sdp_choice", # returns an int
91
+ "_print", # no return
92
+ "_sink_tokens", # no return
93
+ "_nested_get_ragged_idx", # returns an int
94
+ ]
95
+
96
+ INPLACE_OPS_THAT_DONT_GET_GROUPED_PROPERLY = [
97
+ # polygamma and polygamma.out both exist, but have a
98
+ # pre-self arg (while polygamma_ does not)
99
+ # We should either fix this schema so it can be grouped properly,
100
+ # or allow the codegen to generate new functional/out= NativeFunctions for this op
101
+ # (which would require changing its overload name to prevent overload ambiguity).
102
+ "polygamma_"
103
+ ]
104
+
105
+
106
+ # Groups "similar" NativeFunctions together
107
+ # example add.Tensor, add_.Tensor, add.out
108
+ # "similar" NativeFunctions are all expected to have an identical `signature()`,
109
+ # But have differing SchemaKinds.
110
+ def pre_group_native_functions(
111
+ native_functions: Sequence[NativeFunction],
112
+ ) -> dict[FunctionSchema, dict[SchemaKind, NativeFunction]]:
113
+ pre_grouped_native_functions: dict[
114
+ FunctionSchema, dict[SchemaKind, NativeFunction]
115
+ ] = defaultdict(dict)
116
+ for f in native_functions:
117
+ d = pre_grouped_native_functions[f.func.signature()]
118
+ assert f.func.kind() not in d
119
+ d[f.func.kind()] = f
120
+ return pre_grouped_native_functions
121
+
122
+
123
+ # Returns the out variant overload name given a base function overload name
124
+ def get_expected_out_variant_overload_name(overload_name: str | None) -> str:
125
+ return "out" if not overload_name else f"{overload_name}_out"
126
+
127
+
128
+ # Helper function: given an inplace FunctionSchema, generate its corresponding out= variant
129
+ # Example before:
130
+ # _add_relu_.Scalar(Tensor(a!) self, Scalar other, Scalar alpha=1) -> Tensor(a!)
131
+ # Example after:
132
+ # _add_relu.Scalar_out(Tensor self, Scalar other, Scalar alpha=1, *, Tensor(a!) out)
133
+ def self_to_out_signature(func: FunctionSchema) -> FunctionSchema:
134
+ # Generating an out= schema from an inplace schema.
135
+ assert func.kind() == SchemaKind.inplace
136
+ assert func.arguments.self_arg is not None
137
+ # The new out= schema has:
138
+ # - a new out argument with the same type as "func" (but with a mutable annotation)
139
+ # - The returns (if any) now alias the out= argument instead of "func"
140
+ # - an "out" overload name
141
+ return FunctionSchema(
142
+ name=func.name.remove_inplace().with_overload(
143
+ get_expected_out_variant_overload_name(func.name.overload_name)
144
+ ),
145
+ arguments=func.arguments.remove_self_annotation().with_out_args(
146
+ [
147
+ Argument(
148
+ name="out",
149
+ type=func.arguments.self_arg.argument.type,
150
+ default=None,
151
+ annotation=func.arguments.self_arg.argument.annotation,
152
+ )
153
+ ]
154
+ ),
155
+ returns=func.returns,
156
+ )
157
+
158
+
159
+ # Helper function: given a functional FunctionSchema, generate its corresponding out= variant
160
+ # Example before:
161
+ # _to_copy(Tensor self, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None,
162
+ # bool? pin_memory=None, bool non_blocking=False, MemoryFormat? memory_format=None) -> Tensor
163
+ # Example after:
164
+ # _to_copy._out(Tensor self, *, bool non_blocking=False, MemoryFormat? memory_format=None,
165
+ # Tensor(a!) out) -> Tensor(a!)
166
+ def functional_to_out_signature(func: FunctionSchema) -> FunctionSchema:
167
+ # Generating an out= schema from a functional schema.
168
+ assert func.kind() == SchemaKind.functional
169
+
170
+ new_returns, new_out_args = generate_out_args_from_schema(func)
171
+ # The new out= schema has:
172
+ # - one or more new out argument(s) with the same type as returns (but with a mutable annotation)
173
+ # - The returns now alias the out= arguments
174
+ # - an "_out" overload name
175
+ return FunctionSchema(
176
+ name=func.name.with_overload(
177
+ get_expected_out_variant_overload_name(func.name.overload_name)
178
+ ),
179
+ arguments=func.arguments.signature().with_out_args(
180
+ new_out_args,
181
+ ),
182
+ returns=tuple(new_returns),
183
+ )
184
+
185
+
186
+ # Helper function: given a function schema, generate corresponding out arguments, also the updated return annotations.
187
+ def generate_out_args_from_schema(
188
+ func: FunctionSchema,
189
+ ) -> tuple[list[Return], list[Argument]]:
190
+ # More of a sanity check - our existing restrictions on schemas should enforce that
191
+ # mutable schema kinds never return their mutable arguments.
192
+ assert not any(
193
+ r.annotation is not None and r.annotation.is_write for r in func.returns
194
+ )
195
+
196
+ tensorlike_rets = [r for r in func.returns if r.type.is_tensor_like()]
197
+ assert len(tensorlike_rets) > 0
198
+
199
+ used_annotations = concatMap(
200
+ lambda a: [] if a.annotation is None else a.annotation.alias_set,
201
+ func.arguments.flat_all,
202
+ )
203
+ valid_annotations = [x for x in string.ascii_lowercase if x not in used_annotations]
204
+
205
+ all_rets_are_tensors = all(r.type == BaseType(BaseTy.Tensor) for r in func.returns)
206
+
207
+ new_out_args: list[Argument] = []
208
+ # The end result of new_returns is that:
209
+ # - If every return is a plain tensor, then the new returns == the old returns, but with the out= alias annotations added.
210
+ # - Otherwise, none of the out arguments show up in the returns (and we're only left with non-tensor-like returns, if any).
211
+ new_returns: list[Return] = []
212
+ for i, r in enumerate(func.returns):
213
+ if r.type.is_tensor_like():
214
+ new_out = Argument(
215
+ name="out" if len(func.returns) == 1 else f"out{i}",
216
+ type=r.type,
217
+ default=None,
218
+ annotation=Annotation.parse(f"{valid_annotations[i]}!"),
219
+ )
220
+ new_out_args.append(new_out)
221
+ if all_rets_are_tensors:
222
+ # The convention for out= schemas is that they only return their out arguments
223
+ # if the return is a plain Tensor (or if it's a tuple of plain Tensors)
224
+ new_ret = Return(
225
+ name=None, type=new_out.type, annotation=new_out.annotation
226
+ )
227
+ new_returns.append(new_ret)
228
+ else:
229
+ new_returns.append(r)
230
+ return new_returns, new_out_args
231
+
232
+
233
+ # Helper function: given a mutable FunctionSchema, generate its corresponding out= variant
234
+ # Example before:
235
+ # _fused_moving_avg_obs_fq_helper(Tensor self, Tensor observer_on, Tensor fake_quant_on, Tensor(a!) running_min, Tensor(b!) running_max, Tensor(c!) scale, Tensor(d!) zero_point, float averaging_const, int quant_min, int quant_max, int ch_axis, bool per_row_fake_quant=False, bool symmetric_quant=False) -> (Tensor output, Tensor mask) # noqa: B950
236
+ # Example after:
237
+ # _fused_moving_avg_obs_fq_helper._out(Tensor self, Tensor observer_on, Tensor fake_quant_on, Tensor(a!) running_min, Tensor(b!) running_max, Tensor(c!) scale, Tensor(d!) zero_point, float averaging_const, int quant_min, int quant_max, int ch_axis, bool per_row_fake_quant=False, bool symmetric_quant=False, *, Tensor(e!) out0, Tensor(f!) out1) -> (Tensor(e!), Tensor(f!)) # noqa: B950
238
+ def mutable_to_out_signature(func: FunctionSchema) -> FunctionSchema:
239
+ # Generating an out= schema from a mutable schema.
240
+ assert func.kind() == SchemaKind.mutable
241
+ # The new out= schema has:
242
+ # - Any non-aliased tensor-like returns are converted to mutable, aliased out= arguments
243
+ # (if the argument is a tensor then we also return it for method chaining,
244
+ # otherwise we return nothing)
245
+ # - an "out" overload name
246
+ #
247
+ # Note that:
248
+ # (1) This also means that we can *only* generate an out= variant from a mutable schema
249
+ # if the mutable schema has at least one tensor-like non-aliasing return.
250
+ # (2) The generated out= variant still has mutable positional arguments,
251
+ # but if necessary we could probably add another out= variant that also
252
+ # functionalizes the mutable arguments (a functional_out variant)
253
+
254
+ new_returns, new_out_args = generate_out_args_from_schema(func)
255
+
256
+ return FunctionSchema(
257
+ name=func.name.remove_inplace().with_overload(
258
+ get_expected_out_variant_overload_name(func.name.overload_name)
259
+ ),
260
+ arguments=func.arguments.with_out_args(new_out_args),
261
+ returns=tuple(new_returns),
262
+ )
263
+
264
+
265
+ # This function, given function of one SchemaKind, as well as a target SchemaKind,
266
+ # generates a new NativeFunction with the same properties, but using the target SchemaKind.
267
+ # We only actually generate functions for either functional or out= SchemaKinds.
268
+ # This function returns a tuple, with:
269
+ # - The generated NativeFunction
270
+ # - a dictionary of `BackendIndex` objects, describing which dispatch keys
271
+ # we will generate kernels for, for the new NativeFunction.
272
+ # Details are in the function, but we only generate composite kernels (in some cases) today.
273
+ def generate_function(
274
+ f: NativeFunction, k: SchemaKind
275
+ ) -> tuple[NativeFunction, dict[DispatchKey, dict[OperatorName, BackendMetadata]]]:
276
+ from torchgen.api import cpp
277
+
278
+ if k == SchemaKind.functional:
279
+ assert f.func.kind() != SchemaKind.functional
280
+ # The new "functional" NativeFunction has:
281
+ # - any mutable arguments have been converted into (immutable) returns.
282
+ # (if a mutable argument was not also a return, it gets converted to one)
283
+ # - "_functional" appended to the base name, ONLY IF this op has a mutable variant.
284
+ # See Note [Overload Ambiguity With Functional Variants]
285
+ # The default grouping logic in signature() actually already does this,
286
+ # so we can piggy-back off it (but we still want return names)
287
+ func = f.func.signature(keep_return_names=True).with_name(
288
+ OperatorName(
289
+ name=BaseOperatorName(
290
+ base=f.func.name.name.base,
291
+ inplace=False,
292
+ dunder_method=f.func.name.name.dunder_method,
293
+ # See Note [Overload Ambiguity With Functional Variants]
294
+ functional_overload=f.func.kind() == SchemaKind.mutable,
295
+ ),
296
+ overload_name=f.func.name.overload_name,
297
+ )
298
+ )
299
+ elif k == SchemaKind.out:
300
+ # We generate out= ops mostly just so that we can pair up NativeFunctions into groups easily,
301
+ # but at least today, there is no good reason to actually use them.
302
+ # we'll generate a dispatcher entry for them, but won't actually register any kernels for them.
303
+ if f.func.kind() == SchemaKind.inplace:
304
+ func = self_to_out_signature(f.func)
305
+ elif f.func.kind() == SchemaKind.mutable:
306
+ func = mutable_to_out_signature(f.func)
307
+ elif f.func.kind() == SchemaKind.functional:
308
+ func = functional_to_out_signature(f.func)
309
+ else:
310
+ raise AssertionError(
311
+ "We only bother generating out= functions from either inplace or mutable or functional variants"
312
+ )
313
+ else:
314
+ raise AssertionError(
315
+ "We currently only generate either functional or out= NativeFunctions"
316
+ )
317
+
318
+ # Generated kernel naming convention for out: <op_name>_<overload_name>. The reason for this is to
319
+ # disambiguate operator with the same name but different overload name, e.g., `randn.names_out` and
320
+ # `randn.generator_with_names_out`.
321
+ kernel_name = (
322
+ func.name.unambiguous_name()
323
+ if func.kind() == SchemaKind.out
324
+ else cpp.name(func)
325
+ )
326
+ if f.func.has_symint():
327
+ kernel_name += "_symint"
328
+ backend_metadata = {
329
+ DispatchKey.CompositeExplicitAutograd: {
330
+ func.name: BackendMetadata(
331
+ kernel=kernel_name,
332
+ structured=False,
333
+ cpp_namespace=DEFAULT_KERNEL_NAMESPACE,
334
+ )
335
+ }
336
+ }
337
+ tags = {"generated"} | set(
338
+ f.tags & {"nondeterministic_seeded", "view_copy", "pt2_compliant_tag"}
339
+ )
340
+
341
+ return (
342
+ NativeFunction(
343
+ func=func,
344
+ use_const_ref_for_mutable_tensors=f.use_const_ref_for_mutable_tensors,
345
+ # These generated fn's aren't meant to be user friendly- don't generate methods.
346
+ variants={Variant.function},
347
+ structured=False,
348
+ structured_delegate=None,
349
+ structured_inherits=None,
350
+ precomputed=None,
351
+ autogen=[],
352
+ ufunc_inner_loop={},
353
+ manual_kernel_registration=False,
354
+ manual_cpp_binding=False,
355
+ python_module=None,
356
+ category_override=None,
357
+ device_guard=False,
358
+ device_check=DeviceCheckType.NoCheck,
359
+ loc=f.loc,
360
+ cpp_no_default_args=set(),
361
+ is_abstract=f.is_abstract,
362
+ has_composite_implicit_autograd_kernel=False,
363
+ has_composite_implicit_autograd_nested_tensor_kernel=False,
364
+ has_composite_explicit_autograd_kernel=True,
365
+ has_composite_explicit_autograd_non_functional_kernel=False,
366
+ # Every generated NativeFunction gets a "generated" tag, so it's easy to tell
367
+ # which NativeFunction objects did not come directly from native_functions.yaml.
368
+ tags=tags,
369
+ namespace=f.namespace,
370
+ ),
371
+ backend_metadata,
372
+ )
373
+
374
+
375
+ # This function is responsible for adding generated NativeFunctions which don't appear
376
+ # explicitly in the codegen.
377
+ # You can inspect the full list of NativeFunctions yourself with the torchgen package, by running
378
+ # torchgen.parse_native_yaml("aten/src/ATen/native/native_functions.yaml", "aten/src/ATen/native/tags.yaml")
379
+ # (Maybe we should make a friendly API for this)
380
+ #
381
+ # Note: this function *mutates* its two inputs,
382
+ # adding the new NativeFunctions / BackendMetadata to them
383
+ def add_generated_native_functions(
384
+ rs: list[NativeFunction],
385
+ indices: dict[DispatchKey, dict[OperatorName, BackendMetadata]],
386
+ ) -> None:
387
+ # The main code for generating new NativeFunctions
388
+ # First we group of NativeFunctions by schema kind,
389
+ # then we detect which ones are missing and generate them.
390
+ pre_grouped_native_functions = pre_group_native_functions(rs)
391
+ for d in pre_grouped_native_functions.values():
392
+ has_functional = SchemaKind.functional in d
393
+ has_inplace = SchemaKind.inplace in d
394
+ has_mutable = SchemaKind.mutable in d
395
+ has_out = SchemaKind.out in d
396
+ is_core = any("core" in variant.tags for variant in d.values())
397
+
398
+ # We automatically generate a few native functions that don't exist in the yaml, for a few reasons:
399
+ # (1) If an operator has an inplace/out= variant but no functional variant, we can generate
400
+ # a simple functional variant that the functionalization pass can consume.
401
+ # (2) If an operator has an inplace or functional but no out= variant, we generate an out=
402
+ # variant, mostly so we can easily pair up functions into NativeFunctionsGroup,
403
+ # while maintaining the constraint that the out= variant is "required".
404
+ if has_mutable or has_inplace or has_out or has_functional:
405
+ # Don't bother generating functions trio's for native functions that bypass the dispatcher.
406
+ are_manual = all(f.manual_cpp_binding for f in d.values())
407
+ # Don't bother generating functional + out= variants for view operators
408
+ # set_ is technically an inplace_view, but for now it is treated
409
+ # as a normal inplace op in the codegen
410
+ has_view_ops = any(
411
+ f.is_view_op and str(f.func.name.name) != "set_" for f in d.values()
412
+ )
413
+ # Don't generate the other variants for non-core CompositeImplicitAutograd operators.
414
+ # We could probably do this, but the main benefit of generating the function triplets
415
+ # is for transforms that need them, and transforms don't need to act directly
416
+ # on CompositeImplicitAutograd operators (since we let them decompose).
417
+ are_composite_implicit = all(
418
+ f.has_composite_implicit_autograd_kernel for f in d.values()
419
+ )
420
+ if are_manual or has_view_ops or are_composite_implicit and not is_core:
421
+ continue
422
+ if has_out and len(d.values()) == 1:
423
+ # Note: [Out ops with functional variants that don't get grouped properly]
424
+ # In theory we could validly have an out= operator in native_functions.yaml
425
+ # that has no other variants.
426
+ # But today, all of the operators where that's the case actually do have
427
+ # functional variants, that we are just unable to pair up properly.
428
+ # I think banning this all together is probably safer
429
+ # (you can always add a functional variant yourself if you want to add a new out= operator).
430
+ #
431
+ # We should probably fix the existing cases; this check is to prevent us from adding more over time.
432
+ if (
433
+ str(d[SchemaKind.out].func.name)
434
+ not in OUT_OPS_THAT_DONT_GET_GROUPED_PROPERLY
435
+ ):
436
+ raise AssertionError(
437
+ f"Found an out= operator that we could not find any other variants of: {str(d[SchemaKind.out].func)}"
438
+ )
439
+ continue
440
+
441
+ # Some inplace ops that have problematic schemas (that we should fix), which prevent us
442
+ # from generating out= and functional variants
443
+ if (
444
+ has_inplace
445
+ and str(d[SchemaKind.inplace].func.name)
446
+ in INPLACE_OPS_THAT_DONT_GET_GROUPED_PROPERLY
447
+ ):
448
+ continue
449
+
450
+ base_fn = (
451
+ d[SchemaKind.mutable]
452
+ if has_mutable
453
+ else d[SchemaKind.inplace]
454
+ if has_inplace
455
+ else d[SchemaKind.out]
456
+ if has_out
457
+ else d[SchemaKind.functional]
458
+ )
459
+
460
+ # Note: [Mutable ops that cannot get an out variant]
461
+ # We can only generate an out= variant if either:
462
+ # - the original function has tensor-like returns (since we can convert them to out kwargs)
463
+ # - or it's inplace (since we can convert `self` to an out kwarg)
464
+ # There are only two functions that don't fit this criteria today though,
465
+ # and they both look like they should be fixed to be out= variants,
466
+ # so if feels safer to ban this schema all-together
467
+ base_fn_valid = base_fn.func.kind() == SchemaKind.inplace or any(
468
+ r.type.is_tensor_like() for r in base_fn.func.returns
469
+ )
470
+ # Note: [Loosen the assertion that all functional should have out variant]
471
+ # By design all functional operators should have our variants. The needs_out check
472
+ # is loosening this requirement, changing it to only generate out variant if there's
473
+ # an `autogen` block in the native function, in the long run it should be removed.
474
+ # FIXME: Remove this after figuring out CI job failures related to min, max, mean
475
+ needs_out = any("out" in str(op_name) for op_name in base_fn.autogen)
476
+ gets_out_variant = not has_out and base_fn_valid and needs_out
477
+ if not has_out and not base_fn_valid:
478
+ if (
479
+ str(base_fn.func.name)
480
+ not in MUTABLE_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT
481
+ and str(base_fn.func.name)
482
+ not in FUNCTIONAL_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT
483
+ ):
484
+ raise AssertionError(
485
+ f"""Found an operator that we could not generate an out= variant for: {str(base_fn.func)}.
486
+ This type of operators don't have tensor-like return, making it difficult to generate a proper out= variant. If
487
+ out= variant is not needed, please add the function name into FUNCTIONAL_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT list."""
488
+ )
489
+
490
+ # Generate an out= variant
491
+ if gets_out_variant:
492
+ fn, metadata = generate_function(base_fn, SchemaKind.out)
493
+ d[SchemaKind.out] = fn
494
+ BackendIndex.grow_index(indices, metadata)
495
+ rs.append(fn)
496
+
497
+ # Generate a functional variant, but only do it if the operator got an out= variant
498
+ # (Functional variants are only useful if we can group up the variants,
499
+ # which we can only do if they have an out= variant)
500
+ if not has_functional and (has_out or gets_out_variant):
501
+ fn, metadata = generate_function(base_fn, SchemaKind.functional)
502
+ d[SchemaKind.functional] = fn
503
+ BackendIndex.grow_index(indices, metadata)
504
+ rs.append(fn)
505
+
506
+
507
+ def return_str(rets: tuple[Return, ...], names: list[str]) -> str:
508
+ assert len(rets) == len(names)
509
+ if len(rets) == 0:
510
+ return ""
511
+ elif len(rets) == 1:
512
+ return f"return {names[0]};"
513
+ else:
514
+ return f"return {dispatcher.returns_type(rets).cpp_type()}({', '.join(names)});"
515
+
516
+
517
+ # Given a function, and the name of a variable corresponding to the output of that function,
518
+ # gather up all of the individual returns that are not aliased
519
+ def gather_nonaliased_inner_rets(func: FunctionSchema, out_var: str) -> list[str]:
520
+ aliased_rets = func.aliased_return_names()
521
+ non_aliased_names = []
522
+ is_out_var_a_tuple = len(func.returns) > 1
523
+ for i, r in enumerate(aliased_rets):
524
+ if r is None:
525
+ non_aliased_names.append(
526
+ f"std::get<{i}>({out_var})" if is_out_var_a_tuple else out_var
527
+ )
528
+ return non_aliased_names
529
+
530
+
531
+ # Generates functional kernels in terms of their inplace.mutable counterparts.
532
+ # We only do this for "generated" NativeFunctions
533
+ @with_native_function
534
+ def gen_composite_functional_kernel(g: NativeFunctionsGroup) -> str | None:
535
+ # We should only be generating these for code-generated NativeFunctions
536
+ if "generated" not in g.functional.tags:
537
+ return None
538
+ # And we always write the kernel for a generated op in terms of a non-generated op.
539
+ if g.inplace is not None and "generated" not in g.inplace.tags:
540
+ target_f = g.inplace
541
+ elif g.mutable is not None and "generated" not in g.mutable.tags:
542
+ target_f = g.mutable
543
+ else:
544
+ # We should be guaranteed to have a valid inplace/mutable variant to call into.
545
+ # See Note: [Mutable Ops Not Using Functionalization]
546
+ raise AssertionError(str(g.functional.func))
547
+
548
+ sig = DispatcherSignature(g.functional.func)
549
+ target_sig = DispatcherSignature(target_f.func)
550
+
551
+ context: list[Binding | Expr] = []
552
+ clone_mutable_inputs = []
553
+ cloned_return_names = []
554
+ # We can't just directly pass all of the arguments from the functional op into the mutating op.
555
+ # We need to check for which inputs to the mutating operator are mutable,
556
+ # and clone those inputs first.
557
+ for a_curr, a_tgt in zip(
558
+ dispatcher.jit_arguments(g.functional.func),
559
+ dispatcher.jit_arguments(target_f.func),
560
+ ):
561
+ if a_tgt.annotation is not None and a_tgt.annotation.is_write:
562
+ clone_mutable_inputs.append(
563
+ f"auto {a_curr.name}_clone = clone_arg({a_curr.name});"
564
+ )
565
+ context.append(
566
+ Expr(
567
+ expr=f"{a_curr.name}_clone",
568
+ type=dispatcher.argument_type(a_curr, binds=a_curr.name),
569
+ )
570
+ )
571
+ # Invariant: mutable arguments on the inner mutable op are always returns on the functional op.
572
+ cloned_return_names.append(f"{a_curr.name}_clone")
573
+ else:
574
+ context.append(dispatcher.argument(a_curr))
575
+ exprs = ", ".join([e.expr for e in translate(context, target_sig.arguments())])
576
+
577
+ out_name = "output"
578
+ maybe_assign = f"auto {out_name} = " if len(target_f.func.returns) > 0 else ""
579
+ inner_return_names = gather_nonaliased_inner_rets(target_f.func, out_name)
580
+ ret_str = return_str(
581
+ g.functional.func.returns, inner_return_names + cloned_return_names
582
+ )
583
+
584
+ clone_mutable_inputs_str = "\n".join(clone_mutable_inputs)
585
+ return f"""
586
+ {sig.defn(name=sig.name() + ("_symint" if g.out.func.has_symint() else ""))} {{
587
+ {clone_mutable_inputs_str}
588
+ {maybe_assign}at::_ops::{target_f.func.name.unambiguous_name()}::call({exprs});
589
+ {ret_str}
590
+ }}
591
+ """
592
+
593
+
594
+ # Generates out= kernels in terms of their functional counterparts.
595
+ # We only do this for "generated" NativeFunctions
596
+ @with_native_function
597
+ def gen_composite_out_kernel(g: NativeFunctionsGroup) -> str | None:
598
+ # We should only be generating these for code-generated NativeFunctions
599
+ if "generated" not in g.out.tags:
600
+ return None
601
+ # And we always write the kernel for the out= op in terms of the functional.
602
+ # Note that the functional op might have also been generated, but we don't have to
603
+ # worry about cycles, because the generated functional kernels are always implemented
604
+ # in terms of non-generated kernels (see gen_composite_functional_kernel).
605
+
606
+ sig = DispatcherSignature(g.out.func)
607
+ target_sig = DispatcherSignature(g.functional.func)
608
+
609
+ exprs = ", ".join(
610
+ [e.expr for e in translate(sig.arguments(), target_sig.arguments())]
611
+ )
612
+
613
+ copy_outs = []
614
+ out_name = "tmp_output"
615
+ for i, out_arg in enumerate(g.out.func.arguments.out):
616
+ functional_return_name = (
617
+ out_name
618
+ if len(g.functional.func.returns) == 1
619
+ else f"std::get<{i}>({out_name})"
620
+ )
621
+ copy_outs.append(
622
+ f"""\
623
+ resize_out_helper({out_arg.name}, {functional_return_name});
624
+ copy_arg({out_arg.name}, {functional_return_name});"""
625
+ )
626
+
627
+ rets = []
628
+ # For each return arg in the calling (out=) operator,
629
+ # If it corresponds to an aliased input, return the input.
630
+ # Otherwise, return the corresponding output from calling the functional operator.
631
+ for i, ret_name in enumerate(g.out.func.aliased_return_names()):
632
+ if ret_name is not None:
633
+ rets.append(ret_name)
634
+ else:
635
+ functional_return_name = (
636
+ out_name
637
+ if len(g.functional.func.returns) == 1
638
+ else f"std::get<{i}>({out_name})"
639
+ )
640
+ rets.append(functional_return_name)
641
+
642
+ copy_outs_str = "\n".join(copy_outs)
643
+
644
+ # Kernel name needs to follow the naming convention defined in `generate_function()`
645
+ return f"""
646
+ {sig.defn(name=g.out.func.name.unambiguous_name() + ("_symint" if g.out.func.has_symint() else ""))} {{
647
+ auto {out_name} = at::_ops::{g.functional.func.name.unambiguous_name()}::call({exprs});
648
+ {copy_outs_str}
649
+ {return_str(g.out.func.returns, rets)}
650
+ }}
651
+ """
normalizer.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:655847268f9ff668e36268319e9e202056c33038014bec44346f031db40ac9b5
3
+ size 108450
numpy-2.0.2-cp312-cp312-win_amd64.whl ADDED
File without changes
numpy-config.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:980d55316535217f8748a295df5784e4eb26100a1110bae9a110492242fe7c34
3
+ size 108440
pip.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6bf6f1c22184613cb885fc8cadd6e9407d20d1ebcafec3282fbd1a52c25210a8
3
+ size 108445
pip3.12.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6bf6f1c22184613cb885fc8cadd6e9407d20d1ebcafec3282fbd1a52c25210a8
3
+ size 108445
pip3.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6bf6f1c22184613cb885fc8cadd6e9407d20d1ebcafec3282fbd1a52c25210a8
3
+ size 108445
pygmentize.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be176558d7b05f8849604d14f1885243e5c96fd78711fdccd01ef12014e41a1b
3
+ size 108439
python.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3470f7919170d235d7e6079691462c4b217745ec67ee612e745730e46d98f238
3
+ size 270104
pythonw.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dbb5bf39746dadaf2d2513da6746ed61a04b493289272dbed72923eabfd552f8
3
+ size 258840
saved_model_cli.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:abeeaed0c37d09ad4bb9710ee2af44fd6eb08053cd4b4528e7ca6f5c1a709ee6
3
+ size 108462
six.py ADDED
@@ -0,0 +1,1003 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2010-2024 Benjamin Peterson
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ """Utilities for writing code that runs on Python 2 and 3"""
22
+
23
+ from __future__ import absolute_import
24
+
25
+ import functools
26
+ import itertools
27
+ import operator
28
+ import sys
29
+ import types
30
+
31
+ __author__ = "Benjamin Peterson <[email protected]>"
32
+ __version__ = "1.17.0"
33
+
34
+
35
+ # Useful for very coarse version differentiation.
36
+ PY2 = sys.version_info[0] == 2
37
+ PY3 = sys.version_info[0] == 3
38
+ PY34 = sys.version_info[0:2] >= (3, 4)
39
+
40
+ if PY3:
41
+ string_types = str,
42
+ integer_types = int,
43
+ class_types = type,
44
+ text_type = str
45
+ binary_type = bytes
46
+
47
+ MAXSIZE = sys.maxsize
48
+ else:
49
+ string_types = basestring,
50
+ integer_types = (int, long)
51
+ class_types = (type, types.ClassType)
52
+ text_type = unicode
53
+ binary_type = str
54
+
55
+ if sys.platform.startswith("java"):
56
+ # Jython always uses 32 bits.
57
+ MAXSIZE = int((1 << 31) - 1)
58
+ else:
59
+ # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
60
+ class X(object):
61
+
62
+ def __len__(self):
63
+ return 1 << 31
64
+ try:
65
+ len(X())
66
+ except OverflowError:
67
+ # 32-bit
68
+ MAXSIZE = int((1 << 31) - 1)
69
+ else:
70
+ # 64-bit
71
+ MAXSIZE = int((1 << 63) - 1)
72
+ del X
73
+
74
+ if PY34:
75
+ from importlib.util import spec_from_loader
76
+ else:
77
+ spec_from_loader = None
78
+
79
+
80
+ def _add_doc(func, doc):
81
+ """Add documentation to a function."""
82
+ func.__doc__ = doc
83
+
84
+
85
+ def _import_module(name):
86
+ """Import module, returning the module after the last dot."""
87
+ __import__(name)
88
+ return sys.modules[name]
89
+
90
+
91
+ class _LazyDescr(object):
92
+
93
+ def __init__(self, name):
94
+ self.name = name
95
+
96
+ def __get__(self, obj, tp):
97
+ result = self._resolve()
98
+ setattr(obj, self.name, result) # Invokes __set__.
99
+ try:
100
+ # This is a bit ugly, but it avoids running this again by
101
+ # removing this descriptor.
102
+ delattr(obj.__class__, self.name)
103
+ except AttributeError:
104
+ pass
105
+ return result
106
+
107
+
108
+ class MovedModule(_LazyDescr):
109
+
110
+ def __init__(self, name, old, new=None):
111
+ super(MovedModule, self).__init__(name)
112
+ if PY3:
113
+ if new is None:
114
+ new = name
115
+ self.mod = new
116
+ else:
117
+ self.mod = old
118
+
119
+ def _resolve(self):
120
+ return _import_module(self.mod)
121
+
122
+ def __getattr__(self, attr):
123
+ _module = self._resolve()
124
+ value = getattr(_module, attr)
125
+ setattr(self, attr, value)
126
+ return value
127
+
128
+
129
+ class _LazyModule(types.ModuleType):
130
+
131
+ def __init__(self, name):
132
+ super(_LazyModule, self).__init__(name)
133
+ self.__doc__ = self.__class__.__doc__
134
+
135
+ def __dir__(self):
136
+ attrs = ["__doc__", "__name__"]
137
+ attrs += [attr.name for attr in self._moved_attributes]
138
+ return attrs
139
+
140
+ # Subclasses should override this
141
+ _moved_attributes = []
142
+
143
+
144
+ class MovedAttribute(_LazyDescr):
145
+
146
+ def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
147
+ super(MovedAttribute, self).__init__(name)
148
+ if PY3:
149
+ if new_mod is None:
150
+ new_mod = name
151
+ self.mod = new_mod
152
+ if new_attr is None:
153
+ if old_attr is None:
154
+ new_attr = name
155
+ else:
156
+ new_attr = old_attr
157
+ self.attr = new_attr
158
+ else:
159
+ self.mod = old_mod
160
+ if old_attr is None:
161
+ old_attr = name
162
+ self.attr = old_attr
163
+
164
+ def _resolve(self):
165
+ module = _import_module(self.mod)
166
+ return getattr(module, self.attr)
167
+
168
+
169
+ class _SixMetaPathImporter(object):
170
+
171
+ """
172
+ A meta path importer to import six.moves and its submodules.
173
+
174
+ This class implements a PEP302 finder and loader. It should be compatible
175
+ with Python 2.5 and all existing versions of Python3
176
+ """
177
+
178
+ def __init__(self, six_module_name):
179
+ self.name = six_module_name
180
+ self.known_modules = {}
181
+
182
+ def _add_module(self, mod, *fullnames):
183
+ for fullname in fullnames:
184
+ self.known_modules[self.name + "." + fullname] = mod
185
+
186
+ def _get_module(self, fullname):
187
+ return self.known_modules[self.name + "." + fullname]
188
+
189
+ def find_module(self, fullname, path=None):
190
+ if fullname in self.known_modules:
191
+ return self
192
+ return None
193
+
194
+ def find_spec(self, fullname, path, target=None):
195
+ if fullname in self.known_modules:
196
+ return spec_from_loader(fullname, self)
197
+ return None
198
+
199
+ def __get_module(self, fullname):
200
+ try:
201
+ return self.known_modules[fullname]
202
+ except KeyError:
203
+ raise ImportError("This loader does not know module " + fullname)
204
+
205
+ def load_module(self, fullname):
206
+ try:
207
+ # in case of a reload
208
+ return sys.modules[fullname]
209
+ except KeyError:
210
+ pass
211
+ mod = self.__get_module(fullname)
212
+ if isinstance(mod, MovedModule):
213
+ mod = mod._resolve()
214
+ else:
215
+ mod.__loader__ = self
216
+ sys.modules[fullname] = mod
217
+ return mod
218
+
219
+ def is_package(self, fullname):
220
+ """
221
+ Return true, if the named module is a package.
222
+
223
+ We need this method to get correct spec objects with
224
+ Python 3.4 (see PEP451)
225
+ """
226
+ return hasattr(self.__get_module(fullname), "__path__")
227
+
228
+ def get_code(self, fullname):
229
+ """Return None
230
+
231
+ Required, if is_package is implemented"""
232
+ self.__get_module(fullname) # eventually raises ImportError
233
+ return None
234
+ get_source = get_code # same as get_code
235
+
236
+ def create_module(self, spec):
237
+ return self.load_module(spec.name)
238
+
239
+ def exec_module(self, module):
240
+ pass
241
+
242
+ _importer = _SixMetaPathImporter(__name__)
243
+
244
+
245
+ class _MovedItems(_LazyModule):
246
+
247
+ """Lazy loading of moved objects"""
248
+ __path__ = [] # mark as package
249
+
250
+
251
+ _moved_attributes = [
252
+ MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
253
+ MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
254
+ MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
255
+ MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
256
+ MovedAttribute("intern", "__builtin__", "sys"),
257
+ MovedAttribute("map", "itertools", "builtins", "imap", "map"),
258
+ MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
259
+ MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
260
+ MovedAttribute("getoutput", "commands", "subprocess"),
261
+ MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
262
+ MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
263
+ MovedAttribute("reduce", "__builtin__", "functools"),
264
+ MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
265
+ MovedAttribute("StringIO", "StringIO", "io"),
266
+ MovedAttribute("UserDict", "UserDict", "collections", "IterableUserDict", "UserDict"),
267
+ MovedAttribute("UserList", "UserList", "collections"),
268
+ MovedAttribute("UserString", "UserString", "collections"),
269
+ MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
270
+ MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
271
+ MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
272
+ MovedModule("builtins", "__builtin__"),
273
+ MovedModule("configparser", "ConfigParser"),
274
+ MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"),
275
+ MovedModule("copyreg", "copy_reg"),
276
+ MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
277
+ MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
278
+ MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"),
279
+ MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
280
+ MovedModule("http_cookies", "Cookie", "http.cookies"),
281
+ MovedModule("html_entities", "htmlentitydefs", "html.entities"),
282
+ MovedModule("html_parser", "HTMLParser", "html.parser"),
283
+ MovedModule("http_client", "httplib", "http.client"),
284
+ MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
285
+ MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
286
+ MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
287
+ MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
288
+ MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
289
+ MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
290
+ MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
291
+ MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
292
+ MovedModule("cPickle", "cPickle", "pickle"),
293
+ MovedModule("queue", "Queue"),
294
+ MovedModule("reprlib", "repr"),
295
+ MovedModule("socketserver", "SocketServer"),
296
+ MovedModule("_thread", "thread", "_thread"),
297
+ MovedModule("tkinter", "Tkinter"),
298
+ MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
299
+ MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
300
+ MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
301
+ MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
302
+ MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
303
+ MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
304
+ MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
305
+ MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
306
+ MovedModule("tkinter_colorchooser", "tkColorChooser",
307
+ "tkinter.colorchooser"),
308
+ MovedModule("tkinter_commondialog", "tkCommonDialog",
309
+ "tkinter.commondialog"),
310
+ MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
311
+ MovedModule("tkinter_font", "tkFont", "tkinter.font"),
312
+ MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
313
+ MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
314
+ "tkinter.simpledialog"),
315
+ MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
316
+ MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
317
+ MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
318
+ MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
319
+ MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
320
+ MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
321
+ ]
322
+ # Add windows specific modules.
323
+ if sys.platform == "win32":
324
+ _moved_attributes += [
325
+ MovedModule("winreg", "_winreg"),
326
+ ]
327
+
328
+ for attr in _moved_attributes:
329
+ setattr(_MovedItems, attr.name, attr)
330
+ if isinstance(attr, MovedModule):
331
+ _importer._add_module(attr, "moves." + attr.name)
332
+ del attr
333
+
334
+ _MovedItems._moved_attributes = _moved_attributes
335
+
336
+ moves = _MovedItems(__name__ + ".moves")
337
+ _importer._add_module(moves, "moves")
338
+
339
+
340
+ class Module_six_moves_urllib_parse(_LazyModule):
341
+
342
+ """Lazy loading of moved objects in six.moves.urllib_parse"""
343
+
344
+
345
+ _urllib_parse_moved_attributes = [
346
+ MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
347
+ MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
348
+ MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
349
+ MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
350
+ MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
351
+ MovedAttribute("urljoin", "urlparse", "urllib.parse"),
352
+ MovedAttribute("urlparse", "urlparse", "urllib.parse"),
353
+ MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
354
+ MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
355
+ MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
356
+ MovedAttribute("quote", "urllib", "urllib.parse"),
357
+ MovedAttribute("quote_plus", "urllib", "urllib.parse"),
358
+ MovedAttribute("unquote", "urllib", "urllib.parse"),
359
+ MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
360
+ MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"),
361
+ MovedAttribute("urlencode", "urllib", "urllib.parse"),
362
+ MovedAttribute("splitquery", "urllib", "urllib.parse"),
363
+ MovedAttribute("splittag", "urllib", "urllib.parse"),
364
+ MovedAttribute("splituser", "urllib", "urllib.parse"),
365
+ MovedAttribute("splitvalue", "urllib", "urllib.parse"),
366
+ MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
367
+ MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
368
+ MovedAttribute("uses_params", "urlparse", "urllib.parse"),
369
+ MovedAttribute("uses_query", "urlparse", "urllib.parse"),
370
+ MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
371
+ ]
372
+ for attr in _urllib_parse_moved_attributes:
373
+ setattr(Module_six_moves_urllib_parse, attr.name, attr)
374
+ del attr
375
+
376
+ Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
377
+
378
+ _importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
379
+ "moves.urllib_parse", "moves.urllib.parse")
380
+
381
+
382
+ class Module_six_moves_urllib_error(_LazyModule):
383
+
384
+ """Lazy loading of moved objects in six.moves.urllib_error"""
385
+
386
+
387
+ _urllib_error_moved_attributes = [
388
+ MovedAttribute("URLError", "urllib2", "urllib.error"),
389
+ MovedAttribute("HTTPError", "urllib2", "urllib.error"),
390
+ MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
391
+ ]
392
+ for attr in _urllib_error_moved_attributes:
393
+ setattr(Module_six_moves_urllib_error, attr.name, attr)
394
+ del attr
395
+
396
+ Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
397
+
398
+ _importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
399
+ "moves.urllib_error", "moves.urllib.error")
400
+
401
+
402
+ class Module_six_moves_urllib_request(_LazyModule):
403
+
404
+ """Lazy loading of moved objects in six.moves.urllib_request"""
405
+
406
+
407
+ _urllib_request_moved_attributes = [
408
+ MovedAttribute("urlopen", "urllib2", "urllib.request"),
409
+ MovedAttribute("install_opener", "urllib2", "urllib.request"),
410
+ MovedAttribute("build_opener", "urllib2", "urllib.request"),
411
+ MovedAttribute("pathname2url", "urllib", "urllib.request"),
412
+ MovedAttribute("url2pathname", "urllib", "urllib.request"),
413
+ MovedAttribute("getproxies", "urllib", "urllib.request"),
414
+ MovedAttribute("Request", "urllib2", "urllib.request"),
415
+ MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
416
+ MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
417
+ MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
418
+ MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
419
+ MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
420
+ MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
421
+ MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
422
+ MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
423
+ MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
424
+ MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
425
+ MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
426
+ MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
427
+ MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
428
+ MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
429
+ MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
430
+ MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
431
+ MovedAttribute("FileHandler", "urllib2", "urllib.request"),
432
+ MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
433
+ MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
434
+ MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
435
+ MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
436
+ MovedAttribute("urlretrieve", "urllib", "urllib.request"),
437
+ MovedAttribute("urlcleanup", "urllib", "urllib.request"),
438
+ MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
439
+ MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
440
+ MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
441
+ ]
442
+ if sys.version_info[:2] < (3, 14):
443
+ _urllib_request_moved_attributes.extend(
444
+ [
445
+ MovedAttribute("URLopener", "urllib", "urllib.request"),
446
+ MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
447
+ ]
448
+ )
449
+ for attr in _urllib_request_moved_attributes:
450
+ setattr(Module_six_moves_urllib_request, attr.name, attr)
451
+ del attr
452
+
453
+ Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
454
+
455
+ _importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
456
+ "moves.urllib_request", "moves.urllib.request")
457
+
458
+
459
+ class Module_six_moves_urllib_response(_LazyModule):
460
+
461
+ """Lazy loading of moved objects in six.moves.urllib_response"""
462
+
463
+
464
+ _urllib_response_moved_attributes = [
465
+ MovedAttribute("addbase", "urllib", "urllib.response"),
466
+ MovedAttribute("addclosehook", "urllib", "urllib.response"),
467
+ MovedAttribute("addinfo", "urllib", "urllib.response"),
468
+ MovedAttribute("addinfourl", "urllib", "urllib.response"),
469
+ ]
470
+ for attr in _urllib_response_moved_attributes:
471
+ setattr(Module_six_moves_urllib_response, attr.name, attr)
472
+ del attr
473
+
474
+ Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
475
+
476
+ _importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
477
+ "moves.urllib_response", "moves.urllib.response")
478
+
479
+
480
+ class Module_six_moves_urllib_robotparser(_LazyModule):
481
+
482
+ """Lazy loading of moved objects in six.moves.urllib_robotparser"""
483
+
484
+
485
+ _urllib_robotparser_moved_attributes = [
486
+ MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
487
+ ]
488
+ for attr in _urllib_robotparser_moved_attributes:
489
+ setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
490
+ del attr
491
+
492
+ Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
493
+
494
+ _importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
495
+ "moves.urllib_robotparser", "moves.urllib.robotparser")
496
+
497
+
498
+ class Module_six_moves_urllib(types.ModuleType):
499
+
500
+ """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
501
+ __path__ = [] # mark as package
502
+ parse = _importer._get_module("moves.urllib_parse")
503
+ error = _importer._get_module("moves.urllib_error")
504
+ request = _importer._get_module("moves.urllib_request")
505
+ response = _importer._get_module("moves.urllib_response")
506
+ robotparser = _importer._get_module("moves.urllib_robotparser")
507
+
508
+ def __dir__(self):
509
+ return ['parse', 'error', 'request', 'response', 'robotparser']
510
+
511
+ _importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
512
+ "moves.urllib")
513
+
514
+
515
+ def add_move(move):
516
+ """Add an item to six.moves."""
517
+ setattr(_MovedItems, move.name, move)
518
+
519
+
520
+ def remove_move(name):
521
+ """Remove item from six.moves."""
522
+ try:
523
+ delattr(_MovedItems, name)
524
+ except AttributeError:
525
+ try:
526
+ del moves.__dict__[name]
527
+ except KeyError:
528
+ raise AttributeError("no such move, %r" % (name,))
529
+
530
+
531
+ if PY3:
532
+ _meth_func = "__func__"
533
+ _meth_self = "__self__"
534
+
535
+ _func_closure = "__closure__"
536
+ _func_code = "__code__"
537
+ _func_defaults = "__defaults__"
538
+ _func_globals = "__globals__"
539
+ else:
540
+ _meth_func = "im_func"
541
+ _meth_self = "im_self"
542
+
543
+ _func_closure = "func_closure"
544
+ _func_code = "func_code"
545
+ _func_defaults = "func_defaults"
546
+ _func_globals = "func_globals"
547
+
548
+
549
+ try:
550
+ advance_iterator = next
551
+ except NameError:
552
+ def advance_iterator(it):
553
+ return it.next()
554
+ next = advance_iterator
555
+
556
+
557
+ try:
558
+ callable = callable
559
+ except NameError:
560
+ def callable(obj):
561
+ return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
562
+
563
+
564
+ if PY3:
565
+ def get_unbound_function(unbound):
566
+ return unbound
567
+
568
+ create_bound_method = types.MethodType
569
+
570
+ def create_unbound_method(func, cls):
571
+ return func
572
+
573
+ Iterator = object
574
+ else:
575
+ def get_unbound_function(unbound):
576
+ return unbound.im_func
577
+
578
+ def create_bound_method(func, obj):
579
+ return types.MethodType(func, obj, obj.__class__)
580
+
581
+ def create_unbound_method(func, cls):
582
+ return types.MethodType(func, None, cls)
583
+
584
+ class Iterator(object):
585
+
586
+ def next(self):
587
+ return type(self).__next__(self)
588
+
589
+ callable = callable
590
+ _add_doc(get_unbound_function,
591
+ """Get the function out of a possibly unbound function""")
592
+
593
+
594
+ get_method_function = operator.attrgetter(_meth_func)
595
+ get_method_self = operator.attrgetter(_meth_self)
596
+ get_function_closure = operator.attrgetter(_func_closure)
597
+ get_function_code = operator.attrgetter(_func_code)
598
+ get_function_defaults = operator.attrgetter(_func_defaults)
599
+ get_function_globals = operator.attrgetter(_func_globals)
600
+
601
+
602
+ if PY3:
603
+ def iterkeys(d, **kw):
604
+ return iter(d.keys(**kw))
605
+
606
+ def itervalues(d, **kw):
607
+ return iter(d.values(**kw))
608
+
609
+ def iteritems(d, **kw):
610
+ return iter(d.items(**kw))
611
+
612
+ def iterlists(d, **kw):
613
+ return iter(d.lists(**kw))
614
+
615
+ viewkeys = operator.methodcaller("keys")
616
+
617
+ viewvalues = operator.methodcaller("values")
618
+
619
+ viewitems = operator.methodcaller("items")
620
+ else:
621
+ def iterkeys(d, **kw):
622
+ return d.iterkeys(**kw)
623
+
624
+ def itervalues(d, **kw):
625
+ return d.itervalues(**kw)
626
+
627
+ def iteritems(d, **kw):
628
+ return d.iteritems(**kw)
629
+
630
+ def iterlists(d, **kw):
631
+ return d.iterlists(**kw)
632
+
633
+ viewkeys = operator.methodcaller("viewkeys")
634
+
635
+ viewvalues = operator.methodcaller("viewvalues")
636
+
637
+ viewitems = operator.methodcaller("viewitems")
638
+
639
+ _add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
640
+ _add_doc(itervalues, "Return an iterator over the values of a dictionary.")
641
+ _add_doc(iteritems,
642
+ "Return an iterator over the (key, value) pairs of a dictionary.")
643
+ _add_doc(iterlists,
644
+ "Return an iterator over the (key, [values]) pairs of a dictionary.")
645
+
646
+
647
+ if PY3:
648
+ def b(s):
649
+ return s.encode("latin-1")
650
+
651
+ def u(s):
652
+ return s
653
+ unichr = chr
654
+ import struct
655
+ int2byte = struct.Struct(">B").pack
656
+ del struct
657
+ byte2int = operator.itemgetter(0)
658
+ indexbytes = operator.getitem
659
+ iterbytes = iter
660
+ import io
661
+ StringIO = io.StringIO
662
+ BytesIO = io.BytesIO
663
+ del io
664
+ _assertCountEqual = "assertCountEqual"
665
+ if sys.version_info[1] <= 1:
666
+ _assertRaisesRegex = "assertRaisesRegexp"
667
+ _assertRegex = "assertRegexpMatches"
668
+ _assertNotRegex = "assertNotRegexpMatches"
669
+ else:
670
+ _assertRaisesRegex = "assertRaisesRegex"
671
+ _assertRegex = "assertRegex"
672
+ _assertNotRegex = "assertNotRegex"
673
+ else:
674
+ def b(s):
675
+ return s
676
+ # Workaround for standalone backslash
677
+
678
+ def u(s):
679
+ return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
680
+ unichr = unichr
681
+ int2byte = chr
682
+
683
+ def byte2int(bs):
684
+ return ord(bs[0])
685
+
686
+ def indexbytes(buf, i):
687
+ return ord(buf[i])
688
+ iterbytes = functools.partial(itertools.imap, ord)
689
+ import StringIO
690
+ StringIO = BytesIO = StringIO.StringIO
691
+ _assertCountEqual = "assertItemsEqual"
692
+ _assertRaisesRegex = "assertRaisesRegexp"
693
+ _assertRegex = "assertRegexpMatches"
694
+ _assertNotRegex = "assertNotRegexpMatches"
695
+ _add_doc(b, """Byte literal""")
696
+ _add_doc(u, """Text literal""")
697
+
698
+
699
+ def assertCountEqual(self, *args, **kwargs):
700
+ return getattr(self, _assertCountEqual)(*args, **kwargs)
701
+
702
+
703
+ def assertRaisesRegex(self, *args, **kwargs):
704
+ return getattr(self, _assertRaisesRegex)(*args, **kwargs)
705
+
706
+
707
+ def assertRegex(self, *args, **kwargs):
708
+ return getattr(self, _assertRegex)(*args, **kwargs)
709
+
710
+
711
+ def assertNotRegex(self, *args, **kwargs):
712
+ return getattr(self, _assertNotRegex)(*args, **kwargs)
713
+
714
+
715
+ if PY3:
716
+ exec_ = getattr(moves.builtins, "exec")
717
+
718
+ def reraise(tp, value, tb=None):
719
+ try:
720
+ if value is None:
721
+ value = tp()
722
+ if value.__traceback__ is not tb:
723
+ raise value.with_traceback(tb)
724
+ raise value
725
+ finally:
726
+ value = None
727
+ tb = None
728
+
729
+ else:
730
+ def exec_(_code_, _globs_=None, _locs_=None):
731
+ """Execute code in a namespace."""
732
+ if _globs_ is None:
733
+ frame = sys._getframe(1)
734
+ _globs_ = frame.f_globals
735
+ if _locs_ is None:
736
+ _locs_ = frame.f_locals
737
+ del frame
738
+ elif _locs_ is None:
739
+ _locs_ = _globs_
740
+ exec("""exec _code_ in _globs_, _locs_""")
741
+
742
+ exec_("""def reraise(tp, value, tb=None):
743
+ try:
744
+ raise tp, value, tb
745
+ finally:
746
+ tb = None
747
+ """)
748
+
749
+
750
+ if sys.version_info[:2] > (3,):
751
+ exec_("""def raise_from(value, from_value):
752
+ try:
753
+ raise value from from_value
754
+ finally:
755
+ value = None
756
+ """)
757
+ else:
758
+ def raise_from(value, from_value):
759
+ raise value
760
+
761
+
762
+ print_ = getattr(moves.builtins, "print", None)
763
+ if print_ is None:
764
+ def print_(*args, **kwargs):
765
+ """The new-style print function for Python 2.4 and 2.5."""
766
+ fp = kwargs.pop("file", sys.stdout)
767
+ if fp is None:
768
+ return
769
+
770
+ def write(data):
771
+ if not isinstance(data, basestring):
772
+ data = str(data)
773
+ # If the file has an encoding, encode unicode with it.
774
+ if (isinstance(fp, file) and
775
+ isinstance(data, unicode) and
776
+ fp.encoding is not None):
777
+ errors = getattr(fp, "errors", None)
778
+ if errors is None:
779
+ errors = "strict"
780
+ data = data.encode(fp.encoding, errors)
781
+ fp.write(data)
782
+ want_unicode = False
783
+ sep = kwargs.pop("sep", None)
784
+ if sep is not None:
785
+ if isinstance(sep, unicode):
786
+ want_unicode = True
787
+ elif not isinstance(sep, str):
788
+ raise TypeError("sep must be None or a string")
789
+ end = kwargs.pop("end", None)
790
+ if end is not None:
791
+ if isinstance(end, unicode):
792
+ want_unicode = True
793
+ elif not isinstance(end, str):
794
+ raise TypeError("end must be None or a string")
795
+ if kwargs:
796
+ raise TypeError("invalid keyword arguments to print()")
797
+ if not want_unicode:
798
+ for arg in args:
799
+ if isinstance(arg, unicode):
800
+ want_unicode = True
801
+ break
802
+ if want_unicode:
803
+ newline = unicode("\n")
804
+ space = unicode(" ")
805
+ else:
806
+ newline = "\n"
807
+ space = " "
808
+ if sep is None:
809
+ sep = space
810
+ if end is None:
811
+ end = newline
812
+ for i, arg in enumerate(args):
813
+ if i:
814
+ write(sep)
815
+ write(arg)
816
+ write(end)
817
+ if sys.version_info[:2] < (3, 3):
818
+ _print = print_
819
+
820
+ def print_(*args, **kwargs):
821
+ fp = kwargs.get("file", sys.stdout)
822
+ flush = kwargs.pop("flush", False)
823
+ _print(*args, **kwargs)
824
+ if flush and fp is not None:
825
+ fp.flush()
826
+
827
+ _add_doc(reraise, """Reraise an exception.""")
828
+
829
+ if sys.version_info[0:2] < (3, 4):
830
+ # This does exactly the same what the :func:`py3:functools.update_wrapper`
831
+ # function does on Python versions after 3.2. It sets the ``__wrapped__``
832
+ # attribute on ``wrapper`` object and it doesn't raise an error if any of
833
+ # the attributes mentioned in ``assigned`` and ``updated`` are missing on
834
+ # ``wrapped`` object.
835
+ def _update_wrapper(wrapper, wrapped,
836
+ assigned=functools.WRAPPER_ASSIGNMENTS,
837
+ updated=functools.WRAPPER_UPDATES):
838
+ for attr in assigned:
839
+ try:
840
+ value = getattr(wrapped, attr)
841
+ except AttributeError:
842
+ continue
843
+ else:
844
+ setattr(wrapper, attr, value)
845
+ for attr in updated:
846
+ getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
847
+ wrapper.__wrapped__ = wrapped
848
+ return wrapper
849
+ _update_wrapper.__doc__ = functools.update_wrapper.__doc__
850
+
851
+ def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
852
+ updated=functools.WRAPPER_UPDATES):
853
+ return functools.partial(_update_wrapper, wrapped=wrapped,
854
+ assigned=assigned, updated=updated)
855
+ wraps.__doc__ = functools.wraps.__doc__
856
+
857
+ else:
858
+ wraps = functools.wraps
859
+
860
+
861
+ def with_metaclass(meta, *bases):
862
+ """Create a base class with a metaclass."""
863
+ # This requires a bit of explanation: the basic idea is to make a dummy
864
+ # metaclass for one level of class instantiation that replaces itself with
865
+ # the actual metaclass.
866
+ class metaclass(type):
867
+
868
+ def __new__(cls, name, this_bases, d):
869
+ if sys.version_info[:2] >= (3, 7):
870
+ # This version introduced PEP 560 that requires a bit
871
+ # of extra care (we mimic what is done by __build_class__).
872
+ resolved_bases = types.resolve_bases(bases)
873
+ if resolved_bases is not bases:
874
+ d['__orig_bases__'] = bases
875
+ else:
876
+ resolved_bases = bases
877
+ return meta(name, resolved_bases, d)
878
+
879
+ @classmethod
880
+ def __prepare__(cls, name, this_bases):
881
+ return meta.__prepare__(name, bases)
882
+ return type.__new__(metaclass, 'temporary_class', (), {})
883
+
884
+
885
+ def add_metaclass(metaclass):
886
+ """Class decorator for creating a class with a metaclass."""
887
+ def wrapper(cls):
888
+ orig_vars = cls.__dict__.copy()
889
+ slots = orig_vars.get('__slots__')
890
+ if slots is not None:
891
+ if isinstance(slots, str):
892
+ slots = [slots]
893
+ for slots_var in slots:
894
+ orig_vars.pop(slots_var)
895
+ orig_vars.pop('__dict__', None)
896
+ orig_vars.pop('__weakref__', None)
897
+ if hasattr(cls, '__qualname__'):
898
+ orig_vars['__qualname__'] = cls.__qualname__
899
+ return metaclass(cls.__name__, cls.__bases__, orig_vars)
900
+ return wrapper
901
+
902
+
903
+ def ensure_binary(s, encoding='utf-8', errors='strict'):
904
+ """Coerce **s** to six.binary_type.
905
+
906
+ For Python 2:
907
+ - `unicode` -> encoded to `str`
908
+ - `str` -> `str`
909
+
910
+ For Python 3:
911
+ - `str` -> encoded to `bytes`
912
+ - `bytes` -> `bytes`
913
+ """
914
+ if isinstance(s, binary_type):
915
+ return s
916
+ if isinstance(s, text_type):
917
+ return s.encode(encoding, errors)
918
+ raise TypeError("not expecting type '%s'" % type(s))
919
+
920
+
921
+ def ensure_str(s, encoding='utf-8', errors='strict'):
922
+ """Coerce *s* to `str`.
923
+
924
+ For Python 2:
925
+ - `unicode` -> encoded to `str`
926
+ - `str` -> `str`
927
+
928
+ For Python 3:
929
+ - `str` -> `str`
930
+ - `bytes` -> decoded to `str`
931
+ """
932
+ # Optimization: Fast return for the common case.
933
+ if type(s) is str:
934
+ return s
935
+ if PY2 and isinstance(s, text_type):
936
+ return s.encode(encoding, errors)
937
+ elif PY3 and isinstance(s, binary_type):
938
+ return s.decode(encoding, errors)
939
+ elif not isinstance(s, (text_type, binary_type)):
940
+ raise TypeError("not expecting type '%s'" % type(s))
941
+ return s
942
+
943
+
944
+ def ensure_text(s, encoding='utf-8', errors='strict'):
945
+ """Coerce *s* to six.text_type.
946
+
947
+ For Python 2:
948
+ - `unicode` -> `unicode`
949
+ - `str` -> `unicode`
950
+
951
+ For Python 3:
952
+ - `str` -> `str`
953
+ - `bytes` -> decoded to `str`
954
+ """
955
+ if isinstance(s, binary_type):
956
+ return s.decode(encoding, errors)
957
+ elif isinstance(s, text_type):
958
+ return s
959
+ else:
960
+ raise TypeError("not expecting type '%s'" % type(s))
961
+
962
+
963
+ def python_2_unicode_compatible(klass):
964
+ """
965
+ A class decorator that defines __unicode__ and __str__ methods under Python 2.
966
+ Under Python 3 it does nothing.
967
+
968
+ To support Python 2 and 3 with a single code base, define a __str__ method
969
+ returning text and apply this decorator to the class.
970
+ """
971
+ if PY2:
972
+ if '__str__' not in klass.__dict__:
973
+ raise ValueError("@python_2_unicode_compatible cannot be applied "
974
+ "to %s because it doesn't define __str__()." %
975
+ klass.__name__)
976
+ klass.__unicode__ = klass.__str__
977
+ klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
978
+ return klass
979
+
980
+
981
+ # Complete the moves implementation.
982
+ # This code is at the end of this module to speed up module loading.
983
+ # Turn this module into a package.
984
+ __path__ = [] # required for PEP 302 and PEP 451
985
+ __package__ = __name__ # see PEP 366 @ReservedAssignment
986
+ if globals().get("__spec__") is not None:
987
+ __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
988
+ # Remove other six meta path importers, since they cause problems. This can
989
+ # happen if six is removed from sys.modules and then reloaded. (Setuptools does
990
+ # this for some reason.)
991
+ if sys.meta_path:
992
+ for i, importer in enumerate(sys.meta_path):
993
+ # Here's some real nastiness: Another "instance" of the six module might
994
+ # be floating around. Therefore, we can't use isinstance() to check for
995
+ # the six meta path importer, since the other six instance will have
996
+ # inserted an importer with different class.
997
+ if (type(importer).__name__ == "_SixMetaPathImporter" and
998
+ importer.name == __name__):
999
+ del sys.meta_path[i]
1000
+ break
1001
+ del i, importer
1002
+ # Finally, add the importer to the meta path import hook.
1003
+ sys.meta_path.append(_importer)