|
73 | 73 | "from line_profiler import profile, LineProfiler\n",
|
74 | 74 | "from time import time\n",
|
75 | 75 | "\n",
|
| 76 | + "\n", |
76 | 77 | "def Lanczos_PRO_original(A, q, m=None, toll=np.sqrt(np.finfo(float).eps)):\n",
|
77 | 78 | " \"\"\"\n",
|
78 | 79 | " Perform the Lanczos algorithm for symmetric matrices.\n",
|
|
134 | 135 | " if np.abs(beta[j]) < 1e-15:\n",
|
135 | 136 | " return Q, alpha, beta[:-1]\n",
|
136 | 137 | "\n",
|
137 |
| - "\n", |
138 | 138 | " return Q, alpha, beta[:-1]\n",
|
139 | 139 | "\n",
|
140 | 140 | "\n",
|
141 |
| - "#@jit(parallel=True) \n", |
142 |
| - "def Lanczos_PRO(A, q, m=None, toll=np.sqrt(np.finfo(float).eps)):\n", |
| 141 | + "# @jit(parallel=True)\n", |
| 142 | + "def Lanczos_PRO(A, q, m=None, toll=np.sqrt(np.finfo(float).eps)):\n", |
143 | 143 | " \"\"\"\n",
|
144 | 144 | " Lanczos algorithm for symmetric matrices\n",
|
145 | 145 | " :param A: symmetric matrix square matrix of size n\n",
|
|
152 | 152 | " alpha: vector of size m. Diagonal of the tridiagonal matrix\n",
|
153 | 153 | " beta: vector of size m-1. Upper diagonal of the tridiagonal matrix\n",
|
154 | 154 | " \"\"\"\n",
|
155 |
| - " if m==None:\n", |
156 |
| - " m=A.shape[0]\n", |
157 |
| - " \n", |
158 |
| - " q=q/np.linalg.norm(q)\n", |
159 |
| - " #Q=np.array([q])\n", |
| 155 | + " if m == None:\n", |
| 156 | + " m = A.shape[0]\n", |
| 157 | + "\n", |
| 158 | + " q = q / np.linalg.norm(q)\n", |
| 159 | + " # Q=np.array([q])\n", |
160 | 160 | " Q = np.zeros((m, A.shape[0]))\n",
|
161 | 161 | " Q[0] = q\n",
|
162 |
| - " r=A@q\n", |
163 |
| - " alpha=[]\n", |
164 |
| - " beta=[]\n", |
165 |
| - " alpha.append(q@r)\n", |
166 |
| - " r=r-alpha[0]*q\n", |
| 162 | + " r = A @ q\n", |
| 163 | + " alpha = []\n", |
| 164 | + " beta = []\n", |
| 165 | + " alpha.append(q @ r)\n", |
| 166 | + " r = r - alpha[0] * q\n", |
167 | 167 | " beta.append(np.linalg.norm(r))\n",
|
168 | 168 | "\n",
|
169 | 169 | " for j in range(1, m):\n",
|
170 |
| - " q=r/beta[j-1]\n", |
171 |
| - " if np.any(np.abs(q@Q[:j-1].T)>toll):\n", |
172 |
| - " for q_bbasis in Q[:j-1]:\n", |
| 170 | + " q = r / beta[j - 1]\n", |
| 171 | + " if np.any(np.abs(q @ Q[: j - 1].T) > toll):\n", |
| 172 | + " for q_bbasis in Q[: j - 1]:\n", |
173 | 173 | " q = q - (q @ q_bbasis) * q_bbasis\n",
|
174 | 174 | " # for i in prange(j-1):\n",
|
175 | 175 | " # q = q - (q @ Q[i]) * Q[i]\n",
|
176 | 176 | "\n",
|
177 |
| - " q=q/np.linalg.norm(q)\n", |
178 |
| - " Q[j]=q\n", |
179 |
| - " r=A@q-beta[j-1]*Q[j-1]\n", |
180 |
| - " alpha.append(q@r)\n", |
181 |
| - " r=r-alpha[j]*q\n", |
| 177 | + " q = q / np.linalg.norm(q)\n", |
| 178 | + " Q[j] = q\n", |
| 179 | + " r = A @ q - beta[j - 1] * Q[j - 1]\n", |
| 180 | + " alpha.append(q @ r)\n", |
| 181 | + " r = r - alpha[j] * q\n", |
182 | 182 | " beta.append(np.linalg.norm(r))\n",
|
183 | 183 | "\n",
|
184 |
| - " if np.abs(beta[j])<1e-15:\n", |
185 |
| - " \n", |
| 184 | + " if np.abs(beta[j]) < 1e-15:\n", |
| 185 | + "\n", |
186 | 186 | " return Q, alpha, beta[:-1]\n",
|
187 |
| - " return Q, alpha, beta[:-1]\n", |
188 |
| - "\n" |
| 187 | + " return Q, alpha, beta[:-1]" |
189 | 188 | ]
|
190 | 189 | },
|
191 | 190 | {
|
|
331 | 330 | "size = 1000\n",
|
332 | 331 | "A = np.random.rand(size, size)\n",
|
333 | 332 | "A = (A + A.T) / 2\n",
|
334 |
| - "A=np.array(A, dtype=float)\n", |
| 333 | + "A = np.array(A, dtype=float)\n", |
335 | 334 | "q = np.random.rand(size)\n",
|
336 | 335 | "lp = LineProfiler()\n",
|
337 | 336 | "lp.add_function(Lanczos_PRO_original)\n",
|
338 |
| - "result = lp.run('Lanczos_PRO_original(A, q)')\n", |
339 |
| - "#lp.print_stats()\n", |
340 |
| - "#Q, alpha, beta = Lanczos_PRO(A, q)\n", |
| 337 | + "result = lp.run(\"Lanczos_PRO_original(A, q)\")\n", |
| 338 | + "# lp.print_stats()\n", |
| 339 | + "# Q, alpha, beta = Lanczos_PRO(A, q)\n", |
341 | 340 | "\n",
|
342 | 341 | "\n",
|
343 |
| - "\n", |
344 |
| - "t_s=time()\n", |
| 342 | + "t_s = time()\n", |
345 | 343 | "lp.add_function(Lanczos_PRO)\n",
|
346 |
| - "result = lp.run('Lanczos_PRO(A, q)')\n", |
| 344 | + "result = lp.run(\"Lanczos_PRO(A, q)\")\n", |
347 | 345 | "lp.print_stats()\n",
|
348 | 346 | "\n",
|
349 |
| - "t_e=time()\n", |
350 |
| - "print(f\"Optimized function time: {t_e-t_s}\")\n", |
351 |
| - "\n" |
| 347 | + "t_e = time()\n", |
| 348 | + "print(f\"Optimized function time: {t_e-t_s}\")" |
352 | 349 | ]
|
353 | 350 | },
|
354 | 351 | {
|
|
388 | 385 | " A = A_copy.copy()\n",
|
389 | 386 | " iter = 0\n",
|
390 | 387 | " Q = np.eye(A.shape[0])\n",
|
391 |
| - " \n", |
| 388 | + "\n", |
392 | 389 | " # Correctly preallocate as a 2D array (n-1, 2)\n",
|
393 | 390 | " Matrix_trigonometry = np.zeros((A.shape[0] - 1, 2))\n",
|
394 | 391 | "\n",
|
|
397 | 394 | " for i in range(A.shape[0] - 1):\n",
|
398 | 395 | " c = A[i, i] / np.sqrt(A[i, i] ** 2 + A[i + 1, i] ** 2)\n",
|
399 | 396 | " s = -A[i + 1, i] / np.sqrt(A[i, i] ** 2 + A[i + 1, i] ** 2)\n",
|
400 |
| - " Matrix_trigonometry[i, :] = [c, s] \n", |
401 |
| - " R=np.eye(A.shape[0])\n", |
| 397 | + " Matrix_trigonometry[i, :] = [c, s]\n", |
| 398 | + " R = np.eye(A.shape[0])\n", |
402 | 399 | " # Apply the Givens rotation to A (modify in place)\n",
|
403 |
| - " R[i:i+2, i:i+2] = np.array([[c, -s], [s, c]])\n", |
404 |
| - " A= R @ A\n", |
405 |
| - " A[i+1, i] = 0 \n", |
406 |
| - "\n", |
407 |
| - "\n", |
408 |
| - " Q=np.eye(A.shape[0])\n", |
409 |
| - " i=0\n", |
410 |
| - " Q[0:2, 0:2]=np.array([[Matrix_trigonometry[i, 0], Matrix_trigonometry[i, 1]], [-Matrix_trigonometry[i, 1], Matrix_trigonometry[i, 0]]])\n", |
411 |
| - " for i in range(1, A.shape[0]-1):\n", |
412 |
| - " R=np.eye(A.shape[0])\n", |
413 |
| - " R[i: i+2, i:i+2]=np.array([[Matrix_trigonometry[i, 0], Matrix_trigonometry[i, 1]], [-Matrix_trigonometry[i, 1], Matrix_trigonometry[i, 0]]])\n", |
414 |
| - " Q = Q@R\n", |
415 |
| - " A=A@Q\n", |
| 400 | + " R[i : i + 2, i : i + 2] = np.array([[c, -s], [s, c]])\n", |
| 401 | + " A = R @ A\n", |
| 402 | + " A[i + 1, i] = 0\n", |
| 403 | + "\n", |
| 404 | + " Q = np.eye(A.shape[0])\n", |
| 405 | + " i = 0\n", |
| 406 | + " Q[0:2, 0:2] = np.array(\n", |
| 407 | + " [\n", |
| 408 | + " [Matrix_trigonometry[i, 0], Matrix_trigonometry[i, 1]],\n", |
| 409 | + " [-Matrix_trigonometry[i, 1], Matrix_trigonometry[i, 0]],\n", |
| 410 | + " ]\n", |
| 411 | + " )\n", |
| 412 | + " for i in range(1, A.shape[0] - 1):\n", |
| 413 | + " R = np.eye(A.shape[0])\n", |
| 414 | + " R[i : i + 2, i : i + 2] = np.array(\n", |
| 415 | + " [\n", |
| 416 | + " [Matrix_trigonometry[i, 0], Matrix_trigonometry[i, 1]],\n", |
| 417 | + " [-Matrix_trigonometry[i, 1], Matrix_trigonometry[i, 0]],\n", |
| 418 | + " ]\n", |
| 419 | + " )\n", |
| 420 | + " Q = Q @ R\n", |
| 421 | + " A = A @ Q\n", |
416 | 422 | " A = A @ Q # Update A\n",
|
417 | 423 | " iter += 1\n",
|
418 | 424 | "\n",
|
|
421 | 427 | "\n",
|
422 | 428 | " return np.diag(A), Q\n",
|
423 | 429 | "\n",
|
424 |
| - "#@jit(nopython=True)\n", |
| 430 | + "\n", |
| 431 | + "# @jit(nopython=True)\n", |
425 | 432 | "def QR_method_optimized(A_copy, tol=1e-10, max_iter=100):\n",
|
426 | 433 | " A = A_copy.copy()\n",
|
427 | 434 | " iter = 0\n",
|
428 | 435 | " Q = np.eye(A.shape[0])\n",
|
429 |
| - " \n", |
| 436 | + "\n", |
430 | 437 | " # Correctly preallocate as a 2D array (n-1, 2)\n",
|
431 | 438 | " Matrix_trigonometry = np.zeros((A.shape[0] - 1, 2))\n",
|
432 |
| - " d=np.zeros(A.shape[0])\n", |
433 |
| - " #while np.linalg.norm((np.diag(A, -1)), np.inf) > tol and iter < max_iter:\n", |
434 |
| - " while np.linalg.norm((np.diag(A, 0)-d)/np.diag(A, 0), np.inf) > tol and iter < max_iter:\n", |
| 439 | + " d = np.zeros(A.shape[0])\n", |
| 440 | + " # while np.linalg.norm((np.diag(A, -1)), np.inf) > tol and iter < max_iter:\n", |
| 441 | + " while (\n", |
| 442 | + " np.linalg.norm((np.diag(A, 0) - d) / np.diag(A, 0), np.inf) > tol\n", |
| 443 | + " and iter < max_iter\n", |
| 444 | + " ):\n", |
435 | 445 | " # Compute Givens rotation\n",
|
436 |
| - " d=np.diag(A, 0)\n", |
| 446 | + " d = np.diag(A, 0)\n", |
437 | 447 | " for i in range(A.shape[0] - 1):\n",
|
438 | 448 | " c = A[i, i] / np.sqrt(A[i, i] ** 2 + A[i + 1, i] ** 2)\n",
|
439 | 449 | " s = -A[i + 1, i] / np.sqrt(A[i, i] ** 2 + A[i + 1, i] ** 2)\n",
|
440 |
| - " Matrix_trigonometry[i, :] = [c, s] \n", |
| 450 | + " Matrix_trigonometry[i, :] = [c, s]\n", |
441 | 451 | "\n",
|
442 | 452 | " # Apply the Givens rotation to A (modify in place)\n",
|
443 | 453 | " R = np.array([[c, -s], [s, c]])\n",
|
444 |
| - " A[i:i+2, i:] = R @ A[i:i+2, i:]\n", |
445 |
| - " A[i+1, i] = 0 \n", |
| 454 | + " A[i : i + 2, i:] = R @ A[i : i + 2, i:]\n", |
| 455 | + " A[i + 1, i] = 0\n", |
446 | 456 | "\n",
|
447 | 457 | " # Construct full Q matrix from stored Givens rotations\n",
|
448 | 458 | " Q = np.eye(A.shape[0])\n",
|
449 | 459 | " for i in range(A.shape[0] - 1):\n",
|
450 |
| - " R=np.array([[Matrix_trigonometry[i, 0], Matrix_trigonometry[i, 1]], [-Matrix_trigonometry[i, 1], Matrix_trigonometry[i, 0]]])\n", |
451 |
| - " Q[:, i:i+2] = Q[:, i:i+2]@R\n", |
| 460 | + " R = np.array(\n", |
| 461 | + " [\n", |
| 462 | + " [Matrix_trigonometry[i, 0], Matrix_trigonometry[i, 1]],\n", |
| 463 | + " [-Matrix_trigonometry[i, 1], Matrix_trigonometry[i, 0]],\n", |
| 464 | + " ]\n", |
| 465 | + " )\n", |
| 466 | + " Q[:, i : i + 2] = Q[:, i : i + 2] @ R\n", |
452 | 467 | " A = A @ Q # Update A\n",
|
453 | 468 | " iter += 1\n",
|
454 | 469 | "\n",
|
455 | 470 | " return np.diag(A), Q\n",
|
456 | 471 | "\n",
|
457 | 472 | "\n",
|
458 |
| - "\n", |
459 |
| - "\n", |
460 |
| - "\n", |
461 | 473 | "np.random.seed(0)\n",
|
462 | 474 | "size = 300\n",
|
463 | 475 | "A = np.random.rand(size, size)\n",
|
|
466 | 478 | "\n",
|
467 | 479 | "q, alpha, beta = Lanczos_PRO(A, x0, size)\n",
|
468 | 480 | "\n",
|
469 |
| - "T=np.diag(alpha)+np.diag(beta, k=1)+np.diag(beta, k=-1)\n", |
| 481 | + "T = np.diag(alpha) + np.diag(beta, k=1) + np.diag(beta, k=-1)\n", |
470 | 482 | "QR_method_optimized(T)\n",
|
471 | 483 | "lp_QR = LineProfiler()\n",
|
472 | 484 | "lp_QR.add_function(QR_method)\n",
|
473 |
| - "result = lp_QR.run('QR_method(T)')\n", |
| 485 | + "result = lp_QR.run(\"QR_method(T)\")\n", |
474 | 486 | "\n",
|
475 | 487 | "\n",
|
476 | 488 | "lp_QR.add_function(QR_method_optimized)\n",
|
477 |
| - "result = lp_QR.run('QR_method_optimized(T)')\n", |
| 489 | + "result = lp_QR.run(\"QR_method_optimized(T)\")\n", |
478 | 490 | "lp_QR.print_stats()\n",
|
479 | 491 | "# t_s=time()\n",
|
480 | 492 | "# result= QR_method_optimized(T)\n",
|
481 | 493 | "# t_e=time()\n",
|
482 |
| - "# print(f\"Optimized function time: {t_e-t_s}\")\n", |
483 |
| - "\n" |
| 494 | + "# print(f\"Optimized function time: {t_e-t_s}\")" |
484 | 495 | ]
|
485 | 496 | },
|
486 | 497 | {
|
|
513 | 524 | "x0 = np.random.rand(size)\n",
|
514 | 525 | "q, alpha, beta = Lanczos_PRO(A, x0, size)\n",
|
515 | 526 | "\n",
|
516 |
| - "t_s=time()\n", |
| 527 | + "t_s = time()\n", |
517 | 528 | "np.linalg.eig(A)\n",
|
518 |
| - "t_e=time()\n", |
| 529 | + "t_e = time()\n", |
519 | 530 | "\n",
|
520 | 531 | "print(f\"{t_e-t_s: .4e}\")\n",
|
521 | 532 | "\n",
|
522 | 533 | "# T=np.diag(alpha)+np.diag(beta, k=1)+np.diag(beta, k=-1)\n",
|
523 | 534 | "# t_s=time()\n",
|
524 | 535 | "# result= QR_method_optimized(T, max_iter=5000, tol=1e-6)\n",
|
525 | 536 | "# t_e=time()\n",
|
526 |
| - "# print(f\"Optimized function time: {t_e-t_s}\")\n", |
527 |
| - "\n" |
| 537 | + "# print(f\"Optimized function time: {t_e-t_s}\")" |
528 | 538 | ]
|
529 | 539 | }
|
530 | 540 | ],
|
|
0 commit comments